From 8b7ed4b5da0a743e8f5a5ed4ee5214123b02f860 Mon Sep 17 00:00:00 2001 From: BoLThompson <60304460+BoLThompson@users.noreply.github.com> Date: Sun, 7 Jun 2026 21:28:48 -0700 Subject: [PATCH] Interpolation fixes (fishing rod, key door chains, hookshot chain) (#2008) * fishing rod line (item and minigame) interpolated * small key, big key door chains interpolated * hookshot chain interpolated --- include/d/actor/d_a_alink.h | 12 ++++++++ include/d/actor/d_a_mg_rod.h | 9 ++++-- include/d/actor/d_a_obj_keyhole.h | 9 ++++++ src/d/actor/d_a_alink.cpp | 48 ++++++++++++++++++++---------- src/d/actor/d_a_alink_hook.inc | 23 +++++++++++++++ src/d/actor/d_a_mg_rod.cpp | 49 +++++++++++++++++++++++++++++++ src/d/actor/d_a_obj_keyhole.cpp | 38 ++++++++++++++++++++++++ 7 files changed, 170 insertions(+), 18 deletions(-) diff --git a/include/d/actor/d_a_alink.h b/include/d/actor/d_a_alink.h index 1c2963b8e8..fa75c085fb 100644 --- a/include/d/actor/d_a_alink.h +++ b/include/d/actor/d_a_alink.h @@ -4568,6 +4568,18 @@ public: cXyz mIBChainInterpCurrHandRoot; bool mIBChainInterpPrevValid; bool mIBChainInterpCurrValid; + + cXyz mHsChainInterpPrevTop; + cXyz mHsChainInterpCurrTop; + cXyz mHsChainInterpPrevRoot; + cXyz mHsChainInterpCurrRoot; + cXyz mHsChainInterpPrevSubRoot; + cXyz mHsChainInterpCurrSubRoot; + cXyz mHsChainInterpPrevSubTop; + cXyz mHsChainInterpCurrSubTop; + bool mHsChainInterpPrevValid; + bool mHsChainInterpCurrValid; + bool mIsRollstab = false; #endif }; // Size: 0x385C diff --git a/include/d/actor/d_a_mg_rod.h b/include/d/actor/d_a_mg_rod.h index d91cda43f1..97a0bb1c72 100644 --- a/include/d/actor/d_a_mg_rod.h +++ b/include/d/actor/d_a_mg_rod.h @@ -299,8 +299,13 @@ public: /* 0x168C */ u8 field_0x168c; /* 0x168D */ u8 field_0x168d; /* 0x168E */ u8 HIOInit; + +#if TARGET_PC + cXyz mLineInterpPrev[MG_ROD_LURE_LINE_LEN]; + cXyz mLineInterpCurr[MG_ROD_LURE_LINE_LEN]; + bool mLineInterpPrevValid; + bool mLineInterpCurrValid; +#endif }; -STATIC_ASSERT(sizeof(dmg_rod_class) == 0x1690); - #endif /* D_A_MG_ROD_H */ diff --git a/include/d/actor/d_a_obj_keyhole.h b/include/d/actor/d_a_obj_keyhole.h index fd39641ad8..b8a813776d 100644 --- a/include/d/actor/d_a_obj_keyhole.h +++ b/include/d/actor/d_a_obj_keyhole.h @@ -66,9 +66,18 @@ public: /* 0x2CA7 */ s8 hide_lock; /* 0x2CA8 */ cXyz field_0x2ca8; /* 0x2CB4 */ u8 field_0x2cb4; + +#if TARGET_PC + Mtx mChainInterpPrev[6][16]; + Mtx mChainInterpCurr[6][16]; + bool mChainInterpPrevValid; + bool mChainInterpCurrValid; +#endif }; +#if !TARGET_PC STATIC_ASSERT(sizeof(obj_keyhole_class) == 0x2CB8); +#endif class daObj_Keyhole_HIO_c : public JORReflexible { public: diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index 2852076334..e5e23600e5 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -14808,6 +14808,8 @@ void daAlink_c::deleteEquipItem(BOOL i_isPlaySound, BOOL i_isDeleteKantera) { #if TARGET_PC mIBChainInterpPrevValid = false; mIBChainInterpCurrValid = false; + mHsChainInterpPrevValid = false; + mHsChainInterpCurrValid = false; #endif field_0x0774 = NULL; field_0x0778 = NULL; @@ -19780,23 +19782,37 @@ int daAlink_c::draw() { dComIfGd_getOpaListDark()->entryImm(mpHookChain, 0); #if TARGET_PC - if (dusk::frame_interp::is_enabled() && - mEquipItem == dItemNo_IRONBALL_e && - mIronBallChainPos != NULL && mIronBallChainAngle != NULL) - { - if (mIBChainInterpCurrValid) { - memcpy(mIBChainInterpPrevPos, mIBChainInterpCurrPos, IRON_BALL_CHAIN_COUNT * sizeof(cXyz)); - memcpy(mIBChainInterpPrevAngle, mIBChainInterpCurrAngle, IRON_BALL_CHAIN_COUNT * sizeof(csXyz)); - mIBChainInterpPrevHandRoot = mIBChainInterpCurrHandRoot; - mIBChainInterpPrevValid = true; + if (dusk::frame_interp::is_enabled()) { + if (mEquipItem == dItemNo_IRONBALL_e && + mIronBallChainPos != NULL && mIronBallChainAngle != NULL) + { + if (mIBChainInterpCurrValid) { + memcpy(mIBChainInterpPrevPos, mIBChainInterpCurrPos, IRON_BALL_CHAIN_COUNT * sizeof(cXyz)); + memcpy(mIBChainInterpPrevAngle, mIBChainInterpCurrAngle, IRON_BALL_CHAIN_COUNT * sizeof(csXyz)); + mIBChainInterpPrevHandRoot = mIBChainInterpCurrHandRoot; + mIBChainInterpPrevValid = true; + } + + memcpy(mIBChainInterpCurrPos, mIronBallChainPos, IRON_BALL_CHAIN_COUNT * sizeof(cXyz)); + memcpy(mIBChainInterpCurrAngle, mIronBallChainAngle, IRON_BALL_CHAIN_COUNT * sizeof(csXyz)); + mIBChainInterpCurrHandRoot = mHookshotTopPos; + mIBChainInterpCurrValid = true; + + dusk::frame_interp::add_interpolation_callback(&ironBallChainInterpCallback, this); + } else { + if (mHsChainInterpCurrValid) { + mHsChainInterpPrevTop = mHsChainInterpCurrTop; + mHsChainInterpPrevRoot = mHsChainInterpCurrRoot; + mHsChainInterpPrevSubRoot = mHsChainInterpCurrSubRoot; + mHsChainInterpPrevSubTop = mHsChainInterpCurrSubTop; + mHsChainInterpPrevValid = true; + } + mHsChainInterpCurrTop = mHookshotTopPos; + mHsChainInterpCurrRoot = mHeldItemRootPos; + mHsChainInterpCurrSubRoot = field_0x3810; + mHsChainInterpCurrSubTop = mIronBallBgChkPos; + mHsChainInterpCurrValid = true; } - - memcpy(mIBChainInterpCurrPos, mIronBallChainPos, IRON_BALL_CHAIN_COUNT * sizeof(cXyz)); - memcpy(mIBChainInterpCurrAngle, mIronBallChainAngle, IRON_BALL_CHAIN_COUNT * sizeof(csXyz)); - mIBChainInterpCurrHandRoot = mHookshotTopPos; - mIBChainInterpCurrValid = true; - - dusk::frame_interp::add_interpolation_callback(&ironBallChainInterpCallback, this); } #endif } diff --git a/src/d/actor/d_a_alink_hook.inc b/src/d/actor/d_a_alink_hook.inc index 36fba0c6d8..660cf3b2ce 100644 --- a/src/d/actor/d_a_alink_hook.inc +++ b/src/d/actor/d_a_alink_hook.inc @@ -136,8 +136,26 @@ void daAlink_c::hsChainShape_c::draw() { } } } else { +#if TARGET_PC + cXyz hsInterpTop, hsInterpRoot, hsInterpSubRoot, hsInterpSubTop; + if (dusk::frame_interp::is_enabled() && alink->mHsChainInterpPrevValid && alink->mHsChainInterpCurrValid) { + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + hsInterpTop = alink->mHsChainInterpPrevTop + (alink->mHsChainInterpCurrTop - alink->mHsChainInterpPrevTop) * alpha; + hsInterpRoot = alink->mHsChainInterpPrevRoot + (alink->mHsChainInterpCurrRoot - alink->mHsChainInterpPrevRoot) * alpha; + hsInterpSubRoot = alink->mHsChainInterpPrevSubRoot + (alink->mHsChainInterpCurrSubRoot - alink->mHsChainInterpPrevSubRoot) * alpha; + hsInterpSubTop = alink->mHsChainInterpPrevSubTop + (alink->mHsChainInterpCurrSubTop - alink->mHsChainInterpPrevSubTop) * alpha; + } else { + hsInterpTop = alink->getHsChainTopPos(); + hsInterpRoot = alink->getHsChainRootPos(); + hsInterpSubRoot = alink->getHsSubChainRootPos(); + hsInterpSubTop = alink->getHsSubChainTopPos(); + } + const cXyz& chainRootPos = hsInterpRoot; + const cXyz& chainTopPos = hsInterpTop; +#else const cXyz& chainRootPos = alink->getHsChainRootPos(); const cXyz& chainTopPos = alink->getHsChainTopPos(); +#endif cXyz maxDistance = chainRootPos - chainTopPos; f32 maxDistanceF = maxDistance.abs(); @@ -200,8 +218,13 @@ void daAlink_c::hsChainShape_c::draw() { } } +#if TARGET_PC + const cXyz& subChainRootPos = hsInterpSubRoot; + const cXyz& subChainTopPos = hsInterpSubTop; +#else const cXyz& subChainRootPos = alink->getHsSubChainRootPos(); const cXyz& subChainTopPos = alink->getHsSubChainTopPos(); +#endif maxDistance = subChainRootPos - subChainTopPos; maxDistanceF = maxDistance.abs(); diff --git a/src/d/actor/d_a_mg_rod.cpp b/src/d/actor/d_a_mg_rod.cpp index 271b212a57..f6f3b8d6c6 100644 --- a/src/d/actor/d_a_mg_rod.cpp +++ b/src/d/actor/d_a_mg_rod.cpp @@ -26,6 +26,7 @@ #include #if TARGET_PC +#include "dusk/frame_interpolation.h" #include "dusk/settings.h" #include "dusk/version.hpp" #endif @@ -180,6 +181,25 @@ static int Worm_nodeCallBack(J3DJoint* i_joint, int param_1) { return 1; } +#if TARGET_PC +static void dmg_rod_interp_callback(bool isSimFrame, void* pUserWork) { + dmg_rod_class* i_this = (dmg_rod_class*)pUserWork; + if (!i_this->mLineInterpPrevValid || !i_this->mLineInterpCurrValid) { + return; + } + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + const int count = i_this->kind == MG_ROD_KIND_LURE ? MG_ROD_LURE_LINE_LEN : MG_ROD_UKI_LINE_LEN; + cXyz* dst = i_this->linemat.getPos(0); + for (int i = 0; i < count; i++) { + const cXyz& p0 = i_this->mLineInterpPrev[i]; + const cXyz& p1 = i_this->mLineInterpCurr[i]; + dst[i] = p0 + (p1 - p0) * alpha; + } + static GXColor l_color = {0xFF, 0xFF, 0x96, 0xFF}; + i_this->linemat.update(count, l_color, &i_this->actor.tevStr); +} +#endif + static int dmg_rod_Draw(dmg_rod_class* i_this) { int unused; fopAc_ac_c* actor = &i_this->actor; @@ -220,6 +240,18 @@ static int dmg_rod_Draw(dmg_rod_class* i_this) { i_this->linemat.update(MG_ROD_LURE_LINE_LEN, l_color, &i_this->actor.tevStr); dComIfGd_set3DlineMat(&i_this->linemat); +#if TARGET_PC + if (dusk::frame_interp::is_enabled()) { + if (i_this->mLineInterpCurrValid) { + memcpy(i_this->mLineInterpPrev, i_this->mLineInterpCurr, MG_ROD_LURE_LINE_LEN * sizeof(cXyz)); + i_this->mLineInterpPrevValid = true; + } + memcpy(i_this->mLineInterpCurr, i_this->linemat.getPos(0), MG_ROD_LURE_LINE_LEN * sizeof(cXyz)); + i_this->mLineInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&dmg_rod_interp_callback, i_this); + } +#endif + model = i_this->rod_modelMorf->getModel(); g_env_light.setLightTevColorType_MAJI(model, &i_this->actor.tevStr); i_this->rod_modelMorf->entryDL(); @@ -244,6 +276,18 @@ static int dmg_rod_Draw(dmg_rod_class* i_this) { i_this->linemat.update(MG_ROD_UKI_LINE_LEN, l_color, &i_this->actor.tevStr); dComIfGd_set3DlineMat(&i_this->linemat); +#if TARGET_PC + if (dusk::frame_interp::is_enabled()) { + if (i_this->mLineInterpCurrValid) { + memcpy(i_this->mLineInterpPrev, i_this->mLineInterpCurr, MG_ROD_UKI_LINE_LEN * sizeof(cXyz)); + i_this->mLineInterpPrevValid = true; + } + memcpy(i_this->mLineInterpCurr, i_this->linemat.getPos(0), MG_ROD_UKI_LINE_LEN * sizeof(cXyz)); + i_this->mLineInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&dmg_rod_interp_callback, i_this); + } +#endif + for (int i = 0; i < 15; i++) { g_env_light.setLightTevColorType_MAJI(i_this->rod_uki_model[i], &actor->tevStr); mDoExt_modelUpdateDL(i_this->rod_uki_model[i]); @@ -6405,6 +6449,11 @@ static int dmg_rod_Create(fopAc_ac_c* i_this) { return cPhs_ERROR_e; } +#if TARGET_PC + rod->mLineInterpPrevValid = false; + rod->mLineInterpCurrValid = false; +#endif + OS_REPORT("//////////////MG_ROD SET 2 !!\n"); if (!hio_set) { rod->HIOInit = TRUE; diff --git a/src/d/actor/d_a_obj_keyhole.cpp b/src/d/actor/d_a_obj_keyhole.cpp index 8b120f77e3..d56f39f40b 100644 --- a/src/d/actor/d_a_obj_keyhole.cpp +++ b/src/d/actor/d_a_obj_keyhole.cpp @@ -10,6 +10,9 @@ #include "d/d_s_play.h" #include "d/actor/d_a_player.h" #include "Z2AudioLib/Z2Instances.h" +#if TARGET_PC +#include "dusk/frame_interpolation.h" +#endif daObj_Keyhole_HIO_c::daObj_Keyhole_HIO_c() { id = -1; @@ -53,6 +56,21 @@ static int daObj_Keyhole_Draw(obj_keyhole_class* i_this) { for (int i = 0; i < 6; i++) { kh_chain_s* chain_s = &i_this->chain_s[i]; for (int j = 0; j < i_this->chain_num; j++) { +#if TARGET_PC + if (dusk::frame_interp::is_enabled() && i_this->mChainInterpPrevValid && i_this->mChainInterpCurrValid) { + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + Mtx mtx; + const f32* p0 = (const f32*)i_this->mChainInterpPrev[i][j]; + const f32* p1 = (const f32*)i_this->mChainInterpCurr[i][j]; + f32* dst = (f32*)mtx; + for (int k = 0; k < 12; k++) { + dst[k] = p0[k] + (p1[k] - p0[k]) * alpha; + } + chain_s->model[j]->setBaseTRMtx(mtx); + g_env_light.setLightTevColorType_MAJI(chain_s->model[j], &actor->tevStr); + mDoExt_modelUpdateDL(chain_s->model[j]); + } else +#endif dComIfGp_entrySimpleModel(chain_s->model[j], fopAcM_GetRoomNo(actor)); } } @@ -370,6 +388,21 @@ static void chain_move(obj_keyhole_class* i_this) { ANGLE_ADD(sp8, TREG_S(0) + 0x3D00); } } + +#if TARGET_PC + if (dusk::frame_interp::is_enabled()) { + if (i_this->mChainInterpCurrValid) { + memcpy(i_this->mChainInterpPrev, i_this->mChainInterpCurr, sizeof(i_this->mChainInterpCurr)); + i_this->mChainInterpPrevValid = true; + } + for (int i = 0; i < 6; i++) { + for (int j = 0; j < i_this->chain_num; j++) { + MTXCopy(i_this->chain_s[i].model[j]->getBaseTRMtx(), i_this->mChainInterpCurr[i][j]); + } + } + i_this->mChainInterpCurrValid = true; + } +#endif } static void open(obj_keyhole_class* i_this) { @@ -750,6 +783,11 @@ static int daObj_Keyhole_Create(fopAc_ac_c* a_this) { return cPhs_ERROR_e; } +#if TARGET_PC + i_this->mChainInterpPrevValid = false; + i_this->mChainInterpCurrValid = false; +#endif + OS_REPORT("//////////////OBJ_KEYHOLE SET 2 !!\n"); if (i_this->arg0 == 3) {