diff --git a/include/reign.h b/include/reign.h
index 9018670..5ece7b9 100644
--- a/include/reign.h
+++ b/include/reign.h
@@ -91,9 +91,7 @@ struct RE_plugin {
bool use_power2_texture;
int shadow_map_resolution_level;
int texture_resolution_level;
- float global_ambient_r;
- float global_ambient_g;
- float global_ambient_b;
+ vec3 global_ambient;
float post_effect_filter_y;
float post_effect_filter_cb;
float post_effect_filter_cr;
@@ -108,16 +106,23 @@ struct RE_instance {
enum RE_instance_type type;
vec3 pos;
float pitch, roll, yaw; // in degrees
- vec3 vec;
vec3 scale;
float alpha;
bool draw;
float fps;
bool motion_blend;
float motion_blend_rate;
+ vec3 ambient;
+ // Lights
+ vec3 vec;
+ vec3 diffuse;
+ vec3 globe_diffuse;
+
+ // Private
bool local_transform_needs_update;
mat4 local_transform;
+ mat3 normal_transform;
mat4 *bone_transforms; // model->nr_bones elements
};
diff --git a/shaders/reign.f.glsl b/shaders/reign.f.glsl
index b65de50..bafb563 100644
--- a/shaders/reign.f.glsl
+++ b/shaders/reign.f.glsl
@@ -14,14 +14,49 @@
* along with this program; if not, see .
*/
+#define NR_DIR_LIGHTS 3
+
+struct dir_light {
+ vec3 dir;
+ vec3 diffuse;
+ vec3 globe_diffuse;
+};
+
uniform sampler2D tex;
uniform float alpha_mod;
+uniform vec3 ambient;
+uniform dir_light dir_lights[NR_DIR_LIGHTS];
+uniform vec3 specular_light_dir;
+uniform float specular_strength;
+uniform float specular_shininess;
+uniform vec3 view_pos;
+
in vec2 tex_coord;
+in vec3 normal;
+in vec3 frag_pos;
out vec4 frag_color;
void main() {
- // TODO: Implement lighting.
+ vec3 norm = normalize(normal);
+ vec3 frag_rgb = ambient;
+
+ // Diffuse lighting
+ vec3 diffuse = vec3(0.0);
+ for (int i = 0; i < NR_DIR_LIGHTS; i++) {
+ float half_lambert = dot(norm, -dir_lights[i].dir) * 0.5 + 0.5;
+ diffuse += mix(dir_lights[i].globe_diffuse, dir_lights[i].diffuse, half_lambert);
+ }
vec4 texel = texture(tex, tex_coord);
- frag_color = vec4(texel.rgb, texel.a * alpha_mod);
+ frag_rgb += texel.rgb * diffuse;
+
+ // Specular lighting
+ if (specular_strength > 0.0) {
+ vec3 view_dir = normalize(view_pos - frag_pos);
+ vec3 reflect_dir = reflect(specular_light_dir, norm);
+ float specular = pow(max(dot(view_dir, reflect_dir), 0.0), specular_shininess) * specular_strength;
+ frag_rgb += vec3(specular);
+ }
+
+ frag_color = vec4(frag_rgb, texel.a * alpha_mod);
}
diff --git a/shaders/reign.v.glsl b/shaders/reign.v.glsl
index 363b568..832b229 100644
--- a/shaders/reign.v.glsl
+++ b/shaders/reign.v.glsl
@@ -17,6 +17,7 @@
uniform mat4 local_transform;
uniform mat4 view_transform;
uniform mat4 proj_transform;
+uniform mat3 normal_transform;
const int MAX_BONES = 211; // see 3d_internal.h
const int NR_WEIGHTS = 4;
@@ -30,6 +31,8 @@ in ivec4 vertex_bone_index;
in vec4 vertex_bone_weight;
out vec2 tex_coord;
+out vec3 normal;
+out vec3 frag_pos;
void main() {
mat4 bone_transform = mat4(1.0f);
@@ -42,6 +45,10 @@ void main() {
}
}
- gl_Position = proj_transform * view_transform * local_transform * bone_transform * vec4(vertex_pos, 1.0);
+ vec4 world_pos = local_transform * bone_transform * vec4(vertex_pos, 1.0);
+ gl_Position = proj_transform * view_transform * world_pos;
+ normal = normal_transform * mat3(bone_transform) * vertex_normal;
+
tex_coord = vertex_uv;
+ frag_pos = vec3(world_pos);
}
diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h
index 9b8af3d..5292d31 100644
--- a/src/3d/3d_internal.h
+++ b/src/3d/3d_internal.h
@@ -24,6 +24,7 @@
#include "gfx/gl.h"
#include "gfx/gfx.h"
+#define NR_DIR_LIGHTS 3
#define MAX_BONES 211 // Maximum in TT3
struct model {
@@ -75,9 +76,21 @@ struct RE_renderer {
// Uniform variable locations
GLint local_transform;
GLint proj_transform;
+ GLint normal_transform;
GLint alpha_mod;
GLint has_bones;
GLint bone_matrices;
+ GLint ambient;
+ struct {
+ GLint dir;
+ GLint diffuse;
+ GLint globe_diffuse;
+ GLint ambient;
+ } dir_lights[NR_DIR_LIGHTS];
+ GLint specular_light_dir;
+ GLint specular_strength;
+ GLint specular_shininess;
+ GLint view_pos;
// Attribute variable locations
GLint vertex_normal;
diff --git a/src/3d/debug.c b/src/3d/debug.c
index e8c41ec..3de2782 100644
--- a/src/3d/debug.c
+++ b/src/3d/debug.c
@@ -21,6 +21,8 @@
#include "sprite.h"
#include "xsystem4.h"
+#define SPREAD_VEC3(v) (v)[0], (v)[1], (v)[2]
+
static const char *instance_type_name(enum RE_instance_type type)
{
switch (type) {
@@ -65,17 +67,24 @@ static void print_instance(struct RE_instance *inst, int index, int indent)
indent++;
indent_printf(indent, "type = %s,\n", instance_type_name(inst->type));
- indent_printf(indent, "draw = %d,\n", inst->draw);
- indent_printf(indent, "pos = {x=%f, y=%f, z=%f},\n", inst->pos[0], inst->pos[1], inst->pos[2]);
- indent_printf(indent, "vec = {x=%f, y=%f, z=%f},\n", inst->vec[0], inst->vec[1], inst->vec[2]);
- indent_printf(indent, "scale = {x=%f, y=%f, z=%f},\n", inst->scale[0], inst->scale[1], inst->scale[2]);
+ if (inst->type == RE_ITYPE_DIRECTIONAL_LIGHT || inst->type == RE_ITYPE_SPECULAR_LIGHT) {
+ indent_printf(indent, "vec = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->vec));
+ indent_printf(indent, "diffuse = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->diffuse));
+ indent_printf(indent, "globe_diffuse = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->globe_diffuse));
+ } else {
+ indent_printf(indent, "draw = %d,\n", inst->draw);
+ indent_printf(indent, "pos = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->pos));
+ indent_printf(indent, "scale = {x=%f, y=%f, z=%f},\n", SPREAD_VEC3(inst->scale));
+ indent_printf(indent, "ambient = {r=%f, g=%f, b=%f},\n", SPREAD_VEC3(inst->ambient));
+ }
if (inst->model)
indent_printf(indent, "path = \"%s\",\n", inst->model->path);
- if (inst->motion)
+ if (inst->motion) {
+ indent_printf(indent, "fps = %f,\n", inst->fps);
print_motion("motion", inst->motion, indent);
+ }
if (inst->next_motion)
print_motion("next_motion", inst->next_motion, indent);
- indent_printf(indent, "fps = %f,\n", inst->fps);
if (inst->motion_blend)
indent_printf(indent, "motion_blend_rate = %f,\n", inst->motion_blend_rate);
@@ -109,8 +118,7 @@ void RE_debug_print(struct sact_sprite *sp, int indent)
indent_printf(indent, "name = \"%s\",\n", p->plugin.name);
indent_printf(indent, "camera = {x=%f, y=%f, z=%f, pitch=%f, roll=%f, yaw=%f},\n",
- p->camera.pos[0], p->camera.pos[1], p->camera.pos[2],
- p->camera.pitch, p->camera.roll, p->camera.yaw);
+ SPREAD_VEC3(p->camera.pos), p->camera.pitch, p->camera.roll, p->camera.yaw);
for (int i = 0; i < RE_MAX_INSTANCES; i++)
print_instance(p->instances[i], i, indent);
diff --git a/src/3d/reign.c b/src/3d/reign.c
index 47918ca..bf265c7 100644
--- a/src/3d/reign.c
+++ b/src/3d/reign.c
@@ -42,6 +42,7 @@ static struct RE_instance *create_instance(struct RE_plugin *plugin)
instance->alpha = 1.0;
instance->fps = 30.0;
glm_mat4_identity(instance->local_transform);
+ glm_mat3_identity(instance->normal_transform);
return instance;
}
diff --git a/src/3d/renderer.c b/src/3d/renderer.c
index b2efed8..e8e3d21 100644
--- a/src/3d/renderer.c
+++ b/src/3d/renderer.c
@@ -65,9 +65,24 @@ struct RE_renderer *RE_renderer_new(struct texture *texture)
gfx_load_shader(&r->shader, "shaders/reign.v.glsl", "shaders/reign.f.glsl");
r->local_transform = glGetUniformLocation(r->shader.program, "local_transform");
r->proj_transform = glGetUniformLocation(r->shader.program, "proj_transform");
+ r->normal_transform = glGetUniformLocation(r->shader.program, "normal_transform");
r->alpha_mod = glGetUniformLocation(r->shader.program, "alpha_mod");
r->has_bones = glGetUniformLocation(r->shader.program, "has_bones");
r->bone_matrices = glGetUniformLocation(r->shader.program, "bone_matrices");
+ r->ambient = glGetUniformLocation(r->shader.program, "ambient");
+ for (int i = 0; i < NR_DIR_LIGHTS; i++) {
+ char buf[64];
+ sprintf(buf, "dir_lights[%d].dir", i);
+ r->dir_lights[i].dir = glGetUniformLocation(r->shader.program, buf);
+ sprintf(buf, "dir_lights[%d].diffuse", i);
+ r->dir_lights[i].diffuse = glGetUniformLocation(r->shader.program, buf);
+ sprintf(buf, "dir_lights[%d].globe_diffuse", i);
+ r->dir_lights[i].globe_diffuse = glGetUniformLocation(r->shader.program, buf);
+ }
+ r->specular_light_dir = glGetUniformLocation(r->shader.program, "specular_light_dir");
+ r->specular_strength = glGetUniformLocation(r->shader.program, "specular_strength");
+ r->specular_shininess = glGetUniformLocation(r->shader.program, "specular_shininess");
+ r->view_pos = glGetUniformLocation(r->shader.program, "view_pos");
r->vertex_normal = glGetAttribLocation(r->shader.program, "vertex_normal");
r->vertex_uv = glGetAttribLocation(r->shader.program, "vertex_uv");
r->vertex_bone_index = glGetAttribLocation(r->shader.program, "vertex_bone_index");
@@ -156,6 +171,11 @@ static void update_local_transform(struct RE_instance *inst)
glm_mat4_mul(inst->local_transform, rot, inst->local_transform);
glm_scale(inst->local_transform, inst->scale);
+ mat3 normal;
+ glm_mat4_pick3(inst->local_transform, normal);
+ glm_mat3_inv(normal, normal);
+ glm_mat3_transpose_to(normal, inst->normal_transform);
+
inst->local_transform_needs_update = false;
}
@@ -236,12 +256,26 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r)
update_local_transform(inst);
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, inst->local_transform[0]);
+ glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, inst->normal_transform[0]);
glUniform1f(r->alpha_mod, inst->alpha);
+ vec3 ambient;
+ glm_vec3_add(inst->plugin->global_ambient, inst->ambient, ambient);
+ glUniform3fv(r->ambient, 1, ambient);
for (int i = 0; i < model->nr_meshes; i++) {
struct mesh *mesh = &model->meshes[i];
+ struct material *material = &model->materials[mesh->material];
+
+ if (inst->plugin->specular_mode) {
+ glUniform1f(r->specular_strength, material->specular_strength);
+ glUniform1f(r->specular_shininess, material->specular_shininess);
+ } else {
+ glUniform1f(r->specular_strength, 0.0);
+ glUniform1f(r->specular_shininess, 0.0);
+ }
+
glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, model->materials[mesh->material].color_map);
+ glBindTexture(GL_TEXTURE_2D, material->color_map);
glUniform1i(r->shader.texture, 0);
glBindVertexArray(mesh->vao);
@@ -288,10 +322,20 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma
glm_mat4_pick3t(view_mat, rot);
glm_mat4_ins3(rot, local_transform);
glm_scale(local_transform, inst->scale);
+ mat3 normal_transform;
+ // This should be safe because billboards do not have non-uniform scaling.
+ glm_mat4_pick3(local_transform, normal_transform);
+
+ vec3 ambient;
+ glm_vec3_add(inst->plugin->global_ambient, inst->ambient, ambient);
+ glUniform3fv(r->ambient, 1, ambient);
glUniformMatrix4fv(r->local_transform, 1, GL_FALSE, local_transform[0]);
+ glUniformMatrix3fv(r->normal_transform, 1, GL_FALSE, normal_transform[0]);
glUniform1i(r->has_bones, GL_FALSE);
glUniform1f(r->alpha_mod, inst->alpha);
+ glUniform1f(r->specular_strength, 0.0);
+ glUniform1f(r->specular_shininess, 0.0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, bt->texture);
@@ -313,6 +357,41 @@ static void render_back_cg(struct texture *dst, struct RE_back_cg *bcg, struct R
gfx_copy_stretch_blend(dst, bcg->x, bcg->y, sw * bcg->mag, sh * bcg->mag, &bcg->texture, 0, 0, sw, sh, bcg->blend_rate * 255);
}
+static void setup_lights(struct RE_plugin *plugin)
+{
+ struct RE_renderer *r = plugin->renderer;
+ glUniform3fv(r->view_pos, 1, plugin->camera.pos);
+ int light_index = 0;
+ for (int i = 0; i < RE_MAX_INSTANCES; i++) {
+ struct RE_instance *inst = plugin->instances[i];
+ if (!inst)
+ continue;
+ switch (inst->type) {
+ case RE_ITYPE_DIRECTIONAL_LIGHT:
+ if (light_index >= NR_DIR_LIGHTS) {
+ WARNING("too many directional lights");
+ break;
+ }
+ glUniform3fv(r->dir_lights[light_index].dir, 1, inst->vec);
+ glUniform3fv(r->dir_lights[light_index].diffuse, 1, inst->diffuse);
+ glUniform3fv(r->dir_lights[light_index].globe_diffuse, 1, inst->globe_diffuse);
+ light_index++;
+ break;
+ case RE_ITYPE_SPECULAR_LIGHT:
+ glUniform3fv(r->specular_light_dir, 1, inst->vec);
+ break;
+ default:
+ break;
+ }
+ }
+ for (; light_index < NR_DIR_LIGHTS; light_index++) {
+ const vec3 zero = {0.0, 0.0, 0.0};
+ glUniform3fv(r->dir_lights[light_index].dir, 1, zero);
+ glUniform3fv(r->dir_lights[light_index].diffuse, 1, zero);
+ glUniform3fv(r->dir_lights[light_index].globe_diffuse, 1, zero);
+ }
+}
+
void RE_render(struct sact_sprite *sp)
{
uint32_t timestamp = SDL_GetTicks();
@@ -363,6 +442,8 @@ void RE_render(struct sact_sprite *sp)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ setup_lights(plugin);
+
for (int i = 0; i < RE_MAX_INSTANCES; i++) {
struct RE_instance *inst = plugin->instances[i];
if (!inst || !inst->draw)
diff --git a/src/hll/ReignEngine.c b/src/hll/ReignEngine.c
index a73efaa..b98325f 100644
--- a/src/hll/ReignEngine.c
+++ b/src/hll/ReignEngine.c
@@ -14,6 +14,7 @@
* along with this program; if not, see .
*/
+#include
#include
#include "system4.h"
@@ -135,6 +136,7 @@ static bool ReignEngine_SetInstanceVector(int plugin, int instance, float x, flo
ri->vec[0] = x;
ri->vec[1] = y;
ri->vec[2] = -z;
+ glm_vec3_normalize(ri->vec);
return true;
}
@@ -219,14 +221,44 @@ static bool ReignEngine_SetInstanceScaleZ(int plugin, int instance, float scale_
//bool ReignEngine_SetInstanceZBias(int plugin, int instance, float fZBias);
//float ReignEngine_GetInstanceZBias(int plugin, int instance);
-bool ReignEngine_SetInstanceVertexPos(int plugin, int instance, int index, float x, float y, float z)
+static bool ReignEngine_SetInstanceVertexPos(int plugin, int instance, int index, float x, float y, float z)
{
return RE_instance_set_vertex_pos(get_instance(plugin, instance), index, x, y, z);
}
-HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDiffuse, int plugin, int instance, float r, float g, float b);
-HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceGlobeDiffuse, int plugin, int instance, float r, float g, float b);
-HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceAmbient, int plugin, int instance, float r, float g, float b);
+static bool ReignEngine_SetInstanceDiffuse(int plugin, int instance, float r, float g, float b)
+{
+ struct RE_instance *ri = get_instance(plugin, instance);
+ if (!ri)
+ return false;
+ ri->diffuse[0] = r;
+ ri->diffuse[1] = g;
+ ri->diffuse[2] = b;
+ return true;
+}
+
+static bool ReignEngine_SetInstanceGlobeDiffuse(int plugin, int instance, float r, float g, float b)
+{
+ struct RE_instance *ri = get_instance(plugin, instance);
+ if (!ri)
+ return false;
+ ri->globe_diffuse[0] = r;
+ ri->globe_diffuse[1] = g;
+ ri->globe_diffuse[2] = b;
+ return true;
+}
+
+static bool ReignEngine_SetInstanceAmbient(int plugin, int instance, float r, float g, float b)
+{
+ struct RE_instance *ri = get_instance(plugin, instance);
+ if (!ri)
+ return false;
+ ri->ambient[0] = r;
+ ri->ambient[1] = g;
+ ri->ambient[2] = b;
+ return true;
+}
+
//bool ReignEngine_SetInstanceSpecular(int plugin, int instance, float fSpecular);
static bool ReignEngine_SetInstanceAlpha(int plugin, int instance, float alpha)
@@ -882,9 +914,9 @@ static bool ReignEngine_GetGlobalAmbient(int plugin, float *r, float *g, float *
struct RE_plugin *p = get_plugin(plugin);
if (!p)
return false;
- *r = p->global_ambient_r;
- *g = p->global_ambient_g;
- *b = p->global_ambient_b;
+ *r = p->global_ambient[0];
+ *g = p->global_ambient[1];
+ *b = p->global_ambient[2];
return true;
}
@@ -893,9 +925,9 @@ static bool ReignEngine_SetGlobalAmbient(int plugin, float r, float g, float b)
struct RE_plugin *p = get_plugin(plugin);
if (!p)
return false;
- p->global_ambient_r = r;
- p->global_ambient_g = g;
- p->global_ambient_b = b;
+ p->global_ambient[0] = r;
+ p->global_ambient[1] = g;
+ p->global_ambient[2] = b;
return true;
}
@@ -1085,7 +1117,7 @@ HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, IsLoading, int plugin);
//bool ReignEngine_SetDebugInfoMode(int plugin, int nMode);
HLL_WARN_UNIMPLEMENTED(30, int, ReignEngine, GetVertexShaderVersion, void);
HLL_WARN_UNIMPLEMENTED(30, int, ReignEngine, GetPixelShaderVersion, void);
-HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceSpecularReflectRate, int plugin, int instance, float rate);
+HLL_QUIET_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceSpecularReflectRate, int plugin, int instance, float rate); // the value is unused?
HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceFresnelReflectRate, int plugin, int instance, float rate);
//float ReignEngine_GetInstanceSpecularReflectRate(int plugin, int instance);
//float ReignEngine_GetInstanceFresnelReflectRate(int plugin, int instance);