Frame interp: Fix Epona's reins

This commit is contained in:
Irastris
2026-04-11 21:45:54 -04:00
parent 62df2c0460
commit 0e2bd104b1
9 changed files with 192 additions and 5 deletions
+3
View File
@@ -196,6 +196,9 @@ public:
void copyReinPos();
void setReinPosHandSubstance(int);
void setReinPosNormalSubstance();
#if TARGET_PC
void lerpControlPoints(f32 alpha);
#endif
void bgCheck();
bool checkSpecialWallHitSubstance(cXyz const&) const;
void setServiceWaitTimer();
+4
View File
@@ -435,6 +435,10 @@ public:
m3DLineMatSortPacket[param_1->getMaterialID()].setMatDark(param_1);
}
#if TARGET_PC
void refresh3DlineMats(const cXyz& eye);
#endif
void peekZdata() { mPeekZ.peekData(); }
void entryZSortListZxlu(J3DPacket* i_packet, cXyz& param_1) {
entryZSortXluDrawList(mDrawBuffers[DB_LIST_Z_XLU], i_packet, param_1);
+5
View File
@@ -6,6 +6,8 @@
#include <stddef.h>
#include <stdint.h>
struct cXyz;
#ifdef __cplusplus
namespace dusk {
namespace frame_interp {
@@ -15,6 +17,7 @@ void ensure_initialized();
void begin_record();
void end_record();
void interpolate(float step);
float get_interpolation_step();
void notify_sim_tick_complete();
uint32_t begin_presentation_ui_pass();
uint32_t get_presentation_ui_advance_ticks();
@@ -27,6 +30,8 @@ void record_final_mtx_raw(const Mtx* dest, const Mtx src);
bool lookup_replacement(const void* source, Mtx out);
bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out);
void camera_eye_from_view_mtx(MtxP view_mtx, cXyz* o_eye);
} // namespace frame_interp
} // namespace dusk
#endif
+19
View File
@@ -541,6 +541,9 @@ public:
virtual int getMaterialID() = 0;
virtual void setMaterial() = 0;
virtual void draw() = 0;
#if TARGET_PC
virtual void refreshGeometryForPresentationEye(const cXyz& eye) {}
#endif
/* 0x4 */ mDoExt_3DlineMat_c* field_0x4;
};
@@ -582,11 +585,19 @@ class dKy_tevstr_c;
class mDoExt_3DlineMat1_c : public mDoExt_3DlineMat_c {
public:
int init(u16, u16, ResTIMG*, int);
#if TARGET_PC
void update(int, GXColor&, dKy_tevstr_c*, const cXyz* presentationEye = nullptr);
void update(int, f32, GXColor&, u16, dKy_tevstr_c*, const cXyz* presentationEye = nullptr);
#else
void update(int, GXColor&, dKy_tevstr_c*);
void update(int, f32, GXColor&, u16, dKy_tevstr_c*);
#endif
int getMaterialID() { return 1; }
void setMaterial();
void draw();
#if TARGET_PC
void refreshGeometryForPresentationEye(const cXyz& eye) override;
#endif
cXyz* getPos(int i_idx) { return mpLines[i_idx].field_0x0; }
f32* getSize(int i_idx) { return mpLines[i_idx].field_0x4; }
@@ -600,6 +611,11 @@ private:
/* 0x34 */ u16 field_0x34;
/* 0x36 */ u8 mIsDrawn;
/* 0x38 */ mDoExt_3Dline_c* mpLines;
#if TARGET_PC
u8 mInterpLineKind;
f32 mInterpLineF;
u16 mInterpLineU16;
#endif
};
class mDoExt_3DlineMat2_c : public mDoExt_3DlineMat1_c {
@@ -616,6 +632,9 @@ public:
void setMatDark(mDoExt_3DlineMat_c* i_mat) { setMat(i_mat); }
void setMat(mDoExt_3DlineMat_c*);
#if TARGET_PC
mDoExt_3DlineMat_c* getFirstMat() const { return mp3DlineMat; }
#endif
virtual void draw();
virtual ~mDoExt_3DlineMatSortPacket() {}
+53
View File
@@ -20,6 +20,21 @@
#include <cmath>
#include <cstring>
#if TARGET_PC
#include "dusk/dusk.h"
namespace {
// FRAME INTERP NOTE: Sim tick control point snapshots for interpolation
constexpr int kHorseReinSimMax = 75;
cXyz s_horseReinSimPrev[kHorseReinSimMax];
cXyz s_horseReinSimCurr[kHorseReinSimMax];
int s_horseReinSimNumPrev;
int s_horseReinSimNumCurr;
bool s_horseReinSimPrevValid;
bool s_horseReinSimCurrValid;
} // namespace
#endif
#define ANM_HS_BACK_WALK 6
#define ANM_HS_WALK_START 7
#define ANM_HS_EXCITEMENT 8
@@ -3016,6 +3031,20 @@ void daHorse_c::copyReinPos() {
for (i = rein->field_0x8[0] - 1; i >= 0; i--, pos_p++) {
*pos_p = rein->field_0x0[0][i];
}
#if TARGET_PC
if (field_0x1204 > 0) {
if (s_horseReinSimCurrValid && s_horseReinSimNumCurr > 0) {
memcpy(s_horseReinSimPrev, s_horseReinSimCurr, s_horseReinSimNumCurr * sizeof(cXyz));
s_horseReinSimNumPrev = s_horseReinSimNumCurr;
s_horseReinSimPrevValid = true;
}
memcpy(s_horseReinSimCurr, m_reinLine.getPos(0), field_0x1204 * sizeof(cXyz));
s_horseReinSimNumCurr = field_0x1204;
s_horseReinSimCurrValid = true;
} else {
s_horseReinSimCurrValid = false;
}
#endif
}
void daHorse_c::setReinPosHandSubstance(int param_0) {
@@ -3127,6 +3156,30 @@ void daHorse_c::setReinPosNormalSubstance() {
copyReinPos();
}
#if TARGET_PC
void daHorse_c::lerpControlPoints(f32 alpha) {
// FRAME INTERP NOTE: Currently only lerping points for Epona's reins. Need a more global solution.
if (!dusk::getSettings().game.enableFrameInterpolation || !s_horseReinSimPrevValid || !s_horseReinSimCurrValid) {
return;
}
const int nCurr = s_horseReinSimNumCurr;
const int nPrev = s_horseReinSimNumPrev;
if (nCurr <= 0) {
return;
}
int n = nPrev < nCurr ? nPrev : nCurr;
if (n <= 0 || n > kHorseReinSimMax) {
return;
}
cXyz* dst = m_reinLine.getPos(0);
for (int i = 0; i < n; i++) {
const cXyz& p0 = s_horseReinSimPrev[i];
const cXyz& p1 = s_horseReinSimCurr[i];
dst[i] = p0 + (p1 - p0) * alpha;
}
}
#endif
void daHorse_c::bgCheck() {
if (m_procID != PROC_LARGE_DAMAGE_e) {
static cXyz localCenterPos(0.0f, 100.0f, 0.0f);
+10
View File
@@ -2017,3 +2017,13 @@ void dDlst_list_c::calcWipe() {
dComIfGd_set2DXlu(&mWipeDlst);
}
}
#if TARGET_PC
void dDlst_list_c::refresh3DlineMats(const cXyz& eye) {
for (int i = 0; i < 3; i++) {
for (mDoExt_3DlineMat_c* mat = m3DLineMatSortPacket[i].getFirstMat(); mat != NULL; mat = mat->field_0x4) {
mat->refreshGeometryForPresentationEye(eye);
}
}
}
#endif
+11
View File
@@ -300,6 +300,10 @@ void interpolate(float step) {
interpolate_branch(g_previous_recording.root, g_current_recording.root, g_step);
}
float get_interpolation_step() {
return g_step;
}
void notify_sim_tick_complete() {
ensure_initialized();
g_pending_presentation_ui_ticks++;
@@ -394,5 +398,12 @@ bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out) {
return true;
}
// TODO: Is there already a built-in function for this?
void camera_eye_from_view_mtx(MtxP view_mtx, cXyz* o_eye) {
o_eye->x = -(view_mtx[0][0] * view_mtx[0][3] + view_mtx[1][0] * view_mtx[1][3] + view_mtx[2][0] * view_mtx[2][3]);
o_eye->y = -(view_mtx[0][1] * view_mtx[0][3] + view_mtx[1][1] * view_mtx[1][3] + view_mtx[2][1] * view_mtx[2][3]);
o_eye->z = -(view_mtx[0][2] * view_mtx[0][3] + view_mtx[1][2] * view_mtx[1][3] + view_mtx[2][2] * view_mtx[2][3]);
}
} // namespace frame_interp
} // namespace dusk
+74 -5
View File
@@ -2398,7 +2398,12 @@ void mDoExt_3DlineMat0_c::draw() {
var_r28++;
}
field_0x16 ^= (u8)1;
#if TARGET_PC
if (!dusk::getSettings().game.enableFrameInterpolation)
#endif
{
field_0x16 ^= (u8)1;
}
}
void mDoExt_3DlineMat0_c::update(int param_0, f32 param_1, GXColor& param_2, u16 param_3,
@@ -2648,6 +2653,9 @@ int mDoExt_3DlineMat1_c::init(u16 param_0, u16 param_1, ResTIMG* param_2, int pa
field_0x4 = 0;
mIsDrawn = 0;
#if TARGET_PC
mInterpLineKind = 0;
#endif
GXInitTexObj(&mTextureObject, (void*)((intptr_t)param_2 + param_2->imageOffset), param_2->width,
param_2->height, (GXTexFmt)param_2->format, (GXTexWrapMode)param_2->wrapS,
@@ -2720,11 +2728,19 @@ void mDoExt_3DlineMat1_c::draw() {
lines++;
}
GXSetTexCoordScaleManually(GX_TEXCOORD0, 0, 0, 0);
mIsDrawn ^= (u8)1;
#if TARGET_PC
if (!dusk::getSettings().game.enableFrameInterpolation)
#endif
{
mIsDrawn ^= (u8)1;
}
}
void mDoExt_3DlineMat1_c::update(int param_0, f32 param_1, GXColor& param_2, u16 param_3,
dKy_tevstr_c* param_4) {
#if TARGET_PC
void mDoExt_3DlineMat1_c::update(int param_0, f32 param_1, GXColor& param_2, u16 param_3, dKy_tevstr_c* param_4, const cXyz* presentationEye) {
#else
void mDoExt_3DlineMat1_c::update(int param_0, f32 param_1, GXColor& param_2, u16 param_3, dKy_tevstr_c* param_4) {
#endif
mColor = param_2;
this->mpTevStr = param_4;
if (param_0 < 0) {
@@ -2734,6 +2750,13 @@ void mDoExt_3DlineMat1_c::update(int param_0, f32 param_1, GXColor& param_2, u16
} else {
field_0x34 = param_0;
}
#if TARGET_PC
mInterpLineKind = 1;
mInterpLineF = param_1;
mInterpLineU16 = param_3;
#endif
view_class* sp_3c = dComIfGd_getView();
mDoExt_3Dline_c* sp_38 = mpLines;
f32 local_f27 = param_3 != 0 ? param_1 / param_3 : 0.0f;
@@ -2787,7 +2810,12 @@ void mDoExt_3DlineMat1_c::update(int param_0, f32 param_1, GXColor& param_2, u16
local_f31 += local_f30 * 0.02f * (8.0f / param_1);
}
#if TARGET_PC
const cXyz& lineEye = (presentationEye != nullptr && dusk::getSettings().game.enableFrameInterpolation) ? *presentationEye : sp_3c->lookat.eye;
sp_13c = *local_r27 - lineEye;
#else
sp_13c = *local_r27 - sp_3c->lookat.eye;
#endif
sp_130 = sp_130.outprod(sp_13c);
sp_130.normalizeZP();
@@ -2822,7 +2850,11 @@ void mDoExt_3DlineMat1_c::update(int param_0, f32 param_1, GXColor& param_2, u16
local_f31 += local_f30 * 0.02f * (8.0f / param_1);
}
#if TARGET_PC
sp_13c = local_r27[0] - lineEye;
#else
sp_13c = local_r27[0] - sp_3c->lookat.eye;
#endif
sp_130 = sp_130.outprod(sp_13c);
sp_130.normalizeZP();
@@ -2894,7 +2926,11 @@ void mDoExt_3DlineMat2_c::setMaterial() {
GXLoadNrmMtxImm(cMtx_getIdentity(), 0);
}
void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* param_4) {
#if TARGET_PC
void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* param_4, const cXyz* presentationEye) {
#else
void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* param_4
#endif
mColor = param_2;
this->mpTevStr = param_4;
if (param_0 < 0) {
@@ -2904,6 +2940,11 @@ void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* pa
} else {
field_0x34 = param_0;
}
#if TARGET_PC
mInterpLineKind = 2;
#endif
view_class* stack_3c = dComIfGd_getView();
mDoExt_3Dline_c* sp_38 = mpLines;
f32 local_f30;
@@ -2929,6 +2970,12 @@ void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* pa
for (s32 sp_14 = 0; sp_14 < mNumLines; sp_14++) {
local_r27 = sp_38[0].field_0x0;
size_p = sp_38->field_0x4;
#if TARGET_PC
if (presentationEye != nullptr && dusk::getSettings().game.enableFrameInterpolation && size_p == NULL) {
sp_38 += 1;
continue;
}
#endif
JUT_ASSERT(5875, size_p != NULL);
sp_24 = sp_38->field_0x8[mIsDrawn];
sp_28 = sp_24;
@@ -2942,7 +2989,12 @@ void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* pa
sp_130 = local_r27[1] - local_r27[0];
local_f30 = sp_130.abs();
local_f31 += local_f30 * 0.1f;
#if TARGET_PC
const cXyz& lineEye = (presentationEye != nullptr && dusk::getSettings().game.enableFrameInterpolation) ? *presentationEye : stack_3c->lookat.eye;
sp_13c = local_r27[0] - lineEye;
#else
sp_13c = local_r27[0] - stack_3c->lookat.eye;
#endif
sp_130 = sp_130.outprod(sp_13c);
sp_130.normalizeZP();
local_r30->x = sp_130.x * 64.0f;
@@ -2964,7 +3016,11 @@ void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* pa
sp_130 = local_r27[1] - local_r27[0];
local_f30 = sp_130.abs();
local_f31 += local_f30 * 0.1f;
#if TARGET_PC
sp_13c = local_r27[0] - lineEye;
#else
sp_13c = local_r27[0] - stack_3c->lookat.eye;
#endif
sp_130 = sp_130.outprod(sp_13c);
sp_130.normalizeZP();
local_r30 += 2;
@@ -3008,6 +3064,19 @@ void mDoExt_3DlineMat1_c::update(int param_0, GXColor& param_2, dKy_tevstr_c* pa
}
}
#if TARGET_PC
void mDoExt_3DlineMat1_c::refreshGeometryForPresentationEye(const cXyz& eye) {
if (!dusk::getSettings().game.enableFrameInterpolation) {
return;
}
if (mInterpLineKind == 1) {
update(field_0x34, mInterpLineF, mColor, mInterpLineU16, mpTevStr, &eye);
} else if (mInterpLineKind == 2) {
update(field_0x34, mColor, mpTevStr, &eye);
}
}
#endif
void mDoExt_3DlineMatSortPacket::setMat(mDoExt_3DlineMat_c* i_3DlineMat) {
if (mp3DlineMat == NULL) {
dComIfGd_getListPacket()->entryImm(this, 0);
+13
View File
@@ -51,6 +51,7 @@
#endif
#if TARGET_PC
#include "d/actor/d_a_horse.h"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/dusk.h"
#endif
@@ -1952,6 +1953,18 @@ int mDoGph_Painter() {
GX_DEBUG_GROUP(dComIfGd_drawOpaListDark);
}
#if TARGET_PC
if (dusk::getSettings().game.enableFrameInterpolation) {
cXyz pres_eye;
dusk::frame_interp::camera_eye_from_view_mtx(j3dSys.getViewMtx(), &pres_eye);
// FRAME INTERP NOTE: Currently only recalculating points for Epona's reins. Need a more global solution.
if (daHorse_c* horse = dComIfGp_getHorseActor()) {
horse->lerpControlPoints(dusk::frame_interp::get_interpolation_step());
}
g_dComIfG_gameInfo.drawlist.refresh3DlineMats(pres_eye);
}
#endif
GX_DEBUG_GROUP(dComIfGd_drawOpaListPacket);
#if DEBUG