| @@ -14,6 +14,7 @@ liblol_a_SOURCES = \ | |||
| profiler.cpp profiler.h text.cpp text.h emitter.cpp emitter.h numeric.h \ | |||
| worldentity.cpp worldentity.h gradient.cpp gradient.h gradient.lolfx \ | |||
| platform.cpp platform.h sprite.cpp sprite.h camera.cpp camera.h \ | |||
| light.cpp light.h \ | |||
| \ | |||
| lol/base/log.h lol/base/array.h lol/base/types.h lol/base/array.h \ | |||
| lol/base/string.h lol/base/hash.h lol/base/map.h \ | |||
| @@ -116,6 +116,7 @@ static inline int isnan(float f) | |||
| #include "worldentity.h" | |||
| #include "camera.h" | |||
| #include "light.h" | |||
| #include "emitter.h" | |||
| #include "font.h" | |||
| #include "gradient.h" | |||
| @@ -79,6 +79,7 @@ void EasyMesh::MeshConvert(Shader* provided_shader) | |||
| m_gpu.proj = m_gpu.shader->GetUniformLocation("in_Proj"); | |||
| m_gpu.normalmat = m_gpu.shader->GetUniformLocation("in_NormalMat"); | |||
| m_gpu.damage = m_gpu.shader->GetUniformLocation("in_Damage"); | |||
| m_gpu.lights = m_gpu.shader->GetUniformLocation("u_Lights"); | |||
| m_gpu.coord = m_gpu.shader->GetAttribLocation("in_Vertex", | |||
| VertexUsage::Position, 0); | |||
| m_gpu.norm = m_gpu.shader->GetAttribLocation("in_Normal", | |||
| @@ -125,6 +126,17 @@ void EasyMesh::Render(mat4 const &model, float damage) | |||
| mat3 normalmat = transpose(inverse(mat3(modelview))); | |||
| m_gpu.shader->Bind(); | |||
| /* FIXME: this should be hidden in the shader */ | |||
| /* FIXME: the 4th component of the position can be used for other things */ | |||
| Array<Light *> const lights = Scene::GetDefault()->GetLights(); | |||
| Array<vec4> light_data; | |||
| for (int i = 0; i < lights.Count(); ++i) | |||
| light_data << lights[i]->GetPosition() << lights[i]->GetColor(); | |||
| while (light_data.Count() < 8) | |||
| light_data << vec4(0.f) << vec4(0.f); | |||
| m_gpu.shader->SetUniform(m_gpu.lights, light_data); | |||
| m_gpu.shader->SetUniform(m_gpu.modelview, modelview); | |||
| m_gpu.shader->SetUniform(m_gpu.view, Scene::GetDefault()->GetViewMatrix()); | |||
| m_gpu.shader->SetUniform(m_gpu.invview, inverse(Scene::GetDefault()->GetViewMatrix())); | |||
| @@ -119,7 +119,7 @@ private: | |||
| { | |||
| Shader *shader; | |||
| ShaderAttrib coord, norm, color; | |||
| ShaderUniform modelview, view, invview, proj, normalmat, damage; | |||
| ShaderUniform modelview, view, invview, proj, normalmat, damage, lights; | |||
| VertexDeclaration *vdecl; | |||
| VertexBuffer *vbo; | |||
| IndexBuffer *ibo; | |||
| @@ -38,24 +38,19 @@ uniform float in_Damage; | |||
| uniform mat4 in_View; | |||
| uniform mat4 in_Inv_View; | |||
| uniform vec4 u_Lights[8 * 2]; | |||
| varying vec4 pass_Vertex; /* View space */ | |||
| varying vec3 pass_TNormal; | |||
| varying vec4 pass_Color; | |||
| // FIXME: all the light parameters should be passed in the code | |||
| //Dir Light | |||
| vec3 in_LightDir = vec3(-0.3, -0.3, -0.7); | |||
| //Point Light | |||
| vec4 in_Light2_Pos = vec4(20.0, 10.0, 0.0, 1.0); | |||
| float in_Light2_Radius = 20.0; | |||
| vec3 in_Light2_diffuse = vec3(0.4, 0.4, 1.0); | |||
| #if 0 | |||
| //Cube Light | |||
| vec4 in_Light3_Pos = vec4(-10.0, 10.0, 5.0, 1.0); | |||
| vec3 in_Light3_Size_Inner = vec3(3.0, 1.0, 3.0); | |||
| vec3 in_Light3_Size_Outer = vec3(15.0, 15.0, 15.0); | |||
| vec3 in_Light3_diffuse = vec3(0.4, 1.0, 0.4); | |||
| #endif | |||
| void main(void) | |||
| { | |||
| @@ -64,53 +59,49 @@ void main(void) | |||
| float specular_power = 60.0; | |||
| /* World properties */ | |||
| float ambient_mul = 0.5; | |||
| vec3 ambient_color = vec3(0.0, 0.0, 0.0); | |||
| vec3 diffuse_color = vec3(0.4, 0.4, 0.4); | |||
| vec3 specular_color = vec3(1.0, 1.0, 0.6); | |||
| vec3 ambient = ambient_color; | |||
| vec3 ambient = vec3(0.1, 0.1, 0.1); | |||
| vec3 specular = vec3(0.0, 0.0, 0.0); | |||
| vec3 diffuse = vec3(0.0, 0.0, 0.0); | |||
| vec3 s = vec3(0.0, 0.0, 0.0); | |||
| vec3 v = vec3(0.0, 0.0, 0.0); | |||
| vec3 r = vec3(0.0, 0.0, 0.0); | |||
| float sdotn = 0.0; | |||
| float light_radius_mod = 0.0; | |||
| //Light calculation for directional light | |||
| s = normalize(-in_LightDir); | |||
| v = normalize(-pass_Vertex.xyz); | |||
| r = reflect(s, pass_TNormal); | |||
| sdotn = max(dot(s, pass_TNormal), 0.0); | |||
| diffuse += diffuse_color * sdotn; | |||
| if (sdotn > 0.0) | |||
| specular += specular_color * specular_reflect | |||
| * pow(max(dot(r, v), 0.0), specular_power); | |||
| //---------- | |||
| //Light calculation for point light | |||
| vec3 tmpLightDir = (in_View * in_Light2_Pos).xyz - pass_Vertex.xyz; | |||
| light_radius_mod = max(0.0, 1.0 - (length(tmpLightDir) / in_Light2_Radius)); | |||
| s = normalize(tmpLightDir); | |||
| v = normalize(-pass_Vertex.xyz); | |||
| r = reflect(-s, pass_TNormal); | |||
| sdotn = max(dot(s, pass_TNormal), 0.0); | |||
| diffuse += in_Light2_diffuse * min(sdotn, light_radius_mod); | |||
| if (sdotn > 0.0 && light_radius_mod > 0.0) | |||
| specular += specular_color * min(specular_reflect, light_radius_mod) | |||
| * pow(max(dot(r, v), 0.0), specular_power); | |||
| //---------- | |||
| /* Light precalculations */ | |||
| vec3 v = normalize(-pass_Vertex.xyz); | |||
| /* Apply lighting */ | |||
| for (int i = 0; i < 8; i++) | |||
| { | |||
| vec4 pos = u_Lights[i * 2]; | |||
| vec4 color = u_Lights[i * 2 + 1]; | |||
| vec3 s, r; | |||
| if (pos.w > 0.0) | |||
| { | |||
| /* Point light -- no attenuation yet */ | |||
| s = normalize((in_View * pos).xyz - pass_Vertex.xyz); | |||
| r = reflect(-s, pass_TNormal); | |||
| } | |||
| else | |||
| { | |||
| /* Directional light */ | |||
| s = normalize(-pos.xyz); | |||
| r = reflect(s, pass_TNormal); | |||
| } | |||
| float sdotn = max(dot(s, pass_TNormal), 0.0); | |||
| diffuse += color.xyz * sdotn; | |||
| if (sdotn > 0.0) | |||
| specular += color.xyz * specular_reflect | |||
| * pow(max(dot(r, v), 0.0), specular_power); | |||
| } | |||
| #if 0 | |||
| //Light calculation for cube light | |||
| vec3 specular_color = vec3(1.0, 1.0, 0.6); | |||
| vec3 Local_Vertex = (in_Inv_View * pass_Vertex).xyz - (in_Light3_Pos).xyz; | |||
| vec3 Proj_Vertex = clamp(Local_Vertex.xyz, -in_Light3_Size_Inner, in_Light3_Size_Inner); | |||
| vec3 new_LightDir = Local_Vertex - Proj_Vertex; | |||
| vec3 light_radius = max(vec3(0.0,0.0,0.0), vec3(1.0,1.0,1.0) - abs(new_LightDir / in_Light3_Size_Outer)); | |||
| light_radius_mod = min(light_radius.x, min(light_radius.y, light_radius.z)); | |||
| float light_radius_mod = min(light_radius.x, min(light_radius.y, light_radius.z)); | |||
| if (length(new_LightDir) == 0.0) | |||
| sdotn = 1.0; | |||
| @@ -125,11 +116,11 @@ void main(void) | |||
| } | |||
| diffuse += in_Light3_diffuse * min(sdotn, light_radius_mod); | |||
| //---------- | |||
| #endif | |||
| vec3 light = ambient + diffuse + specular; | |||
| vec4 real_color = in_Damage * vec4(1.2, 1.2, 1.2, 1.0) | |||
| + (1.0 - in_Damage) * pass_Color; | |||
| vec4 real_color = mix(pass_Color, vec4(1.2, 1.2, 1.2, 1.0), in_Damage); | |||
| gl_FragColor = real_color * vec4(light, 1.0); | |||
| } | |||
| @@ -59,6 +59,7 @@ protected: | |||
| enum | |||
| { | |||
| DRAWGROUP_BEFORE = GAMEGROUP_END, | |||
| DRAWGROUP_LIGHT, | |||
| DRAWGROUP_CAMERA, | |||
| DRAWGROUP_DEFAULT, | |||
| DRAWGROUP_HUD, | |||
| @@ -0,0 +1,71 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; you can redistribute it and/or | |||
| // modify it under the terms of the Do What The Fuck You Want To | |||
| // Public License, Version 2, as published by Sam Hocevar. See | |||
| // http://www.wtfpl.net/ for more details. | |||
| // | |||
| #if defined HAVE_CONFIG_H | |||
| # include "config.h" | |||
| #endif | |||
| #include <cstring> | |||
| #include <cstdlib> | |||
| #include "core.h" | |||
| namespace lol | |||
| { | |||
| Light::Light() | |||
| : m_color(1.f), | |||
| m_directional(true) | |||
| { | |||
| m_gamegroup = GAMEGROUP_BEFORE; | |||
| m_drawgroup = DRAWGROUP_CAMERA; | |||
| SetPosition(vec4(0.f)); | |||
| } | |||
| Light::~Light() | |||
| { | |||
| } | |||
| void Light::SetPosition(vec4 const &pos) | |||
| { | |||
| m_directional = (pos.w > 0.f); | |||
| m_position = pos.xyz; | |||
| } | |||
| vec4 Light::GetPosition() | |||
| { | |||
| return vec4(m_position, m_directional ? 1.f : 0.f); | |||
| } | |||
| void Light::SetColor(vec4 const &color) | |||
| { | |||
| m_color = color; | |||
| } | |||
| vec4 Light::GetColor() | |||
| { | |||
| return m_color; | |||
| } | |||
| void Light::TickGame(float seconds) | |||
| { | |||
| WorldEntity::TickGame(seconds); | |||
| } | |||
| void Light::TickDraw(float seconds) | |||
| { | |||
| WorldEntity::TickDraw(seconds); | |||
| Scene::GetDefault()->AddLight(this); | |||
| } | |||
| } /* namespace lol */ | |||
| @@ -0,0 +1,50 @@ | |||
| // | |||
| // Lol Engine | |||
| // | |||
| // Copyright: (c) 2010-2013 Sam Hocevar <sam@hocevar.net> | |||
| // This program is free software; you can redistribute it and/or | |||
| // modify it under the terms of the Do What The Fuck You Want To | |||
| // Public License, Version 2, as published by Sam Hocevar. See | |||
| // http://www.wtfpl.net/ for more details. | |||
| // | |||
| // | |||
| // The Light class | |||
| // --------------- | |||
| // | |||
| #if !defined __LIGHT_H__ | |||
| #define __LIGHT_H__ | |||
| #include "worldentity.h" | |||
| namespace lol | |||
| { | |||
| class Light : public WorldEntity | |||
| { | |||
| public: | |||
| Light(); | |||
| ~Light(); | |||
| char const *GetName() { return "<light>"; } | |||
| void SetColor(vec4 const &col); | |||
| vec4 GetColor(); | |||
| void SetPosition(vec4 const &pos); | |||
| vec4 GetPosition(); | |||
| protected: | |||
| virtual void TickGame(float seconds); | |||
| virtual void TickDraw(float seconds); | |||
| private: | |||
| vec4 m_color; | |||
| bool m_directional; | |||
| }; | |||
| } /* namespace lol */ | |||
| #endif /* __LIGHT_H__ */ | |||
| @@ -273,6 +273,7 @@ | |||
| <ClCompile Include="input\keyboard.cpp" /> | |||
| <ClCompile Include="input\stick.cpp" /> | |||
| <ClCompile Include="layer.cpp" /> | |||
| <ClCompile Include="light.cpp" /> | |||
| <ClCompile Include="map.cpp" /> | |||
| <ClCompile Include="math\geometry.cpp" /> | |||
| <ClCompile Include="math\half.cpp" /> | |||
| @@ -583,6 +584,7 @@ | |||
| <ClInclude Include="input\keyboard.h" /> | |||
| <ClInclude Include="input\stick.h" /> | |||
| <ClInclude Include="layer.h" /> | |||
| <ClInclude Include="light.h" /> | |||
| <ClInclude Include="loldebug.h" /> | |||
| <ClInclude Include="lolgl.h" /> | |||
| <ClInclude Include="lol\base\array.h" /> | |||
| @@ -189,6 +189,9 @@ | |||
| <ClCompile Include="layer.cpp"> | |||
| <Filter>...</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="light.cpp"> | |||
| <Filter>...</Filter> | |||
| </ClCompile> | |||
| <ClCompile Include="ticker.cpp"> | |||
| <Filter>...</Filter> | |||
| </ClCompile> | |||
| @@ -776,6 +779,9 @@ | |||
| <ClInclude Include="layer.h"> | |||
| <Filter>...</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="light.h"> | |||
| <Filter>...</Filter> | |||
| </ClInclude> | |||
| <ClInclude Include="loldebug.h"> | |||
| <Filter>...</Filter> | |||
| </ClInclude> | |||
| @@ -61,7 +61,8 @@ private: | |||
| mat4 m_view_matrix; | |||
| mat4 m_proj_matrix; | |||
| Array<Tile> tiles; | |||
| Array<Tile> m_tiles; | |||
| Array<Light *> m_lights; | |||
| Shader *m_shader; | |||
| VertexDeclaration *m_vdecl; | |||
| @@ -113,6 +114,7 @@ void Scene::Reset() | |||
| for (int i = 0; i < data->bufs.Count(); i++) | |||
| delete data->bufs[i]; | |||
| data->bufs.Empty(); | |||
| data->m_lights.Empty(); | |||
| } | |||
| void Scene::SetViewMatrix(mat4 const &m) | |||
| @@ -146,13 +148,23 @@ void Scene::AddTile(TileSet *tileset, int id, vec3 pos, int o, vec2 scale) | |||
| t.o = o; | |||
| t.scale = scale; | |||
| data->tiles.Push(t); | |||
| data->m_tiles.Push(t); | |||
| } | |||
| void Scene::AddLight(Light *l) | |||
| { | |||
| data->m_lights.Push(l); | |||
| } | |||
| Array<Light *> const &Scene::GetLights() const | |||
| { | |||
| return data->m_lights; | |||
| } | |||
| void Scene::Render() // XXX: rename to Blit() | |||
| { | |||
| /* Early exit if nothing needs to be rendered */ | |||
| if (!data->tiles.Count()) | |||
| if (!data->m_tiles.Count()) | |||
| return; | |||
| if (!data->m_shader) | |||
| @@ -160,15 +172,15 @@ void Scene::Render() // XXX: rename to Blit() | |||
| #if 0 | |||
| // Randomise, then sort. | |||
| for (int i = 0; i < data->tiles.Count(); i++) | |||
| for (int i = 0; i < data->m_tiles.Count(); i++) | |||
| { | |||
| Tile tmp = data->tiles[i]; | |||
| int j = rand() % data->tiles.Count(); | |||
| data->tiles[i] = data->tiles[j]; | |||
| data->tiles[j] = tmp; | |||
| Tile tmp = data->m_tiles[i]; | |||
| int j = rand() % data->m_tiles.Count(); | |||
| data->m_tiles[i] = data->m_tiles[j]; | |||
| data->m_tiles[j] = tmp; | |||
| } | |||
| #endif | |||
| qsort(&data->tiles[0], data->tiles.Count(), | |||
| qsort(&data->m_tiles[0], data->m_tiles.Count(), | |||
| sizeof(Tile), SceneData::Compare); | |||
| // XXX: debug stuff | |||
| @@ -219,11 +231,11 @@ void Scene::Render() // XXX: rename to Blit() | |||
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |||
| #endif | |||
| for (int buf = 0, i = 0, n; i < data->tiles.Count(); i = n, buf += 2) | |||
| for (int buf = 0, i = 0, n; i < data->m_tiles.Count(); i = n, buf += 2) | |||
| { | |||
| /* Count how many quads will be needed */ | |||
| for (n = i + 1; n < data->tiles.Count(); n++) | |||
| if (data->tiles[i].tileset != data->tiles[n].tileset) | |||
| for (n = i + 1; n < data->m_tiles.Count(); n++) | |||
| if (data->m_tiles[i].tileset != data->m_tiles[n].tileset) | |||
| break; | |||
| /* Create a vertex array object */ | |||
| @@ -237,9 +249,9 @@ void Scene::Render() // XXX: rename to Blit() | |||
| for (int j = i; j < n; j++) | |||
| { | |||
| data->tiles[i].tileset->BlitTile(data->tiles[j].id, | |||
| data->tiles[j].pos, data->tiles[j].o, | |||
| data->tiles[j].scale, | |||
| data->m_tiles[i].tileset->BlitTile(data->m_tiles[j].id, | |||
| data->m_tiles[j].pos, data->m_tiles[j].o, | |||
| data->m_tiles[j].scale, | |||
| vertex + 18 * (j - i), texture + 12 * (j - i)); | |||
| } | |||
| @@ -247,7 +259,7 @@ void Scene::Render() // XXX: rename to Blit() | |||
| vb2->Unlock(); | |||
| /* Bind texture */ | |||
| data->tiles[i].tileset->Bind(); | |||
| data->m_tiles[i].tileset->Bind(); | |||
| /* Bind vertex and texture coordinate buffers */ | |||
| data->m_vdecl->Bind(); | |||
| @@ -257,10 +269,10 @@ void Scene::Render() // XXX: rename to Blit() | |||
| /* Draw arrays */ | |||
| data->m_vdecl->DrawElements(MeshPrimitive::Triangles, 0, (n - i) * 6); | |||
| data->m_vdecl->Unbind(); | |||
| data->tiles[i].tileset->Unbind(); | |||
| data->m_tiles[i].tileset->Unbind(); | |||
| } | |||
| data->tiles.Empty(); | |||
| data->m_tiles.Empty(); | |||
| data->m_shader->Unbind(); | |||
| @@ -19,6 +19,7 @@ | |||
| #include <stdint.h> | |||
| #include "tileset.h" | |||
| #include "light.h" | |||
| namespace lol | |||
| { | |||
| @@ -45,6 +46,9 @@ public: | |||
| * the architecture we want to build */ | |||
| void AddTile(TileSet *tileset, int id, vec3 pos, int o, vec2 scale); | |||
| void AddLight(Light *light); | |||
| Array<Light *> const &GetLights() const; | |||
| private: | |||
| SceneData *data; | |||
| }; | |||
| @@ -54,12 +54,26 @@ public: | |||
| m_camera->SetPosition(vec3(-15.f, 5.f, 0.f)); | |||
| Ticker::Ref(m_camera); | |||
| /* Add a white directional light */ | |||
| m_light1 = new Light(); | |||
| m_light1->SetPosition(vec4(0.2f, 0.2f, 0.f, 0.f)); | |||
| m_light1->SetColor(vec4(0.5f, 0.5f, 0.5f, 1.f)); | |||
| Ticker::Ref(m_light1); | |||
| /* Add an orangeish point light */ | |||
| m_light2 = new Light(); | |||
| m_light2->SetPosition(vec4(-15.f, 15.f, 15.f, 1.f)); | |||
| m_light2->SetColor(vec4(0.4f, 0.3f, 0.2f, 1.f)); | |||
| Ticker::Ref(m_light2); | |||
| m_ready = false; | |||
| } | |||
| ~EasyMeshTutorial() | |||
| { | |||
| Ticker::Unref(m_camera); | |||
| Ticker::Unref(m_light1); | |||
| Ticker::Unref(m_light2); | |||
| } | |||
| virtual void TickGame(float seconds) | |||
| @@ -114,6 +128,7 @@ private: | |||
| float m_angle; | |||
| mat4 m_mat; | |||
| Camera *m_camera; | |||
| Light *m_light1, *m_light2; | |||
| bool m_ready; | |||
| }; | |||