diff --git a/include/reign.h b/include/reign.h index f6c4888..b5424dc 100644 --- a/include/reign.h +++ b/include/reign.h @@ -165,6 +165,8 @@ struct RE_instance { mat4 local_transform; mat3 normal_transform; mat4 *bone_transforms; // model->nr_bones elements + vec4 bounding_sphere; + struct RE_instance *shadow_volume_instance; float z_from_camera; }; @@ -186,6 +188,7 @@ bool RE_instance_set_vertex_pos(struct RE_instance *instance, int index, float x int RE_instance_get_bone_index(struct RE_instance *instance, const char *name); bool RE_instance_trans_local_pos_to_world_pos_by_bone(struct RE_instance *instance, int bone, vec3 offset, vec3 out); float RE_instance_calc_height(struct RE_instance *instance, float x, float z); +bool RE_instance_set_debug_draw_shadow_volume(struct RE_instance *instance, bool draw); 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 6517383..fd29a6b 100644 --- a/shaders/reign.f.glsl +++ b/shaders/reign.f.glsl @@ -52,7 +52,7 @@ uniform bool use_specular_map; uniform float rim_exponent; uniform vec3 rim_color; uniform int diffuse_type; -uniform bool use_shadow_map; +uniform float shadow_darkness; uniform float shadow_bias; uniform int fog_type; uniform float fog_near; @@ -133,26 +133,26 @@ void main() { } // Shadow mapping - if (use_shadow_map) { + if (shadow_darkness > 0.0) { vec3 shadow_coords = shadow_frag_pos.xyz / shadow_frag_pos.w * 0.5 + 0.5; shadow_coords.z = min(1.0, shadow_coords.z - shadow_bias); // PCF with 9 samples. - float shadow_factor = 1.0; + float brightness = 1.0; vec2 texel_size = 1.0 / vec2(textureSize(shadow_texture, 0)); for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { float depth = texture(shadow_texture, shadow_coords.xy + vec2(x, y) * texel_size).r; if (depth < shadow_coords.z) - shadow_factor -= 0.05; + brightness -= 0.05 * shadow_darkness; } } - frag_rgb *= shadow_factor; + frag_rgb *= brightness; } // Alpha mapping float alpha = texel.a * alpha_mod; if (alpha_mode == ALPHA_TEST) { - if (alpha < 1.0) + if (alpha < 0.8) discard; } else if (alpha_mode == ALPHA_MAP_BLEND) { alpha *= texture(alpha_texture, tex_coord).r; diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index 3ef56e1..ff078f0 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -51,7 +51,9 @@ struct mesh { uint32_t flags; GLuint vao; GLuint attr_buffer; + GLuint index_buffer; int nr_vertices; + int nr_indices; int material; }; @@ -65,6 +67,7 @@ struct material { GLuint normal_map; float specular_strength; float specular_shininess; + float shadow_darkness; float rim_exponent; vec3 rim_color; }; @@ -143,7 +146,7 @@ struct RE_renderer { GLint light_texture; GLint use_normal_map; GLint normal_texture; - GLint use_shadow_map; + GLint shadow_darkness; GLint shadow_transform; GLint shadow_texture; GLint shadow_bias; @@ -176,6 +179,7 @@ void RE_instance_update_local_transform(struct RE_instance *inst); struct model *model_load(struct archive *aar, const char *path); void model_free(struct model *model); +struct model *model_create_sphere(int r, int g, int b, int a); struct motion *motion_load(const char *name, struct RE_instance *instance, struct archive *aar); void motion_free(struct motion *motion); @@ -393,6 +397,7 @@ enum mesh_flags { MESH_NOMAKESHADOW = 1 << 1, MESH_ENVMAP = 1 << 2, MESH_BOTH = 1 << 3, + MESH_SPRITE = 1 << 4, }; struct pol_mesh { @@ -425,7 +430,7 @@ struct pol_triangle { uint32_t uv_index[3]; uint32_t light_uv_index[3]; vec3 normals[3]; - uint32_t material; // index in the material group + uint32_t material_group_index; }; struct pol_bone { @@ -468,6 +473,8 @@ struct amt_material { enum amt_field_index { AMT_SPECULAR_STRENGTH = 0, AMT_SPECULAR_SHININESS = 2, + // amt v4+ + AMT_SHADOW_DARKNESS = 6, // amt v5+ AMT_RIM_EXPONENT = 7, AMT_RIM_R = 8, diff --git a/src/3d/model.c b/src/3d/model.c index 15ac432..3936284 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -110,12 +110,15 @@ static bool init_material(struct material *material, const struct pol_material * if (m->textures[NORMAL_MAP]) material->normal_map = load_texture(aar, path, m->textures[NORMAL_MAP], NULL); - material->is_transparent = has_alpha || material->alpha_map; + material->is_transparent = (has_alpha || material->alpha_map) && !(material->flags & MATERIAL_SPRITE); + material->shadow_darkness = 1.0f; 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 >= 4) + material->shadow_darkness = amt_m->fields[AMT_SHADOW_DARKNESS]; if (amt->version >= 5) { material->rim_exponent = amt_m->fields[AMT_RIM_EXPONENT]; material->rim_color[0] = amt_m->fields[AMT_RIM_R]; @@ -211,7 +214,7 @@ static void *buf_alloc(uint8_t **ptr, int size) return p; } -static void add_mesh(struct model *model, struct pol_mesh *m, int material_index, int material) +static void add_mesh(struct model *model, struct pol_mesh *m, uint32_t material_group_index, int material) { bool has_light_map = m->light_uvs && model->materials[material].light_map; bool has_normal_map = model->materials[material].normal_map != 0; @@ -231,7 +234,7 @@ static void add_mesh(struct model *model, struct pol_mesh *m, int material_index 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) + if (t->material_group_index != material_group_index) continue; vec4 tangent[3]; if (has_normal_map) @@ -336,6 +339,8 @@ static void destroy_mesh(struct mesh *mesh) { glDeleteVertexArrays(1, &mesh->vao); glDeleteBuffers(1, &mesh->attr_buffer); + if (mesh->index_buffer) + glDeleteBuffers(1, &mesh->index_buffer); } static struct bone *add_bone(struct model *model, struct pol *pol, struct pol_bone *pol_bone) @@ -460,7 +465,7 @@ struct model *model_load(struct archive *aar, const char *path) struct pol_material_group *mg = &pol->materials[pol->meshes[i]->material]; int m_off = material_offsets[pol->meshes[i]->material]; if (mg->nr_children == 0) { - add_mesh(model, pol->meshes[i], -1, m_off); + add_mesh(model, pol->meshes[i], 0, m_off); continue; } for (uint32_t j = 0; j < mg->nr_children; j++) { @@ -499,6 +504,101 @@ void model_free(struct model *model) free(model); } +static void init_sphere_mesh(struct mesh *mesh) +{ + const int w_segments = 16; + const int h_segments = 16; + const int nr_vertices = (w_segments + 1) * (h_segments + 1); + struct vertex_common *vertices = xcalloc(nr_vertices, sizeof(struct vertex_common)); + struct vertex_common *v = vertices; + for (int y = 0; y <= h_segments; y++) { + float theta = GLM_PIf * y / h_segments; + for (int x = 0; x <= w_segments; x++, v++) { + float phi = 2.0f * GLM_PIf * x / w_segments; + v->pos[0] = -cosf(phi) * sinf(theta); + v->pos[1] = cosf(theta); + v->pos[2] = sinf(phi) * sinf(theta); + glm_vec3_copy(v->pos, v->normal); + v->uv[0] = v->uv[1] = 0.0f; + } + } + assert(v == vertices + nr_vertices); + + const int nr_indices = 3 * 2 * w_segments * (h_segments - 1); + GLushort *indices = xcalloc(nr_indices, sizeof(GLushort)); + GLushort *pi = indices; + for (int y = 0; y < h_segments; y++) { + for (int x = 0; x < w_segments; x++) { + GLushort a = y * w_segments + x + 1; + GLushort b = y * w_segments + x; + GLushort c = (y + 1) * w_segments + x; + GLushort d = (y + 1) * w_segments + x + 1; + if (y > 0) { + *pi++ = a; + *pi++ = b; + *pi++ = d; + } + if (y < h_segments - 1) { + *pi++ = b; + *pi++ = c; + *pi++ = d; + } + } + } + assert(pi == indices + nr_indices); + + mesh->flags = MESH_NOLIGHTING; + mesh->nr_vertices = nr_vertices; + mesh->nr_indices = nr_indices; + glGenVertexArrays(1, &mesh->vao); + glBindVertexArray(mesh->vao); + glGenBuffers(1, &mesh->attr_buffer); + glBindBuffer(GL_ARRAY_BUFFER, mesh->attr_buffer); + glBufferData(GL_ARRAY_BUFFER, nr_vertices * sizeof(struct vertex_common), vertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(VATTR_POS); + glVertexAttribPointer(VATTR_POS, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex_common), (void*)offsetof(struct vertex_common, pos)); + glEnableVertexAttribArray(VATTR_NORMAL); + glVertexAttribPointer(VATTR_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(struct vertex_common), (void*)offsetof(struct vertex_common, normal)); + glEnableVertexAttribArray(VATTR_UV); + glVertexAttribPointer(VATTR_UV, 2, GL_FLOAT, GL_FALSE, sizeof(struct vertex_common), (void*)offsetof(struct vertex_common, uv)); + + glGenBuffers(1, &mesh->index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->index_buffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, nr_indices * sizeof(GLushort), indices, GL_STATIC_DRAW); + glBindVertexArray(0); + + free(vertices); + free(indices); +} + +struct model *model_create_sphere(int r, int g, int b, int a) +{ + struct model *model = xcalloc(1, sizeof(struct model)); + + model->nr_meshes = 1; + model->meshes = xcalloc(1, sizeof(struct mesh)); + init_sphere_mesh(&model->meshes[0]); + model->aabb[0][0] = -1.0f; + model->aabb[0][1] = -1.0f; + model->aabb[0][2] = -1.0f; + model->aabb[1][0] = 1.0f; + model->aabb[1][1] = 1.0f; + model->aabb[1][2] = 1.0f; + + model->nr_materials = 1; + model->materials = xcalloc(1, sizeof(struct material)); + struct material *material = &model->materials[0]; + material->is_transparent = true; + glGenTextures(1, &material->color_map); + glBindTexture(GL_TEXTURE_2D, material->color_map); + uint8_t pixel[4] = {r, g, b, a}; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixel); + glBindTexture(GL_TEXTURE_2D, 0); + model->has_transparent_material = true; + + return model; +} + static int cmp_motions_by_bone_id(const void *lhs, const void *rhs) { return (*(struct mot_bone **)lhs)->id - (*(struct mot_bone **)rhs)->id; diff --git a/src/3d/parser.c b/src/3d/parser.c index 38d975a..228853f 100644 --- a/src/3d/parser.c +++ b/src/3d/parser.c @@ -134,7 +134,7 @@ static void destroy_vertex(struct pol_vertex *v) free(v->weights); } -static void parse_triangle(struct buffer *r, struct pol_mesh *mesh, int triangle_index, int unknowns_length) +static void parse_triangle(struct buffer *r, struct pol_mesh *mesh, int triangle_index, int unknowns_length, const struct pol_material_group *mg) { struct pol_triangle *t = &mesh->triangles[triangle_index]; t->vert_index[0] = buffer_read_int32(r); @@ -154,7 +154,9 @@ static void parse_triangle(struct buffer *r, struct pol_mesh *mesh, int triangle read_direction(r, t->normals[0]); read_direction(r, t->normals[1]); read_direction(r, t->normals[2]); - t->material = buffer_read_int32(r); + t->material_group_index = buffer_read_int32(r); + if (t->material_group_index >= mg->nr_children) + t->material_group_index = 0; } static uint32_t parse_mesh_attributes(const char *name) @@ -168,10 +170,12 @@ static uint32_t parse_mesh_attributes(const char *name) flags |= MESH_ENVMAP; if (strstr(name, "(both)")) flags |= MESH_BOTH; + if (strstr(name, "(sprite)")) + flags |= MESH_SPRITE; return flags; } -static struct pol_mesh *parse_mesh(struct buffer *r, int pol_version) +static struct pol_mesh *parse_mesh(struct buffer *r, const struct pol *pol) { int type = buffer_read_int32(r); if (type != 0) { @@ -183,11 +187,15 @@ static struct pol_mesh *parse_mesh(struct buffer *r, int pol_version) mesh->name = read_cstring(r); mesh->flags = parse_mesh_attributes(mesh->name); mesh->material = buffer_read_int32(r); + if (mesh->material >= pol->nr_materials) { + WARNING("material index out of range (%d >= %d)", mesh->material, pol->nr_materials); + mesh->material = 0; + } mesh->nr_vertices = buffer_read_int32(r); mesh->vertices = xcalloc(mesh->nr_vertices, sizeof(struct pol_vertex)); for (uint32_t i = 0; i < mesh->nr_vertices; i++) { - parse_vertex(r, pol_version, &mesh->vertices[i]); + parse_vertex(r, pol->version, &mesh->vertices[i]); } mesh->nr_uvs = buffer_read_int32(r); @@ -207,7 +215,7 @@ static struct pol_mesh *parse_mesh(struct buffer *r, int pol_version) } int triangle_unknowns_length = 12; - if (pol_version == 1) { + if (pol->version == 1) { int nr_unknown_vecs = buffer_read_int32(r); buffer_skip(r, nr_unknown_vecs * 12); } else { @@ -223,10 +231,10 @@ 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, mesh, i, triangle_unknowns_length); + parse_triangle(r, mesh, i, triangle_unknowns_length, &pol->materials[mesh->material]); } - if (pol_version == 1) { + if (pol->version == 1) { if (buffer_read_int32(r) != 1) WARNING("unexpected mesh footer"); if (buffer_read_int32(r) != 0) @@ -288,7 +296,7 @@ struct pol *pol_parse(uint8_t *data, size_t size) pol->nr_meshes = buffer_read_int32(&r); pol->meshes = xcalloc(pol->nr_meshes, sizeof(struct pol_mesh *)); for (uint32_t i = 0; i < pol->nr_meshes; i++) { - pol->meshes[i] = parse_mesh(&r, pol->version); + pol->meshes[i] = parse_mesh(&r, pol); } pol->nr_bones = buffer_read_int32(&r); diff --git a/src/3d/reign.c b/src/3d/reign.c index d432488..a1e546f 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -39,19 +39,22 @@ static struct RE_instance *create_instance(struct RE_plugin *plugin) instance->plugin = plugin; for (int i = 0; i < RE_NR_INSTANCE_TARGETS; i++) instance->target[i] = -1; - instance->scale[0] = 1.0; - instance->scale[1] = 1.0; - instance->scale[2] = 1.0; - instance->alpha = 1.0; + instance->scale[0] = 1.0f; + instance->scale[1] = 1.0f; + instance->scale[2] = 1.0f; + instance->alpha = 1.0f; + instance->shadow_volume_bone_radius = 0.1f; instance->draw_bump = true; - instance->fps = 30.0; - instance->column_height = 1.0; - instance->column_radius = 1.0; + instance->fps = 30.0f; + instance->column_height = 1.0f; + instance->column_radius = 1.0f; glm_mat4_identity(instance->local_transform); glm_mat3_identity(instance->normal_transform); return instance; } +static void free_instance(struct RE_instance *instance); + static void unload_instance(struct RE_instance *instance) { if (instance->motion) { @@ -78,6 +81,10 @@ static void unload_instance(struct RE_instance *instance) RE_renderer_free_height_detector(instance->height_detector); instance->height_detector = NULL; } + if (instance->shadow_volume_instance) { + free_instance(instance->shadow_volume_instance); + instance->shadow_volume_instance = NULL; + } } static void free_instance(struct RE_instance *instance) @@ -143,6 +150,10 @@ static void update_bones(struct RE_instance *inst) return; mat4 parent_transforms[MAX_BONES]; + vec3 aabb[2]; + glm_aabb_invalidate(aabb); + + // Update inst->bone_transforms. for (int i = 0; i < inst->model->nr_bones; i++) { struct mot_frame mf; calc_motion_frame(inst->motion, i, &mf); @@ -162,6 +173,24 @@ static void update_bones(struct RE_instance *inst) glm_mat4_copy(bone_transform, parent_transforms[i]); glm_mat4_mul(bone_transform, inst->model->bones[i].inverse_bind_matrix, inst->bone_transforms[i]); + + glm_vec3_minv(aabb[0], bone_transform[3], aabb[0]); + glm_vec3_maxv(aabb[1], bone_transform[3], aabb[1]); + } + + // Update inst->bounding_sphere. + vec3 center; + glm_aabb_center(aabb, center); + if (inst->local_transform_needs_update) + RE_instance_update_local_transform(inst); + glm_mat4_mulv3(inst->local_transform, center, 1.0f, inst->bounding_sphere); + inst->bounding_sphere[3] = glm_aabb_radius(aabb) * inst->scale[0] + inst->shadow_volume_bone_radius; + + struct RE_instance *shvol = inst->shadow_volume_instance; + if (shvol) { + glm_vec3_copy(inst->bounding_sphere, shvol->pos); + glm_vec3_broadcast(inst->bounding_sphere[3], shvol->scale); + RE_instance_update_local_transform(shvol); } } @@ -443,6 +472,19 @@ float RE_instance_calc_height(struct RE_instance *instance, float x, float z) return y; } +bool RE_instance_set_debug_draw_shadow_volume(struct RE_instance *inst, bool draw) +{ + if (!inst) + return false; + if (draw && !inst->shadow_volume_instance) { + inst->shadow_volume_instance = create_instance(inst->plugin); + inst->shadow_volume_instance->model = model_create_sphere(255, 0, 0, 64); + } + if (inst->shadow_volume_instance) + inst->shadow_volume_instance->draw = draw; + return true; +} + 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 7fcfd9c..ef8974e 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -27,8 +27,8 @@ #include "sact.h" // TODO: Respect RE_plugin.shadow_map_resolution_level -#define SHADOW_WIDTH 1024 -#define SHADOW_HEIGHT 1024 +#define SHADOW_WIDTH 512 +#define SHADOW_HEIGHT 512 enum { COLOR_TEXTURE_UNIT, @@ -201,7 +201,7 @@ struct RE_renderer *RE_renderer_new(struct texture *texture) r->light_texture = glGetUniformLocation(r->program, "light_texture"); r->use_normal_map = glGetUniformLocation(r->program, "use_normal_map"); r->normal_texture = glGetUniformLocation(r->program, "normal_texture"); - r->use_shadow_map = glGetUniformLocation(r->program, "use_shadow_map"); + r->shadow_darkness = glGetUniformLocation(r->program, "shadow_darkness"); r->shadow_transform = glGetUniformLocation(r->program, "shadow_transform"); r->shadow_texture = glGetUniformLocation(r->program, "shadow_texture"); r->shadow_bias = glGetUniformLocation(r->program, "shadow_bias"); @@ -317,7 +317,7 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d for (int i = 0; i < model->nr_meshes; i++) { struct mesh *mesh = &model->meshes[i]; struct material *material = &model->materials[mesh->material]; - bool is_transparent = material->is_transparent || inst->alpha < 1.0f; + bool is_transparent = (material->is_transparent && !(mesh->flags & MESH_SPRITE)) || inst->alpha < 1.0f; if (phase != (is_transparent ? DRAW_TRANSPARENT : DRAW_OPAQUE)) continue; @@ -347,7 +347,10 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d glBindTexture(GL_TEXTURE_2D, material->color_map); glUniform1i(r->texture, COLOR_TEXTURE_UNIT); - glUniform1i(r->use_shadow_map, draw_shadow && !(mesh->flags & MESH_BOTH)); + if (draw_shadow && !(mesh->flags & MESH_BOTH)) + glUniform1f(r->shadow_darkness, material->shadow_darkness); + else + glUniform1f(r->shadow_darkness, 0.0f); if (mesh->flags & MESH_ENVMAP) { glUniform1i(r->diffuse_type, DIFFUSE_ENV_MAP); @@ -376,14 +379,19 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d glActiveTexture(GL_TEXTURE0 + ALPHA_TEXTURE_UNIT); glBindTexture(GL_TEXTURE_2D, material->alpha_map); glUniform1i(r->alpha_texture, ALPHA_TEXTURE_UNIT); - } else if (material->flags & MATERIAL_SPRITE) { + } else if (material->flags & MATERIAL_SPRITE || mesh->flags & MESH_SPRITE) { glUniform1i(r->alpha_mode, ALPHA_TEST); } else { glUniform1i(r->alpha_mode, ALPHA_BLEND); } glBindVertexArray(mesh->vao); - glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices); + + if (mesh->nr_indices) + glDrawElements(GL_TRIANGLES, mesh->nr_indices, GL_UNSIGNED_SHORT, NULL); + else + glDrawArrays(GL_TRIANGLES, 0, mesh->nr_vertices); + glBindVertexArray(0); glBindTexture(GL_TEXTURE_2D, 0); } @@ -405,13 +413,16 @@ static void render_skinned_model(struct RE_instance *inst, struct RE_renderer *r if (!model) return; - if (model->nr_bones > 0) { + if (model->nr_bones > 0 && inst->motion) { glUniform1i(r->has_bones, GL_TRUE); glUniformMatrix4fv(r->bone_matrices, model->nr_bones, GL_FALSE, inst->bone_transforms[0][0]); } else { glUniform1i(r->has_bones, GL_FALSE); } render_model(inst, r, phase); + + if (inst->shadow_volume_instance && phase == DRAW_TRANSPARENT) + render_static_model(inst->shadow_volume_instance, r, phase); } static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, mat4 view_mat, enum draw_phase phase) @@ -452,7 +463,7 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma glUniform1f(r->rim_exponent, 0.0); glUniform1i(r->diffuse_type, DIFFUSE_NORMAL); glUniform1i(r->use_normal_map, GL_FALSE); - glUniform1i(r->use_shadow_map, GL_FALSE); + glUniform1f(r->shadow_darkness, 0.0f); glUniform1i(r->alpha_mode, ALPHA_BLEND); glUniform1i(r->fog_type, inst->plugin->fog_mode ? inst->plugin->fog_type : 0); switch (inst->draw_type) { @@ -572,7 +583,7 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer glUniform1i(r->use_specular_map, GL_FALSE); glUniform1f(r->rim_exponent, 0.0); glUniform1i(r->use_normal_map, GL_FALSE); - glUniform1i(r->use_shadow_map, GL_FALSE); + glUniform1f(r->shadow_darkness, 0.0f); glUniform1i(r->alpha_mode, ALPHA_BLEND); glDepthMask(GL_FALSE); @@ -626,52 +637,27 @@ static void render_instance(struct RE_instance *inst, struct RE_renderer *r, mat static bool calc_shadow_light_transform(struct RE_plugin *plugin, mat4 dest) { - // Compute AABB of shadow casters. - vec3 aabb[2]; - glm_aabb_invalidate(aabb); + // Compute a bounding sphere of shadow casters. + vec4 bounding_sphere = {}; for (int i = 0; i < plugin->nr_instances; i++) { struct RE_instance *inst = plugin->instances[i]; if (!inst || !inst->draw || !inst->make_shadow || !inst->model) continue; - // Start with the model's AABB, inflated with shadow_volume_bone_radius. - vec3 inst_aabb[2]; - glm_vec3_subs(inst->model->aabb[0], inst->shadow_volume_bone_radius, inst_aabb[0]); - glm_vec3_adds(inst->model->aabb[1], inst->shadow_volume_bone_radius, inst_aabb[1]); - // To save CPU cycles, consider only the translation components of bone transforms. - vec3 bone_translation_aabb[2]; - glm_aabb_invalidate(bone_translation_aabb); - for (int j = 0; j < inst->model->nr_bones; j++) { - glm_vec3_minv(inst->bone_transforms[j][3], bone_translation_aabb[0], bone_translation_aabb[0]); - glm_vec3_maxv(inst->bone_transforms[j][3], bone_translation_aabb[1], bone_translation_aabb[1]); - } - if (glm_aabb_isvalid(bone_translation_aabb)) { - glm_vec3_add(inst_aabb[0], bone_translation_aabb[0], inst_aabb[0]); - glm_vec3_add(inst_aabb[1], bone_translation_aabb[1], inst_aabb[1]); - } - // Apply local transform. - if (inst->local_transform_needs_update) - RE_instance_update_local_transform(inst); - glm_aabb_transform(inst_aabb, inst->local_transform, inst_aabb); - - glm_aabb_merge(inst_aabb, aabb, aabb); + if (bounding_sphere[3] > 0.0f) + glm_sphere_merge(inst->bounding_sphere, bounding_sphere, inst->bounding_sphere); + else + glm_vec4_copy(inst->bounding_sphere, bounding_sphere); } - if (!glm_aabb_isvalid(aabb)) + + float radius = bounding_sphere[3] * 1.2f; // Add some padding. + if (radius <= 0.0f) return false; - // Create a orthographic frustum that contains the AABB. - vec3 center; - glm_aabb_center(aabb, center); - vec3 light_pos; - glm_vec3_scale(plugin->shadow_map_light_dir, -glm_aabb_radius(aabb), light_pos); - glm_vec3_add(light_pos, center, light_pos); + // Create a orthographic frustum that contains the bounding sphere. mat4 view_matrix; - vec3 up = {0.0, 1.0, 0.0}; - glm_lookat(light_pos, center, up, view_matrix); - + glm_look(bounding_sphere, plugin->shadow_map_light_dir, GLM_YUP, view_matrix); mat4 proj_matrix; - glm_aabb_transform(aabb, view_matrix, aabb); - glm_ortho_aabb(aabb, proj_matrix); - + glm_ortho(-radius, radius, -radius, radius, -radius, radius, proj_matrix); glm_mat4_mul(proj_matrix, view_matrix, dest); return true; } diff --git a/src/hll/ReignEngine.c b/src/hll/ReignEngine.c index bc16071..cc52541 100644 --- a/src/hll/ReignEngine.c +++ b/src/hll/ReignEngine.c @@ -651,8 +651,17 @@ static bool ReignEngine_SetInstanceShadowVolumeBoneRadius(int plugin, int instan return true; } -//bool ReignEngine_GetInstanceDebugDrawShadowVolume(int plugin, int instance); -//bool ReignEngine_SetInstanceDebugDrawShadowVolume(int plugin, int instance, bool flag); +static bool ReignEngine_GetInstanceDebugDrawShadowVolume(int plugin, int instance) +{ + struct RE_instance *ri = get_instance(plugin, instance); + return ri && ri->shadow_volume_instance && ri->shadow_volume_instance->draw; +} + +static bool ReignEngine_SetInstanceDebugDrawShadowVolume(int plugin, int instance, bool flag) +{ + return RE_instance_set_debug_draw_shadow_volume(get_instance(plugin, instance), flag); +} + //bool ReignEngine_SaveEffect(int plugin, int instance); static bool ReignEngine_GetEffectFrameRange(int plugin, int instance, int *begin_frame, int *end_frame) @@ -1899,8 +1908,8 @@ HLL_LIBRARY(ReignEngine, HLL_EXPORT(SetInstanceSoftFogEdgeLength, ReignEngine_SetInstanceSoftFogEdgeLength), HLL_EXPORT(GetInstanceShadowVolumeBoneRadius, ReignEngine_GetInstanceShadowVolumeBoneRadius), HLL_EXPORT(SetInstanceShadowVolumeBoneRadius, ReignEngine_SetInstanceShadowVolumeBoneRadius), - HLL_TODO_EXPORT(GetInstanceDebugDrawShadowVolume, ReignEngine_GetInstanceDebugDrawShadowVolume), - HLL_TODO_EXPORT(SetInstanceDebugDrawShadowVolume, ReignEngine_SetInstanceDebugDrawShadowVolume), + HLL_EXPORT(GetInstanceDebugDrawShadowVolume, ReignEngine_GetInstanceDebugDrawShadowVolume), + HLL_EXPORT(SetInstanceDebugDrawShadowVolume, ReignEngine_SetInstanceDebugDrawShadowVolume), HLL_TODO_EXPORT(SaveEffect, ReignEngine_SaveEffect), HLL_EXPORT(GetEffectFrameRange, ReignEngine_GetEffectFrameRange), HLL_EXPORT(GetEffectObjectType, ReignEngine_GetEffectObjectType),