From defeb0ba175ee43fdb859525460410f6a42bd5b3 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 18 Dec 2022 09:33:52 +0900 Subject: [PATCH 1/7] ReignEngine: Cache loaded models When there are multiple instances of a model, now they share a single model object. Model objects are retained in a hash table until the plugin is released, which is fine because Toushin Toshi 3 doesn't reuse a plugin across scenes. --- include/reign.h | 3 +++ src/3d/reign.c | 13 +++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/include/reign.h b/include/reign.h index b5424dc..c03e4c7 100644 --- a/include/reign.h +++ b/include/reign.h @@ -25,6 +25,8 @@ #include "gfx/gfx.h" #include "plugin.h" +struct hash_table; + enum RE_instance_type { RE_ITYPE_UNINITIALIZED = 0, RE_ITYPE_STATIC = 1, @@ -82,6 +84,7 @@ struct RE_plugin { int nr_instances; struct RE_instance **instances; struct archive *aar; + struct hash_table *model_cache; struct RE_renderer *renderer; struct RE_camera camera; mat4 proj_transform; diff --git a/src/3d/reign.c b/src/3d/reign.c index a1e546f..b647775 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -24,6 +24,7 @@ #include "system4.h" #include "system4/aar.h" #include "system4/cg.h" +#include "system4/hashtable.h" #include "system4/string.h" #include "3d_internal.h" @@ -66,7 +67,7 @@ static void unload_instance(struct RE_instance *instance) instance->next_motion = NULL; } if (instance->model) { - model_free(instance->model); + // No need to free, model is owned by plugin->model_cache. instance->model = NULL; } if (instance->effect) { @@ -215,6 +216,7 @@ struct RE_plugin *RE_plugin_new(void) plugin->nr_instances = 16; plugin->instances = xcalloc(plugin->nr_instances, sizeof(struct RE_instance *)); plugin->aar = aar; + plugin->model_cache = ht_create(32); for (int i = 0; i < RE_NR_BACK_CGS; i++) RE_back_cg_init(&plugin->back_cg[i]); plugin->fog_type = RE_FOG_NONE; @@ -232,6 +234,8 @@ void RE_plugin_free(struct RE_plugin *plugin) } free(plugin->instances); archive_free(plugin->aar); + ht_foreach_value(plugin->model_cache, (void(*)(void*))model_free); + ht_free(plugin->model_cache); if (plugin->renderer) RE_renderer_free(plugin->renderer); for (int i = 0; i < RE_NR_BACK_CGS; i++) @@ -375,7 +379,12 @@ bool RE_instance_load(struct RE_instance *instance, const char *name) switch (instance->type) { case RE_ITYPE_STATIC: case RE_ITYPE_SKINNED: - instance->model = model_load(instance->plugin->aar, name); + instance->model = ht_get(instance->plugin->model_cache, name, NULL); + if (!instance->model) { + instance->model = model_load(instance->plugin->aar, name); + if (instance->model) + ht_put(instance->plugin->model_cache, name, instance->model); + } if (instance->model && instance->model->nr_bones > 0) instance->bone_transforms = xcalloc(instance->model->nr_bones, sizeof(mat4)); return !!instance->model; From 10710e9908155da67ed860f36feaf3f604f8377e Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 18 Dec 2022 22:51:42 +0900 Subject: [PATCH 2/7] ReignEngine: Cache parsed particle effects Now parsed particle-effect definitions are cached in a hash map in the plugin object. To make it possible, static part of `struct particle_effect` and `struct particle_object` are factored out to `struct pae` and `struct pae_object` respectively. --- include/reign.h | 1 + src/3d/3d_internal.h | 37 +++++---- src/3d/debug.c | 2 +- src/3d/particle.c | 169 ++++++++++++++++++++++++------------------ src/3d/reign.c | 173 +++++++++++++++++++++++-------------------- src/3d/renderer.c | 26 ++++--- 6 files changed, 229 insertions(+), 179 deletions(-) diff --git a/include/reign.h b/include/reign.h index c03e4c7..a98e1f2 100644 --- a/include/reign.h +++ b/include/reign.h @@ -85,6 +85,7 @@ struct RE_plugin { struct RE_instance **instances; struct archive *aar; struct hash_table *model_cache; + struct hash_table *pae_cache; struct RE_renderer *renderer; struct RE_camera camera; mat4 proj_transform; diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index ff078f0..38e4e21 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -272,7 +272,14 @@ struct particle_position { struct particle_position_unit units[NR_PARTICLE_POSITION_UNITS]; }; -struct particle_object { +struct pae { + char *path; + struct hash_table *textures; // name -> struct billboard_texture* + int nr_objects; + struct pae_object *objects; +}; + +struct pae_object { char *name; enum particle_type type; enum particle_move_type move_type; @@ -325,9 +332,18 @@ struct particle_object { float offset_x; float offset_y; - // Runtime data struct model *model; - struct particle_instance *instances; +}; + +struct particle_effect { + struct pae *pae; + struct particle_object *objects; // pae->nr_objects elements + bool camera_quake_enabled; +}; + +struct particle_object { + struct pae_object *pae_obj; + struct particle_instance *instances; // pae_obj->nr_particles elements vec3_range pos; vec3 move_vec, move_ortho; }; @@ -340,20 +356,15 @@ struct particle_instance { float pitch_angle; }; -struct particle_effect { - char *path; - struct hash_table *textures; // name -> struct billboard_texture* - int nr_objects; - struct particle_object *objects; - bool camera_quake_enabled; -}; +struct pae *pae_load(struct archive *aar, const char *path); +void pae_free(struct pae *pae); +void pae_calc_frame_range(struct pae *pae, struct motion *motion); +float pae_object_calc_alpha(struct pae_object *po, struct particle_instance *pi, float frame); -struct particle_effect *particle_effect_load(struct archive *aar, const char *path); +struct particle_effect *particle_effect_create(struct pae *pae); void particle_effect_free(struct particle_effect *effect); -void particle_effect_calc_frame_range(struct particle_effect *effect, struct motion *motion); void particle_effect_update(struct RE_instance *inst); void particle_object_calc_local_transform(struct RE_instance *inst, struct particle_object *po, struct particle_instance *pi, float frame, mat4 dest); -float particle_object_calc_alpha(struct particle_object *po, struct particle_instance *pi, float frame); // parser.c diff --git a/src/3d/debug.c b/src/3d/debug.c index 0552eee..2379b4f 100644 --- a/src/3d/debug.c +++ b/src/3d/debug.c @@ -101,7 +101,7 @@ static void print_instance(struct RE_instance *inst, int index, int indent) if (inst->motion_blend) indent_printf(indent, "motion_blend_rate = %f,\n", inst->motion_blend_rate); if (inst->effect) - indent_printf(indent, "path = \"%s\",\n", inst->effect->path); + indent_printf(indent, "path = \"%s\",\n", inst->effect->pae->path); indent--; indent_printf(indent, "},\n"); diff --git a/src/3d/particle.c b/src/3d/particle.c index b9ac076..723cf20 100644 --- a/src/3d/particle.c +++ b/src/3d/particle.c @@ -239,10 +239,10 @@ static struct particle_position *parse_position(char **ptext) return epos; } -static struct particle_effect *parse_pae(char *text) +static struct pae *parse_pae(char *text) { - struct particle_effect *pae = xcalloc(1, sizeof(struct particle_effect)); - struct particle_object *current_object = NULL; + struct pae *pae = xcalloc(1, sizeof(struct pae)); + struct pae_object *current_object = NULL; for (;;) { // Skip whitespaces and comments @@ -269,7 +269,7 @@ static struct particle_effect *parse_pae(char *text) if (!*text) { // EOF return pae; } else if (MATCH("オブジェクト " QUOTED_STRING " = {", string_buf)) { - pae->objects = xrealloc_array(pae->objects, pae->nr_objects, pae->nr_objects + 1, sizeof(struct particle_object)); + pae->objects = xrealloc_array(pae->objects, pae->nr_objects, pae->nr_objects + 1, sizeof(struct pae_object)); current_object = &pae->objects[pae->nr_objects++]; current_object->name = utf2sjis(string_buf, 0); // Default values. @@ -449,15 +449,15 @@ static struct particle_effect *parse_pae(char *text) } } err: - particle_effect_free(pae); + pae_free(pae); return NULL; } -static void load_textures(struct particle_effect *effect, struct archive *aar) +static void load_textures(struct pae *effect, struct archive *aar) { effect->textures = ht_create(16); for (int i = 0; i < effect->nr_objects; i++) { - struct particle_object *po = &effect->objects[i]; + struct pae_object *po = &effect->objects[i]; for (int j = 0; j < po->nr_textures; j++) { const char *name = po->textures[j]; if (ht_get(effect->textures, name, NULL)) @@ -587,7 +587,7 @@ static void eval_pos_for_instance(struct particle_position *pp, vec3 dest) } } -static float eval_child_slope(struct particle_object *po) +static float eval_child_slope(struct pae_object *po) { float slope = glm_lerp(po->child_begin_slope, po->child_end_slope, randf()); if (slope > 1.0) @@ -607,29 +607,30 @@ static void interpolate_pos(vec3 begin, vec3 end, float move_curve, float t, vec static void init_particle_instances(struct particle_object *po) { - po->instances = xcalloc(po->nr_particles, sizeof(struct particle_instance)); + struct pae_object *pae_obj = po->pae_obj; + po->instances = xcalloc(pae_obj->nr_particles, sizeof(struct particle_instance)); - for (int i = 0; i < po->nr_particles; i++) { + for (int i = 0; i < pae_obj->nr_particles; i++) { struct particle_instance *pi = &po->instances[i]; - switch (po->move_type) { + switch (pae_obj->move_type) { case PARTICLE_MOVE_FIXED: case PARTICLE_MOVE_LINEAR: - pi->begin_frame = po->begin_frame; - pi->end_frame = po->end_frame; + pi->begin_frame = pae_obj->begin_frame; + pi->end_frame = pae_obj->end_frame; break; case PARTICLE_MOVE_EMITTER: - pi->begin_frame = glm_lerp(po->child_create_begin_frame, po->child_create_end_frame, (float)i / po->nr_particles); - pi->end_frame = pi->begin_frame + po->child_frame; - pi->roll_angle = eval_child_slope(po); + pi->begin_frame = glm_lerp(pae_obj->child_create_begin_frame, pae_obj->child_create_end_frame, (float)i / pae_obj->nr_particles); + pi->end_frame = pi->begin_frame + pae_obj->child_frame; + pi->roll_angle = eval_child_slope(pae_obj); pi->pitch_angle = randf() * (2.0f * GLM_PIf); break; } - eval_pos_for_instance(po->position[0], pi->random_offset.begin); - eval_pos_for_instance(po->position[1], pi->random_offset.end); + eval_pos_for_instance(pae_obj->position[0], pi->random_offset.begin); + eval_pos_for_instance(pae_obj->position[1], pi->random_offset.end); } } -struct particle_effect *particle_effect_load(struct archive *aar, const char *path) +struct pae *pae_load(struct archive *aar, const char *path) { const char *basename = strrchr(path, '\\'); basename = basename ? basename + 1 : path; @@ -653,20 +654,19 @@ struct particle_effect *particle_effect_load(struct archive *aar, const char *pa // clarity. char *text = sjis2utf(sjis_text, dfile->size); free(sjis_text); - struct particle_effect *effect = parse_pae(text); + struct pae *pae = parse_pae(text); free(text); - if (!effect) { + if (!pae) { WARNING("could not parse %s", dfile->name); archive_free_data(dfile); return NULL; } archive_free_data(dfile); - effect->path = strdup(path); - effect->camera_quake_enabled = true; - load_textures(effect, aar); - for (int i = 0; i < effect->nr_objects; i++) { - struct particle_object *po = &effect->objects[i]; + pae->path = strdup(path); + load_textures(pae, aar); + for (int i = 0; i < pae->nr_objects; i++) { + struct pae_object *po = &pae->objects[i]; if (po->polygon_name && *po->polygon_name) { char *pol_path = xmalloc(strlen(path) + strlen(po->polygon_name) + 2); @@ -674,10 +674,22 @@ struct particle_effect *particle_effect_load(struct archive *aar, const char *pa po->model = model_load(aar, pol_path); free(pol_path); } - - init_particle_instances(po); } + return pae; +} + +struct particle_effect *particle_effect_create(struct pae *pae) +{ + struct particle_effect *effect = xcalloc(1, sizeof(struct particle_effect)); + effect->pae = pae; + effect->objects = xcalloc(pae->nr_objects, sizeof(struct particle_object)); + effect->camera_quake_enabled = true; + for (int i = 0; i < pae->nr_objects; i++) { + struct particle_object *po = &effect->objects[i]; + po->pae_obj = &pae->objects[i]; + init_particle_instances(po); + } return effect; } @@ -699,10 +711,10 @@ static void particle_position_free(struct particle_position *pos) free(pos); } -void particle_effect_free(struct particle_effect *effect) +void pae_free(struct pae *pae) { - for (int i = 0; i < effect->nr_objects; i++) { - struct particle_object *po = &effect->objects[i]; + for (int i = 0; i < pae->nr_objects; i++) { + struct pae_object *po = &pae->objects[i]; free(po->name); for (int j = 0; j < NR_PARTICLE_POSITIONS; j++) particle_position_free(po->position[j]); @@ -719,21 +731,30 @@ void particle_effect_free(struct particle_effect *effect) free(po->damages); if (po->model) model_free(po->model); - free(po->instances); } - ht_foreach_value(effect->textures, free_billboard_texture); - ht_free(effect->textures); + ht_foreach_value(pae->textures, free_billboard_texture); + ht_free(pae->textures); + free(pae->objects); + free(pae->path); + free(pae); +} + +void particle_effect_free(struct particle_effect *effect) +{ + for (int i = 0; i < effect->pae->nr_objects; i++) { + struct particle_object *obj = &effect->objects[i]; + free(obj->instances); + } free(effect->objects); - free(effect->path); free(effect); } -void particle_effect_calc_frame_range(struct particle_effect *effect, struct motion *motion) +void pae_calc_frame_range(struct pae *pae, struct motion *motion) { int begin_frame = INT_MAX; int end_frame = INT_MIN; - for (int i = 0; i < effect->nr_objects; i++) { - struct particle_object *po = &effect->objects[i]; + for (int i = 0; i < pae->nr_objects; i++) { + struct pae_object *po = &pae->objects[i]; int obj_begin = po->begin_frame; int obj_end = max(po->end_frame, po->child_create_end_frame + po->child_frame); if (begin_frame > obj_begin) @@ -745,7 +766,7 @@ void particle_effect_calc_frame_range(struct particle_effect *effect, struct mot motion->frame_end = motion->loop_frame_end = end_frame; } -static void update_camera_quake(struct RE_instance *inst, struct particle_object *po) +static void update_camera_quake(struct RE_instance *inst, struct pae_object *po) { float frame = inst->motion->current_frame - po->begin_frame; float total_frames = po->end_frame - po->begin_frame; @@ -769,19 +790,20 @@ void particle_effect_update(struct RE_instance *inst) struct particle_effect *effect = inst->effect; if (!effect) return; - for (int i = 0; i < effect->nr_objects; i++) { + for (int i = 0; i < effect->pae->nr_objects; i++) { struct particle_object *po = &effect->objects[i]; - if (po->type == PARTICLE_TYPE_CAMERA_QUAKE) { + struct pae_object *pae_obj = po->pae_obj; + if (pae_obj->type == PARTICLE_TYPE_CAMERA_QUAKE) { if (effect->camera_quake_enabled) - update_camera_quake(inst, po); + update_camera_quake(inst, pae_obj); continue; } // These cannot be precomputed, because they may depend on the target's // *current* bone matrix. - eval_pos_for_object(inst, po->position[0], po->pos.begin); - eval_pos_for_object(inst, po->position[1], po->pos.end); + eval_pos_for_object(inst, pae_obj->position[0], po->pos.begin); + eval_pos_for_object(inst, pae_obj->position[1], po->pos.end); glm_vec3_sub(po->pos.end, po->pos.begin, po->move_vec); - switch (po->dir_type) { + switch (pae_obj->dir_type) { case PARTICLE_DIR_TYPE_NORMAL: glm_vec3_normalize(po->move_vec); glm_vec3_ortho(po->move_vec, po->move_ortho); @@ -798,45 +820,47 @@ void particle_effect_update(struct RE_instance *inst) static void calc_emitter_pos(struct particle_object *po, struct particle_instance *pi, float t, vec3 dest, vec3 move_vec) { + struct pae_object *pae_obj = po->pae_obj; vec3 begin, end; glm_vec3_add(po->pos.begin, pi->random_offset.begin, begin); glm_vec3_add(po->pos.end, pi->random_offset.end, end); - interpolate_pos(begin, end, po->move_curve, t, dest); + interpolate_pos(begin, end, pae_obj->move_curve, t, dest); if (move_vec) glm_vec3_sub(end, begin, move_vec); // Orbital rotation. vec3 angle, dist; - glm_vec3_lerp(po->revolution_angle.begin, po->revolution_angle.end, t, angle); - glm_vec3_lerp(po->revolution_distance.begin, po->revolution_distance.end, t, dist); + glm_vec3_lerp(pae_obj->revolution_angle.begin, pae_obj->revolution_angle.end, t, angle); + glm_vec3_lerp(pae_obj->revolution_distance.begin, pae_obj->revolution_distance.end, t, dist); glm_vec3_scale(angle, GLM_PIf / 180.0f, angle); // deg -> rad - if (po->revolution_angle.begin[0] != 0.0f || po->revolution_angle.end[0] != 0.0f) { + if (pae_obj->revolution_angle.begin[0] != 0.0f || pae_obj->revolution_angle.end[0] != 0.0f) { dest[1] += dist[0] * sinf(angle[0]); dest[2] -= dist[0] * cosf(angle[0]); } - if (po->revolution_angle.begin[1] != 0.0f || po->revolution_angle.end[1] != 0.0f) { + if (pae_obj->revolution_angle.begin[1] != 0.0f || pae_obj->revolution_angle.end[1] != 0.0f) { dest[0] += dist[1] * sinf(angle[1]); dest[2] -= dist[1] * cosf(angle[1]); } - if (po->revolution_angle.begin[2] != 0.0f || po->revolution_angle.end[2] != 0.0f) { + if (pae_obj->revolution_angle.begin[2] != 0.0f || pae_obj->revolution_angle.end[2] != 0.0f) { dest[1] += dist[2] * sinf(angle[2]); dest[0] += dist[2] * cosf(angle[2]); } // Apply the curve. - glm_vec3_muladds(po->curve_length, 4.9f * t * (1.0f - t), dest); + glm_vec3_muladds(pae_obj->curve_length, 4.9f * t * (1.0f - t), dest); } static void calc_pos_and_up_vector(struct particle_object *po, struct particle_instance *pi, float t, vec3 pos, vec3 up_vector) { - switch (po->move_type) { + struct pae_object *pae_obj = po->pae_obj; + switch (pae_obj->move_type) { case PARTICLE_MOVE_FIXED: glm_vec3_add(po->pos.begin, pi->random_offset.begin, pos); glm_vec3_copy(GLM_YUP, up_vector); break; case PARTICLE_MOVE_LINEAR: calc_emitter_pos(po, pi, t, pos, up_vector); - switch (po->up_vector_type) { + switch (pae_obj->up_vector_type) { case PARTICLE_UP_VECTOR_Y_AXIS: case PARTICLE_UP_VECTOR_INSTANCE_MOVE: glm_vec3_copy(GLM_YUP, up_vector); @@ -852,12 +876,12 @@ static void calc_pos_and_up_vector(struct particle_object *po, struct particle_i case PARTICLE_MOVE_EMITTER: { // Calculate the instance's initial and final position. - float t0 = glm_clamp_zo(glm_percent(po->begin_frame, po->end_frame, pi->begin_frame)); + float t0 = glm_clamp_zo(glm_percent(pae_obj->begin_frame, pae_obj->end_frame, pi->begin_frame)); vec3_range inst_pos; calc_emitter_pos(po, pi, t0, inst_pos.begin, NULL); vec3 inst_move; glm_vec3_copy(po->move_vec, inst_move); - switch (po->dir_type) { + switch (pae_obj->dir_type) { case PARTICLE_DIR_TYPE_NORMAL: glm_vec3_rotate(inst_move, pi->roll_angle, po->move_ortho); glm_vec3_rotate(inst_move, pi->pitch_angle, po->move_vec); @@ -867,12 +891,12 @@ static void calc_pos_and_up_vector(struct particle_object *po, struct particle_i break; } glm_vec3_copy(inst_pos.begin, inst_pos.end); - switch (po->child_move_dir_type) { + switch (pae_obj->child_move_dir_type) { case PARTICLE_CHILD_MOVE_DIR_NORMAL: - glm_vec3_muladds(inst_move, po->child_length, inst_pos.end); + glm_vec3_muladds(inst_move, pae_obj->child_length, inst_pos.end); break; case PARTICLE_CHILD_MOVE_DIR_REVERSE: - glm_vec3_muladds(inst_move, po->child_length, inst_pos.begin); + glm_vec3_muladds(inst_move, pae_obj->child_length, inst_pos.begin); glm_vec3_negate(inst_move); break; } @@ -880,7 +904,7 @@ static void calc_pos_and_up_vector(struct particle_object *po, struct particle_i glm_vec3_lerp(inst_pos.begin, inst_pos.end, t, pos); // Calculate the up vector. - switch (po->up_vector_type) { + switch (pae_obj->up_vector_type) { case PARTICLE_UP_VECTOR_Y_AXIS: glm_vec3_copy(GLM_YUP, up_vector); break; @@ -888,13 +912,13 @@ static void calc_pos_and_up_vector(struct particle_object *po, struct particle_i glm_vec3_copy(po->move_vec, up_vector); break; case PARTICLE_UP_VECTOR_INSTANCE_MOVE: - if (po->child_length != 0.0f) + if (pae_obj->child_length != 0.0f) glm_vec3_copy(inst_move, up_vector); else glm_vec3_copy(GLM_XUP, up_vector); break; } - if (po->dir_type == PARTICLE_DIR_TYPE_XY_PLANE) { + if (pae_obj->dir_type == PARTICLE_DIR_TYPE_XY_PLANE) { mat3 rot = {{ inst_move[1], -inst_move[0], 0.0f }, { inst_move[0], inst_move[1], 0.0f }, { 0.0f, 0.0f, 1.0f }}; @@ -905,7 +929,7 @@ static void calc_pos_and_up_vector(struct particle_object *po, struct particle_i } } -static void calc_scale(struct particle_object *po, int frame, vec3 dest) +static void calc_scale(struct pae_object *po, int frame, vec3 dest) { glm_vec3_broadcast(po->sizes2[min(frame, po->nr_sizes2 - 1)], dest); if (po->nr_sizes_x) @@ -916,6 +940,7 @@ static void calc_scale(struct particle_object *po, int frame, vec3 dest) void particle_object_calc_local_transform(struct RE_instance *inst, struct particle_object *po, struct particle_instance *pi, float frame, mat4 dest) { + struct pae_object *pae_obj = po->pae_obj; float t = glm_percent(pi->begin_frame, pi->end_frame, frame); vec3 pos, up_vector; @@ -927,7 +952,7 @@ void particle_object_calc_local_transform(struct RE_instance *inst, struct parti float step_frac = rel_frame - cur_step; glm_translate_make(dest, pos); - if (po->type == PARTICLE_TYPE_BILLBOARD) { + if (pae_obj->type == PARTICLE_TYPE_BILLBOARD) { mat4 view_mat; RE_calc_view_matrix(&inst->plugin->camera, up_vector, view_mat); mat3 rot; @@ -936,7 +961,7 @@ void particle_object_calc_local_transform(struct RE_instance *inst, struct parti } vec3 angles; - glm_vec3_lerp(po->rotation.begin, po->rotation.end, t, angles); + glm_vec3_lerp(pae_obj->rotation.begin, pae_obj->rotation.end, t, angles); angles[0] *= -GLM_PIf / 180.0f; angles[1] *= -GLM_PIf / 180.0f; angles[2] *= GLM_PIf / 180.0f; @@ -944,21 +969,21 @@ void particle_object_calc_local_transform(struct RE_instance *inst, struct parti glm_euler_zxy(angles, rotation_mat); glm_mat4_mul(dest, rotation_mat, dest); - if (po->nr_sizes2 > 0) { + if (pae_obj->nr_sizes2 > 0) { vec3 scale, scale2; - calc_scale(po, cur_step, scale); - calc_scale(po, next_step, scale2); + calc_scale(pae_obj, cur_step, scale); + calc_scale(pae_obj, next_step, scale2); glm_vec3_lerp(scale, scale2, step_frac, scale); glm_scale(dest, scale); } else { - glm_scale_uni(dest, glm_lerp(po->size[0], po->size[1], t)); + glm_scale_uni(dest, glm_lerp(pae_obj->size[0], pae_obj->size[1], t)); } - glm_translate_x(dest, -po->offset_x); - glm_translate_y(dest, -po->offset_y); + glm_translate_x(dest, -pae_obj->offset_x); + glm_translate_y(dest, -pae_obj->offset_y); } -float particle_object_calc_alpha(struct particle_object *po, struct particle_instance *pi, float frame) +float pae_object_calc_alpha(struct pae_object *po, struct particle_instance *pi, float frame) { frame -= pi->begin_frame; if (frame < po->alpha_fadein_frame) diff --git a/src/3d/reign.c b/src/3d/reign.c index b647775..42e7027 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -217,6 +217,7 @@ struct RE_plugin *RE_plugin_new(void) plugin->instances = xcalloc(plugin->nr_instances, sizeof(struct RE_instance *)); plugin->aar = aar; plugin->model_cache = ht_create(32); + plugin->pae_cache = ht_create(32); for (int i = 0; i < RE_NR_BACK_CGS; i++) RE_back_cg_init(&plugin->back_cg[i]); plugin->fog_type = RE_FOG_NONE; @@ -236,6 +237,8 @@ void RE_plugin_free(struct RE_plugin *plugin) archive_free(plugin->aar); ht_foreach_value(plugin->model_cache, (void(*)(void*))model_free); ht_free(plugin->model_cache); + ht_foreach_value(plugin->pae_cache, (void(*)(void*))pae_free); + ht_free(plugin->pae_cache); if (plugin->renderer) RE_renderer_free(plugin->renderer); for (int i = 0; i < RE_NR_BACK_CGS; i++) @@ -376,6 +379,7 @@ bool RE_instance_load(struct RE_instance *instance, const char *name) if (name[0] == '\0') return false; + struct pae *pae; switch (instance->type) { case RE_ITYPE_STATIC: case RE_ITYPE_SKINNED: @@ -389,13 +393,20 @@ bool RE_instance_load(struct RE_instance *instance, const char *name) instance->bone_transforms = xcalloc(instance->model->nr_bones, sizeof(mat4)); return !!instance->model; case RE_ITYPE_PARTICLE_EFFECT: - instance->effect = particle_effect_load(instance->plugin->aar, name); + pae = ht_get(instance->plugin->pae_cache, name, NULL); + if (!pae) { + pae = pae_load(instance->plugin->aar, name); + if (!pae) + return false; + ht_put(instance->plugin->pae_cache, name, pae); + } + instance->effect = particle_effect_create(pae); if (!instance->motion) { instance->motion = xcalloc(1, sizeof(struct motion)); instance->motion->instance = instance; - particle_effect_calc_frame_range(instance->effect, instance->motion); + pae_calc_frame_range(instance->effect->pae, instance->motion); } - return !!instance->effect; + return true; default: WARNING("Invalid instance type %d", instance->type); return false; @@ -574,7 +585,7 @@ bool RE_motion_set_loop_frame_range(struct motion *motion, float begin, float en int RE_effect_get_num_object(struct particle_effect *effect) { - return effect ? effect->nr_objects : 0; + return effect ? effect->pae->nr_objects : 0; } bool RE_effect_get_camera_quake_flag(struct particle_effect *effect) @@ -592,47 +603,47 @@ bool RE_effect_set_camera_quake_flag(struct particle_effect *effect, bool enable struct particle_object *RE_get_effect_object(struct particle_effect *effect, unsigned object) { - if (!effect || object >= (unsigned)effect->nr_objects) + if (!effect || object >= (unsigned)effect->pae->nr_objects) return NULL; return &effect->objects[object]; } int RE_particle_get_type(struct particle_object *po) { - return po ? po->type : 0; + return po ? po->pae_obj->type : 0; } int RE_particle_get_move_type(struct particle_object *po) { - return po ? po->move_type : 0; + return po ? po->pae_obj->move_type : 0; } int RE_particle_get_up_vec_type(struct particle_object *po) { - return po ? po->up_vector_type : 0; + return po ? po->pae_obj->up_vector_type : 0; } float RE_particle_get_move_curve(struct particle_object *po) { - return po ? po->move_curve : 0.0; + return po ? po->pae_obj->move_curve : 0.0; } void RE_particle_get_frame(struct particle_object *po, int *begin_frame, int *end_frame) { if (!po) return; - *begin_frame = po->begin_frame; - *end_frame = po->end_frame; + *begin_frame = po->pae_obj->begin_frame; + *end_frame = po->pae_obj->end_frame; } int RE_particle_get_stop_frame(struct particle_object *po) { - return po ? po->stop_frame : 0; + return po ? po->pae_obj->stop_frame : 0; } const char *RE_particle_get_name(struct particle_object *po) { - return po ? po->name : NULL; + return po ? po->pae_obj->name : NULL; } int RE_particle_get_num_pos(struct particle_object *po) @@ -647,9 +658,9 @@ int RE_particle_get_num_pos_unit(struct particle_object *po, int pos) static struct particle_position_unit *get_position_unit(struct particle_object *po, int pos, int unit) { - if (!po || pos >= NR_PARTICLE_POSITIONS || !po->position[pos] || unit >= NR_PARTICLE_POSITION_UNITS) + if (!po || pos >= NR_PARTICLE_POSITIONS || !po->pae_obj->position[pos] || unit >= NR_PARTICLE_POSITION_UNITS) return NULL; - return &po->position[pos]->units[unit]; + return &po->pae_obj->position[pos]->units[unit]; } int RE_particle_get_pos_unit_type(struct particle_object *po, int pos, int unit) @@ -675,298 +686,298 @@ int RE_particle_get_pos_unit_index(struct particle_object *po, int pos, int unit int RE_particle_get_num_texture(struct particle_object *po) { - return po ? po->nr_textures : 0; + return po ? po->pae_obj->nr_textures : 0; } const char *RE_particle_get_texture(struct particle_object *po, int texture) { - if (!po || texture >= po->nr_textures) + if (!po || texture >= po->pae_obj->nr_textures) return NULL; - return po->textures[texture]; + return po->pae_obj->textures[texture]; } bool RE_particle_get_size(struct particle_object *po, float *begin_size, float *end_size) { if (!po) return false; - *begin_size = po->size[0]; - *end_size = po->size[1]; + *begin_size = po->pae_obj->size[0]; + *end_size = po->pae_obj->size[1]; return true; } bool RE_particle_get_size2(struct particle_object *po, int frame, float *size) { - if (!po || frame >= po->nr_sizes2) + if (!po || frame >= po->pae_obj->nr_sizes2) return false; - *size = po->sizes2[frame]; + *size = po->pae_obj->sizes2[frame]; return true; } bool RE_particle_get_size_x(struct particle_object *po, int frame, float *size) { - if (!po || frame >= po->nr_sizes_x) + if (!po || frame >= po->pae_obj->nr_sizes_x) return false; - *size = po->sizes_x[frame]; + *size = po->pae_obj->sizes_x[frame]; return true; } bool RE_particle_get_size_y(struct particle_object *po, int frame, float *size) { - if (!po || frame >= po->nr_sizes_y) + if (!po || frame >= po->pae_obj->nr_sizes_y) return false; - *size = po->sizes_y[frame]; + *size = po->pae_obj->sizes_y[frame]; return true; } bool RE_particle_get_size_type(struct particle_object *po, int frame, int *type) { - if (!po || frame >= po->nr_size_types) + if (!po || frame >= po->pae_obj->nr_size_types) return false; - *type = po->size_types[frame]; + *type = po->pae_obj->size_types[frame]; return true; } bool RE_particle_get_size_x_type(struct particle_object *po, int frame, int *type) { - if (!po || frame >= po->nr_size_x_types) + if (!po || frame >= po->pae_obj->nr_size_x_types) return false; - *type = po->size_x_types[frame]; + *type = po->pae_obj->size_x_types[frame]; return true; } bool RE_particle_get_size_y_type(struct particle_object *po, int frame, int *type) { - if (!po || frame >= po->nr_size_y_types) + if (!po || frame >= po->pae_obj->nr_size_y_types) return false; - *type = po->size_y_types[frame]; + *type = po->pae_obj->size_y_types[frame]; return true; } int RE_particle_get_num_size2(struct particle_object *po) { - return po ? po->nr_sizes2 : 0; + return po ? po->pae_obj->nr_sizes2 : 0; } int RE_particle_get_num_size_x(struct particle_object *po) { - return po ? po->nr_sizes_x : 0; + return po ? po->pae_obj->nr_sizes_x : 0; } int RE_particle_get_num_size_y(struct particle_object *po) { - return po ? po->nr_sizes_y : 0; + return po ? po->pae_obj->nr_sizes_y : 0; } int RE_particle_get_num_size_type(struct particle_object *po) { - return po ? po->nr_size_types : 0; + return po ? po->pae_obj->nr_size_types : 0; } int RE_particle_get_num_size_x_type(struct particle_object *po) { - return po ? po->nr_size_x_types : 0; + return po ? po->pae_obj->nr_size_x_types : 0; } int RE_particle_get_num_size_y_type(struct particle_object *po) { - return po ? po->nr_size_y_types : 0; + return po ? po->pae_obj->nr_size_y_types : 0; } int RE_particle_get_blend_type(struct particle_object *po) { - return po ? po->blend_type : 0; + return po ? po->pae_obj->blend_type : 0; } const char *RE_particle_get_polygon_name(struct particle_object *po) { - return po ? po->polygon_name : NULL; + return po ? po->pae_obj->polygon_name : NULL; } int RE_particle_get_num_particles(struct particle_object *po) { - return po ? po->nr_particles : 0; + return po ? po->pae_obj->nr_particles : 0; } int RE_particle_get_alpha_fadein_time(struct particle_object *po) { - return po ? po->alpha_fadein_time : 0; + return po ? po->pae_obj->alpha_fadein_time : 0; } int RE_particle_get_alpha_fadeout_time(struct particle_object *po) { - return po ? po->alpha_fadeout_time : 0; + return po ? po->pae_obj->alpha_fadeout_time : 0; } int RE_particle_get_texture_anime_time(struct particle_object *po) { - return po ? po->texture_anime_time : 0; + return po ? po->pae_obj->texture_anime_time : 0; } float RE_particle_get_alpha_fadein_frame(struct particle_object *po) { - return po ? po->alpha_fadein_frame : 0.0; + return po ? po->pae_obj->alpha_fadein_frame : 0.0; } float RE_particle_get_alpha_fadeout_frame(struct particle_object *po) { - return po ? po->alpha_fadeout_frame : 0.0; + return po ? po->pae_obj->alpha_fadeout_frame : 0.0; } float RE_particle_get_texture_anime_frame(struct particle_object *po) { - return po ? po->texture_anime_frame : 0.0; + return po ? po->pae_obj->texture_anime_frame : 0.0; } int RE_particle_get_frame_ref_type(struct particle_object *po) { - return po ? po->frame_ref_type : 0; + return po ? po->pae_obj->frame_ref_type : 0; } int RE_particle_get_frame_ref_param(struct particle_object *po) { - return po ? po->frame_ref_param : 0; + return po ? po->pae_obj->frame_ref_param : 0; } void RE_particle_get_x_rotation_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->rotation.begin[0]; - *end_angle = po->rotation.end[0]; + *begin_angle = po->pae_obj->rotation.begin[0]; + *end_angle = po->pae_obj->rotation.end[0]; } void RE_particle_get_y_rotation_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->rotation.begin[1]; - *end_angle = po->rotation.end[1]; + *begin_angle = po->pae_obj->rotation.begin[1]; + *end_angle = po->pae_obj->rotation.end[1]; } void RE_particle_get_z_rotation_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->rotation.begin[2]; - *end_angle = po->rotation.end[2]; + *begin_angle = po->pae_obj->rotation.begin[2]; + *end_angle = po->pae_obj->rotation.end[2]; } void RE_particle_get_x_revolution_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->revolution_angle.begin[0]; - *end_angle = po->revolution_angle.end[0]; + *begin_angle = po->pae_obj->revolution_angle.begin[0]; + *end_angle = po->pae_obj->revolution_angle.end[0]; } void RE_particle_get_x_revolution_distance(struct particle_object *po, float *begin_distance, float *end_distance) { if (!po) return; - *begin_distance = po->revolution_distance.begin[0]; - *end_distance = po->revolution_distance.end[0]; + *begin_distance = po->pae_obj->revolution_distance.begin[0]; + *end_distance = po->pae_obj->revolution_distance.end[0]; } void RE_particle_get_y_revolution_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->revolution_angle.begin[1]; - *end_angle = po->revolution_angle.end[1]; + *begin_angle = po->pae_obj->revolution_angle.begin[1]; + *end_angle = po->pae_obj->revolution_angle.end[1]; } void RE_particle_get_y_revolution_distance(struct particle_object *po, float *begin_distance, float *end_distance) { if (!po) return; - *begin_distance = po->revolution_distance.begin[1]; - *end_distance = po->revolution_distance.end[1]; + *begin_distance = po->pae_obj->revolution_distance.begin[1]; + *end_distance = po->pae_obj->revolution_distance.end[1]; } void RE_particle_get_z_revolution_angle(struct particle_object *po, float *begin_angle, float *end_angle) { if (!po) return; - *begin_angle = po->revolution_angle.begin[2]; - *end_angle = po->revolution_angle.end[2]; + *begin_angle = po->pae_obj->revolution_angle.begin[2]; + *end_angle = po->pae_obj->revolution_angle.end[2]; } void RE_particle_get_z_revolution_distance(struct particle_object *po, float *begin_distance, float *end_distance) { if (!po) return; - *begin_distance = po->revolution_distance.begin[2]; - *end_distance = po->revolution_distance.end[2]; + *begin_distance = po->pae_obj->revolution_distance.begin[2]; + *end_distance = po->pae_obj->revolution_distance.end[2]; } bool RE_particle_get_curve_length(struct particle_object *po, vec3 out) { if (!po) return false; - glm_vec3_copy(po->curve_length, out); + glm_vec3_copy(po->pae_obj->curve_length, out); return true; } int RE_particle_get_child_frame(struct particle_object *po) { - return po ? po->child_frame : 0; + return po ? po->pae_obj->child_frame : 0; } float RE_particle_get_child_length(struct particle_object *po) { - return po ? po->child_length : 0.0; + return po ? po->pae_obj->child_length : 0.0; } float RE_particle_get_child_begin_slope(struct particle_object *po) { - return po ? po->child_begin_slope : 0.0; + return po ? po->pae_obj->child_begin_slope : 0.0; } float RE_particle_get_child_end_slope(struct particle_object *po) { - return po ? po->child_end_slope : 0.0; + return po ? po->pae_obj->child_end_slope : 0.0; } float RE_particle_get_child_create_begin_frame(struct particle_object *po) { - return po ? po->child_create_begin_frame : 0.0; + return po ? po->pae_obj->child_create_begin_frame : 0.0; } float RE_particle_get_child_create_end_frame(struct particle_object *po) { - return po ? po->child_create_end_frame : 0.0; + return po ? po->pae_obj->child_create_end_frame : 0.0; } int RE_particle_get_child_move_dir_type(struct particle_object *po) { - return po ? po->child_move_dir_type : 0; + return po ? po->pae_obj->child_move_dir_type : 0; } int RE_particle_get_dir_type(struct particle_object *po) { - return po ? po->dir_type : 0; + return po ? po->pae_obj->dir_type : 0; } int RE_particle_get_num_damage(struct particle_object *po) { - return po ? po->nr_damages : 0; + return po ? po->pae_obj->nr_damages : 0; } int RE_particle_get_damage(struct particle_object *po, int frame) { - if (!po || frame >= po->nr_damages) + if (!po || frame >= po->pae_obj->nr_damages) return 0; - return po->damages[frame]; + return po->pae_obj->damages[frame]; } float RE_particle_get_offset_x(struct particle_object *po) { - return po ? po->offset_x : 0.0; + return po ? po->pae_obj->offset_x : 0.0; } float RE_particle_get_offset_y(struct particle_object *po) { - return po ? po->offset_y : 0.0; + return po ? po->pae_obj->offset_y : 0.0; } bool RE_effect_get_frame_range(struct RE_instance *instance, int *begin_frame, int *end_frame) diff --git a/src/3d/renderer.c b/src/3d/renderer.c index ef8974e..f17f2cd 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -490,7 +490,8 @@ static void render_billboard(struct RE_instance *inst, struct RE_renderer *r, ma static void render_billboard_particles(struct RE_renderer *r, struct RE_instance *inst, struct particle_object *po, float frame) { - if (po->nr_textures == 0) + struct pae_object *pae_obj = po->pae_obj; + if (pae_obj->nr_textures == 0) return; glUniform1i(r->diffuse_type, DIFFUSE_EMISSIVE); @@ -500,19 +501,19 @@ static void render_billboard_particles(struct RE_renderer *r, struct RE_instance glUniform1i(r->texture, 0); glBindVertexArray(r->billboard_vao); - for (int index = 0; index < po->nr_particles; index++) { + for (int index = 0; index < pae_obj->nr_particles; index++) { struct particle_instance *pi = &po->instances[index]; if (frame < pi->begin_frame || pi->end_frame < frame) continue; - int step = (int)((frame - pi->begin_frame) / po->texture_anime_frame); - struct billboard_texture *bt = ht_get(inst->effect->textures, po->textures[step % po->nr_textures], NULL); + int step = (int)((frame - pi->begin_frame) / pae_obj->texture_anime_frame); + struct billboard_texture *bt = ht_get(inst->effect->pae->textures, pae_obj->textures[step % pae_obj->nr_textures], NULL); if (!bt) continue; glBindTexture(GL_TEXTURE_2D, bt->texture); - float alpha = particle_object_calc_alpha(po, pi, frame); - if (po->blend_type == PARTICLE_BLEND_ADDITIVE && !bt->has_alpha) + float alpha = pae_object_calc_alpha(pae_obj, pi, frame); + if (pae_obj->blend_type == PARTICLE_BLEND_ADDITIVE && !bt->has_alpha) alpha *= alpha; // why... glUniform1f(r->alpha_mod, alpha); @@ -530,19 +531,20 @@ static void render_billboard_particles(struct RE_renderer *r, struct RE_instance static void render_polygon_particles(struct RE_renderer *r, struct RE_instance *inst, struct particle_object *po, float frame) { - struct model *model = po->model; + struct pae_object *pae_obj = po->pae_obj; + struct model *model = pae_obj->model; if (!model) return; glUniform1i(r->diffuse_type, DIFFUSE_NORMAL); glUniform1i(r->fog_type, inst->plugin->fog_mode ? inst->plugin->fog_type : 0); - for (int index = 0; index < po->nr_particles; index++) { + for (int index = 0; index < pae_obj->nr_particles; index++) { struct particle_instance *pi = &po->instances[index]; if (frame < pi->begin_frame || pi->end_frame < frame) continue; - float alpha = particle_object_calc_alpha(po, pi, frame); + float alpha = pae_object_calc_alpha(pae_obj, pi, frame); glUniform1f(r->alpha_mod, alpha); mat4 local_transform; @@ -588,10 +590,10 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer glDepthMask(GL_FALSE); - for (int i = 0; i < inst->effect->nr_objects; i++) { + for (int i = 0; i < inst->effect->pae->nr_objects; i++) { struct particle_object *po = &inst->effect->objects[i]; - switch (po->blend_type) { + switch (po->pae_obj->blend_type) { case PARTICLE_BLEND_NORMAL: glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); break; @@ -600,7 +602,7 @@ static void render_particle_effect(struct RE_instance *inst, struct RE_renderer break; } - switch (po->type) { + switch (po->pae_obj->type) { case PARTICLE_TYPE_BILLBOARD: render_billboard_particles(r, inst, po, inst->motion->current_frame); break; From 9465ee1c639b0d48e6e6157d42b496f0b8f34c78 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 25 Dec 2022 16:00:13 +0900 Subject: [PATCH 3/7] ReignEngine: Cache parsed motions Motions are cached in `struct model`. --- src/3d/3d_internal.h | 5 +++-- src/3d/debug.c | 4 ++-- src/3d/model.c | 33 ++++++++++++++++++++++----------- src/3d/parser.c | 4 +++- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index 38e4e21..f157cc2 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -43,6 +43,7 @@ struct model { struct bone *bones; struct hash_table *bone_map; // bone id in POL/MOT -> struct bone * struct hash_table *bone_name_map; // bone name -> (struct bone * | NULL) + struct hash_table *mot_cache; // name -> struct mot * vec3 aabb[2]; // axis-aligned bounding box bool has_transparent_material; }; @@ -82,7 +83,6 @@ struct bone { struct motion { struct RE_instance *instance; struct mot *mot; - char *name; int state; float current_frame; float frame_begin, frame_end; @@ -453,6 +453,7 @@ struct pol_bone { }; struct mot { + char *name; uint32_t nr_frames; uint32_t nr_bones; struct mot_bone *motions[]; @@ -498,7 +499,7 @@ void pol_free(struct pol *pol); void pol_compute_aabb(struct pol *model, vec3 dest[2]); struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id); -struct mot *mot_parse(uint8_t *data, size_t size); +struct mot *mot_parse(uint8_t *data, size_t size, const char *name); void mot_free(struct mot *mot); struct amt *amt_parse(uint8_t *data, size_t size); diff --git a/src/3d/debug.c b/src/3d/debug.c index 2379b4f..a7b9bfc 100644 --- a/src/3d/debug.c +++ b/src/3d/debug.c @@ -63,9 +63,9 @@ static void print_motion(const char *name, struct motion *m, int indent) indent_printf(indent, "%s = {state=%s, frame=%f, range=(%d,%d), loop_range=(%d,%d)},\n", name, motion_state_name(m->state), m->current_frame, (int)m->frame_begin, (int)m->frame_end, (int)m->loop_frame_begin, (int)m->loop_frame_end); - } else { + } else if (m->mot) { indent_printf(indent, "%s = {name=\"%s\", state=%s, frame=%f},\n", - name, m->name, motion_state_name(m->state), m->current_frame); + name, m->mot->name, motion_state_name(m->state), m->current_frame); } } diff --git a/src/3d/model.c b/src/3d/model.c index 3936284..fb63fb6 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -422,6 +422,7 @@ struct model *model_load(struct archive *aar, const char *path) ERROR("%s: Too many bones (%u)", model->path, pol->nr_bones); model->bone_map = ht_create(pol->nr_bones * 3 / 2); model->bone_name_map = ht_create(pol->nr_bones * 3 / 2); + model->mot_cache = ht_create(16); model->bones = xcalloc(pol->nr_bones, sizeof(struct bone)); for (uint32_t i = 0; i < pol->nr_bones; i++) { add_bone(model, pol, &pol->bones[i]); @@ -499,6 +500,10 @@ void model_free(struct model *model) ht_free_int(model->bone_map); if (model->bone_name_map) ht_free(model->bone_name_map); + if (model->mot_cache) { + ht_foreach_value(model->mot_cache, (void(*)(void*))mot_free); + ht_free(model->mot_cache); + } free(model->path); free(model); @@ -604,18 +609,14 @@ static int cmp_motions_by_bone_id(const void *lhs, const void *rhs) return (*(struct mot_bone **)lhs)->id - (*(struct mot_bone **)rhs)->id; } -struct motion *motion_load(const char *name, struct RE_instance *instance, struct archive *aar) +static struct mot *mot_load(const char *name, struct model *model, struct archive *aar) { - struct model *model = instance->model; - if (!model) - return NULL; - struct archive_data *dfile = RE_get_aar_entry(aar, model->path, name, ".MOT"); if (!dfile) { WARNING("%s\\%s.MOT: not found", model->path, name); return NULL; } - struct mot *mot = mot_parse(dfile->data, dfile->size); + struct mot *mot = mot_parse(dfile->data, dfile->size, name); if (!mot) { WARNING("%s: parse error", dfile->name); archive_free_data(dfile); @@ -640,18 +641,28 @@ struct motion *motion_load(const char *name, struct RE_instance *instance, struc } qsort(mot->motions, mot->nr_bones, sizeof(struct mot_bone *), cmp_motions_by_bone_id); + return mot; +} + +struct motion *motion_load(const char *name, struct RE_instance *instance, struct archive *aar) +{ + struct model *model = instance->model; + if (!model || !model->mot_cache) + return NULL; + struct mot *mot = ht_get(model->mot_cache, name, NULL); + if (!mot) { + mot = mot_load(name, model, aar); + if (!mot) + return NULL; + ht_put(model->mot_cache, name, mot); + } struct motion *motion = xcalloc(1, sizeof(struct motion)); motion->instance = instance; motion->mot = mot; - motion->name = strdup(name); return motion; } void motion_free(struct motion *motion) { - if (motion->mot) - mot_free(motion->mot); - if (motion->name) - free(motion->name); free(motion); } diff --git a/src/3d/parser.c b/src/3d/parser.c index 228853f..87383c2 100644 --- a/src/3d/parser.c +++ b/src/3d/parser.c @@ -353,7 +353,7 @@ struct pol_bone *pol_find_bone(struct pol *pol, uint32_t id) return NULL; } -struct mot *mot_parse(uint8_t *data, size_t size) +struct mot *mot_parse(uint8_t *data, size_t size, const char *name) { struct buffer r; buffer_init(&r, data, size); @@ -369,6 +369,7 @@ struct mot *mot_parse(uint8_t *data, size_t size) uint32_t nr_bones = buffer_read_int32(&r); struct mot *mot = xcalloc(1, sizeof(struct mot) + nr_bones * sizeof(struct mot_bone *)); + mot->name = strdup(name); mot->nr_frames = nr_frames; mot->nr_bones = nr_bones; for (uint32_t i = 0; i < nr_bones; i++) { @@ -391,6 +392,7 @@ struct mot *mot_parse(uint8_t *data, size_t size) void mot_free(struct mot *mot) { + free(mot->name); for (uint32_t i = 0; i < mot->nr_bones; i++) { free(mot->motions[i]->name); free(mot->motions[i]); From 6e63b4a5e98e650a626e076e6ab08b91f46f184a Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 25 Dec 2022 14:42:34 +0900 Subject: [PATCH 4/7] ReignEngine: Do not draw particle effect if current_frame == end_frame --- src/3d/renderer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/3d/renderer.c b/src/3d/renderer.c index f17f2cd..a959df9 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -503,7 +503,7 @@ static void render_billboard_particles(struct RE_renderer *r, struct RE_instance for (int index = 0; index < pae_obj->nr_particles; index++) { struct particle_instance *pi = &po->instances[index]; - if (frame < pi->begin_frame || pi->end_frame < frame) + if (frame < pi->begin_frame || pi->end_frame <= frame) continue; int step = (int)((frame - pi->begin_frame) / pae_obj->texture_anime_frame); @@ -541,7 +541,7 @@ static void render_polygon_particles(struct RE_renderer *r, struct RE_instance * for (int index = 0; index < pae_obj->nr_particles; index++) { struct particle_instance *pi = &po->instances[index]; - if (frame < pi->begin_frame || pi->end_frame < frame) + if (frame < pi->begin_frame || pi->end_frame <= frame) continue; float alpha = pae_object_calc_alpha(pae_obj, pi, frame); From 1edf95bcde817a64de4ac46b2933fead87396ae0 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 25 Dec 2022 17:16:39 +0900 Subject: [PATCH 5/7] ReignEngine: Fix height detection This fixes an issue where height detection fails due to gaps in suspension bridge planks. If the depth map has no value for the given point, return the average of 4 neighbors. --- src/3d/3d_internal.h | 2 +- src/3d/reign.c | 15 +++++++++++++-- src/3d/renderer.c | 11 +++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index f157cc2..1e156a3 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -193,7 +193,7 @@ void RE_renderer_free(struct RE_renderer *r); bool RE_renderer_load_billboard_texture(struct RE_renderer *r, int cg_no); struct height_detector *RE_renderer_create_height_detector(struct RE_renderer *r, struct model *model); void RE_renderer_free_height_detector(struct height_detector *hd); -float RE_renderer_detect_height(struct height_detector *hd, float x, float z); +bool RE_renderer_detect_height(struct height_detector *hd, float x, float z, float *y_out); void RE_calc_view_matrix(struct RE_camera *camera, vec3 up, mat4 out); // particle.c diff --git a/src/3d/reign.c b/src/3d/reign.c index 42e7027..7244cd5 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -488,8 +488,19 @@ float RE_instance_calc_height(struct RE_instance *instance, float x, float z) if (!instance->height_detector) { instance->height_detector = RE_renderer_create_height_detector(instance->plugin->renderer, instance->model); } - float y = RE_renderer_detect_height(instance->height_detector, x, z); - return y; + + float y; + if (RE_renderer_detect_height(instance->height_detector, x, z, &y)) + return y; + + // Return the average of 4 neighbors. + int cnt = 0; + float total = 0.0f; + if (RE_renderer_detect_height(instance->height_detector, x - 0.5f, z, &y)) { cnt++; total += y; } + if (RE_renderer_detect_height(instance->height_detector, x + 0.5f, z, &y)) { cnt++; total += y; } + if (RE_renderer_detect_height(instance->height_detector, x, z - 0.5f, &y)) { cnt++; total += y; } + if (RE_renderer_detect_height(instance->height_detector, x, z + 0.5f, &y)) { cnt++; total += y; } + return cnt ? total / cnt : 0.0f; } bool RE_instance_set_debug_draw_shadow_volume(struct RE_instance *inst, bool draw) diff --git a/src/3d/renderer.c b/src/3d/renderer.c index a959df9..bf4fd5b 100644 --- a/src/3d/renderer.c +++ b/src/3d/renderer.c @@ -970,7 +970,7 @@ void RE_renderer_free_height_detector(struct height_detector *hd) free(hd); } -float RE_renderer_detect_height(struct height_detector *hd, float x, float z) +bool RE_renderer_detect_height(struct height_detector *hd, float x, float z, float *y_out) { float minx = hd->aabb[0][0]; float maxx = hd->aabb[1][0]; @@ -979,9 +979,12 @@ float RE_renderer_detect_height(struct height_detector *hd, float x, float z) float minz = hd->aabb[0][2]; float maxz = hd->aabb[1][2]; if (x < minx || x > maxx || z < minz || z > maxz) - return 0.0; + return false; int px = glm_percent(minx, maxx, x) * SHADOW_WIDTH; int pz = glm_percent(maxz, minz, z) * SHADOW_HEIGHT; - float py = hd->buf[pz * SHADOW_WIDTH + px] / 65535.0; - return glm_lerp(maxy, miny, py); + GLushort val = hd->buf[pz * SHADOW_WIDTH + px]; + if (!val) + return false; + *y_out = glm_lerp(maxy, miny, val / 65535.0f); + return true; } From 68eff9a12273d63fb7f14a067fc59c3d61f960eb Mon Sep 17 00:00:00 2001 From: kichikuou Date: Tue, 27 Dec 2022 10:43:35 +0900 Subject: [PATCH 6/7] ReignEngine: Fix out-of-bounds access in calc_motion_frame Happens when frame range in MonsterInfo.txt is wrong. --- src/3d/reign.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/3d/reign.c b/src/3d/reign.c index 7244cd5..ac56605 100644 --- a/src/3d/reign.c +++ b/src/3d/reign.c @@ -138,8 +138,12 @@ static void update_motion(struct motion *m, float delta_frame) static void calc_motion_frame(struct motion *m, int bone, struct mot_frame *out) { - int cur_frame = m->current_frame; - int next_frame = ceilf(m->current_frame); + uint32_t cur_frame = m->current_frame; + uint32_t next_frame = ceilf(m->current_frame); + if (next_frame >= m->mot->nr_frames) { + *out = m->mot->motions[bone]->frames[m->mot->nr_frames - 1]; + return; + } float t = m->current_frame - cur_frame; struct mot_frame *frames = m->mot->motions[bone]->frames; interpolate_motion_frame(&frames[cur_frame], &frames[next_frame], t, out); From d3902470c27b10c68f685f20fae46deeab5e4067 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Wed, 28 Dec 2022 13:51:49 +0900 Subject: [PATCH 7/7] Update game compatibility table Toushin Toshi 3 is now supported. --- game_compatibility.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game_compatibility.md b/game_compatibility.md index fe06470..9d5bb78 100644 --- a/game_compatibility.md +++ b/game_compatibility.md @@ -57,7 +57,7 @@ issues, please let me know or open a pull request to update this table. | Sengoku Rance -Three for the Slash! Thrust! Burn!- (EN) | Unknown | | | AliveZ | Unknown | | | エドランゼ ~Come on!水戸姫様~ | Unknown | | -| 闘神都市III | Unsupported | | +| 闘神都市III | Supported | | | ばにしゅ!~おっぱいの消えた王国~ | Unknown | | | 僕だけの保健室 | Unknown | | | ももいろガーディアン | Unknown | |