diff options
-rw-r--r-- | Scripts/init.lua | 45 | ||||
-rw-r--r-- | Shaders/world.frag | 85 | ||||
-rw-r--r-- | Shaders/world.vert | 4 | ||||
-rw-r--r-- | src/components/Light.hpp | 54 | ||||
-rw-r--r-- | src/components/Render.hpp | 6 | ||||
-rw-r--r-- | src/render.cpp | 36 | ||||
-rw-r--r-- | src/script.cpp | 13 |
7 files changed, 239 insertions, 4 deletions
diff --git a/Scripts/init.lua b/Scripts/init.lua index 9983c98..37b1f0d 100644 --- a/Scripts/init.lua +++ b/Scripts/init.lua @@ -17,6 +17,12 @@ bird = { texture = "Assets/player.png", visible = true }, + Light = { + r = 1.0, + g = 1.0, + b = 1.0, + strength = 1.0 + }, Idle = function(self) --if (self.visibleTick >= 20) then -- self.Render.visible = not self.Render.visible @@ -38,6 +44,7 @@ cat = { }, Render = { texture = "Assets/cat.png", + normal = "Assets/cat_normal.png", visible = true }, Init = function(self) @@ -61,6 +68,12 @@ animal = { texture = "Assets/rabbit.png", visible = true }, + Light = { + r = 0.0, + b = 1.0, + g = 0.2, + strength = 2.0 + }, Idle = function(self) self.Velocity.x = -200 * math.sin(math.rad(self.counter)); self.Velocity.y = 500 * math.cos(math.rad(self.counter*5)); @@ -69,8 +82,40 @@ animal = { counter = 0; } +wall = { + Position = { + y = -100 + }, + Render = { + texture = "Assets/rock.png", + normal = "Assets/rock_normal.png", + visible = true + } +} + birdSpawn = game.spawn(bird); dogSpawn = game.spawn(cat); animalSpawn = game.spawn(animal); + +wallSpawn = game.spawn(wall); + +game.spawn({ + Velocity = { + x = 0, + y = 0 + }, + Light = { + r = 0.8, + g = 0.1, + b = 0.2, + strength = 0.75 + }, + counter = 0; + Idle = function(self) + self.Velocity.x = -100 * math.sin(math.rad(self.counter)); + self.Velocity.y = 100 * math.cos(math.rad(self.counter)); + self.counter = self.counter + 5; + end +}); diff --git a/Shaders/world.frag b/Shaders/world.frag index ded3ec0..5ef399d 100644 --- a/Shaders/world.frag +++ b/Shaders/world.frag @@ -7,11 +7,94 @@ precision mediump float; #endif uniform sampler2D textu; +uniform sampler2D normu; in vec2 texCoord; +in vec4 fragCoord; out vec4 FragColor; +uniform vec3 LightPos[32]; +uniform vec4 LightColor[32]; +uniform int LightNum; + void main() { - FragColor = texture(textu, texCoord); + //vec3 LightPos = vec3(0.0, 0.0, 0.0); + //vec4 LightColor = vec4(1.0, 1.0, 1.0, 1.0); + vec3 Falloff = vec3(0.1, 0.2, 0.0); + + vec4 DiffuseColor = texture2D(textu, texCoord); + + if (DiffuseColor.a < 0.1f) + discard; + + vec3 NormalMap = texture2D(normu, texCoord).rgb; + vec3 SumLight = vec3(0.0); + + for (int i = 0; i < LightNum; i++) { + vec3 LightDir = vec3(LightPos[i].xy - fragCoord.xy, LightPos[i].z); + + float D = length(LightDir); + + vec3 N = normalize(NormalMap * 2.0 - 1.0); + vec3 L = normalize(LightDir); + + vec3 Diffuse = (LightColor[i].rgb * LightColor[i].a) * max(dot(N, L), 0.0); + + vec3 Ambient = vec3(0.0); + + float Attenuation = + 1.0 / (Falloff.x + (Falloff.y * D) + (Falloff.z * D * D)); + + vec3 Intensity = Ambient + Diffuse + Attenuation; + vec3 FinalColor = DiffuseColor.rgb * Intensity; + + SumLight += FinalColor; + } + + FragColor = vec4(SumLight, DiffuseColor.a); +}; + +/* + vec4 normalMap = texture2D(normu, texCoord); + vec3 normal = normalMap.xyz * 2.0 - 1.0; + + if (pixTex.a < 0.1f) + discard; + + vec4 shadeColor = vec4(0.0f, 0.0f, 0.0f, 0.0f); + + float dist = length(light.xy - fragCoord.xy); + if (dist < light.w) { + float attenuation = clamp(1.0f - dist*dist/(light.w*light.w), 0.0f, 1.0f); + attenuation *= attenuation; + shadeColor += vec4(attenuation, attenuation, attenuation, 1.0f) * vec4(normal.xyz, 1); + //shadeColor = vec4(1.0) + 0.1*normal; + //shadeColor = vec4(1.0); + } + + //FragColor = pixTex * shadeColor; + FragColor = vec4(normal.xyz, 1); } +*/ + +/* + vec2 texLoc = vec2(texCoord.x, 1-texCoord.y); + vec4 pixTex = texture2D(texture, texLoc); + if (pixTex.a < 0.1f) + discard; + + vec4 shadeColor = vec4(0.0f, 0.0f, 0.0f, 0.0f); + if (lightImpact > 0.0f) { + for (int i = 0; i < lightSize; i++) { + vec2 loc = light[i].xy; + float dist = length(loc - fragCoord.xy); + if (dist < light[i].w) { + float attenuation = clamp(1.0f - dist*dist/(light[i].w*light[i].w), 0.0f, 1.0f); + attenuation *= attenuation; + shadeColor += (vec4(attenuation, attenuation, attenuation, 0.0f) * vec4(lightColor[i])) * lightImpact; + } + } + } + shadeColor += ambientLight; +*/ diff --git a/Shaders/world.vert b/Shaders/world.vert index 743ff3d..0760183 100644 --- a/Shaders/world.vert +++ b/Shaders/world.vert @@ -9,9 +9,11 @@ uniform mat4 view; uniform mat4 model; out vec2 texCoord; +out vec4 fragCoord; void main() { texCoord = texc; - gl_Position = projection * view * model * vec4(vertex, 1.0f); + fragCoord = vec4(vertex, 1.0f); + gl_Position = projection * view * model * fragCoord; } diff --git a/src/components/Light.hpp b/src/components/Light.hpp new file mode 100644 index 0000000..ee215a6 --- /dev/null +++ b/src/components/Light.hpp @@ -0,0 +1,54 @@ +/** + * @file Light.hpp + * + * Copyright (C) 2019 Belle-Isle, Andrew <drumsetmonkey@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef COMPONENT_LIGHT_HPP_ +#define COMPONENT_LIGHT_HPP_ + +#include "Component.hpp" + +struct Light : Component<Light>, entityx::Component<Light> +{ +public: + float r, g, b; + float strength; + + Light() {} + Light(float _r, float _g, float _z, float _s) : + r(_r), g(_g), b(_z), strength(_s) {} + + Light FromLua(sol::object ref) + { + if (ref.get_type() == sol::type::table) { + sol::table tab = ref; + if (tab["r"] == sol::type::number) + this->r = tab["r"]; + if (tab["g"] == sol::type::number) + this->g = tab["g"]; + if (tab["b"] == sol::type::number) + this->b = tab["b"]; + if (tab["strength"] == sol::type::number) + this->strength = tab["strength"]; + } else { + throw std::string("Light component must be a table"); + } + return *this; + } +}; + +#endif//COMPONENT_LIGHT_HPP_ diff --git a/src/components/Render.hpp b/src/components/Render.hpp index 6cc26db..f5936ea 100644 --- a/src/components/Render.hpp +++ b/src/components/Render.hpp @@ -25,7 +25,9 @@ struct Render : Component<Render>, entityx::Component<Render> { public: Texture texture; + Texture normal; bool visible; + bool hasNormal = false; Render(std::string _file) : texture(_file), visible(true) {} @@ -40,6 +42,10 @@ public: this->visible = tab["visible"]; if (tab["texture"].get_type() == sol::type::string) this->texture = Texture(static_cast<std::string>(tab["texture"])); + if (tab["normal"].get_type() == sol::type::string) { + this->normal = Texture(static_cast<std::string>(tab["normal"])); + hasNormal = true; + } } else { throw std::string( "Render component table formatted incorrectly" diff --git a/src/render.cpp b/src/render.cpp index 8e9cbdf..bd168ed 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -21,6 +21,7 @@ #include <render.hpp> #include <components/Render.hpp> #include <components/Position.hpp> +#include <components/Light.hpp> void RenderSystem::configure([[maybe_unused]] entityx::EntityManager& entities, [[maybe_unused]] entityx::EventManager& events) @@ -40,6 +41,7 @@ void RenderSystem::update([[maybe_unused]] entityx::EntityManager& entities, GLuint t = worldShader.getAttribute("texc"); GLuint q = worldShader.getUniform("textu"); + GLuint n = worldShader.getUniform("normu"); /*********** * SETUP * @@ -84,8 +86,29 @@ void RenderSystem::update([[maybe_unused]] entityx::EntityManager& entities, * DRAWING * *************/ + std::vector<glm::vec3> lightPos; + std::vector<glm::vec4> lightColor; + int lightNum = 0; + + entities.each<Light, Position>( + [&] + (entityx::Entity, Light &l, Position &p){ + + lightPos.push_back(glm::vec3(p.x, p.y, 0.0)); + lightColor.push_back(glm::vec4(l.r, l.g, l.b, l.strength)); + lightNum++; + }); + + glUniform1i(worldShader.getUniform("LightNum"), lightNum); + glUniform3fv(worldShader.getUniform("LightPos"), + lightPos.size(), + reinterpret_cast<GLfloat*>(lightPos.data())); + glUniform4fv(worldShader.getUniform("LightColor"), + lightColor.size(), + reinterpret_cast<GLfloat*>(lightColor.data())); + entities.each<Render, Position>( - [this, a, q, t](entityx::Entity, Render &r, Position &p) { + [this, a, q, t, n](entityx::Entity, Render &r, Position &p) { if (!r.visible) return; @@ -108,6 +131,10 @@ void RenderSystem::update([[maybe_unused]] entityx::EntityManager& entities, glBindTexture(GL_TEXTURE_2D, r.texture.tex); glUniform1i(q, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, r.normal.tex); + glUniform1i(n, 1); + glGenBuffers(1, &tri_vbo); glBindBuffer(GL_ARRAY_BUFFER, tri_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(tri_data), tri_data, GL_STREAM_DRAW); @@ -183,6 +210,11 @@ int RenderSystem::init(void) worldShader.addAttribute("texc"); worldShader.addUniform("textu"); + worldShader.addUniform("normu"); + + worldShader.addUniform("LightPos"); + worldShader.addUniform("LightColor"); + worldShader.addUniform("LightNum"); glEnableVertexAttribArray(worldShader.getAttribute("vertex")); glUseProgram(worldShader.getProgram()); @@ -190,7 +222,7 @@ int RenderSystem::init(void) // TODO //glPolygonOffset(1.0, 1.0); - glClearColor(0.6, 0.8, 1.0, 0.0); + //glClearColor(0.6, 0.8, 1.0, 0.0); return 0; } diff --git a/src/script.cpp b/src/script.cpp index 80ac538..30328ab 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -80,6 +80,7 @@ void ScriptSystem::doFile(void) #include <components/Render.hpp> #include <components/Script.hpp> #include <components/Velocity.hpp> +#include <components/Light.hpp> void ScriptSystem::scriptExport(void) { @@ -108,6 +109,13 @@ void ScriptSystem::scriptExport(void) lua.new_usertype<Player>("Player", sol::constructors<Player(void), Player()>()); + lua.new_usertype<Light>("Light", + sol::constructors<Light(float, float, float, float)>(), + "r", &Light::r, + "g", &Light::g, + "b", &Light::b, + "strength", &Light::strength); + auto gamespace = lua["game"].get_or_create<sol::table>(); gamespace.set_function("spawn", func); } @@ -162,6 +170,11 @@ sol::table ScriptSystem::spawn(sol::object param) (*toRet)["Player"] = e.assign<Player>().get(); } + if (tab["Light"] != nullptr) { + (*toRet)["Light"] = + e.assign<Light>(Light().FromLua(tab["Light"])).get(); + } + } else { // TODO better logging std::cerr << "Parameter to spawn() must be a table!" << std::endl; |