From 06b9da800c657fc19790ec20bcbc1917ec948dfb Mon Sep 17 00:00:00 2001 From: kichikuou Date: Thu, 1 Dec 2022 13:46:51 +0900 Subject: [PATCH] Implement ReignEngine.SetInstanceDebugDrawShadowVolume It visualizes the bounding sphere of the instance. Although it is only called from dead code in Toushin Toshi 3, it's useful for debugging shadow mapping. --- include/reign.h | 2 + src/3d/3d_internal.h | 3 ++ src/3d/model.c | 97 +++++++++++++++++++++++++++++++++++++++++++ src/3d/reign.c | 26 ++++++++++++ src/3d/renderer.c | 10 ++++- src/hll/ReignEngine.c | 17 ++++++-- 6 files changed, 150 insertions(+), 5 deletions(-) diff --git a/include/reign.h b/include/reign.h index 56bee5e..b5424dc 100644 --- a/include/reign.h +++ b/include/reign.h @@ -166,6 +166,7 @@ struct RE_instance { mat3 normal_transform; mat4 *bone_transforms; // model->nr_bones elements vec4 bounding_sphere; + struct RE_instance *shadow_volume_instance; float z_from_camera; }; @@ -187,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/src/3d/3d_internal.h b/src/3d/3d_internal.h index 3ef56e1..6325583 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; }; @@ -176,6 +178,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); diff --git a/src/3d/model.c b/src/3d/model.c index 15ac432..0806f13 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -336,6 +336,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) @@ -499,6 +501,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/reign.c b/src/3d/reign.c index e32cc71..a1e546f 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -53,6 +53,8 @@ static struct RE_instance *create_instance(struct RE_plugin *plugin) return instance; } +static void free_instance(struct RE_instance *instance); + static void unload_instance(struct RE_instance *instance) { if (instance->motion) { @@ -79,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) @@ -179,6 +185,13 @@ static void update_bones(struct RE_instance *inst) 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); + } } struct RE_plugin *RE_plugin_new(void) @@ -459,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 0300150..9bd97fe 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -383,7 +383,12 @@ static void render_model(struct RE_instance *inst, struct RE_renderer *r, enum d } 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); } @@ -412,6 +417,9 @@ static void render_skinned_model(struct RE_instance *inst, struct RE_renderer *r 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) 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),