From 5c288f87e54f988e034006899a8b704ad85db2c4 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 9 Oct 2022 10:29:03 +0900 Subject: [PATCH 1/3] Implement EFFECT_TV_SWITCH_OFF Used in Toushin Toshi 3. --- src/effect.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/effect.c b/src/effect.c index 9804ce6..847b548 100644 --- a/src/effect.c +++ b/src/effect.c @@ -217,6 +217,21 @@ static void effect_oscillate(float rate) gfx_copy(dst, delta_x, delta_y, &effect.new, 0, 0, dst->w, dst->h); } +static void effect_tv_switch_off(float rate) +{ + Texture *dst = gfx_main_surface(); + if (rate < 0.5f) { + int h = max(1, (int)(dst->h * (1.0f - rate * 2.0f))); + gfx_copy_stretch(dst, 0, dst->h * rate, dst->w, h, + &effect.old, 0, 0, effect.old.w, effect.old.h); + } else { + rate -= 0.5f; + int w = dst->w * (1.0f - rate * 2.0f); + gfx_copy_stretch(dst, dst->w * rate, dst->h / 2, w, 1, + &effect.old, 0, 0, effect.old.w, effect.old.h); + } +} + static void effect_zoom_in_crossfade(float rate) { Texture *dst = gfx_main_surface(); @@ -238,6 +253,7 @@ static effect_fun effect_functions[NR_EFFECTS] = { [EFFECT_WHITEOUT] = effect_whiteout, [EFFECT_WHITEIN] = effect_whitein, [EFFECT_OSCILLATE] = effect_oscillate, + [EFFECT_TV_SWITCH_OFF] = effect_tv_switch_off, [EFFECT_ZOOM_LR] = effect_zoom_lr, [EFFECT_ZOOM_RL] = effect_zoom_rl, [EFFECT_ZOOM_IN_CROSSFADE] = effect_zoom_in_crossfade, From 252f1b54648430b1189c7811defe8ebce6441bb2 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sun, 9 Oct 2022 13:35:35 +0900 Subject: [PATCH 2/3] Fix out-of-bounds access in MsgSkip HLL Toushin Toshi 3 calls MsgSkip.{Get,Set}Flag with msgnum = -1. --- src/hll/MsgSkip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hll/MsgSkip.c b/src/hll/MsgSkip.c index c35ed46..257f379 100644 --- a/src/hll/MsgSkip.c +++ b/src/hll/MsgSkip.c @@ -80,14 +80,14 @@ static int MsgSkip_Init(struct string *name) static void MsgSkip_SetFlag(int msgnum) { - if (msgnum >= nr_flags) + if (msgnum < 0 || msgnum >= nr_flags) return; flags[msgnum] = 1; } static int MsgSkip_GetFlag(int msgnum) { - if (msgnum >= nr_flags) + if (msgnum < 0 || msgnum >= nr_flags) return 0; return !!flags[msgnum]; } From 2370052b543613099bbbd27350a2adb1794bc2ed Mon Sep 17 00:00:00 2001 From: kichikuou Date: Mon, 10 Oct 2022 14:13:22 +0900 Subject: [PATCH 3/3] ReignEngine: Fix bone mapping between model and motion Some motion files (e.g. maidsan_ahoge_* and otokomae_*) have wrong bone IDs, so bone names should be used to look up matching bones in the model. However, this does not always work because masokan.POL has multiple bones with the same name. In that case ID matching must be used. --- src/3d/3d_internal.h | 1 + src/3d/model.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/3d/3d_internal.h b/src/3d/3d_internal.h index 4900926..f4a07ab 100644 --- a/src/3d/3d_internal.h +++ b/src/3d/3d_internal.h @@ -42,6 +42,7 @@ struct model { int nr_bones; 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) vec3 aabb[2]; // axis-aligned bounding box }; diff --git a/src/3d/model.c b/src/3d/model.c index 600a2c2..2bed90e 100644 --- a/src/3d/model.c +++ b/src/3d/model.c @@ -355,6 +355,14 @@ static struct bone *add_bone(struct model *model, struct pol *pol, struct pol_bo glm_quat_mat4(pol_bone->rotq, bone->inverse_bind_matrix); glm_translate(bone->inverse_bind_matrix, pol_bone->pos); + // Update bone_name_map. If the bone name is not unique in the POL, set the + // map value to NULL so that ID matching will be used. + struct ht_slot *slot = ht_put(model->bone_name_map, pol_bone->name, bone); + if (slot->value != bone) { + NOTICE("%s: non-unique bone %s", model->path, pol_bone->name); + slot->value = NULL; + } + model->nr_bones++; return bone; } @@ -401,6 +409,7 @@ struct model *model_load(struct archive *aar, const char *path) if (pol->nr_bones > MAX_BONES) 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->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]); @@ -470,6 +479,8 @@ void model_free(struct model *model) free(model->bones); if (model->bone_map) ht_free_int(model->bone_map); + if (model->bone_name_map) + ht_free(model->bone_name_map); free(model->path); free(model); @@ -505,9 +516,13 @@ struct motion *motion_load(const char *name, struct RE_instance *instance, struc // Reorder mot->motions so that motion for model->bones[i] can be // accessed by mot->motions[i]. for (uint32_t i = 0; i < mot->nr_bones; i++) { - struct bone *bone = ht_get_int(model->bone_map, mot->motions[i]->id, NULL); + // Match by name first, since some MOT have wrong bone IDs (e.g. maidsan_ahoge_*). + struct bone *bone = ht_get(model->bone_name_map, mot->motions[i]->name, NULL); + // If it is not found or is NULL (non-unique bone name), match by bone ID. if (!bone) - ERROR("%s: invalid bone id %d", name, mot->motions[i]->id); + bone = ht_get_int(model->bone_map, mot->motions[i]->id, NULL); + if (!bone) + ERROR("%s: invalid bone \"%s\" (%d)", name, mot->motions[i]->name, mot->motions[i]->id); mot->motions[i]->id = bone->index; } qsort(mot->motions, mot->nr_bones, sizeof(struct mot_bone *), cmp_motions_by_bone_id);