diff --git a/include/reign.h b/include/reign.h index 5ece7b9..dea70c4 100644 --- a/include/reign.h +++ b/include/reign.h @@ -109,6 +109,7 @@ struct RE_instance { vec3 scale; float alpha; bool draw; + bool draw_bump; float fps; bool motion_blend; float motion_blend_rate; diff --git a/shaders/reign.f.glsl b/shaders/reign.f.glsl index 791f79b..0f67ba9 100644 --- a/shaders/reign.f.glsl +++ b/shaders/reign.f.glsl @@ -24,40 +24,57 @@ struct dir_light { uniform sampler2D tex; uniform sampler2D specular_texture; +uniform sampler2D light_texture; uniform float alpha_mod; +uniform bool use_normal_map; +uniform sampler2D normal_texture; + 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 bool use_specular_map; uniform float rim_exponent; uniform vec3 rim_color; -uniform vec3 view_pos; +uniform bool use_light_map; in vec2 tex_coord; -in vec3 normal; +in vec2 light_tex_coord; in vec3 frag_pos; +in vec3 eye; +in vec3 normal; +in vec3 light_dir[NR_DIR_LIGHTS]; +in vec3 specular_dir; out vec4 frag_color; void main() { - vec3 norm = normalize(normal); - vec3 view_dir = normalize(view_pos - frag_pos); + vec3 norm; + if (use_normal_map) { + // NOTE: TT3's shader doesn't normalize this vector. + norm = texture(normal_texture, tex_coord).rgb * 2.0 - 1.0; + } else { + norm = normalize(normal); + } + + vec3 view_dir = normalize(eye - frag_pos); 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; + float half_lambert = dot(norm, -light_dir[i]) * 0.5 + 0.5; diffuse += mix(dir_lights[i].globe_diffuse, dir_lights[i].diffuse, half_lambert); } + if (use_light_map) { + diffuse *= texture(light_texture, light_tex_coord).rgb; + } vec4 texel = texture(tex, tex_coord); frag_rgb += texel.rgb * diffuse; // Specular lighting if (specular_strength > 0.0) { - vec3 reflect_dir = reflect(specular_light_dir, norm); + vec3 reflect_dir = reflect(specular_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; @@ -66,8 +83,9 @@ void main() { } // Rim lighting - if (rim_exponent > 0) { - frag_rgb += pow(1.0 - max(dot(norm, view_dir), 0.0), rim_exponent) * rim_color; + if (rim_exponent > 0.0) { + // Normal map is not used here. + frag_rgb += pow(1.0 - max(dot(normalize(normal), view_dir), 0.0), rim_exponent) * rim_color; } frag_color = vec4(frag_rgb, texel.a * alpha_mod); diff --git a/shaders/reign.v.glsl b/shaders/reign.v.glsl index 832b229..4d16479 100644 --- a/shaders/reign.v.glsl +++ b/shaders/reign.v.glsl @@ -14,6 +14,14 @@ * along with this program; if not, see . */ +#define NR_DIR_LIGHTS 3 + +struct dir_light { + vec3 dir; + vec3 diffuse; + vec3 globe_diffuse; +}; + uniform mat4 local_transform; uniform mat4 view_transform; uniform mat4 proj_transform; @@ -24,31 +32,66 @@ const int NR_WEIGHTS = 4; uniform bool has_bones; uniform mat4 bone_matrices[MAX_BONES]; +uniform bool use_normal_map; + +uniform vec3 view_pos; +uniform dir_light dir_lights[NR_DIR_LIGHTS]; +uniform vec3 specular_light_dir; + in vec3 vertex_pos; in vec3 vertex_normal; in vec2 vertex_uv; +in vec2 vertex_light_uv; +in vec4 vertex_tangent; in ivec4 vertex_bone_index; in vec4 vertex_bone_weight; out vec2 tex_coord; -out vec3 normal; +out vec2 light_tex_coord; out vec3 frag_pos; +out vec3 eye; +out vec3 normal; +out vec3 light_dir[NR_DIR_LIGHTS]; +out vec3 specular_dir; void main() { - mat4 bone_transform = mat4(1.0f); + mat4 local_bone_transform = local_transform; + mat3 normal_bone_transform = normal_transform; if (has_bones) { - bone_transform = mat4(0.f); + mat4 bone_transform = mat4(0.f); for (int i = 0; i < NR_WEIGHTS; i++) { if (vertex_bone_index[i] >= 0) { bone_transform += bone_matrices[vertex_bone_index[i]] * vertex_bone_weight[i]; } } + local_bone_transform *= bone_transform; + normal_bone_transform *= mat3(bone_transform); } - vec4 world_pos = local_transform * bone_transform * vec4(vertex_pos, 1.0); + // World-space normal vector. + normal = normal_bone_transform * vertex_normal; + + mat3 TBN = mat3(1.0f); + if (use_normal_map) { + vec3 tangent = normal_bone_transform * vertex_tangent.xyz; + vec3 bitangent = cross(normal, tangent) * vertex_tangent.w; + TBN = transpose(mat3(tangent, bitangent, normal)); + // Tangent-space normal vector. + normal = vec3(0.0, 0.0, 1.0); + } + + vec4 world_pos = local_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); + light_tex_coord = vertex_light_uv; + + // These are in tangent-space if use_normal_map is true, in world-space + // otherwise. + frag_pos = TBN * vec3(world_pos); + eye = TBN * view_pos; + 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; } diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index 9877710..f06be1f 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -48,6 +48,8 @@ struct mesh { struct material { GLuint color_map; GLuint specular_map; + GLuint light_map; + GLuint normal_map; float specular_strength; float specular_shininess; float rim_exponent; @@ -97,10 +99,16 @@ struct RE_renderer { GLint rim_exponent; GLint rim_color; GLint view_pos; + GLint use_light_map; + GLint light_texture; + GLint use_normal_map; + GLint normal_texture; // Attribute variable locations GLint vertex_normal; GLint vertex_uv; + GLint vertex_light_uv; + GLint vertex_tangent; GLint vertex_bone_index; GLint vertex_bone_weight; @@ -144,6 +152,8 @@ struct pol { enum pol_texture_type { COLOR_MAP = 1, SPECULAR_MAP = 4, + LIGHT_MAP = 7, + NORMAL_MAP = 8, MAX_TEXTURE_TYPE }; @@ -165,6 +175,8 @@ struct pol_mesh { struct pol_vertex *vertices; uint32_t nr_uvs; vec2 *uvs; + uint32_t nr_light_uvs; + vec2 *light_uvs; uint32_t nr_triangles; struct pol_triangle *triangles; }; @@ -183,6 +195,7 @@ struct pol_bone_weight { struct pol_triangle { uint32_t vert_index[3]; uint32_t uv_index[3]; + uint32_t light_uv_index[3]; vec3 normals[3]; uint32_t material; // index in the material group }; diff --git a/src/3d/model.c b/src/3d/model.c index 8e9099f..4460130 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -14,6 +14,7 @@ * along with this program; if not, see . */ +#include #include #include #include @@ -28,10 +29,21 @@ #define NR_WEIGHTS 4 -struct vertex { +struct vertex_common { GLfloat pos[3]; GLfloat normal[3]; GLfloat uv[2]; +}; + +struct vertex_light_uv { + GLfloat uv[2]; +}; + +struct vertex_tangent { + GLfloat tangent[4]; +}; + +struct vertex_bones { GLint bone_id[NR_WEIGHTS]; GLfloat bone_weight[NR_WEIGHTS]; }; @@ -84,9 +96,12 @@ static bool init_material(struct material *material, const struct pol_material * if (!material->color_map) return false; - if (m->textures[SPECULAR_MAP]) { + if (m->textures[SPECULAR_MAP]) material->specular_map = load_texture(aar, path, m->textures[SPECULAR_MAP]); - } + if (m->textures[LIGHT_MAP]) + material->light_map = load_texture(aar, path, m->textures[LIGHT_MAP]); + if (m->textures[NORMAL_MAP]) + material->normal_map = load_texture(aar, path, m->textures[NORMAL_MAP]); struct amt_material *amt_m = amt ? amt_find_material(amt, m->name) : NULL; if (amt_m) { @@ -109,6 +124,10 @@ static void destroy_material(struct material *material) glDeleteTextures(1, &material->color_map); if (material->specular_map) glDeleteTextures(1, &material->specular_map); + if (material->light_map) + glDeleteTextures(1, &material->light_map); + if (material->normal_map) + glDeleteTextures(1, &material->normal_map); } static int cmp_by_bone_weight(const void *lhs, const void *rhs) @@ -130,65 +149,171 @@ static void sort_and_normalize_bone_weights(struct pol_vertex *v) } } +static void calc_tangent(struct pol_mesh *m, struct pol_triangle *t, vec4 tangent[3]) +{ + vec3 v1, v2; + glm_vec3_sub(m->vertices[t->vert_index[1]].pos, m->vertices[t->vert_index[0]].pos, v1); + glm_vec3_sub(m->vertices[t->vert_index[2]].pos, m->vertices[t->vert_index[0]].pos, v2); + + vec2 w1, w2; + glm_vec2_sub(m->uvs[t->uv_index[1]], m->uvs[t->uv_index[0]], w1); + glm_vec2_sub(m->uvs[t->uv_index[2]], m->uvs[t->uv_index[0]], w2); + + float r = 1.0 / (w1[0] * w2[1] - w2[0] * w1[1]); + if (!isfinite(r)) // degenerate uv triangle + r = 1.0; // ?? + + vec3 sdir, tdir; + glm_vec3_scale(v1, w2[1], sdir); + glm_vec3_muladds(v2, -w1[1], sdir); + glm_vec3_scale(sdir, r, sdir); + + glm_vec3_scale(v2, w1[0], tdir); + glm_vec3_muladds(v1, -w2[0], tdir); + glm_vec3_scale(tdir, r, tdir); + + for (int i = 0; i < 3; i++) { + vec3 s; + glm_vec3_copy(sdir, s); + + // Gram-Schmidt orthogonalize. + glm_vec3_muladds(t->normals[i], -glm_vec3_dot(t->normals[i], s), s); + glm_vec3_normalize(s); + + // Calculate handedness. + vec3 c; + glm_vec3_cross(t->normals[i], sdir, c); + float w = (glm_vec3_dot(c, tdir) < 0.0) ? -1.0 : 1.0; + + glm_vec4(s, w, tangent[i]); + } +} + +static void *buf_alloc(uint8_t **ptr, int size) +{ + void *p = *ptr; + *ptr += size; + return p; +} + static void add_mesh(struct model *model, struct pol_mesh *m, int material_index, int material, struct RE_renderer *r) { - struct vertex *buf = xmalloc(m->nr_triangles * 3 * sizeof(struct vertex)); - int v = 0; + bool has_light_map = m->light_uvs && model->materials[material].light_map; + bool has_normal_map = model->materials[material].normal_map != 0; + bool has_bones = !!model->bone_map; + + GLsizei stride = sizeof(struct vertex_common); + if (has_light_map) + stride += sizeof(struct vertex_light_uv); + if (has_normal_map) + stride += sizeof(struct vertex_tangent); + if (has_bones) + stride += sizeof(struct vertex_bones); + + void *buffer = xmalloc(m->nr_triangles * 3 * stride); + uint8_t *ptr = buffer; + + int nr_vertices = 0; for (uint32_t i = 0; i < m->nr_triangles; i++) { struct pol_triangle *t = &m->triangles[i]; if (material_index >= 0 && t->material != (uint32_t)material_index) continue; + vec4 tangent[3]; + if (has_normal_map) + calc_tangent(m, t, tangent); for (int j = 0; j < 3; j++) { struct pol_vertex *vert = &m->vertices[t->vert_index[j]]; - glm_vec3_copy(vert->pos, buf[v].pos); - glm_vec3_copy(t->normals[j], buf[v].normal); - glm_vec2_copy(m->uvs[t->uv_index[j]], buf[v].uv); - sort_and_normalize_bone_weights(vert); - for (uint32_t k = 0; k < NR_WEIGHTS; k++) { - if (model->bone_map && k < vert->nr_weights) { - struct bone *bone = ht_get_int(model->bone_map, vert->weights[k].bone, NULL); - if (!bone) - WARNING("%s: invalid bone id in vertex data", model->path); - buf[v].bone_id[k] = bone ? bone->index : -1; - buf[v].bone_weight[k] = vert->weights[k].weight; - } else { - buf[v].bone_id[k] = -1; - buf[v].bone_weight[k] = 0.0; + struct vertex_common *v_common = buf_alloc(&ptr, sizeof(struct vertex_common)); + glm_vec3_copy(vert->pos, v_common->pos); + glm_vec3_copy(t->normals[j], v_common->normal); + glm_vec2_copy(m->uvs[t->uv_index[j]], v_common->uv); + if (has_light_map) { + struct vertex_light_uv *v_light_uv = buf_alloc(&ptr, sizeof(struct vertex_light_uv)); + glm_vec2_copy(m->light_uvs[t->light_uv_index[j]], v_light_uv->uv); + } + if (has_normal_map) { + struct vertex_tangent *v_tangent = buf_alloc(&ptr, sizeof(struct vertex_tangent)); + glm_vec4_ucopy(tangent[j], v_tangent->tangent); + } + if (has_bones) { + struct vertex_bones *v_bones = buf_alloc(&ptr, sizeof(struct vertex_bones)); + sort_and_normalize_bone_weights(vert); + for (uint32_t k = 0; k < NR_WEIGHTS; k++) { + if (k < vert->nr_weights) { + struct bone *bone = ht_get_int(model->bone_map, vert->weights[k].bone, NULL); + if (!bone) + WARNING("%s: invalid bone id in vertex data", model->path); + v_bones->bone_id[k] = bone ? bone->index : -1; + v_bones->bone_weight[k] = vert->weights[k].weight; + } else { + v_bones->bone_id[k] = -1; + v_bones->bone_weight[k] = 0.0; + } } } - v++; + nr_vertices++; } } - if (v == 0) { - free(buf); + assert(ptr == (uint8_t *)buffer + nr_vertices * stride); + + if (nr_vertices == 0) { + free(buffer); return; } model->meshes = xrealloc_array(model->meshes, model->nr_meshes, model->nr_meshes + 1, sizeof(struct mesh)); struct mesh *mesh = &model->meshes[model->nr_meshes++]; mesh->material = material; - mesh->nr_vertices = v; + mesh->nr_vertices = nr_vertices; glGenVertexArrays(1, &mesh->vao); glBindVertexArray(mesh->vao); glGenBuffers(1, &mesh->attr_buffer); glBindBuffer(GL_ARRAY_BUFFER, mesh->attr_buffer); + const uint8_t *base = (const uint8_t *)0; glEnableVertexAttribArray(r->shader.vertex); - glVertexAttribPointer(r->shader.vertex, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)0); + glVertexAttribPointer(r->shader.vertex, 3, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_common, pos)); glEnableVertexAttribArray(r->vertex_normal); - glVertexAttribPointer(r->vertex_normal, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)offsetof(struct vertex, normal)); + glVertexAttribPointer(r->vertex_normal, 3, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_common, normal)); glEnableVertexAttribArray(r->vertex_uv); - glVertexAttribPointer(r->vertex_uv, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)offsetof(struct vertex, uv)); - glEnableVertexAttribArray(r->vertex_bone_index); - glVertexAttribIPointer(r->vertex_bone_index, NR_WEIGHTS, GL_INT, sizeof(struct vertex), (const void *)offsetof(struct vertex, bone_id)); - glEnableVertexAttribArray(r->vertex_bone_weight); - glVertexAttribPointer(r->vertex_bone_weight, NR_WEIGHTS, GL_FLOAT, GL_FALSE, sizeof(struct vertex), (const void *)offsetof(struct vertex, bone_weight)); - glBufferData(GL_ARRAY_BUFFER, mesh->nr_vertices * sizeof(struct vertex), buf, GL_STATIC_DRAW); + glVertexAttribPointer(r->vertex_uv, 2, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_common, uv)); + base += sizeof(struct vertex_common); + if (has_light_map) { + glEnableVertexAttribArray(r->vertex_light_uv); + glVertexAttribPointer(r->vertex_light_uv, 2, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_light_uv, uv)); + base += sizeof(struct vertex_light_uv); + } else { + glDisableVertexAttribArray(r->vertex_light_uv); + glVertexAttrib2f(r->vertex_light_uv, 0.0, 0.0); + } + if (has_normal_map) { + glEnableVertexAttribArray(r->vertex_tangent); + glVertexAttribPointer(r->vertex_tangent, 4, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_tangent, tangent)); + base += sizeof(struct vertex_tangent); + } else { + glDisableVertexAttribArray(r->vertex_tangent); + glVertexAttrib3f(r->vertex_tangent, 1.0, 0.0, 0.0); + } + if (has_bones) { + glEnableVertexAttribArray(r->vertex_bone_index); + glVertexAttribIPointer(r->vertex_bone_index, NR_WEIGHTS, GL_INT, stride, base + offsetof(struct vertex_bones, bone_id)); + glEnableVertexAttribArray(r->vertex_bone_weight); + glVertexAttribPointer(r->vertex_bone_weight, NR_WEIGHTS, GL_FLOAT, GL_FALSE, stride, base + offsetof(struct vertex_bones, bone_weight)); + base += sizeof(struct vertex_bones); + } else { + glDisableVertexAttribArray(r->vertex_bone_index); + glVertexAttribI4i(r->vertex_bone_index, 0, 0, 0, 0); + glDisableVertexAttribArray(r->vertex_bone_weight); + glVertexAttrib4f(r->vertex_bone_weight, 0.0, 0.0, 0.0, 0.0); + } + assert((intptr_t)base == stride); + + glBufferData(GL_ARRAY_BUFFER, mesh->nr_vertices * stride, buffer, GL_STATIC_DRAW); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); - free(buf); + free(buffer); } static void destroy_mesh(struct mesh *mesh) diff --git a/src/3d/parser.c b/src/3d/parser.c index 49e0743..6df07ed 100644 --- a/src/3d/parser.c +++ b/src/3d/parser.c @@ -125,14 +125,20 @@ static void destroy_vertex(struct pol_vertex *v) free(v->weights); } -static void parse_triangle(struct buffer *r, int unknowns_length, struct pol_triangle *t) +static void parse_triangle(struct buffer *r, struct pol_mesh *mesh, int triangle_index, int unknowns_length) { + struct pol_triangle *t = &mesh->triangles[triangle_index]; t->vert_index[0] = buffer_read_int32(r); t->vert_index[1] = buffer_read_int32(r); t->vert_index[2] = buffer_read_int32(r); t->uv_index[0] = buffer_read_int32(r); t->uv_index[1] = buffer_read_int32(r); t->uv_index[2] = buffer_read_int32(r); + if (mesh->light_uvs) { + t->light_uv_index[0] = buffer_read_int32(r) - mesh->nr_uvs; + t->light_uv_index[1] = buffer_read_int32(r) - mesh->nr_uvs; + t->light_uv_index[2] = buffer_read_int32(r) - mesh->nr_uvs; + } buffer_skip(r, unknowns_length); @@ -167,14 +173,16 @@ static struct pol_mesh *parse_mesh(struct buffer *r, int pol_version) mesh->uvs[i][1] = buffer_read_float(r); } - int triangle_unknowns_length = 12; - - int nr_unknown_f64s = buffer_read_int32(r); - if (nr_unknown_f64s) { - buffer_skip(r, nr_unknown_f64s * 8); - triangle_unknowns_length += 12; + mesh->nr_light_uvs = buffer_read_int32(r); + if (mesh->nr_light_uvs > 0) { + mesh->light_uvs = xcalloc(mesh->nr_light_uvs, sizeof(vec2)); + for (uint32_t i = 0; i < mesh->nr_light_uvs; i++) { + mesh->light_uvs[i][0] = buffer_read_float(r); + mesh->light_uvs[i][1] = buffer_read_float(r); + } } + int triangle_unknowns_length = 12; if (pol_version == 1) { int nr_unknown_vecs = buffer_read_int32(r); buffer_skip(r, nr_unknown_vecs * 12); @@ -191,7 +199,7 @@ static struct pol_mesh *parse_mesh(struct buffer *r, int pol_version) mesh->nr_triangles = buffer_read_int32(r); mesh->triangles = xcalloc(mesh->nr_triangles, sizeof(struct pol_triangle)); for (uint32_t i = 0; i < mesh->nr_triangles; i++) { - parse_triangle(r, triangle_unknowns_length, &mesh->triangles[i]); + parse_triangle(r, mesh, i, triangle_unknowns_length); } if (pol_version == 1) { @@ -213,6 +221,7 @@ static void free_mesh(struct pol_mesh *mesh) destroy_vertex(&mesh->vertices[i]); free(mesh->vertices); free(mesh->uvs); + free(mesh->light_uvs); free(mesh->triangles); free(mesh); } diff --git a/src/3d/reign.c b/src/3d/reign.c index bf265c7..32b8000 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -40,6 +40,7 @@ static struct RE_instance *create_instance(struct RE_plugin *plugin) instance->scale[1] = 1.0; instance->scale[2] = 1.0; instance->alpha = 1.0; + instance->draw_bump = true; instance->fps = 30.0; glm_mat4_identity(instance->local_transform); glm_mat3_identity(instance->normal_transform); diff --git a/src/3d/renderer.c b/src/3d/renderer.c index 653a45b..b630197 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -30,6 +30,8 @@ enum { COLOR_TEXTURE_UNIT, SPECULAR_TEXTURE_UNIT, + LIGHT_TEXTURE_UNIT, + NORMAL_TEXTURE_UNIT, }; static void init_billboard_mesh(struct RE_renderer *r) @@ -50,8 +52,12 @@ static void init_billboard_mesh(struct RE_renderer *r) glVertexAttribPointer(r->shader.vertex, 3, GL_FLOAT, GL_FALSE, 20, (const void *)0); glEnableVertexAttribArray(r->vertex_uv); glVertexAttribPointer(r->vertex_uv, 2, GL_FLOAT, GL_FALSE, 20, (const void *)12); + glDisableVertexAttribArray(r->vertex_light_uv); + glVertexAttrib2f(r->vertex_light_uv, 0.0, 0.0); glDisableVertexAttribArray(r->vertex_normal); glVertexAttrib3f(r->vertex_normal, 0.0, 0.0, 1.0); + glDisableVertexAttribArray(r->vertex_tangent); + glVertexAttrib3f(r->vertex_tangent, 1.0, 0.0, 0.0); glDisableVertexAttribArray(r->vertex_bone_index); glVertexAttribI4i(r->vertex_bone_index, 0, 0, 0, 0); glDisableVertexAttribArray(r->vertex_bone_weight); @@ -92,8 +98,14 @@ struct RE_renderer *RE_renderer_new(struct texture *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->use_light_map = glGetUniformLocation(r->shader.program, "use_light_map"); + r->light_texture = glGetUniformLocation(r->shader.program, "light_texture"); + r->use_normal_map = glGetUniformLocation(r->shader.program, "use_normal_map"); + r->normal_texture = glGetUniformLocation(r->shader.program, "normal_texture"); r->vertex_normal = glGetAttribLocation(r->shader.program, "vertex_normal"); r->vertex_uv = glGetAttribLocation(r->shader.program, "vertex_uv"); + r->vertex_light_uv = glGetAttribLocation(r->shader.program, "vertex_light_uv"); + r->vertex_tangent = glGetAttribLocation(r->shader.program, "vertex_tangent"); r->vertex_bone_index = glGetAttribLocation(r->shader.program, "vertex_bone_index"); r->vertex_bone_weight = glGetAttribLocation(r->shader.program, "vertex_bone_weight"); @@ -298,6 +310,24 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r) glBindTexture(GL_TEXTURE_2D, material->color_map); glUniform1i(r->shader.texture, COLOR_TEXTURE_UNIT); + if (material->light_map && inst->plugin->light_map_mode) { + glUniform1i(r->use_light_map, GL_TRUE); + glActiveTexture(GL_TEXTURE0 + LIGHT_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, material->light_map); + glUniform1i(r->light_texture, LIGHT_TEXTURE_UNIT); + } else { + glUniform1i(r->use_light_map, GL_FALSE); + } + + if (material->normal_map && inst->draw_bump && inst->plugin->bump_mode) { + glUniform1i(r->use_normal_map, GL_TRUE); + glActiveTexture(GL_TEXTURE0 + NORMAL_TEXTURE_UNIT); + glBindTexture(GL_TEXTURE_2D, material->normal_map); + glUniform1i(r->normal_texture, NORMAL_TEXTURE_UNIT); + } else { + glUniform1i(r->use_normal_map, GL_FALSE); + } + glBindVertexArray(mesh->vao); glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices); glBindVertexArray(0); @@ -358,6 +388,8 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma glUniform1f(r->specular_shininess, 0.0); glUniform1i(r->use_specular_map, GL_FALSE); glUniform1f(r->rim_exponent, 0.0); + glUniform1i(r->use_light_map, GL_FALSE); + glUniform1i(r->use_normal_map, GL_FALSE); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, bt->texture); diff --git a/src/hll/ReignEngine.c b/src/hll/ReignEngine.c index b98325f..41ae03d 100644 --- a/src/hll/ReignEngine.c +++ b/src/hll/ReignEngine.c @@ -285,7 +285,15 @@ static bool ReignEngine_SetInstanceDraw(int plugin, int instance, bool flag) HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDrawShadow, int plugin, int instance, bool flag); HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDrawBackShadow, int plugin, int instance, bool flag); HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDrawMakeShadow, int plugin, int instance, bool flag); -HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDrawBump, int plugin, int instance, bool flag); + +static bool ReignEngine_SetInstanceDrawBump(int plugin, int instance, bool flag) +{ + struct RE_instance *ri = get_instance(plugin, instance); + if (!ri) + return false; + ri->draw_bump = flag; + return true; +} static bool ReignEngine_GetInstanceDraw(int plugin, int instance) { @@ -298,7 +306,15 @@ static bool ReignEngine_GetInstanceDraw(int plugin, int instance) //bool ReignEngine_GetInstanceDrawShadow(int plugin, int instance); //bool ReignEngine_GetInstanceDrawBackShadow(int plugin, int instance); //bool ReignEngine_GetInstanceDrawMakeShadow(int plugin, int instance); -//bool ReignEngine_GetInstanceDrawBump(int plugin, int instance); + +static bool ReignEngine_GetInstanceDrawBump(int plugin, int instance) +{ + struct RE_instance *ri = get_instance(plugin, instance); + if (!ri) + return false; + return ri->draw_bump; +} + //int ReignEngine_GetInstanceDrawType(int plugin, int instance); HLL_WARN_UNIMPLEMENTED(false, bool, ReignEngine, SetInstanceDrawType, int plugin, int instance, int draw_type); @@ -1164,7 +1180,7 @@ HLL_LIBRARY(ReignEngine, HLL_TODO_EXPORT(GetInstanceDrawShadow, ReignEngine_GetInstanceDrawShadow), HLL_TODO_EXPORT(GetInstanceDrawBackShadow, ReignEngine_GetInstanceDrawBackShadow), HLL_TODO_EXPORT(GetInstanceDrawMakeShadow, ReignEngine_GetInstanceDrawMakeShadow), - HLL_TODO_EXPORT(GetInstanceDrawBump, ReignEngine_GetInstanceDrawBump), + HLL_EXPORT(GetInstanceDrawBump, ReignEngine_GetInstanceDrawBump), HLL_TODO_EXPORT(GetInstanceDrawType, ReignEngine_GetInstanceDrawType), HLL_EXPORT(SetInstanceDrawType, ReignEngine_SetInstanceDrawType), HLL_EXPORT(LoadInstanceMotion, ReignEngine_LoadInstanceMotion),