@@ -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; | |||
}; | |||