diff --git a/include/reign.h b/include/reign.h index ea06a57..f1226e7 100644 --- a/include/reign.h +++ b/include/reign.h @@ -19,6 +19,7 @@ #define RE_NR_BACK_CGS 16 #define RE_NR_INSTANCE_TARGETS 2 +#define RE_NR_LIGHT_PARAMS 41 // .lit parameter count #include @@ -57,6 +58,29 @@ enum RE_fog_type { RE_FOG_LIGHT_SCATTERING = 2, }; +// Indices into light_params. Vector entries name their first component. +enum seal_light_param { + SEAL_LP_TONEMAP_EXPOSURE_BIAS = 0, + SEAL_LP_TONEMAP_WHITE_POINT = 1, + SEAL_LP_TONEMAP_A = 2, + SEAL_LP_TONEMAP_B = 3, + SEAL_LP_TONEMAP_C = 4, + SEAL_LP_TONEMAP_D = 5, + SEAL_LP_TONEMAP_E = 6, + SEAL_LP_TONEMAP_F = 7, + SEAL_LP_HEMI_VEC = 8, // x,y,z + SEAL_LP_HEMI_SKY_COLOR = 11, // r,g,b + SEAL_LP_HEMI_MID_COLOR = 14, // r,g,b + SEAL_LP_HEMI_GROUND_COLOR = 17, // r,g,b + SEAL_LP_LS_BETA_R = 20, + SEAL_LP_LS_BETA_M = 21, + SEAL_LP_LS_G = 22, + SEAL_LP_LS_DISTANCE = 23, + SEAL_LP_LS_LIGHT_VEC = 24, // x,y,z + SEAL_LP_LS_LIGHT_COLOR = 27, // r,g,b + SEAL_LP_LS_SUN_COLOR = 30, // r,g,b +}; + enum RE_draw_type { RE_DRAW_TYPE_NORMAL = 0, RE_DRAW_TYPE_ADDITIVE = 1, @@ -158,6 +182,7 @@ struct RE_plugin { // SealEngine int mag_speed; + float light_params[RE_NR_LIGHT_PARAMS]; }; struct RE_instance { @@ -197,6 +222,7 @@ struct RE_instance { // Lights vec3 vec; vec3 globe_diffuse; + float *light_params; // Private bool local_transform_needs_update; @@ -244,6 +270,9 @@ bool RE_instance_optimize_path_line(struct RE_instance *instance); bool RE_instance_calc_path_finder_intersect_eye_vec(struct RE_instance *instance, int mouse_x, int mouse_y, vec3 out); bool RE_plugin_transform_pos_to_view_pos(struct RE_plugin *plugin, float x, float y, float z, int *view_x, int *view_y); bool RE_plugin_get_camera_z_vector(struct RE_plugin *plugin, vec3 out); +void RE_plugin_reset_light_param(struct RE_plugin *plugin); +bool RE_plugin_set_fog_type(struct RE_plugin *plugin, int type); +int RE_plugin_get_fog_type(struct RE_plugin *plugin); int RE_motion_get_state(struct motion *motion); bool RE_motion_set_state(struct motion *motion, int state); diff --git a/shaders/reign.f.glsl b/shaders/reign.f.glsl index ada5cb9..e0f2fad 100644 --- a/shaders/reign.f.glsl +++ b/shaders/reign.f.glsl @@ -24,11 +24,15 @@ #define ALPHA_MAP_BLEND 2 #define ALPHA_MAP_TEST 3 +#define FOG_LINEAR 1 +#define FOG_LIGHT_SCATTERING 2 + +#define ENABLE_SPECULAR (ENGINE == REIGN_ENGINE || ENGINE == SEAL_ENGINE) +#define ENABLE_LIGHT_SCATTERING (ENGINE == REIGN_ENGINE || ENGINE == SEAL_ENGINE) + #if ENGINE == REIGN_ENGINE #define NR_DIR_LIGHTS 3 -#define FOG_LINEAR 1 -#define FOG_LIGHT_SCATTERING 2 struct dir_light { vec3 dir; @@ -36,25 +40,17 @@ struct dir_light { vec3 globe_diffuse; }; -uniform sampler2D specular_texture; uniform dir_light dir_lights[NR_DIR_LIGHTS]; -uniform float specular_strength; -uniform float specular_shininess; -uniform bool use_specular_map; uniform float rim_exponent; uniform vec3 rim_color; -uniform int fog_type; uniform float fog_near; uniform float fog_far; uniform vec3 fog_color; in vec3 light_dir[NR_DIR_LIGHTS]; -in vec3 specular_dir; -in vec3 ls_ex; -in vec3 ls_in; uniform vec3 global_ambient; -vec3 dir_lights_diffuse(vec3 norm) +vec3 compute_diffuse(vec3 norm) { vec3 diffuse = vec3(0.0); for (int i = 0; i < NR_DIR_LIGHTS; i++) { @@ -64,17 +60,71 @@ vec3 dir_lights_diffuse(vec3 norm) return diffuse; } -#else // ENGINE == REIGN_ENGINE +#elif ENGINE == SEAL_ENGINE const vec3 global_ambient = vec3(0.0); -vec3 dir_lights_diffuse(vec3 norm) +// Hemisphere lighting (sky/middle/ground). +uniform vec3 hemi_light_dir; +uniform vec3 hemi_sky_color; +uniform vec3 hemi_mid_color; +uniform vec3 hemi_ground_color; + +vec3 compute_diffuse(vec3 norm) +{ + float t = 0.5 * dot(norm, hemi_light_dir) + 0.5; + vec3 low_mid = mix(hemi_ground_color, hemi_mid_color, t); + vec3 mid_high = mix(hemi_mid_color, hemi_sky_color, t); + return mix(low_mid, mid_high, t); +} + +#else // TAPIR_ENGINE + +const vec3 global_ambient = vec3(0.0); + +vec3 compute_diffuse(vec3 norm) { return vec3(1.0); } #endif // ENGINE == REIGN_ENGINE +#if ENABLE_LIGHT_SCATTERING +uniform int fog_type; +in vec3 ls_ex; +in vec3 ls_in; +#endif + +#if ENABLE_SPECULAR +uniform sampler2D specular_texture; +uniform vec3 specular_color; +uniform float specular_shininess; +uniform bool use_specular_map; +in vec3 specular_dir; +#endif + +#if ENGINE == SEAL_ENGINE +// Uncharted 2 (Hable) filmic tone mapping. +uniform vec4 tonemap_param; // (ExposureBias, WhitePoint, A, B) +uniform vec4 tonemap_param2; // (C, D, E, F) +uniform bool nolighting; + +vec3 hable(vec3 v) +{ + float a = tonemap_param.z, b = tonemap_param.w; + float c = tonemap_param2.x, d = tonemap_param2.y; + float e = tonemap_param2.z, f = tonemap_param2.w; + return ((v * (a * v + c * b) + d * e) / (v * (a * v + b) + d * f)) - e / f; +} + +vec3 tone_map(vec3 color) +{ + vec3 curr = hable(color * tonemap_param.x); + vec3 white = hable(vec3(tonemap_param.y)); + return curr / white; +} +#endif + uniform sampler2D tex; uniform sampler2D blend_tex; uniform bool use_blend_texture; @@ -128,7 +178,7 @@ void main() { texel = mix(texel, texture(blend_tex, blend_tex_coord), blend_weight); } if (diffuse_type != DIFFUSE_EMISSIVE) { - diffuse = dir_lights_diffuse(norm); + diffuse = compute_diffuse(norm); if (diffuse_type == DIFFUSE_LIGHT_MAP) { diffuse *= texture(light_texture, light_tex_coord).rgb; } @@ -136,17 +186,19 @@ void main() { } frag_rgb += texel.rgb * diffuse * color_mod.rgb * diffuse_mod; -#if ENGINE == REIGN_ENGINE +#if ENABLE_SPECULAR // Specular lighting - if (specular_strength > 0.0) { + if (any(greaterThan(specular_color, vec3(0.0)))) { vec3 reflect_dir = reflect(specular_dir, norm); - float specular = pow(max(dot(view_dir, reflect_dir), 0.0), specular_shininess) * specular_strength; + float specular = pow(max(dot(view_dir, reflect_dir), 0.0), specular_shininess); if (use_specular_map) { specular *= texture(specular_texture, tex_coord).r; } - frag_rgb += vec3(specular); + frag_rgb += specular_color * specular; } +#endif +#if ENGINE == REIGN_ENGINE // Rim lighting if (rim_exponent > 0.0) { // Normal map is not used here. @@ -158,7 +210,11 @@ void main() { if (fog_type == FOG_LINEAR) { float fog_factor = clamp((dist - fog_near) / (fog_far - fog_near), 0.0, 1.0); frag_rgb = mix(frag_rgb, fog_color, fog_factor); - } else if (fog_type == FOG_LIGHT_SCATTERING) { + } +#endif + +#if ENABLE_LIGHT_SCATTERING + if (fog_type == FOG_LIGHT_SCATTERING) { frag_rgb = frag_rgb * ls_ex + ls_in; } #endif @@ -180,6 +236,11 @@ void main() { frag_rgb *= brightness; } +#if ENGINE == SEAL_ENGINE + if (!nolighting) + frag_rgb = tone_map(frag_rgb); +#endif + // Alpha mapping float alpha = texel.a * color_mod.a * alpha_mod; if (alpha_mode == ALPHA_TEST) { diff --git a/shaders/reign.v.glsl b/shaders/reign.v.glsl index 12f0973..60fd555 100644 --- a/shaders/reign.v.glsl +++ b/shaders/reign.v.glsl @@ -16,10 +16,14 @@ const float PI = 3.14159265358979323846; +#define FOG_LIGHT_SCATTERING 2 + +#define ENABLE_SPECULAR (ENGINE == REIGN_ENGINE || ENGINE == SEAL_ENGINE) +#define ENABLE_LIGHT_SCATTERING (ENGINE == REIGN_ENGINE || ENGINE == SEAL_ENGINE) + #if ENGINE == REIGN_ENGINE #define NR_DIR_LIGHTS 3 -#define FOG_LIGHT_SCATTERING 2 struct dir_light { vec3 dir; @@ -28,16 +32,7 @@ struct dir_light { }; uniform dir_light dir_lights[NR_DIR_LIGHTS]; -uniform vec3 specular_light_dir; -uniform int fog_type; -uniform vec4 ls_params; // (beta_r, beta_m, g, distance) -uniform vec3 ls_light_dir; -uniform vec3 ls_light_color; -uniform vec3 ls_sun_color; out vec3 light_dir[NR_DIR_LIGHTS]; -out vec3 specular_dir; -out vec3 ls_ex; -out vec3 ls_in; const vec2 uv_scroll = vec2(0.0); @@ -47,6 +42,21 @@ uniform vec2 uv_scroll; #endif // ENGINE == REIGN_ENGINE +#if ENABLE_LIGHT_SCATTERING +uniform int fog_type; +uniform vec4 ls_params; // (beta_r, beta_m, g, distance) +uniform vec3 ls_light_dir; +uniform vec3 ls_light_color; +uniform vec3 ls_sun_color; +out vec3 ls_ex; +out vec3 ls_in; +#endif + +#if ENABLE_SPECULAR +uniform vec3 specular_light_dir; +out vec3 specular_dir; +#endif + uniform mat4 local_transform; uniform mat4 view_transform; uniform mat4 proj_transform; @@ -131,12 +141,15 @@ void main() { frag_pos = TBN * vec3(world_pos); eye = TBN * camera_pos; +#if ENABLE_SPECULAR + specular_dir = TBN * specular_light_dir; +#endif #if ENGINE == REIGN_ENGINE light_dir[0] = TBN * dir_lights[0].dir; light_dir[1] = TBN * dir_lights[1].dir; light_dir[2] = TBN * dir_lights[2].dir; - specular_dir = TBN * specular_light_dir; - +#endif +#if ENABLE_LIGHT_SCATTERING if (fog_type == FOG_LIGHT_SCATTERING) { float beta_r = ls_params.x; float beta_m = ls_params.y; diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index a7aae83..7b944ba 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -63,6 +63,8 @@ struct mesh { vec3 outline_color; float outline_thickness; vec2 uv_scroll; + vec3 specular_color; + float specular_power; }; struct material { @@ -163,7 +165,7 @@ struct RE_renderer { GLint ambient; } dir_lights[NR_DIR_LIGHTS]; GLint specular_light_dir; - GLint specular_strength; + GLint specular_color; GLint specular_shininess; GLint use_specular_map; GLint specular_texture; @@ -186,6 +188,13 @@ struct RE_renderer { GLint ls_light_dir; GLint ls_light_color; GLint ls_sun_color; + GLint hemi_light_dir; + GLint hemi_sky_color; + GLint hemi_mid_color; + GLint hemi_ground_color; + GLint tonemap_param; + GLint tonemap_param2; + GLint nolighting; GLint alpha_mode; GLint alpha_texture; GLint uv_scroll; @@ -665,6 +674,8 @@ enum mesh_flags { MESH_HAS_LIGHT_UV = 1 << 9, MESH_NO_ZWRITE = 1 << 10, MESH_HEIGHT_DETECTION = 1 << 11, + MESH_HAS_SPECULAR_COLOR = 1 << 12, + MESH_HAS_SPECULAR_POWER = 1 << 13, }; struct pol_mesh { @@ -691,6 +702,8 @@ struct pol_mesh { Color edge_color; float edge_size; vec2 uv_scroll; + vec3 specular_color; + float specular_power; }; struct pol_vertex { @@ -784,6 +797,9 @@ struct amt_material *amt_find_material(struct amt *amt, const char *name); void opr_load(uint8_t *data, size_t size, struct pol *pol); void txa_load(uint8_t *data, size_t size, struct mot *mot); +void lit_reset(float *out); +bool lit_parse(uint8_t *data, size_t size, float *out); + // mpr.c struct mpr_float_key { int frame; float v; }; diff --git a/src/3d/model.c b/src/3d/model.c index 3f9f521..05de49c 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -379,6 +379,8 @@ static void add_mesh(struct model *model, struct pol_mesh *m, uint32_t material_ mesh->outline_color[2] = m->edge_color.b / 255.f; mesh->outline_thickness = m->edge_size ? m->edge_size : DEFAULT_OUTLINE_THICKNESS; glm_vec2_copy(m->uv_scroll, mesh->uv_scroll); + glm_vec3_copy(m->specular_color, mesh->specular_color); + mesh->specular_power = m->specular_power; mesh->nr_vertices = nr_vertices; glGenVertexArrays(1, &mesh->vao); diff --git a/src/3d/parser.c b/src/3d/parser.c index 17b4577..9f18552 100644 --- a/src/3d/parser.c +++ b/src/3d/parser.c @@ -574,7 +574,7 @@ void opr_load(uint8_t *data, size_t size, struct pol *pol) char s[200]; int i1, i2, i3; - float f1, f2; + float f1, f2, f3; if (sscanf(line, "Mesh = \"%[^\"]\"", s) == 1) { for (int i = 0; i < pol->nr_meshes; i++) { selected[i] = pol->meshes[i] && !strcmp(pol->meshes[i]->name, s); @@ -640,6 +640,20 @@ void opr_load(uint8_t *data, size_t size, struct pol *pol) pol->meshes[i]->uv_scroll[0] = f1; pol->meshes[i]->uv_scroll[1] = f2; } + } else if (sscanf(line, "SpecularColor = ( %f , %f , %f )", &f1, &f2, &f3) == 3) { + for (int i = 0; i < pol->nr_meshes; i++) { + if (!selected[i]) continue; + pol->meshes[i]->flags |= MESH_HAS_SPECULAR_COLOR; + pol->meshes[i]->specular_color[0] = f1; + pol->meshes[i]->specular_color[1] = f2; + pol->meshes[i]->specular_color[2] = f3; + } + } else if (sscanf(line, "SpecularPower = %f", &f1) == 1) { + for (int i = 0; i < pol->nr_meshes; i++) { + if (!selected[i]) continue; + pol->meshes[i]->flags |= MESH_HAS_SPECULAR_POWER; + pol->meshes[i]->specular_power = f1; + } } else if (strchr(line, '=')) { WARNING("unknown field: %s", line); } @@ -673,3 +687,63 @@ void txa_load(uint8_t *data, size_t size, struct mot *mot) mot->nr_texture_indices = count; mot->texture_indices = indices; } + +void lit_reset(float *out) +{ + static const float lit_param_defaults[RE_NR_LIGHT_PARAMS] = { + [SEAL_LP_TONEMAP_EXPOSURE_BIAS] = 1.0f, + [SEAL_LP_TONEMAP_WHITE_POINT] = 1.0f, + [SEAL_LP_TONEMAP_A] = 0.22f, + [SEAL_LP_TONEMAP_B] = 0.30f, + [SEAL_LP_TONEMAP_C] = 0.10f, + [SEAL_LP_TONEMAP_D] = 0.20f, + [SEAL_LP_TONEMAP_E] = 0.01f, + [SEAL_LP_TONEMAP_F] = 0.30f, + [SEAL_LP_HEMI_VEC + 0] = -1.0f, + [SEAL_LP_HEMI_VEC + 1] = -1.0f, + [SEAL_LP_HEMI_VEC + 2] = 1.0f, + [SEAL_LP_HEMI_SKY_COLOR + 0] = 1.2f, + [SEAL_LP_HEMI_SKY_COLOR + 1] = 1.2f, + [SEAL_LP_HEMI_SKY_COLOR + 2] = 1.2f, + [SEAL_LP_HEMI_MID_COLOR + 0] = 0.5f, + [SEAL_LP_HEMI_MID_COLOR + 1] = 0.5f, + [SEAL_LP_HEMI_MID_COLOR + 2] = 0.5f, + [SEAL_LP_HEMI_GROUND_COLOR + 0] = 0.3f, + [SEAL_LP_HEMI_GROUND_COLOR + 1] = 0.3f, + [SEAL_LP_HEMI_GROUND_COLOR + 2] = 0.3f, + [SEAL_LP_LS_BETA_R] = 0.25f, + [SEAL_LP_LS_BETA_M] = 1.25f, + [SEAL_LP_LS_G] = 0.05f, + [SEAL_LP_LS_DISTANCE] = 140.0f, + [SEAL_LP_LS_LIGHT_VEC + 0] = -1.0f, + [SEAL_LP_LS_LIGHT_VEC + 1] = -1.0f, + [SEAL_LP_LS_LIGHT_VEC + 2] = 1.0f, + [SEAL_LP_LS_LIGHT_COLOR + 0] = 1.0f, + [SEAL_LP_LS_LIGHT_COLOR + 1] = 1.0f, + [SEAL_LP_LS_LIGHT_COLOR + 2] = 1.0f, + [SEAL_LP_LS_SUN_COLOR + 0] = 0.5f, + [SEAL_LP_LS_SUN_COLOR + 1] = 0.5f, + [SEAL_LP_LS_SUN_COLOR + 2] = 0.5f, + }; + memcpy(out, lit_param_defaults, sizeof(lit_param_defaults)); +} + +bool lit_parse(uint8_t *data, size_t size, float *out) +{ + if (size != 8 + RE_NR_LIGHT_PARAMS * 4 || memcmp(data, "LITP", 4) != 0) { + WARNING("invalid .lit file"); + return false; + } + struct buffer r; + buffer_init(&r, data, size); + buffer_skip(&r, 4); // "LITP" + int32_t version = buffer_read_int32(&r); + if (version != 0) { + WARNING("unsupported .lit version %d", version); + return false; + } + lit_reset(out); + for (int i = 0; i < RE_NR_LIGHT_PARAMS; i++) + out[i] = buffer_read_float(&r); + return true; +} diff --git a/src/3d/reign.c b/src/3d/reign.c index c249637..0a3f6bf 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -23,6 +23,7 @@ #include "system4.h" #include "system4/aar.h" +#include "system4/archive.h" #include "system4/cg.h" #include "system4/hashtable.h" #include "system4/string.h" @@ -98,6 +99,7 @@ static void unload_instance(struct RE_instance *instance) static void free_instance(struct RE_instance *instance) { unload_instance(instance); + free(instance->light_params); xfree_aligned(instance); } @@ -249,6 +251,7 @@ struct RE_plugin *RE_plugin_new(enum RE_plugin_version version) plugin->fog_near = 1.0; plugin->fog_far = 10.0; glm_vec3_one(plugin->fog_color); + lit_reset(plugin->light_params); return plugin; } @@ -431,6 +434,10 @@ bool RE_instance_set_type(struct RE_instance *instance, int type) instance->motion->instance = instance; break; case RE_ITYPE_DIRECTIONAL_LIGHT: + if (re_plugin_version >= RE_SEAL_PLUGIN) { + instance->light_params = xmalloc(RE_NR_LIGHT_PARAMS * sizeof(float)); + lit_reset(instance->light_params); + } break; case RE_ITYPE_SPECULAR_LIGHT: break; @@ -526,6 +533,16 @@ bool RE_instance_load(struct RE_instance *instance, const char *name) } } return true; + case RE_ITYPE_DIRECTIONAL_LIGHT: + if (re_plugin_version >= RE_SEAL_PLUGIN) { + struct archive_data *dfile = archive_get_by_name(instance->plugin->aar, name); + if (!dfile) + return false; + bool ok = lit_parse(dfile->data, dfile->size, instance->light_params); + archive_free_data(dfile); + return ok; + } + return false; default: WARNING("Invalid instance type %d", instance->type); return false; @@ -786,6 +803,50 @@ bool RE_plugin_get_camera_z_vector(struct RE_plugin *plugin, vec3 out) return true; } +void RE_plugin_reset_light_param(struct RE_plugin *plugin) +{ + lit_reset(plugin->light_params); +} + +bool RE_plugin_set_fog_type(struct RE_plugin *plugin, int type) +{ + if (re_plugin_version == RE_REIGN_PLUGIN) { + switch (type) { + case 0: plugin->fog_type = RE_FOG_NONE; return true; + case 1: plugin->fog_type = RE_FOG_LINEAR; return true; + case 2: plugin->fog_type = RE_FOG_LIGHT_SCATTERING; return true; + default: break; + } + } else { + switch (type) { + case 0: plugin->fog_type = RE_FOG_NONE; return true; + case 1: plugin->fog_type = RE_FOG_LIGHT_SCATTERING; return true; + default: break; + } + } + WARNING("unknown fog type %d", type); + return false; +} + +int RE_plugin_get_fog_type(struct RE_plugin *plugin) +{ + if (re_plugin_version == RE_REIGN_PLUGIN) { + switch (plugin->fog_type) { + case RE_FOG_NONE: return 0; + case RE_FOG_LINEAR: return 1; + case RE_FOG_LIGHT_SCATTERING: return 2; + default: break; + } + } else { + switch (plugin->fog_type) { + case RE_FOG_NONE: return 0; + case RE_FOG_LIGHT_SCATTERING: return 1; + default: break; + } + } + ERROR("[BUG] unexpected fog type %d", plugin->fog_type); +} + void RE_instance_update_local_transform(struct RE_instance *inst) { vec3 euler = { diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 174d6ce..df48244 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -236,7 +236,7 @@ struct RE_renderer *RE_renderer_new(void) r->dir_lights[i].globe_diffuse = glGetUniformLocation(r->program, buf); } r->specular_light_dir = glGetUniformLocation(r->program, "specular_light_dir"); - r->specular_strength = glGetUniformLocation(r->program, "specular_strength"); + r->specular_color = glGetUniformLocation(r->program, "specular_color"); r->specular_shininess = glGetUniformLocation(r->program, "specular_shininess"); r->use_specular_map = glGetUniformLocation(r->program, "use_specular_map"); r->specular_texture = glGetUniformLocation(r->program, "specular_texture"); @@ -259,6 +259,13 @@ struct RE_renderer *RE_renderer_new(void) r->ls_light_dir = glGetUniformLocation(r->program, "ls_light_dir"); r->ls_light_color = glGetUniformLocation(r->program, "ls_light_color"); r->ls_sun_color = glGetUniformLocation(r->program, "ls_sun_color"); + r->hemi_light_dir = glGetUniformLocation(r->program, "hemi_light_dir"); + r->hemi_sky_color = glGetUniformLocation(r->program, "hemi_sky_color"); + r->hemi_mid_color = glGetUniformLocation(r->program, "hemi_mid_color"); + r->hemi_ground_color = glGetUniformLocation(r->program, "hemi_ground_color"); + r->tonemap_param = glGetUniformLocation(r->program, "tonemap_param"); + r->tonemap_param2 = glGetUniformLocation(r->program, "tonemap_param2"); + r->nolighting = glGetUniformLocation(r->program, "nolighting"); r->alpha_mode = glGetUniformLocation(r->program, "alpha_mode"); r->alpha_texture = glGetUniformLocation(r->program, "alpha_texture"); r->uv_scroll = glGetUniformLocation(r->program, "uv_scroll"); @@ -424,13 +431,22 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); } - glUniform1i(r->fog_type, (inst->plugin->fog_mode && !(mesh->flags & MESH_NOLIGHTING)) - ? inst->plugin->fog_type : 0); + int fog_type = inst->plugin->fog_type; + if (!inst->plugin->fog_mode || (re_plugin_version == RE_REIGN_PLUGIN && (mesh->flags & MESH_NOLIGHTING))) { + fog_type = RE_FOG_NONE; + } + glUniform1i(r->fog_type, fog_type); + glUniform1i(r->nolighting, !!(mesh->flags & MESH_NOLIGHTING)); GLboolean use_specular_map = GL_FALSE; if (inst->plugin->specular_mode && !(mesh->flags & MESH_NOLIGHTING)) { - glUniform1f(r->specular_strength, material->specular_strength); - glUniform1f(r->specular_shininess, material->specular_shininess); + if (mesh->flags & MESH_HAS_SPECULAR_COLOR) { + glUniform3fv(r->specular_color, 1, mesh->specular_color); + } else { + glUniform3f(r->specular_color, material->specular_strength, material->specular_strength, material->specular_strength); + } + float shininess = (mesh->flags & MESH_HAS_SPECULAR_POWER) ? mesh->specular_power : material->specular_shininess; + glUniform1f(r->specular_shininess, shininess); if (material->specular_map) { glActiveTexture(GL_TEXTURE0 + SPECULAR_TEXTURE_UNIT); glBindTexture(GL_TEXTURE_2D, material->specular_map); @@ -438,8 +454,8 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d use_specular_map = GL_TRUE; } } else { - glUniform1f(r->specular_strength, 0.0); - glUniform1f(r->specular_shininess, 0.0); + glUniform3f(r->specular_color, 0.0f, 0.0f, 0.0f); + glUniform1f(r->specular_shininess, 0.0f); } glUniform1i(r->use_specular_map, use_specular_map); @@ -556,7 +572,7 @@ static void reset_draw_uniforms(struct RE_renderer *r) glUniform3f(r->diffuse_mod, 1.0f, 1.0f, 1.0f); glUniform2f(r->uv_scroll, 0.0f, 0.0f); glUniform1i(r->has_bones, GL_FALSE); - glUniform1f(r->specular_strength, 0.0f); + glUniform3f(r->specular_color, 0.0f, 0.0f, 0.0f); glUniform1f(r->specular_shininess, 0.0f); glUniform1i(r->use_specular_map, GL_FALSE); glUniform1f(r->rim_exponent, 0.0f); @@ -1106,6 +1122,53 @@ static void render_back_cg(struct texture *dst, struct RE_back_cg *bcg, struct R gfx_copy_stretch_blend_amap_alpha(dst, bcg->x, bcg->y, sw * bcg->mag, sh * bcg->mag, &bcg->texture, 0, 0, sw, sh, bcg->blend_rate * 255); } +static void setup_light_scattering(struct RE_plugin *plugin) +{ + struct RE_renderer *r = plugin->renderer; + if (re_plugin_version >= RE_SEAL_PLUGIN) { + const float *lp = plugin->light_params; + glUniform4f(r->ls_params, lp[SEAL_LP_LS_BETA_R], lp[SEAL_LP_LS_BETA_M], + lp[SEAL_LP_LS_G], lp[SEAL_LP_LS_DISTANCE]); + glUniform3f(r->ls_light_dir, lp[SEAL_LP_LS_LIGHT_VEC], + lp[SEAL_LP_LS_LIGHT_VEC + 1], -lp[SEAL_LP_LS_LIGHT_VEC + 2]); + glUniform3fv(r->ls_light_color, 1, &lp[SEAL_LP_LS_LIGHT_COLOR]); + glUniform3fv(r->ls_sun_color, 1, &lp[SEAL_LP_LS_SUN_COLOR]); + } else { + glUniform4f(r->ls_params, plugin->ls_beta_r, plugin->ls_beta_m, plugin->ls_g, plugin->ls_distance); + glUniform3fv(r->ls_light_dir, 1, plugin->ls_light_dir); + glUniform3fv(r->ls_light_color, 1, plugin->ls_light_color); + glUniform3fv(r->ls_sun_color, 1, plugin->ls_sun_color); + } +} + +static void setup_hemisphere_light(struct RE_plugin *plugin) +{ + struct RE_renderer *r = plugin->renderer; + const float *lp = plugin->light_params; + vec3 hemi_dir = { + -lp[SEAL_LP_HEMI_VEC], -lp[SEAL_LP_HEMI_VEC + 1], lp[SEAL_LP_HEMI_VEC + 2] + }; + glm_vec3_normalize(hemi_dir); + glUniform3fv(r->hemi_light_dir, 1, hemi_dir); + glUniform3fv(r->hemi_sky_color, 1, &lp[SEAL_LP_HEMI_SKY_COLOR]); + glUniform3fv(r->hemi_mid_color, 1, &lp[SEAL_LP_HEMI_MID_COLOR]); + glUniform3fv(r->hemi_ground_color, 1, &lp[SEAL_LP_HEMI_GROUND_COLOR]); + // SealEngine's specular uses the hemisphere light vector. hemi_dir points + // toward the light, but the shader's specular formula expects the light + // propagation direction. + vec3 spec_dir; + glm_vec3_negate_to(hemi_dir, spec_dir); + glUniform3fv(r->specular_light_dir, 1, spec_dir); +} + +static void setup_tone_mapping(struct RE_plugin *plugin) +{ + struct RE_renderer *r = plugin->renderer; + const float *lp = plugin->light_params; + glUniform4fv(r->tonemap_param, 1, &lp[SEAL_LP_TONEMAP_EXPOSURE_BIAS]); + glUniform4fv(r->tonemap_param2, 1, &lp[SEAL_LP_TONEMAP_C]); +} + static void setup_lights(struct RE_plugin *plugin) { struct RE_renderer *r = plugin->renderer; @@ -1141,6 +1204,9 @@ static void setup_lights(struct RE_plugin *plugin) glUniform3fv(r->dir_lights[light_index].diffuse, 1, zero); glUniform3fv(r->dir_lights[light_index].globe_diffuse, 1, zero); } + + if (re_plugin_version >= RE_SEAL_PLUGIN) + setup_hemisphere_light(plugin); } static int cmp_instances_by_z(const void *lhs, const void *rhs) @@ -1248,10 +1314,7 @@ void RE_render(struct sact_sprite *sp) glUniform3fv(r->fog_color, 1, plugin->fog_color); break; case RE_FOG_LIGHT_SCATTERING: - glUniform4f(r->ls_params, plugin->ls_beta_r, plugin->ls_beta_m, plugin->ls_g, plugin->ls_distance); - glUniform3fv(r->ls_light_dir, 1, plugin->ls_light_dir); - glUniform3fv(r->ls_light_color, 1, plugin->ls_light_color); - glUniform3fv(r->ls_sun_color, 1, plugin->ls_sun_color); + setup_light_scattering(plugin); break; } } @@ -1259,6 +1322,8 @@ void RE_render(struct sact_sprite *sp) glEnable(GL_BLEND); setup_lights(plugin); + if (re_plugin_version >= RE_SEAL_PLUGIN) + setup_tone_mapping(plugin); // Sort instances by z-order. struct RE_instance **sorted_instances = sort_instances(plugin, view_transform); diff --git a/src/hll/ReignEngine.c b/src/hll/ReignEngine.c index c501453..f63f7cf 100644 --- a/src/hll/ReignEngine.c +++ b/src/hll/ReignEngine.c @@ -16,6 +16,7 @@ #include #include +#include #include "system4.h" #include "system4/aar.h" @@ -1178,14 +1179,7 @@ static bool ReignEngine_SetShadowMapResolutionLevel(int plugin, int level) static bool ReignEngine_SetFogType(int plugin, int type) { struct RE_plugin *p = get_plugin(plugin); - if (!p) - return false; - if (type != RE_FOG_LINEAR && type != RE_FOG_LIGHT_SCATTERING) { - WARNING("unknown fog type %d", type); - return false; - } - p->fog_type = type; - return true; + return p ? RE_plugin_set_fog_type(p, type) : false; } static bool ReignEngine_SetFogNear(int plugin, float near) @@ -1220,7 +1214,7 @@ static bool ReignEngine_SetFogColor(int plugin, float r, float g, float b) static int ReignEngine_GetFogType(int plugin) { struct RE_plugin *p = get_plugin(plugin); - return p ? p->fog_type : 0; + return p ? RE_plugin_get_fog_type(p) : 0; } static float ReignEngine_GetFogNear(int plugin) @@ -2449,8 +2443,25 @@ static bool SealEngine_IsExistInstanceMotion(int plugin, int instance, struct st //bool SealEngine_AddLineList(int PluginNumber, int InstanceNumber, float X0, float Y0, float Z0, int Color0, float X1, float Y1, float Z1, int Color1); HLL_WARN_UNIMPLEMENTED(false, bool, SealEngine, SetInstanceCircleShadowRadius, int PluginNumber, int InstanceNumber, float CircleShadowRadius); //float SealEngine_GetInstanceCircleShadowRadius(int PluginNumber, int InstanceNumber); -//bool SealEngine_LoadInstanceLightParam(int PluginNumber, int InstanceNumber); -HLL_WARN_UNIMPLEMENTED(false, bool, SealEngine, StoreInstanceLightParam, int PluginNumber, int InstanceNumber); +static bool SealEngine_LoadInstanceLightParam(int plugin, int instance) +{ + struct RE_plugin *rp = get_plugin(plugin); + struct RE_instance *ri = get_instance(plugin, instance); + if (!rp || !ri || !ri->light_params) + return false; + memcpy(ri->light_params, rp->light_params, RE_NR_LIGHT_PARAMS * sizeof(float)); + return true; +} + +static bool SealEngine_StoreInstanceLightParam(int plugin, int instance) +{ + struct RE_plugin *rp = get_plugin(plugin); + struct RE_instance *ri = get_instance(plugin, instance); + if (!rp || !ri || !ri->light_params) + return false; + memcpy(rp->light_params, ri->light_params, RE_NR_LIGHT_PARAMS * sizeof(float)); + return true; +} static bool SealEngine_SetInstanceUseMagSpeed(int plugin, int instance, bool use_mag_speed) { struct RE_instance *ri = get_instance(plugin, instance); @@ -2517,9 +2528,31 @@ static bool SealEngine_TransformPosToViewPos(int PluginNumber, float x, float y, return RE_plugin_transform_pos_to_view_pos(get_plugin(PluginNumber), x, y, -z, view_x, view_y); } -HLL_WARN_UNIMPLEMENTED(false, bool, SealEngine, ResetLightParam, int PluginNumber); -//bool SealEngine_SetLightParam(int PluginNumber, int Type, float Value); -//float SealEngine_GetLightParam(int PluginNumber, int Type); +static bool SealEngine_ResetLightParam(int plugin) +{ + struct RE_plugin *rp = get_plugin(plugin); + if (!rp) + return false; + RE_plugin_reset_light_param(rp); + return true; +} + +static bool SealEngine_SetLightParam(int plugin, int type, float value) +{ + struct RE_plugin *rp = get_plugin(plugin); + if (!rp || (unsigned)type >= RE_NR_LIGHT_PARAMS) + return false; + rp->light_params[type] = value; + return true; +} + +static float SealEngine_GetLightParam(int plugin, int type) +{ + struct RE_plugin *rp = get_plugin(plugin); + if (!rp || (unsigned)type >= RE_NR_LIGHT_PARAMS) + return 0.0f; + return rp->light_params[type]; +} HLL_QUIET_UNIMPLEMENTED(false, bool, SealEngine, IsThreadLoadingMode, int PluginNumber); //bool SealEngine_ClearCache(int PluginNumber); //bool SealEngine_GetHistogram(int PluginNumber, struct page **HistogramList); @@ -2582,7 +2615,7 @@ HLL_QUIET_UNIMPLEMENTED(false, bool, SealEngine, IsThreadLoadingMode, int Plugin HLL_TODO_EXPORT(AddLineList, SealEngine_AddLineList), \ HLL_EXPORT(SetInstanceCircleShadowRadius, SealEngine_SetInstanceCircleShadowRadius), \ HLL_TODO_EXPORT(GetInstanceCircleShadowRadius, SealEngine_GetInstanceCircleShadowRadius), \ - HLL_TODO_EXPORT(LoadInstanceLightParam, SealEngine_LoadInstanceLightParam), \ + HLL_EXPORT(LoadInstanceLightParam, SealEngine_LoadInstanceLightParam), \ HLL_EXPORT(StoreInstanceLightParam, SealEngine_StoreInstanceLightParam), \ HLL_EXPORT(SetInstanceUseMagSpeed, SealEngine_SetInstanceUseMagSpeed), \ HLL_EXPORT(IsInstanceUseMagSpeed, SealEngine_IsInstanceUseMagSpeed), \ @@ -2623,8 +2656,8 @@ HLL_QUIET_UNIMPLEMENTED(false, bool, SealEngine, IsThreadLoadingMode, int Plugin HLL_TODO_EXPORT(GetOptimizedPathLine, SealEngine_GetOptimizedPathLine), \ HLL_EXPORT(TransformPosToViewPos, SealEngine_TransformPosToViewPos), \ HLL_EXPORT(ResetLightParam, SealEngine_ResetLightParam), \ - HLL_TODO_EXPORT(SetLightParam, SealEngine_SetLightParam), \ - HLL_TODO_EXPORT(GetLightParam, SealEngine_GetLightParam), \ + HLL_EXPORT(SetLightParam, SealEngine_SetLightParam), \ + HLL_EXPORT(GetLightParam, SealEngine_GetLightParam), \ HLL_EXPORT(IsThreadLoadingMode, SealEngine_IsThreadLoadingMode), \ HLL_TODO_EXPORT(ClearCache, SealEngine_ClearCache), \ HLL_TODO_EXPORT(GetHistogram, SealEngine_GetHistogram)