From c9f161fddbdf50aa6df2fc0f58beae0b9d0a851c Mon Sep 17 00:00:00 2001 From: Irastris Date: Thu, 10 Sep 2026 16:52:00 -0400 Subject: [PATCH] Interp minimap player arrow, sights and cursors --- include/d/actor/d_a_alink.h | 4 ++ include/d/actor/d_a_boomerang.h | 4 ++ include/d/actor/d_a_player.h | 6 +- include/d/d_select_cursor.h | 13 +++- src/d/actor/d_a_alink.cpp | 2 +- src/d/actor/d_a_alink_effect.inc | 41 ++++++++----- src/d/actor/d_a_boomerang.cpp | 74 +++++++++++++++++++---- src/d/actor/d_a_player.cpp | 25 ++++++-- src/d/d_map_path_dmap.cpp | 34 ++++++++++- src/d/d_menu_ring.cpp | 2 +- src/d/d_select_cursor.cpp | 79 +++++++++++++++++++++++-- src/d/d_shop_system.cpp | 36 ++++++++--- src/dusk/interp/frame_interpolation.cpp | 16 +++-- src/dusk/interp/sight.h | 23 +++++++ 14 files changed, 305 insertions(+), 54 deletions(-) create mode 100644 src/dusk/interp/sight.h diff --git a/include/d/actor/d_a_alink.h b/include/d/actor/d_a_alink.h index a0b70747bc..90528b27a0 100644 --- a/include/d/actor/d_a_alink.h +++ b/include/d/actor/d_a_alink.h @@ -124,7 +124,11 @@ public: BOOL create(); void update(); virtual void draw(); +#if TARGET_PC + virtual ~daAlink_lockCursor_c(); +#else virtual ~daAlink_lockCursor_c() {} +#endif void initFrame() { field_0x4 = 0; diff --git a/include/d/actor/d_a_boomerang.h b/include/d/actor/d_a_boomerang.h index 2b527afe45..5c4f6f8ede 100644 --- a/include/d/actor/d_a_boomerang.h +++ b/include/d/actor/d_a_boomerang.h @@ -17,7 +17,11 @@ public: void setSight(cXyz const*, int); virtual void draw(); +#if TARGET_PC + virtual ~daBoomerang_sight_c(); +#else virtual ~daBoomerang_sight_c() {} +#endif u8 getReserve() const { return mReserve; } u8 getAlpha(int i_index) { return m_alpha[i_index]; } diff --git a/include/d/actor/d_a_player.h b/include/d/actor/d_a_player.h index ff8a165ef8..85e007bd33 100644 --- a/include/d/actor/d_a_player.h +++ b/include/d/actor/d_a_player.h @@ -33,9 +33,13 @@ class daPy_sightPacket_c : public dDlst_base_c { public: daPy_sightPacket_c() {} virtual void draw(); +#if TARGET_PC + virtual ~daPy_sightPacket_c(); +#else virtual ~daPy_sightPacket_c() {} +#endif - void setSight(); + void setSight(IF_DUSK(bool registerPacket = true)); void setSightImage(ResTIMG* i_img); u8 getDrawFlg() { return mDrawFlag; } diff --git a/include/d/d_select_cursor.h b/include/d/d_select_cursor.h index 766463b5b3..891280e801 100644 --- a/include/d/d_select_cursor.h +++ b/include/d/d_select_cursor.h @@ -42,12 +42,18 @@ public: virtual ~dSelect_cursor_c(); virtual void draw(); +#if TARGET_PC + void setInterp(bool enabled); + void setPos(f32 x, f32 y, const cXyz* world = nullptr); + void setWorldPos(const cXyz& position, f32 offsetX, f32 offsetY) { setPos(offsetX, offsetY, &position); } +#else void setPos(f32 x, f32 y) { mPositionX = x; mPositionY = y; } +#endif -#ifdef TARGET_PC +#if TARGET_PC f32 getPositionX() const { return mPositionX; } f32 getPositionY() const { return mPositionY; } @@ -100,6 +106,11 @@ public: /* 0xB5 */ u8 mNameIdx; /* 0xB6 */ u8 field_0xb6; /* 0xB7 */ bool mUpdateFlag; +#if TARGET_PC + cXyz mWorldPosition{0.0f, 0.0f, 0.0f}; + bool mWorldCursor = false; + bool mInterpolatePosition = true; +#endif }; #endif /* D_D_SELECT_CURSOR_H */ diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index ba8475b9f2..ab4f52b9de 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -54,7 +54,7 @@ #if TARGET_PC #include "dusk/action_bindings.h" #include "dusk/interp/frame_interpolation.h" -#include "dusk/interp/samples.h" +#include "dusk/interp/sight.h" #include "dusk/settings.h" #include "res/Object/Alink.h" #include diff --git a/src/d/actor/d_a_alink_effect.inc b/src/d/actor/d_a_alink_effect.inc index b3a9d7bdc4..724d9d01ab 100644 --- a/src/d/actor/d_a_alink_effect.inc +++ b/src/d/actor/d_a_alink_effect.inc @@ -2110,6 +2110,12 @@ void daAlink_blur_c::draw() { J3DShape::resetVcdVatCache(); } +#if TARGET_PC +daAlink_lockCursor_c::~daAlink_lockCursor_c() { + dusk::interp::erase_owned_samples(this); +} +#endif + BOOL daAlink_lockCursor_c::create() { JKRArchive* arc = dComIfG_getObjectResInfo(l_arcName)->getArchive(); @@ -2217,6 +2223,11 @@ void daAlink_lockCursor_c::update() { } cLib_chaseUC(&field_0x4, 0x80, 30); +#if TARGET_PC + const dusk::interp::SightAnimation frame = {mLockCursorAngle, field_0x30, + static_cast(field_0x4), static_cast(field_0x1c->getFrameMax())}; + dusk::interp::get>(this).capture(&frame, 1); +#endif } void daAlink_lockCursor_c::draw() { @@ -2224,28 +2235,28 @@ void daAlink_lockCursor_c::draw() { return; } - field_0x28->setFrame(mLockCursorAngle); +#if TARGET_PC + auto& samples = dusk::interp::get>(this); + const dusk::interp::SightAnimation current = { + mLockCursorAngle, field_0x30, static_cast(field_0x4), static_cast(field_0x1c->getFrameMax())}; + const auto frame = samples.read(0, current); +#endif + field_0x28->setFrame(DUSK_IF_ELSE(frame.bck, mLockCursorAngle)); - f32 var_f30; - if (mLockCursorAngle > 21.0f) { - var_f30 = 21.0f; - } else { - var_f30 = mLockCursorAngle; - } - - field_0x24->setFrame(var_f30); - field_0x1c->setFrame(field_0x30); + field_0x24->setFrame(DUSK_IF_ELSE(frame.bck, mLockCursorAngle) > 21.0f + ? 21.0f : DUSK_IF_ELSE(frame.bck, mLockCursorAngle)); + field_0x1c->setFrame(DUSK_IF_ELSE(frame.brk, field_0x30)); mScrn->animation(); field_0xc->scale(0.6f, 0.6f); field_0xc->translate(mPosX, mPosY); f32 var_f31; - if (!(mLockCursorAngle < 15.0f)) { - if (mLockCursorAngle < 21.0f) { - var_f31 = ((mLockCursorAngle - 15.0f) * 40.0f) * 0.16666667f; + if (!(DUSK_IF_ELSE(frame.bck, mLockCursorAngle) < 15.0f)) { + if (DUSK_IF_ELSE(frame.bck, mLockCursorAngle) < 21.0f) { + var_f31 = ((DUSK_IF_ELSE(frame.bck, mLockCursorAngle) - 15.0f) * 40.0f) * 0.16666667f; } else { - var_f31 = ((field_0x4 * 0.00390625f) + 0.5f) * 40.0f; + var_f31 = ((DUSK_IF_ELSE(frame.alpha, field_0x4) * 0.00390625f) + 0.5f) * 40.0f; } mCursor0->translate(0.0f, -var_f31); @@ -2267,6 +2278,7 @@ BOOL daAlink_sight_c::create() { void daAlink_sight_c::draw() { if (mLockFlag) { + IF_DUSK(setSight(false);) mLockCursor.setPos(mProjMtx[0][3], mProjMtx[1][3]); mLockCursor.draw(); } else { @@ -2279,5 +2291,6 @@ void daAlink_sight_c::onLockFlg() { return; } mLockFlag = true; + IF_DUSK(dusk::interp::erase_owned_samples(&mLockCursor);) mLockCursor.initFrame(); } diff --git a/src/d/actor/d_a_boomerang.cpp b/src/d/actor/d_a_boomerang.cpp index 9deb7b46b8..96453cb221 100644 --- a/src/d/actor/d_a_boomerang.cpp +++ b/src/d/actor/d_a_boomerang.cpp @@ -14,6 +14,35 @@ #include "Z2AudioLib/Z2Instances.h" #include "SSystem/SComponent/c_math.h" +#if TARGET_PC +#include "dusk/interp/sight.h" + +namespace { +struct SightFrame { + cXyz position; + dusk::interp::SightAnimation animation; +}; + +void lerp(SightFrame& out, const SightFrame& a, const SightFrame& b, f32 step) { + dusk::interp::lerp(out.position, a.position, b.position, step); + dusk::interp::lerp(out.animation, a.animation, b.animation, step); +} + +struct SightSamples { + dusk::interp::Samples slots[BOOMERANG_LOCK_MAX + 1]; +}; + +SightFrame sight_frame(const daBoomerang_sight_c& sight, int i) { + return {sight.m_pos[i], {sight.field_0x98[i], sight.field_0xb0[i], + static_cast(sight.m_alpha[i]), static_cast(sight.m_cursorYellow2Brk->getFrameMax())}}; +} +} // namespace + +daBoomerang_sight_c::~daBoomerang_sight_c() { + dusk::interp::erase_owned_samples(this); +} +#endif + int daBoomerang_sight_c::createHeap() { void* tmpData; JKRArchive* archive = dComIfG_getObjectResInfo(daAlink_c::getAlinkArcName())->getArchive(); @@ -158,6 +187,7 @@ static const u32 l_lockSeFlg[BOOMERANG_LOCK_MAX] = { }; void daBoomerang_sight_c::initialize() { + IF_DUSK(dusk::interp::erase_owned_samples(this);) m_cursorYellowAllPane = m_cursorYellowScrn->search(MULTI_CHAR('n_all')); m_cursorYellow0Pane = m_cursorYellowScrn->search(MULTI_CHAR('cursor0')); m_cursorYellow1Pane = m_cursorYellowScrn->search(MULTI_CHAR('cursor1')); @@ -300,6 +330,7 @@ int daBoomerang_sight_c::playAnime(int param_0, int param_1) { } void daBoomerang_sight_c::initFrame(int i_no) { + IF_DUSK(dusk::interp::get(this).slots[i_no].reset();) m_alpha[i_no] = 0; field_0x98[i_no] = 4.0f; field_0xb0[i_no] = 0.0f; @@ -328,6 +359,10 @@ void daBoomerang_sight_c::copyNumData(int i_no) { cXyz temp_pos = m_pos[i_no]; m_pos[i_no] = m_pos[next_no]; m_pos[next_no] = temp_pos; +#if TARGET_PC + auto& slots = dusk::interp::get(this).slots; + std::swap(slots[i_no], slots[next_no]); +#endif } void daBoomerang_sight_c::setSight(const cXyz* i_pos, int i_no) { @@ -337,7 +372,13 @@ void daBoomerang_sight_c::setSight(const cXyz* i_pos, int i_no) { } Vec proj; - mDoLib_project(&m_pos[i_no], &proj); +#if TARGET_PC + auto& samples = dusk::interp::get(this).slots[i_no]; + const SightFrame current = sight_frame(*this, i_no); + samples.capture(¤t, 1); + cXyz position = samples.read(0, current).position; +#endif + mDoLib_project(DUSK_IF_ELSE(&position, &m_pos[i_no]), &proj); m_proj_posX[i_no] = proj.x; m_proj_posY[i_no] = proj.y; } @@ -357,11 +398,16 @@ void daBoomerang_sight_c::draw() { for (int i = 0; i < 6; i++, alpha_p++) { if (*alpha_p != 0) { - m_cursorYellowBck->setFrame(field_0x98[i]); - m_cursorYellowBpk->setFrame(field_0x98[i] > 21.0f ? 21.0f : field_0x98[i]); +#if TARGET_PC + setSight(NULL, i); + const auto frame = dusk::interp::get(this).slots[i].read(0, sight_frame(*this, i)).animation; +#endif + m_cursorYellowBck->setFrame(DUSK_IF_ELSE(frame.bck, field_0x98[i])); + m_cursorYellowBpk->setFrame(DUSK_IF_ELSE(frame.bck, field_0x98[i]) > 21.0f + ? 21.0f : DUSK_IF_ELSE(frame.bck, field_0x98[i])); if (i == 5) { - m_cursorYellow2Brk->setFrame(field_0xb0[i]); + m_cursorYellow2Brk->setFrame(DUSK_IF_ELSE(frame.brk, field_0xb0[i])); cursor0_pane = m_cursorYellow0Pane; cursor1_pane = m_cursorYellow1Pane; cursor2_pane = m_cursorYellow2Pane; @@ -369,7 +415,7 @@ void daBoomerang_sight_c::draw() { cursorAll_pane = m_cursorYellowAllPane; var_f31 = 80.0f; } else if (i == 0 && m_redSight) { - m_cursorRed2Brk->setFrame(field_0xb0[i]); + m_cursorRed2Brk->setFrame(DUSK_IF_ELSE(frame.brk, field_0xb0[i])); cursor0_pane = m_cursorRed0Pane; cursor1_pane = m_cursorRed1Pane; cursor2_pane = m_cursorRed2Pane; @@ -377,7 +423,7 @@ void daBoomerang_sight_c::draw() { cursorAll_pane = m_cursorRedAllPane; var_f31 = 35.0f; } else { - m_cursorOrange2Brk->setFrame(field_0xb0[i]); + m_cursorOrange2Brk->setFrame(DUSK_IF_ELSE(frame.brk, field_0xb0[i])); cursor0_pane = m_cursorOrange0Pane; cursor1_pane = m_cursorOrange1Pane; cursor2_pane = m_cursorOrange2Pane; @@ -389,15 +435,15 @@ void daBoomerang_sight_c::draw() { screen->animation(); cursorAll_pane->scale(0.6f, 0.6f); cursorAll_pane->translate(m_proj_posX[i], m_proj_posY[i]); - field_0x98[i] = field_0x98[i]; + IF_NOT_DUSK(field_0x98[i] = field_0x98[i]); - if (!(field_0x98[i] < 15.0f)) { - if (field_0x98[i] < 21.0f) { - var_f30 = var_f31 * (field_0x98[i] - 15.0f) * 0.16666667f; + if (!(DUSK_IF_ELSE(frame.bck, field_0x98[i]) < 15.0f)) { + if (DUSK_IF_ELSE(frame.bck, field_0x98[i]) < 21.0f) { + var_f30 = var_f31 * (DUSK_IF_ELSE(frame.bck, field_0x98[i]) - 15.0f) * 0.16666667f; } else if (i == 5) { - var_f30 = var_f31 * (*alpha_p * 0.00390625f + 0.5f); + var_f30 = var_f31 * (DUSK_IF_ELSE(frame.alpha, *alpha_p) * 0.00390625f + 0.5f); } else { - var_f30 = var_f31 * (*alpha_p * 0.0019607844f + 0.5f); + var_f30 = var_f31 * (DUSK_IF_ELSE(frame.alpha, *alpha_p) * 0.0019607844f + 0.5f); } cursor0_pane->translate(0.0f, -var_f30); @@ -406,6 +452,10 @@ void daBoomerang_sight_c::draw() { } screen->draw(0.0f, 0.0f, ctx); +#if TARGET_PC + } else { + dusk::interp::get(this).slots[i].reset(); +#endif } } } diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index e10f7e490c..69add079f4 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -15,6 +15,10 @@ #include "d/actor/d_a_midna.h" #include "d/actor/d_a_spinner.h" +#if TARGET_PC +#include "dusk/interp/samples.h" +#endif + bool daPy_frameCtrl_c::checkAnmEnd() { if (getEndFlg() != 0 && getNowSetFlg() == 0) { return true; @@ -429,11 +433,16 @@ JKRHeap* daPy_anmHeap_c::setAnimeHeap() { #include "assets/l_sightDL__d_a_player.h" #endif +#if TARGET_PC +daPy_sightPacket_c::~daPy_sightPacket_c() { + dusk::interp::erase_owned_samples(this); +} +#endif + void daPy_sightPacket_c::draw() { ZoneScoped; -#if !TARGET_PC - TGXTexObj texObj; -#endif + IF_DUSK(setSight(false);) + IF_NOT_DUSK(TGXTexObj texObj); j3dSys.reinitGX(); GXSetNumIndStages(0); @@ -499,13 +508,21 @@ void daPy_sightPacket_c::draw() { J3DShape::resetVcdVatCache(); } -void daPy_sightPacket_c::setSight() { +void daPy_sightPacket_c::setSight(IF_DUSK(bool registerPacket)) { Vec proj; mDoLib_project(&mPos, &proj); +#if TARGET_PC + auto& positions = dusk::interp::get>(this); + const cXyz screen(proj); + positions.capture(&screen, 1); + proj = positions.read(0, screen); +#endif mDoMtx_stack_c::transS(proj.x, proj.y, proj.z); mDoMtx_stack_c::scaleM(32.0f, 32.0f, 32.0f); mDoMtx_copy(mDoMtx_stack_c::get(), mProjMtx); + IF_DUSK_BLOCK(registerPacket) dComIfGd_set2DXlu(this); + IF_DUSK_BLOCK_END } void daPy_sightPacket_c::setSightImage(ResTIMG* i_img) { diff --git a/src/d/d_map_path_dmap.cpp b/src/d/d_map_path_dmap.cpp index f9d2f4d5f9..020f818cf1 100644 --- a/src/d/d_map_path_dmap.cpp +++ b/src/d/d_map_path_dmap.cpp @@ -12,6 +12,36 @@ #include "d/d_meter_HIO.h" #include "float.h" +#if TARGET_PC +#include "dusk/interp/samples.h" + +namespace { +struct MapPlayer { + dusk::interp::Samples position; + dusk::interp::Samples angle; + fpc_ProcID id = fpcM_ERROR_PROCESS_ID_e; + int room = -1; +}; + +MapPlayer& map_player() { + static MapPlayer samples; + auto* player = daPy_getPlayerActorClass(); + const int room = dComIfGp_roomControl_getStayNo(); + const fpc_ProcID id = player != nullptr ? fopAcM_GetID(player) : fpcM_ERROR_PROCESS_ID_e; + if (samples.id != id || samples.room != room) { + samples = {}; + samples.id = id; + samples.room = room; + } + if (player != nullptr) { + samples.position.capture(&player->current.pos, 1); + samples.angle.capture(&player->shape_angle, 1); + } + return samples; +} +} // namespace +#endif + bool dMapInfo_n::chkGetCompass() { return dComIfGs_isDungeonItemCompass() ? true : false; } @@ -60,7 +90,7 @@ Vec dMapInfo_n::getMapPlayerPos() { BE(Vec) pos; fopAc_ac_c* player = daPy_getPlayerActorClass(); if (player != NULL) { - pos = player->current.pos; + pos = DUSK_IF_ELSE(map_player().position.read(0, player->current.pos, 2000.0f), player->current.pos); } else { pos.x = 0.0f; pos.y = 0.0f; @@ -82,7 +112,7 @@ s16 dMapInfo_n::getMapPlayerAngleY() { daPy_py_c* player = daPy_getPlayerActorClass(); if (player != NULL) { - angle = player->shape_angle.y; + angle = DUSK_IF_ELSE(map_player().angle.read(0, player->shape_angle).y, player->shape_angle.y); } dStage_FileList2_dt_c* fileList2_p = dStage_roomControl_c::getFileList2(stayNo); diff --git a/src/d/d_menu_ring.cpp b/src/d/d_menu_ring.cpp index f1161af804..4b5e0382f6 100644 --- a/src/d/d_menu_ring.cpp +++ b/src/d/d_menu_ring.cpp @@ -101,7 +101,7 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i mCenterPosX = 0.0f; mCenterPosY = -FB_HEIGHT_BASE; } - if (mRingOrigin == 3) { + IF_DUSK(else) if (mRingOrigin == 3) { mCenterPosX = FB_WIDTH_BASE; mCenterPosY = 0.0f; } else if (mRingOrigin == 1) { diff --git a/src/d/d_select_cursor.cpp b/src/d/d_select_cursor.cpp index 5f1b112b1a..b651c617cd 100644 --- a/src/d/d_select_cursor.cpp +++ b/src/d/d_select_cursor.cpp @@ -8,7 +8,17 @@ #include #if TARGET_PC +#include "dusk/interp/samples.h" #include "dusk/interp/user_interface.h" + +#include "m_Do/m_Do_lib.h" + +namespace { +struct CursorSamples { + dusk::interp::Samples positions; + dusk::interp::Samples alpha; +}; +} // namespace #endif dSelect_cursorHIO_c::dSelect_cursorHIO_c() { @@ -205,6 +215,7 @@ dSelect_cursor_c::dSelect_cursor_c(u8 param_0, f32 param_1, JKRArchive* param_2) dSelect_cursor_c::~dSelect_cursor_c() { + IF_DUSK(dusk::interp::erase_owned_samples(this);) JKR_DELETE(mpScreen); mpScreen = NULL; if (mpPaneMgr) { @@ -250,6 +261,15 @@ dSelect_cursor_c::~dSelect_cursor_c() { } void dSelect_cursor_c::draw() { +#if TARGET_PC + const f32 alpha = mpPaneMgr->getAlphaRate(); + const bool visible = mpPaneMgr->isVisible(); + const f32 presentedAlpha = dusk::interp::get(this).alpha.read(0, alpha); + mpPaneMgr->setAlphaRate(presentedAlpha); + if (alpha == 0.0f && presentedAlpha > 0.0f) { + mpPaneMgr->show(); + } +#endif mpPaneMgr->getAlphaRate(); update(); J2DGrafContext* gphCtx = dComIfGp_getCurrentGrafPort(); @@ -258,6 +278,12 @@ void dSelect_cursor_c::draw() { if (mpSelectIcon) { mpSelectIcon->drawSelf(); // inline here, but not sure how to properly define it } +#if TARGET_PC + mpPaneMgr->setAlphaRate(alpha); + if (!visible) { + mpPaneMgr->hide(); + } +#endif } void dSelect_cursor_c::update() { @@ -265,14 +291,31 @@ void dSelect_cursor_c::update() { if (field_0xb6 == 3) { fVar1 = 0.5f; } -#ifdef TARGET_PC + +#if TARGET_PC if (mpPane) { Vec pos = mpPaneMgr->getGlobalVtxCenter(mpPane, false, 0); mPositionX = pos.x; mPositionY = pos.y; } + + auto& samples = dusk::interp::get(this); + cXyz position(mPositionX, mPositionY, 0.0f); + if (mpPane == nullptr) { + if (mInterpolatePosition) { + position = samples.positions.read(0, position); + } + if (mWorldCursor) { + cXyz world = samples.positions.read(1, mWorldPosition); + Vec projected; + mDoLib_project(&world, &projected); + position.x += projected.x; + position.y += projected.y; + } + } #endif - mpPaneMgr->translate(mPositionX, mPositionY); + + mpPaneMgr->translate(DUSK_IF_ELSE(position.x, mPositionX), DUSK_IF_ELSE(position.y, mPositionY)); if (mpCursorHIO->mDebugON) { mParam1 = mpCursorHIO->mXAxisExpansion; mParam2 = mpCursorHIO->mYAxisExpansion; @@ -455,6 +498,7 @@ void dSelect_cursor_c::setAlphaRate(f32 i_alphaRate) { } mpPaneMgr->setAlphaRate(i_alphaRate); + IF_DUSK(dusk::interp::get(this).alpha.capture(&i_alphaRate, 1)); } int dSelect_cursor_c::addAlpha() { @@ -469,7 +513,7 @@ int dSelect_cursor_c::addAlpha() { } else { alpha_timer++; mpPaneMgr->alphaAnimeStart(alpha_timer); - mpPaneMgr->setAlphaRate(alpha_timer/5.0f); + DUSK_IF_ELSE(setAlphaRate, mpPaneMgr->setAlphaRate)(alpha_timer/5.0f); } return 0; @@ -486,7 +530,7 @@ int dSelect_cursor_c::decAlpha() { } else { alpha_timer--; mpPaneMgr->alphaAnimeStart(alpha_timer); - mpPaneMgr->setAlphaRate(alpha_timer/5.0f); + DUSK_IF_ELSE(setAlphaRate, mpPaneMgr->setAlphaRate)(alpha_timer/5.0f); } return 0; @@ -581,7 +625,32 @@ void dSelect_cursor_c::moveCenter(J2DPane* i_pane, f32 i_x, f32 i_y) { i_pane->translate(i_x,i_y); } -#ifdef TARGET_PC +#if TARGET_PC +void dSelect_cursor_c::setInterp(bool enabled) { + if (mInterpolatePosition != enabled) { + mInterpolatePosition = enabled; + dusk::interp::get(this).positions.reset(); + } +} + +void dSelect_cursor_c::setPos(f32 x, f32 y, const cXyz* world) { + auto& positions = dusk::interp::get(this).positions; + if (mWorldCursor != (world != nullptr)) { + positions.reset(); + } + mWorldCursor = world != nullptr; + mPositionX = x; + mPositionY = y; + if (world) { + mpPane = nullptr; + mWorldPosition = *world; + } + if (mInterpolatePosition) { + const cXyz values[] = {cXyz(x, y, 0.0f), mWorldPosition}; + positions.capture(values, mWorldCursor ? 2 : 1); + } +} + void dSelect_cursor_c::refreshAspectScale(f32 param_0) { mParam1 = mBaseParam1 * param_0; } diff --git a/src/d/d_shop_system.cpp b/src/d/d_shop_system.cpp index 1ff45e19a7..2b26ca2a4a 100644 --- a/src/d/d_shop_system.cpp +++ b/src/d/d_shop_system.cpp @@ -19,6 +19,9 @@ #include "d/actor/d_a_tag_shop_item.h" #include +#if TARGET_PC +#include "dusk/interp/lerp.h" +#endif static daTag_ShopItem_c* dShopSystem_itemActor[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -876,10 +879,14 @@ int dShopSystem_c::seq_start(fopAc_ac_c* actor, dMsgFlow_c* i_flow) { } cXyz pos3d; - cXyz pos2d; + cXyz pos2d IF_DUSK((0.0f, 0.0f, 0.0f)); pos3d.set(mItemCtrl.getCurrentPos(0)); +#if TARGET_PC + mpDrawCursor->setWorldPos(pos3d, 0.0f, g_cursorHIO.mShopCursorOffsetY); +#else pos3Dto2D(&pos3d, &pos2d); mpDrawCursor->setPos(pos2d.x, pos2d.y + g_cursorHIO.mShopCursorOffsetY); +#endif if (chkSpMode() && !beforeStartSeqAction(i_flow, field_0xf5c)) { return 0; @@ -1093,9 +1100,9 @@ int dShopSystem_c::seq_select(fopAc_ac_c* actor, dMsgFlow_c* i_flow) { if (old_cursor != 0) { cXyz pos3d; - cXyz pos2d; + cXyz pos2d IF_DUSK((0.0f, 0.0f, 0.0f)); pos3d.set(mItemCtrl.getCurrentPos(old_cursor - 1)); - pos3Dto2D(&pos3d, &pos2d); + IF_NOT_DUSK(pos3Dto2D(&pos3d, &pos2d)); if (old_cursor == 7) { pos2d.x += g_cursorHIO.mMagicArmorCursorOffsetX; @@ -1104,7 +1111,11 @@ int dShopSystem_c::seq_select(fopAc_ac_c* actor, dMsgFlow_c* i_flow) { pos2d.y += g_cursorHIO.mShopCursorOffsetY; } +#if TARGET_PC + mpDrawCursor->setWorldPos(pos3d, pos2d.x, pos2d.y); +#else mpDrawCursor->setPos(pos2d.x, pos2d.y); +#endif } return 0; @@ -1115,11 +1126,11 @@ int dShopSystem_c::seq_moving(fopAc_ac_c*, dMsgFlow_c*) { cXyz last_pos3d; cXyz pos3d; - cXyz last_pos2d; - cXyz pos2d; + cXyz last_pos2d IF_DUSK((0.0f, 0.0f, 0.0f)); + cXyz pos2d IF_DUSK((0.0f, 0.0f, 0.0f)); pos3d.set(mItemCtrl.getCurrentPos(mCursorPos - 1)); - pos3Dto2D(&pos3d, &pos2d); + IF_NOT_DUSK(pos3Dto2D(&pos3d, &pos2d)); if (mCursorPos == 7) { pos2d.x += g_cursorHIO.mMagicArmorCursorOffsetX; @@ -1130,7 +1141,7 @@ int dShopSystem_c::seq_moving(fopAc_ac_c*, dMsgFlow_c*) { if (mLastCursorPos != 0) { last_pos3d.set(mItemCtrl.getCurrentPos(mLastCursorPos - 1)); - pos3Dto2D(&last_pos3d, &last_pos2d); + IF_NOT_DUSK(pos3Dto2D(&last_pos3d, &last_pos2d)); if (mLastCursorPos == 7) { last_pos2d.x += g_cursorHIO.mMagicArmorCursorOffsetX; @@ -1140,11 +1151,22 @@ int dShopSystem_c::seq_moving(fopAc_ac_c*, dMsgFlow_c*) { } f32 tmp = (f32)(field_0xf68 * field_0xf68) / 9.0f; +#if TARGET_PC + cXyz position; + dusk::interp::lerp(position, last_pos3d, pos3d, tmp); + dusk::interp::lerp(pos2d, last_pos2d, pos2d, tmp); + mpDrawCursor->setWorldPos(position, pos2d.x, pos2d.y); +#else mpDrawCursor->setPos(last_pos2d.x + tmp * (pos2d.x - last_pos2d.x), last_pos2d.y + tmp * (pos2d.y - last_pos2d.y)); +#endif } else { +#if TARGET_PC + mpDrawCursor->setWorldPos(pos3d, pos2d.x, pos2d.y); +#else mpDrawCursor->setPos(pos2d.x, pos2d.y); +#endif } if (field_0xf68 >= 3) { diff --git a/src/dusk/interp/frame_interpolation.cpp b/src/dusk/interp/frame_interpolation.cpp index e6aacd436a..ac27d75ce5 100644 --- a/src/dusk/interp/frame_interpolation.cpp +++ b/src/dusk/interp/frame_interpolation.cpp @@ -40,6 +40,7 @@ Recording s_previousRecording; absl::flat_hash_map g_replacements; int s_presentationDepth = 0; +bool s_cameraPresentationActive = false; const Mtx* resolve_replacement(const Mtx* source, Mtx* scratch) { if (!s_replacementsActive || source == nullptr || dusk::interp::presentation_sync_active()) { @@ -111,6 +112,7 @@ void clear_interpolation_history() { clear_callbacks(); dusk::interp::camera_invalidate_snapshots(); s_presentationDepth = 0; + s_cameraPresentationActive = false; } } // namespace @@ -248,12 +250,11 @@ void begin_presentation(float step) { s_presentationDepth++; return; } - if (!camera_apply_presentation()) { - return; - } - s_presentationDepth = 1; - callbacks_run(); + s_cameraPresentationActive = camera_apply_presentation(); + if (s_cameraPresentationActive) { + callbacks_run(); + } } void end_presentation() { @@ -265,7 +266,10 @@ void end_presentation() { return; } - camera_restore_presentation(); + if (s_cameraPresentationActive) { + camera_restore_presentation(); + s_cameraPresentationActive = false; + } } bool is_presentation_active() { diff --git a/src/dusk/interp/sight.h b/src/dusk/interp/sight.h new file mode 100644 index 0000000000..c56c186cae --- /dev/null +++ b/src/dusk/interp/sight.h @@ -0,0 +1,23 @@ +#pragma once + +#include "dusk/interp/samples.h" + +namespace dusk::interp { + +struct SightAnimation { + f32 bck, brk, alpha, brkEnd; +}; + +inline void lerp(SightAnimation& out, const SightAnimation& a, const SightAnimation& b, f32 step) { + out.bck = lerp(a.bck, b.bck < a.bck ? b.bck + 29.0f : b.bck, step); + if (out.bck >= 50.0f) { + out.bck -= 29.0f; + } + out.brk = lerp(a.brk, b.brk < a.brk ? b.brk + b.brkEnd : b.brk, step); + if (out.brk >= b.brkEnd) { + out.brk -= b.brkEnd; + } + out.alpha = lerp(a.alpha, b.alpha, step); +} + +} // namespace dusk::interp