diff --git a/shaders/reign.f.glsl b/shaders/reign.f.glsl index bafb563..791f79b 100644 --- a/shaders/reign.f.glsl +++ b/shaders/reign.f.glsl @@ -23,6 +23,7 @@ struct dir_light { }; uniform sampler2D tex; +uniform sampler2D specular_texture; uniform float alpha_mod; uniform vec3 ambient; @@ -30,6 +31,9 @@ uniform dir_light dir_lights[NR_DIR_LIGHTS]; uniform vec3 specular_light_dir; uniform float specular_strength; uniform float specular_shininess; +uniform bool use_specular_map; +uniform float rim_exponent; +uniform vec3 rim_color; uniform vec3 view_pos; in vec2 tex_coord; @@ -39,6 +43,7 @@ out vec4 frag_color; void main() { vec3 norm = normalize(normal); + vec3 view_dir = normalize(view_pos - frag_pos); vec3 frag_rgb = ambient; // Diffuse lighting @@ -52,11 +57,18 @@ void main() { // 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; + if (use_specular_map) { + specular *= texture(specular_texture, tex_coord).r; + } frag_rgb += vec3(specular); } + // Rim lighting + if (rim_exponent > 0) { + frag_rgb += pow(1.0 - max(dot(norm, view_dir), 0.0), rim_exponent) * rim_color; + } + frag_color = vec4(frag_rgb, texel.a * alpha_mod); } diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index 5292d31..9877710 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -47,9 +47,11 @@ struct mesh { struct material { GLuint color_map; - bool opaque; + GLuint specular_map; float specular_strength; float specular_shininess; + float rim_exponent; + vec3 rim_color; }; struct bone { @@ -90,6 +92,10 @@ struct RE_renderer { GLint specular_light_dir; GLint specular_strength; GLint specular_shininess; + GLint use_specular_map; + GLint specular_texture; + GLint rim_exponent; + GLint rim_color; GLint view_pos; // Attribute variable locations @@ -137,6 +143,7 @@ struct pol { enum pol_texture_type { COLOR_MAP = 1, + SPECULAR_MAP = 4, MAX_TEXTURE_TYPE }; @@ -220,6 +227,11 @@ struct amt_material { enum amt_field_index { AMT_SPECULAR_STRENGTH = 0, AMT_SPECULAR_SHININESS = 2, + // amt v5+ + AMT_RIM_EXPONENT = 7, + AMT_RIM_R = 8, + AMT_RIM_G = 9, + AMT_RIM_B = 10, }; struct pol *pol_parse(uint8_t *data, size_t size); diff --git a/src/3d/model.c b/src/3d/model.c index f8df832..8e9099f 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -45,27 +45,24 @@ static struct archive_data *get_aar_entry(struct archive *aar, const char *dir, return dfile; } -static bool init_material(struct material *material, const struct pol_material *m, struct amt *amt, struct archive *aar, const char *path) +static GLuint load_texture(struct archive *aar, const char *path, const char *name) { - if (!m->textures[COLOR_MAP]) { - WARNING("No color texture"); - return false; - } - struct archive_data *dfile = get_aar_entry(aar, path, m->textures[COLOR_MAP], ""); + struct archive_data *dfile = get_aar_entry(aar, path, name, ""); if (!dfile) { - WARNING("cannot load texture %s\\%s", path, m->textures[COLOR_MAP]); - return false; + WARNING("cannot load texture %s\\%s", path, name); + return 0; } struct cg *cg = cg_load_data(dfile); if (!cg) { WARNING("cg_load_data failed: %s", dfile->name); archive_free_data(dfile); - return false; + return 0; } archive_free_data(dfile); - glGenTextures(1, &material->color_map); - glBindTexture(GL_TEXTURE_2D, material->color_map); + GLuint texture; + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cg->metrics.w, cg->metrics.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, cg->pixels); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); @@ -73,13 +70,34 @@ static bool init_material(struct material *material, const struct pol_material * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); - material->opaque = !cg->metrics.has_alpha; cg_free(cg); + return texture; +} + +static bool init_material(struct material *material, const struct pol_material *m, struct amt *amt, struct archive *aar, const char *path) +{ + if (!m->textures[COLOR_MAP]) { + WARNING("No color texture"); + return false; + } + material->color_map = load_texture(aar, path, m->textures[COLOR_MAP]); + if (!material->color_map) + return false; + + if (m->textures[SPECULAR_MAP]) { + material->specular_map = load_texture(aar, path, m->textures[SPECULAR_MAP]); + } struct amt_material *amt_m = amt ? amt_find_material(amt, m->name) : NULL; if (amt_m) { material->specular_strength = amt_m->fields[AMT_SPECULAR_STRENGTH]; material->specular_shininess = amt_m->fields[AMT_SPECULAR_SHININESS]; + if (amt->version >= 5) { + material->rim_exponent = amt_m->fields[AMT_RIM_EXPONENT]; + material->rim_color[0] = amt_m->fields[AMT_RIM_R]; + material->rim_color[1] = amt_m->fields[AMT_RIM_G]; + material->rim_color[2] = amt_m->fields[AMT_RIM_B]; + } } return true; @@ -89,6 +107,8 @@ static void destroy_material(struct material *material) { if (material->color_map) glDeleteTextures(1, &material->color_map); + if (material->specular_map) + glDeleteTextures(1, &material->specular_map); } static int cmp_by_bone_weight(const void *lhs, const void *rhs) diff --git a/src/3d/renderer.c b/src/3d/renderer.c index e8e3d21..653a45b 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -27,6 +27,11 @@ #include "sact.h" #include "vm.h" +enum { + COLOR_TEXTURE_UNIT, + SPECULAR_TEXTURE_UNIT, +}; + static void init_billboard_mesh(struct RE_renderer *r) { static const GLfloat vertices[] = { @@ -82,6 +87,10 @@ struct RE_renderer *RE_renderer_new(struct texture *texture) 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->use_specular_map = glGetUniformLocation(r->shader.program, "use_specular_map"); + r->specular_texture = glGetUniformLocation(r->shader.program, "specular_texture"); + r->rim_exponent = glGetUniformLocation(r->shader.program, "rim_exponent"); + r->rim_color = glGetUniformLocation(r->shader.program, "rim_color"); 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"); @@ -266,17 +275,28 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r) struct mesh *mesh = &model->meshes[i]; struct material *material = &model->materials[mesh->material]; + GLboolean use_specular_map = GL_FALSE; if (inst->plugin->specular_mode) { glUniform1f(r->specular_strength, material->specular_strength); glUniform1f(r->specular_shininess, material->specular_shininess); + if (material->specular_map) { + glActiveTexture(GL_TEXTURE0 + SPECULAR_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, material->specular_map); + glUniform1i(r->specular_texture, SPECULAR_TEXTURE_UNIT); + use_specular_map = GL_TRUE; + } } else { glUniform1f(r->specular_strength, 0.0); glUniform1f(r->specular_shininess, 0.0); } + glUniform1i(r->use_specular_map, use_specular_map); - glActiveTexture(GL_TEXTURE0); + glUniform1f(r->rim_exponent, material->rim_exponent); + glUniform3fv(r->rim_color, 1, material->rim_color); + + glActiveTexture(GL_TEXTURE0 + COLOR_TEXTURE_UNIT); glBindTexture(GL_TEXTURE_2D, material->color_map); - glUniform1i(r->shader.texture, 0); + glUniform1i(r->shader.texture, COLOR_TEXTURE_UNIT); glBindVertexArray(mesh->vao); glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices); @@ -336,6 +356,8 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma glUniform1f(r->alpha_mod, inst->alpha); glUniform1f(r->specular_strength, 0.0); glUniform1f(r->specular_shininess, 0.0); + glUniform1i(r->use_specular_map, GL_FALSE); + glUniform1f(r->rim_exponent, 0.0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, bt->texture);