From 0ba4e6d9e0ecd42b6c8c320bca3fd590d07dede7 Mon Sep 17 00:00:00 2001 From: Sam Hocevar Date: Mon, 28 Jan 2013 13:23:57 +0000 Subject: [PATCH] easymesh: interface the shiny shader with new Light objects. --- src/Makefile.am | 1 + src/core.h | 1 + src/easymesh/easymesh.cpp | 12 +++++ src/easymesh/easymesh.h | 2 +- src/easymesh/shiny.lolfx | 87 +++++++++++++++++-------------------- src/entity.h | 1 + src/light.cpp | 71 ++++++++++++++++++++++++++++++ src/light.h | 50 +++++++++++++++++++++ src/lolcore.vcxproj | 2 + src/lolcore.vcxproj.filters | 6 +++ src/scene.cpp | 48 ++++++++++++-------- src/scene.h | 4 ++ tutorial/05_easymesh.cpp | 15 +++++++ 13 files changed, 233 insertions(+), 67 deletions(-) create mode 100644 src/light.cpp create mode 100644 src/light.h diff --git a/src/Makefile.am b/src/Makefile.am index 5a21c005..0a922dfe 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/core.h b/src/core.h index ca338a51..930dd7f5 100644 --- a/src/core.h +++ b/src/core.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" diff --git a/src/easymesh/easymesh.cpp b/src/easymesh/easymesh.cpp index 18c0f52a..cf10c029 100644 --- a/src/easymesh/easymesh.cpp +++ b/src/easymesh/easymesh.cpp @@ -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 const lights = Scene::GetDefault()->GetLights(); + Array 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())); diff --git a/src/easymesh/easymesh.h b/src/easymesh/easymesh.h index 29f19b9b..1857ed65 100644 --- a/src/easymesh/easymesh.h +++ b/src/easymesh/easymesh.h @@ -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; diff --git a/src/easymesh/shiny.lolfx b/src/easymesh/shiny.lolfx index 54b05154..ff335dd4 100644 --- a/src/easymesh/shiny.lolfx +++ b/src/easymesh/shiny.lolfx @@ -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); } diff --git a/src/entity.h b/src/entity.h index fa7e396c..12233124 100644 --- a/src/entity.h +++ b/src/entity.h @@ -59,6 +59,7 @@ protected: enum { DRAWGROUP_BEFORE = GAMEGROUP_END, + DRAWGROUP_LIGHT, DRAWGROUP_CAMERA, DRAWGROUP_DEFAULT, DRAWGROUP_HUD, diff --git a/src/light.cpp b/src/light.cpp new file mode 100644 index 00000000..efd31473 --- /dev/null +++ b/src/light.cpp @@ -0,0 +1,71 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Sam Hocevar +// 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 +#include + +#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 */ + diff --git a/src/light.h b/src/light.h new file mode 100644 index 00000000..d9bcd2be --- /dev/null +++ b/src/light.h @@ -0,0 +1,50 @@ +// +// Lol Engine +// +// Copyright: (c) 2010-2013 Sam Hocevar +// 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 ""; } + + 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__ */ + diff --git a/src/lolcore.vcxproj b/src/lolcore.vcxproj index 09411af1..c8684da2 100644 --- a/src/lolcore.vcxproj +++ b/src/lolcore.vcxproj @@ -273,6 +273,7 @@ + @@ -583,6 +584,7 @@ + diff --git a/src/lolcore.vcxproj.filters b/src/lolcore.vcxproj.filters index 60028b51..8500b59d 100644 --- a/src/lolcore.vcxproj.filters +++ b/src/lolcore.vcxproj.filters @@ -189,6 +189,9 @@ ... + + ... + ... @@ -776,6 +779,9 @@ ... + + ... + ... diff --git a/src/scene.cpp b/src/scene.cpp index a3765145..0511902d 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -61,7 +61,8 @@ private: mat4 m_view_matrix; mat4 m_proj_matrix; - Array tiles; + Array m_tiles; + Array 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 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(); diff --git a/src/scene.h b/src/scene.h index 952d5a01..e54a8385 100644 --- a/src/scene.h +++ b/src/scene.h @@ -19,6 +19,7 @@ #include #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 const &GetLights() const; + private: SceneData *data; }; diff --git a/tutorial/05_easymesh.cpp b/tutorial/05_easymesh.cpp index 7cd42dbf..38c19491 100644 --- a/tutorial/05_easymesh.cpp +++ b/tutorial/05_easymesh.cpp @@ -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; };