From 4d4a80891feb7e249fdc28ba126a4c13edbb95f3 Mon Sep 17 00:00:00 2001 From: Pheenoh Date: Fri, 8 May 2026 20:21:37 -0600 Subject: [PATCH] frame interp: fix obj_fchain --- include/d/actor/d_a_obj_fchain.h | 12 ++++++++++ src/d/actor/d_a_obj_fchain.cpp | 39 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/include/d/actor/d_a_obj_fchain.h b/include/d/actor/d_a_obj_fchain.h index 1bd7b9a810..7c4ae74faf 100644 --- a/include/d/actor/d_a_obj_fchain.h +++ b/include/d/actor/d_a_obj_fchain.h @@ -31,6 +31,10 @@ public: csXyz* getAngle() { return field_0x8a4; } J3DModelData* getModelData() { return mModelData; } +#if TARGET_PC + void onInterpCallback(); +#endif + private: /* 0x568 */ request_of_phase_process_class mPhase; /* 0x570 */ J3DModelData* mModelData; @@ -42,6 +46,14 @@ private: /* 0x694 */ cXyz field_0x694[22]; /* 0x79C */ cXyz field_0x79c[22]; /* 0x8A4 */ csXyz field_0x8a4[22]; + +#if TARGET_PC + static const int CHAIN_COUNT = 22; + cXyz mChainInterpPrev[CHAIN_COUNT]; + cXyz mChainInterpCurr[CHAIN_COUNT]; + bool mChainInterpPrevValid; + bool mChainInterpCurrValid; +#endif }; STATIC_ASSERT(sizeof(daObjFchain_c) == 0x928); diff --git a/src/d/actor/d_a_obj_fchain.cpp b/src/d/actor/d_a_obj_fchain.cpp index e681fec4e7..024b4ecf8b 100644 --- a/src/d/actor/d_a_obj_fchain.cpp +++ b/src/d/actor/d_a_obj_fchain.cpp @@ -10,6 +10,8 @@ #include "JSystem/J3DGraphBase/J3DDrawBuffer.h" #include "SSystem/SComponent/c_math.h" #include "d/d_com_inf_game.h" +#include "dusk/frame_interpolation.h" +#include "dusk/settings.h" #include static char const l_arcName[] = "Fchain"; @@ -65,6 +67,10 @@ int daObjFchain_c::create() { local_48++; } rv = cPhs_COMPLEATE_e; +#if TARGET_PC + mChainInterpPrevValid = false; + mChainInterpCurrValid = false; +#endif break; } return rv; @@ -289,6 +295,26 @@ void daObjFchain_shape_c::draw() { } } +#if TARGET_PC +static void fchain_interp_callback(bool isSimFrame, void* pUserWork) { + static_cast(pUserWork)->onInterpCallback(); +} + +void daObjFchain_c::onInterpCallback() { + if (!mChainInterpPrevValid || !mChainInterpCurrValid) { + return; + } + + const f32 alpha = dusk::frame_interp::get_interpolation_step(); + + for (int i = 0; i < CHAIN_COUNT; i++) { + const cXyz& p0 = mChainInterpPrev[i]; + const cXyz& p1 = mChainInterpCurr[i]; + field_0x694[i] = p0 + (p1 - p0) * alpha; + } +} +#endif + int daObjFchain_c::draw() { if (field_0x584 != 0) { g_env_light.settingTevStruct(0, ¤t.pos, &tevStr); @@ -297,6 +323,19 @@ int daObjFchain_c::draw() { return 1; } dComIfGd_getOpaListDark()->entryImm(&mShape, 0); + +#if TARGET_PC + if (dusk::getSettings().game.enableFrameInterpolation) { + if (mChainInterpCurrValid) { + memcpy(mChainInterpPrev, mChainInterpCurr, sizeof(mChainInterpCurr)); + mChainInterpPrevValid = true; + } + + memcpy(mChainInterpCurr, field_0x694, sizeof(mChainInterpCurr)); + mChainInterpCurrValid = true; + dusk::frame_interp::add_interpolation_callback(&fchain_interp_callback, this); + } +#endif } return 1; }