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);