Merge pull request #438 from TwilitRealm/frame-interp-simplify

Frame interp simplify
This commit is contained in:
TakaRikka
2026-04-19 14:58:38 -07:00
committed by GitHub
30 changed files with 379 additions and 518 deletions
+4
View File
@@ -209,6 +209,10 @@ public:
/* 0x04 */ TGXTexObj* mpTexObj;
/* 0x08 */ Mtx mVolumeMtx;
/* 0x38 */ Mtx mMtx;
#if TARGET_PC
const void* mVolumeMtxKey;
const void* mMtxKey;
#endif
}; // Size: 0x68
struct cBgD_Vtx_t;
+12 -23
View File
@@ -1,5 +1,4 @@
#ifndef DUSK_FRAME_INTERP_H
#define DUSK_FRAME_INTERP_H
#pragma once
#include <dolphin/mtx.h>
#include <stdbool.h>
@@ -7,6 +6,7 @@
#include <stdint.h>
class camera_process_class;
class view_class;
#ifdef __cplusplus
namespace dusk {
@@ -16,7 +16,8 @@ void ensure_initialized();
void begin_record();
void end_record();
void interpolate(float step);
void begin_frame(bool enabled, bool is_sim_frame, float step);
void interpolate();
float get_interpolation_step();
void request_presentation_sync();
@@ -28,35 +29,23 @@ bool is_enabled();
void set_ui_tick_pending(bool value);
bool get_ui_tick_pending();
void open_child(const void* key, int32_t id);
void close_child();
void record_camera(::camera_process_class* cam, int camera_id);
void record_final_mtx_raw(const Mtx* dest, const Mtx src);
void record_final_mtx_raw_tagged(const Mtx* dest, const Mtx src, uint64_t stable_tag);
bool is_sim_frame();
bool lookup_replacement(const void* source, Mtx out);
void record_camera(::camera_process_class* cam, int camera_id);
void interp_view(::view_class* view);
void record_final_mtx(Mtx m, const void *key);
void record_final_mtx(Mtx m);
bool lookup_replacement(const void* key, Mtx out);
bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out);
typedef void (*InterpolationCallBack)(void* pUserWork);
void reset_interpolation_callbacks();
typedef void (*InterpolationCallBack)(bool isSimFrame, void* pUserWork);
// call on a sim tick, will get called during presentation
void add_interpolation_callback(InterpolationCallBack pCallBack, void* pUserWork);
void begin_presentation_camera();
void end_presentation_camera();
struct PresentationCameraScope {
PresentationCameraScope() { begin_presentation_camera(); }
~PresentationCameraScope() { end_presentation_camera(); }
PresentationCameraScope(const PresentationCameraScope&) = delete;
PresentationCameraScope& operator=(const PresentationCameraScope&) = delete;
PresentationCameraScope(PresentationCameraScope&&) = delete;
PresentationCameraScope& operator=(PresentationCameraScope&&) = delete;
};
uint64_t alloc_simple_shadow_pair_base();
} // namespace frame_interp
} // namespace dusk
#endif
#endif
+1 -1
View File
@@ -25,7 +25,7 @@ typedef struct leafdraw_class : base_process_class {
#endif
/* 0xB8 */ leafdraw_method_class* leaf_methods;
/* 0xBC */ s8 unk_0xBC;
/* 0xBD */ u8 unk_0xBD;
/* 0xBD */ u8 draw_interp_frame;
/* 0xBE */ draw_priority_class draw_priority;
} leafdraw_class;
+1
View File
@@ -18,6 +18,7 @@ typedef struct process_node_class {
/* 0x0BC */ layer_class layer;
/* 0x0E8 */ node_list_class layer_nodelist[16];
/* 0x1A8 */ s8 unk_0x1A8;
/* 0x1A9 */ s8 draw_interp_frame;
} process_node_class;
typedef struct node_process_profile_definition {
@@ -80,7 +80,7 @@ public:
virtual ~J3DModel() {}
#if TARGET_PC
static void interp_callback(void* pUserWork);
static void interp_callback(bool isSimFrame, void* pUserWork);
#endif
J3DModelData* getModelData() { return mModelData; }
@@ -109,9 +109,7 @@ public:
void setAnmMtx(int jointNo, Mtx m) {
mMtxBuffer->setAnmMtx(jointNo, m);
#ifdef TARGET_PC
dusk::frame_interp::record_final_mtx_raw(
reinterpret_cast<const Mtx*>(mMtxBuffer->getAnmMtx(jointNo)),
mMtxBuffer->getAnmMtx(jointNo));
dusk::frame_interp::record_final_mtx(mMtxBuffer->getAnmMtx(jointNo));
#endif
}
MtxP getAnmMtx(int jointNo) { return mMtxBuffer->getAnmMtx(jointNo); }
@@ -11,8 +11,10 @@
class JUTFader {
public:
enum EStatus {
UNKSTATUS_M1 = -1,
UNKSTATUS_0 = 0,
None,
Wait,
FadeIn,
FadeOut,
};
JUTFader(int, int, int, int, JUtility::TColor);
@@ -29,12 +31,12 @@ public:
void setColor(JUtility::TColor color) { mColor.set(color); }
/* 0x04 */ s32 mStatus;
/* 0x08 */ u16 field_0x8;
/* 0x0A */ u16 field_0xa;
/* 0x08 */ u16 mDuration;
/* 0x0A */ u16 mTimer;
/* 0x0C */ JUtility::TColor mColor;
/* 0x10 */ JGeometry::TBox2<f32> mBox;
/* 0x20 */ int mEStatus;
/* 0x24 */ u32 field_0x24;
/* 0x20 */ int mStatusTimer;
/* 0x24 */ u32 mNextStatus;
};
#endif /* JUTFADER_H */
+10 -8
View File
@@ -98,10 +98,12 @@ s32 J3DModel::entryModelData(J3DModelData* pModelData, u32 mdlFlags, u32 mtxNum)
}
#if TARGET_PC
void J3DModel::interp_callback(void* pUserWork) {
void J3DModel::interp_callback(bool isSimFrame, void* pUserWork) {
J3DModel* i_this = static_cast<J3DModel*>(pUserWork);
i_this->calcMaterial();
i_this->diff();
if (!isSimFrame) {
i_this->calcMaterial();
i_this->diff();
}
}
#endif
@@ -465,11 +467,11 @@ void J3DModel::calc() {
#ifdef TARGET_PC
for (u16 i = 0; i < mModelData->getJointNum(); ++i) {
dusk::frame_interp::record_final_mtx_raw(reinterpret_cast<const Mtx*>(getAnmMtx(i)), getAnmMtx(i));
dusk::frame_interp::record_final_mtx(getAnmMtx(i));
}
for (u16 i = 0; i < mModelData->getWEvlpMtxNum(); ++i) {
dusk::frame_interp::record_final_mtx_raw(reinterpret_cast<const Mtx*>(getWeightAnmMtx(i)), getWeightAnmMtx(i));
dusk::frame_interp::record_final_mtx(getWeightAnmMtx(i));
}
#endif
}
@@ -509,7 +511,7 @@ void J3DModel::viewCalc() {
J3DCalcViewBaseMtx(j3dSys.getViewMtx(), mBaseScale, mBaseTransformMtx,
(MtxP)&mInternalView);
#ifdef TARGET_PC
dusk::frame_interp::record_final_mtx_raw(&mInternalView, mInternalView);
dusk::frame_interp::record_final_mtx(mInternalView);
#endif
}
} else if (isCpuSkinningOn()) {
@@ -517,7 +519,7 @@ void J3DModel::viewCalc() {
J3DCalcViewBaseMtx(j3dSys.getViewMtx(), mBaseScale, mBaseTransformMtx,
(MtxP)&mInternalView);
#ifdef TARGET_PC
dusk::frame_interp::record_final_mtx_raw(&mInternalView, mInternalView);
dusk::frame_interp::record_final_mtx(mInternalView);
#endif
}
} else if (checkFlag(J3DMdlFlag_SkinPosCpu)) {
@@ -541,7 +543,7 @@ void J3DModel::viewCalc() {
#ifdef TARGET_PC
for (u16 i = 0; i < mModelData->getDrawMtxNum(); ++i) {
dusk::frame_interp::record_final_mtx_raw(&getDrawMtxPtr()[i], getDrawMtxPtr()[i]);
dusk::frame_interp::record_final_mtx(getDrawMtxPtr()[i]);
}
#endif
@@ -265,7 +265,7 @@ void J3DMaterial::diff(u32 diffFlags) {
}
void J3DMaterial::calc(f32 const (*param_0)[4]) {
if (j3dSys.checkFlag(0x40000000)) {
if (j3dSys.checkFlag(J3DSysFlag_PostTexMtx)) {
mTexGenBlock->calcPostTexMtx(param_0);
} else {
mTexGenBlock->calc(param_0);
@@ -276,7 +276,7 @@ void J3DMaterial::calc(f32 const (*param_0)[4]) {
}
void J3DMaterial::calcDiffTexMtx(f32 const (*param_0)[4]) {
if (j3dSys.checkFlag(0x40000000)) {
if (j3dSys.checkFlag(J3DSysFlag_PostTexMtx)) {
mTexGenBlock->calcPostTexMtxWithoutViewMtx(param_0);
} else {
mTexGenBlock->calcWithoutViewMtx(param_0);
@@ -288,7 +288,7 @@ void J3DMaterial::setCurrentMtx() {
}
void J3DMaterial::calcCurrentMtx() {
if (!j3dSys.checkFlag(0x40000000)) {
if (!j3dSys.checkFlag(J3DSysFlag_PostTexMtx)) {
mCurrentMtx.setCurrentTexMtx(
getTexCoord(0)->getTexGenMtx(),
getTexCoord(1)->getTexGenMtx(),
+2 -2
View File
@@ -37,9 +37,9 @@ void loadTexCoordGens(u32 texGenNum, J3DTexCoord* texCoords) {
var_r28 = 61;
J3DGDWriteXFCmdHdr(GX_XF_REG_DUALTEX0, texGenNum);
if (j3dSys.checkFlag(0x40000000)) {
if (j3dSys.checkFlag(J3DSysFlag_PostTexMtx)) {
for (int i = 0; i < texGenNum; i++) {
if (texCoords[i].getTexGenMtx() != 60) {
if (texCoords[i].getTexGenMtx() != GX_IDENTITY) {
var_r28 = i * 3;
} else {
var_r28 = 61;
+1 -1
View File
@@ -219,7 +219,7 @@ void JFWDisplay::endGX() {
if (dusk::frame_interp::get_ui_tick_pending()) {
mFader->advance();
}
if (mFader->getStatus() != 1) {
if (mFader->getStatus() != JUTFader::Wait) {
mFader->draw();
}
#else
+44 -44
View File
@@ -10,51 +10,51 @@
JUTFader::JUTFader(int x, int y, int width, int height, JUtility::TColor pColor)
: mColor(pColor), mBox(x, y, x + width, y + height) {
mStatus = 0;
field_0x8 = 0;
field_0xa = 0;
field_0x24 = 0;
mEStatus = UNKSTATUS_M1;
mStatus = None;
mDuration = 0;
mTimer = 0;
mNextStatus = 0;
mStatusTimer = -1;
}
void JUTFader::advance() {
if (0 <= mEStatus && mEStatus-- == 0) {
mStatus = field_0x24;
if (0 <= mStatusTimer && mStatusTimer-- == 0) {
mStatus = mNextStatus;
}
if (mStatus == 1) {
if (mStatus == Wait) {
return;
}
switch (mStatus) {
case 0:
case None:
mColor.a = 0xFF;
break;
case 2:
case FadeIn:
#if AVOID_UB
if (field_0x8 == 0) {
mStatus = 1;
if (mDuration == 0) {
mStatus = Wait;
break;
}
#endif
mColor.a = 0xFF - ((++field_0xa * 0xFF) / field_0x8);
mColor.a = 0xFF - ((++mTimer * 0xFF) / mDuration);
if (field_0xa >= field_0x8) {
mStatus = 1;
if (mTimer >= mDuration) {
mStatus = Wait;
}
break;
case 3:
case FadeOut:
#if AVOID_UB
if (field_0x8 == 0) {
mStatus = 0;
if (mDuration == 0) {
mStatus = None;
break;
}
#endif
mColor.a = ((++field_0xa * 0xFF) / field_0x8);
mColor.a = ((++mTimer * 0xFF) / mDuration);
if (field_0xa >= field_0x8) {
mStatus = 0;
if (mTimer >= mDuration) {
mStatus = None;
}
break;
@@ -77,53 +77,53 @@ void JUTFader::draw() {
}
}
bool JUTFader::startFadeIn(int param_0) {
bool JUTFader::startFadeIn(int duration) {
bool statusCheck = mStatus == 0;
if (statusCheck) {
mStatus = 2;
field_0xa = 0;
field_0x8 = param_0;
mStatus = FadeIn;
mTimer = 0;
mDuration = duration;
}
return statusCheck;
}
bool JUTFader::startFadeOut(int param_0) {
bool JUTFader::startFadeOut(int duration) {
bool statusCheck = mStatus == 1;
if (statusCheck) {
mStatus = 3;
field_0xa = 0;
field_0x8 = param_0;
mStatus = FadeOut;
mTimer = 0;
mDuration = duration;
}
return statusCheck;
}
void JUTFader::setStatus(JUTFader::EStatus i_status, int param_1) {
void JUTFader::setStatus(JUTFader::EStatus i_status, int timer) {
switch (i_status) {
case 0:
if (param_1 != 0) {
field_0x24 = 0;
mEStatus = param_1;
case None:
if (timer != 0) {
mNextStatus = None;
mStatusTimer = timer;
break;
}
mStatus = 0;
field_0x24 = 0;
mEStatus = 0;
mStatus = None;
mNextStatus = None;
mStatusTimer = 0;
break;
case 1:
if (param_1 != 0) {
field_0x24 = 1;
mEStatus = param_1;
case Wait:
if (timer != 0) {
mNextStatus = Wait;
mStatusTimer = timer;
break;
}
mStatus = 1;
field_0x24 = 1;
mEStatus = 0;
mStatus = Wait;
mNextStatus = Wait;
mStatusTimer = 0;
break;
}
}
+5
View File
@@ -623,6 +623,11 @@ int daBg_c::create() {
dComIfGp_roomControl_onStatusFlag(roomNo, 0x10);
OS_REPORT("<BG> room%d\n", roomNo);
#if TARGET_PC
draw_interp_frame = true;
#endif
return cPhs_COMPLEATE_e;
}
+1 -1
View File
@@ -1056,7 +1056,7 @@ void daMidna_c::setBodyPartMatrix() {
#ifdef TARGET_PC
// FRAME INTERP NOTE: Record weight envelopes for Midna here, as they are otherwise missed causing distortion
for (u16 i = 0; i < mpModel->getModelData()->getWEvlpMtxNum(); i++) {
dusk::frame_interp::record_final_mtx_raw(reinterpret_cast<const Mtx*>(mpModel->getWeightAnmMtx(i)), mpModel->getWeightAnmMtx(i));
dusk::frame_interp::record_final_mtx(mpModel->getWeightAnmMtx(i));
}
#endif
}
+9 -1
View File
@@ -13,6 +13,9 @@
#include <gf/GFGeometry.h>
#include <gf/GFLight.h>
#include "m_Do/m_Do_lib.h"
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
#ifndef __MWERKS__
#include "dusk/math.h"
@@ -441,7 +444,12 @@ void dMirror_packet_c::draw() {
}
mDoLib_clipper::resetFar();
reset();
#if TARGET_PC
if (!dusk::frame_interp::is_sim_frame())
#endif
{
reset();
}
}
daMirror_c::daMirror_c() {
+1 -3
View File
@@ -981,9 +981,7 @@ int daObjStone_c::draw() {
if (!model) {
f32 shadow_size = l_shadow_size[mStoneType];
TGXTexObj* pTex = dDlst_shadowControl_c::getSimpleTex();
cXyz pos = current.pos;
dComIfGd_setSimpleShadow(&pos, mChkObj.GetGroundH(), shadow_size, mChkObj.m_gnd, 0,
dComIfGd_setSimpleShadow(&current.pos, mChkObj.GetGroundH(), shadow_size, mChkObj.m_gnd, 0,
1.0f, pTex);
}
return 1;
+5 -4
View File
@@ -700,13 +700,13 @@ void dFlower_packet_c::draw() {
#ifdef TARGET_PC
Mtx flower_mtx;
if (dusk::frame_interp::lookup_replacement(reinterpret_cast<const void*>(&sp44->m_modelMtx), flower_mtx)) {
GXLoadPosMtxImm(flower_mtx, 0);
} else {
} else
#endif
{
GXLoadPosMtxImm(sp44->m_modelMtx, 0);
#ifdef TARGET_PC
}
#endif
GXLoadNrmMtxImm(j3dSys.getViewMtx(), 0);
#if TARGET_PC
@@ -855,6 +855,7 @@ void dFlower_packet_c::draw() {
#ifdef TARGET_PC
Mtx flower_mtx;
if (dusk::frame_interp::lookup_replacement(reinterpret_cast<const void*>(&sp34->m_modelMtx), flower_mtx)) {
cMtx_concat(j3dSys.getViewMtx(), flower_mtx, flower_mtx);
GXLoadPosMtxImm(flower_mtx, 0);
} else {
#endif
@@ -994,7 +995,7 @@ void dFlower_packet_c::update() {
mDoMtx_stack_c::scaleM(temp_f31, temp_f31, temp_f31);
cMtx_concat(j3dSys.getViewMtx(), temp_r28, data_p->m_modelMtx);
#ifdef TARGET_PC
dusk::frame_interp::record_final_mtx_raw(reinterpret_cast<const Mtx*>(&data_p->m_modelMtx), data_p->m_modelMtx);
dusk::frame_interp::record_final_mtx(mDoMtx_stack_c::get(), data_p->m_modelMtx);
#endif
}
}
+4 -4
View File
@@ -756,13 +756,13 @@ void dGrass_packet_c::draw() {
#ifdef TARGET_PC
Mtx grass_mtx;
if (dusk::frame_interp::lookup_replacement(reinterpret_cast<const void*>(&var_r29->m_modelMtx), grass_mtx)) {
cMtx_concat(j3dSys.getViewMtx(), grass_mtx, grass_mtx);
GXLoadPosMtxImm(grass_mtx, 0);
} else {
} else
#endif
{
GXLoadPosMtxImm(var_r29->m_modelMtx, 0);
#ifdef TARGET_PC
}
#endif
GXLoadNrmMtxImm(j3dSys.getViewMtx(), 0);
if (var_r29->field_0x05 <= 3 || var_r29->field_0x05 >= 10) {
if (var_r29->field_0x02 < -1) {
@@ -1018,7 +1018,7 @@ void dGrass_packet_c::update() {
cMtx_concat(j3dSys.getViewMtx(), mDoMtx_stack_c::get(), data_p->m_modelMtx);
}
#ifdef TARGET_PC
dusk::frame_interp::record_final_mtx_raw(reinterpret_cast<const Mtx*>(&data_p->m_modelMtx), data_p->m_modelMtx);
dusk::frame_interp::record_final_mtx(mDoMtx_stack_c::get(), data_p->m_modelMtx);
#endif
}
}
+9 -3
View File
@@ -11018,6 +11018,15 @@ static int camera_execute(camera_process_class* i_this) {
i_this->mCamera.CalcTrimSize();
store(i_this);
#ifdef TARGET_PC
// record new camera for our sim frame
dusk::frame_interp::record_camera(i_this, get_camera_id(i_this));
// interpolate the view now so that this sim frame's view matrix matches what
// we'll be rendering with later
dusk::frame_interp::interp_view(&i_this->view);
#endif
view_setup(i_this);
return 1;
}
@@ -11086,9 +11095,6 @@ static int camera_draw(camera_process_class* i_this) {
C_MTXPerspective(process->view.projMtx, process->view.fovy, process->view.aspect, process->view.near_, process->view.far_);
mDoMtx_lookAt(process->view.viewMtx, &process->view.lookat.eye, &process->view.lookat.center,
&process->view.lookat.up, process->view.bank);
#ifdef TARGET_PC
dusk::frame_interp::record_camera(process, camera_id);
#endif
#if WIDESCREEN_SUPPORT
mDoGph_gInf_c::setWideZoomProjection(process->view.projMtx);
+23 -32
View File
@@ -1096,16 +1096,7 @@ void dDlst_shadowReal_c::draw() {
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetCurrentMtx(GX_PNMTX0);
#ifdef TARGET_PC
Mtx receiver_proj_mtx;
if (dusk::frame_interp::lookup_replacement(&mReceiverProjMtx, receiver_proj_mtx)) {
GXLoadTexMtxImm(receiver_proj_mtx, GX_TEXMTX0, GX_MTX3x4);
} else {
#endif
GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4);
#ifdef TARGET_PC
}
#endif
GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4);
mShadowRealPoly.draw();
}
@@ -1263,14 +1254,9 @@ u8 dDlst_shadowReal_c::setShadowRealMtx(cXyz* param_0, cXyz* param_1, f32 param_
C_MTXOrtho(mRenderProjMtx, param_2, -param_2, -param_2, param_2, 1.0f, 10000.0f);
C_MTXLightOrtho(mReceiverProjMtx, param_2, -param_2, -param_2, param_2, 0.5f, -0.5f, 0.5f, 0.5f);
cMtx_concat(mReceiverProjMtx, mViewMtx, mReceiverProjMtx);
#ifdef TARGET_PC
dusk::frame_interp::record_final_mtx_raw(&mViewMtx, mViewMtx);
dusk::frame_interp::record_final_mtx_raw(&mReceiverProjMtx, mReceiverProjMtx);
#endif
return r29;
}
u32 dDlst_shadowReal_c::set(u32 i_key, J3DModel* i_model, cXyz* param_2, f32 param_3, f32 param_4,
dKy_tevstr_c* param_5, f32 i_cameraZ, f32 param_7) {
dScnKy_env_light_c* env_light = dKy_getEnvlight();
@@ -1292,6 +1278,7 @@ u32 dDlst_shadowReal_c::set(u32 i_key, J3DModel* i_model, cXyz* param_2, f32 par
}
field_0x1 = setShadowRealMtx(&sp60, param_2, param_3, param_4, param_7, param_5);
if (!field_0x1) {
return 0;
}
@@ -1331,14 +1318,14 @@ void dDlst_shadowSimple_c::draw() {
GXSetVtxDesc(GX_VA_POS, GX_INDEX8);
#ifdef TARGET_PC
Mtx volume_mtx;
if (dusk::frame_interp::lookup_replacement(&mVolumeMtx, volume_mtx)) {
if (dusk::frame_interp::lookup_replacement(mVolumeMtxKey, volume_mtx)) {
cMtx_concat(j3dSys.getViewMtx(), volume_mtx, volume_mtx);
GXLoadPosMtxImm(volume_mtx, GX_PNMTX0);
} else {
} else
#endif
{
GXLoadPosMtxImm(mVolumeMtx, GX_PNMTX0);
#ifdef TARGET_PC
}
#endif
GXSetCurrentMtx(GX_PNMTX0);
GXCallDisplayList(l_frontMat, 0x40);
GXCallDisplayList(l_shadowVolumeDL, 0x40);
@@ -1346,14 +1333,14 @@ void dDlst_shadowSimple_c::draw() {
GXCallDisplayList(l_shadowVolumeDL, 0x40);
#ifdef TARGET_PC
Mtx shadow_mtx;
if (dusk::frame_interp::lookup_replacement(&mMtx, shadow_mtx)) {
if (dusk::frame_interp::lookup_replacement(mMtxKey, shadow_mtx)) {
cMtx_concat(j3dSys.getViewMtx(), shadow_mtx, shadow_mtx);
GXLoadPosMtxImm(shadow_mtx, GX_PNMTX1);
} else {
} else
#endif
{
GXLoadPosMtxImm(mMtx, GX_PNMTX1);
#ifdef TARGET_PC
}
#endif
GXSetCurrentMtx(GX_PNMTX1);
if (mpTexObj != NULL) {
@@ -1383,6 +1370,12 @@ void dDlst_shadowSimple_c::draw() {
GXCallDisplayList(l_shadowVolumeDL, 0x40);
}
#if TARGET_PC
static const void* getInterpKey(const void* base, int idx) {
return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(base) ^ idx);
}
#endif
void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* param_3,
s16 param_4, f32 param_5, TGXTexObj* param_6) {
if (param_5 < 0.0f) {
@@ -1406,6 +1399,10 @@ void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* pa
mDoMtx_stack_c::transS(param_0->x, param_1 + f30, param_0->z);
mDoMtx_stack_c::YrotM(param_4);
mDoMtx_stack_c::scaleM(param_2, f30 + f30 + 16.0f, param_2 * param_5);
#if TARGET_PC
mVolumeMtxKey = getInterpKey(param_0, 0x1);
dusk::frame_interp::record_final_mtx(mDoMtx_stack_c::get(), mVolumeMtxKey);
#endif
cMtx_concat(j3dSys.getViewMtx(), mDoMtx_stack_c::get(), mVolumeMtx);
f32 f31 = JMAFastSqrt(1.0f - param_3->x * param_3->x);
f32 f29;
@@ -1431,17 +1428,11 @@ void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* pa
mDoMtx_stack_c::get()[2][3] = param_0->z;
mDoMtx_stack_c::YrotM(param_4);
mDoMtx_stack_c::scaleM(param_2, 1.0f, param_2 * param_5);
cMtx_concat(j3dSys.getViewMtx(), mDoMtx_stack_c::get(), mMtx);
#ifdef TARGET_PC
const uint64_t shadow_tag_base = dusk::frame_interp::alloc_simple_shadow_pair_base();
if (shadow_tag_base != 0) {
dusk::frame_interp::record_final_mtx_raw_tagged(&mVolumeMtx, mVolumeMtx, shadow_tag_base);
dusk::frame_interp::record_final_mtx_raw_tagged(&mMtx, mMtx, shadow_tag_base + 1u);
} else {
dusk::frame_interp::record_final_mtx_raw(&mVolumeMtx, mVolumeMtx);
dusk::frame_interp::record_final_mtx_raw(&mMtx, mMtx);
}
mMtxKey = getInterpKey(param_0, 0x2);
dusk::frame_interp::record_final_mtx(mDoMtx_stack_c::get(), mMtxKey);
#endif
cMtx_concat(j3dSys.getViewMtx(), mDoMtx_stack_c::get(), mMtx);
mpTexObj = param_6;
}
+5
View File
@@ -35,6 +35,7 @@
#if TARGET_PC
#include "dusk/imgui/ImGuiBloomWindow.hpp"
#include "dusk/settings.h"
#include "dusk/frame_interpolation.h"
#endif
static void GxXFog_set();
@@ -8251,6 +8252,10 @@ static int dKy_Create(void* i_this) {
kankyo_class* kankyo = (kankyo_class*)i_this;
BOOL next_time_set = false;
#if TARGET_PC
kankyo->base.draw_interp_frame = true;
#endif
stage_envr_info_class* stage_envr_p = dComIfGp_getStageEnvrInfo();
if (stage_envr_p != NULL && dComIfGp_getStartStageRoomNo() != -1) {
stage_envr_p += dComIfGp_getStartStageRoomNo();
+7 -7
View File
@@ -699,7 +699,7 @@ void dMw_c::collect_open_proc() {
dMeter2Info_set2DVibrationM();
}
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) {
mMenuProc = COLLECT_MOVE;
}
}
@@ -914,7 +914,7 @@ void dMw_c::collect_letter_move_proc() {
}
void dMw_c::collect_letter_close_proc() {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) {
mMenuProc = COLLECT_MOVE;
}
}
@@ -946,7 +946,7 @@ void dMw_c::collect_fishing_move_proc() {
}
void dMw_c::collect_fishing_close_proc() {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) {
mMenuProc = COLLECT_MOVE;
}
}
@@ -977,7 +977,7 @@ void dMw_c::collect_skill_move_proc() {
}
void dMw_c::collect_skill_close_proc() {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) {
mMenuProc = COLLECT_MOVE;
}
}
@@ -1008,13 +1008,13 @@ void dMw_c::collect_insect_move_proc() {
}
void dMw_c::collect_insect_close_proc() {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) {
mMenuProc = COLLECT_MOVE;
}
}
void dMw_c::insect_open_proc() {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) {
field_0x152 = 0;
dComIfGp_setHeapLockFlag(1);
dMw_insect_create(1);
@@ -1050,7 +1050,7 @@ void dMw_c::insect_move_proc() {
}
void dMw_c::insect_close_proc() {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::UNKSTATUS_0) {
if (mDoGph_gInf_c::getFader()->getStatus() == JUTFader::None) {
mMenuProc = NO_MENU;
}
}
+2 -2
View File
@@ -26,8 +26,8 @@ static void dOvlpFd_startFadeIn(int param_0) {
JUTFader* fader = JFWDisplay::getManager()->getFader();
JUT_ASSERT(0, fader != NULL);
fader->setStatus(JUTFader::UNKSTATUS_0, 0);
fader->setStatus(JUTFader::UNKSTATUS_0, -1);
fader->setStatus(JUTFader::None, 0);
fader->setStatus(JUTFader::None, -1);
fader->startFadeIn(param_0);
}
+83 -319
View File
@@ -1,63 +1,16 @@
#include "dusk/frame_interpolation.h"
#include <memory>
#include "mtx.h"
#include "f_op/f_op_camera_mng.h"
#include "m_Do/m_Do_graphic.h"
namespace {
enum class Op : uint8_t {
OpenChild,
FinalMtx,
};
struct Label {
const void* key = nullptr;
int32_t id = 0;
bool operator==(const Label& other) const {
return key == other.key && id == other.id;
}
};
struct Data {
Label child_label{};
size_t child_index = 0;
Mtx matrix{};
const Mtx* dest = nullptr;
uint64_t stable_tag = 0;
};
struct Path;
struct ChildBucket {
Label label{};
std::vector<std::unique_ptr<Path>> nodes;
};
struct OpBucket {
Op op = Op::OpenChild;
std::vector<Data> values;
};
struct Path {
std::vector<ChildBucket> children;
std::vector<OpBucket> ops;
std::vector<std::pair<Op, size_t>> items;
Label draw_scope{};
uint32_t simple_shadow_pair_seq = 0;
};
struct Recording {
Path root;
std::unordered_map<uintptr_t, Mtx> matrix_values;
};
struct MatrixValue {
Mtx value;
};
using FinalMtxLookup = std::unordered_map<const Mtx*, const Data*>;
using FinalMtxLookupTagged = std::unordered_map<uint64_t, const Data*>;
bool s_initialized = false;
bool g_enabled = false;
@@ -66,13 +19,13 @@ bool g_interpolating = false;
bool g_sync_presentation = false;
float g_step = 0.0f;
bool g_is_sim_frame = false;
bool g_ui_tick_pending = false;
Recording g_current_recording;
Recording g_previous_recording;
std::vector<Path*> g_current_path;
std::unordered_map<const Mtx*, MatrixValue> g_replacements;
std::unordered_map<uintptr_t, Mtx> g_replacements;
struct CameraSnapshot {
cXyz eye{};
@@ -100,16 +53,6 @@ struct InterpolationCallBackWork {
std::vector<InterpolationCallBackWork> s_interpolationCallBackWork;
void set_enabled(bool enabled) {
if (g_enabled == enabled)
return;
g_enabled = enabled;
if (!g_enabled)
s_interpolationCallBackWork.clear();
}
void copy_view_to_snap(CameraSnapshot* dst, const view_class& v) {
dst->eye = v.lookat.eye;
dst->center = v.lookat.center;
@@ -122,14 +65,6 @@ void copy_view_to_snap(CameraSnapshot* dst, const view_class& v) {
dst->valid = true;
}
inline void copy_matrix(const Mtx src, Mtx dst) {
MTXCopy(src, dst);
}
inline void concat_matrix(const Mtx lhs, const Mtx rhs, Mtx out) {
MTXConcat(lhs, rhs, out);
}
inline void lerp_matrix(Mtx out, const Mtx lhs, const Mtx rhs, float step) {
const float old_weight = 1.0f - step;
for (size_t row = 0; row < 3; ++row) {
@@ -163,162 +98,22 @@ inline bool matrix_differs(const Mtx lhs, const Mtx rhs, float epsilon = 0.0001f
return false;
}
Data& append_op(Op op) {
auto& items = g_current_path.back()->items;
auto& buckets = g_current_path.back()->ops;
auto it = std::find_if(buckets.begin(), buckets.end(),
[op](const OpBucket& bucket) { return bucket.op == op; });
if (it == buckets.end()) {
buckets.push_back({op, {}});
it = buckets.end() - 1;
}
items.emplace_back(op, it->values.size());
return it->values.emplace_back();
}
const Data* find_matching_data(const Path& path, Op op, size_t index) {
auto it = std::find_if(path.ops.begin(), path.ops.end(),
[op](const OpBucket& bucket) { return bucket.op == op; });
if (it == path.ops.end() || index >= it->values.size()) {
return nullptr;
}
return &it->values[index];
}
const OpBucket* find_op_bucket(const Path& path, Op op) {
auto it = std::find_if(path.ops.begin(), path.ops.end(),
[op](const OpBucket& bucket) { return bucket.op == op; });
if (it == path.ops.end()) {
return nullptr;
}
return &*it;
}
void build_final_mtx_lookups(const Path& path, FinalMtxLookup& dest_lookup, FinalMtxLookupTagged& tag_lookup) {
dest_lookup.clear();
tag_lookup.clear();
const OpBucket* bucket = find_op_bucket(path, Op::FinalMtx);
if (bucket == nullptr) {
return;
}
for (const Data& data : bucket->values) {
if (data.dest != nullptr) {
dest_lookup[data.dest] = &data;
}
if (data.stable_tag != 0) {
tag_lookup[data.stable_tag] = &data;
}
}
}
const Data* find_matching_final_mtx(const FinalMtxLookup& lookup, const Data& new_data) {
if (new_data.dest == nullptr) {
return nullptr;
}
auto it = lookup.find(new_data.dest);
if (it == lookup.end()) {
return nullptr;
}
return it->second;
}
ChildBucket& get_child_bucket(Path& path, const Label& label) {
auto it = std::find_if(path.children.begin(), path.children.end(),
[&label](const ChildBucket& bucket) { return bucket.label == label; });
if (it == path.children.end()) {
path.children.push_back({});
it = path.children.end() - 1;
it->label = label;
}
return *it;
}
const ChildBucket* find_child_bucket(const Path& path, const Label& label) {
auto it = std::find_if(path.children.begin(), path.children.end(),
[&label](const ChildBucket& bucket) { return bucket.label == label; });
if (it == path.children.end()) {
return nullptr;
}
return &*it;
}
void store_replacement(const Data& old_data, const Data& new_data, float step) {
if (new_data.dest == nullptr) {
return;
}
auto& replacement = g_replacements[new_data.dest];
lerp_matrix(replacement.value, old_data.matrix, new_data.matrix, step);
}
void interpolate_branch(const Path& old_path, const Path& new_path, float step) {
FinalMtxLookup old_final_mtx_lookup;
FinalMtxLookupTagged old_final_mtx_lookup_tagged;
build_final_mtx_lookups(old_path, old_final_mtx_lookup, old_final_mtx_lookup_tagged);
for (const auto& item : new_path.items) {
const Op op = item.first;
const size_t index = item.second;
const Data* new_data = find_matching_data(new_path, op, index);
if (new_data == nullptr) {
continue;
}
if (op == Op::OpenChild) {
const ChildBucket* new_children = find_child_bucket(new_path, new_data->child_label);
if (new_children == nullptr || new_data->child_index >= new_children->nodes.size())
{
continue;
}
const Path& new_child = *new_children->nodes[new_data->child_index];
const ChildBucket* old_children = find_child_bucket(old_path, new_data->child_label);
if (old_children != nullptr && new_data->child_index < old_children->nodes.size())
{
interpolate_branch(*old_children->nodes[new_data->child_index], new_child, step);
} else {
interpolate_branch(new_child, new_child, step);
}
continue;
}
const Data* indexed_old_data = find_matching_data(old_path, op, index);
const Data* old_data = nullptr;
if (op == Op::FinalMtx) {
if (new_data->stable_tag != 0) {
const auto it = old_final_mtx_lookup_tagged.find(new_data->stable_tag);
old_data = it != old_final_mtx_lookup_tagged.end() ? it->second : nullptr;
} else {
old_data = find_matching_final_mtx(old_final_mtx_lookup, *new_data);
}
} else {
old_data = indexed_old_data;
}
if (op == Op::FinalMtx) {
store_replacement(old_data != nullptr ? *old_data : *new_data, *new_data, step);
}
}
}
const Mtx* resolve_replacement(const Mtx* source, Mtx* scratch) {
if (!g_interpolating || source == nullptr || dusk::frame_interp::presentation_sync_active()) {
return source;
}
auto it = g_replacements.find(source);
auto it = g_replacements.find(reinterpret_cast<uintptr_t>(source));
if (it == g_replacements.end()) {
return source;
}
copy_matrix(it->second.value, *scratch);
MTXCopy(it->second, *scratch);
return scratch;
}
bool has_recording_data(const Recording& recording) {
return !recording.root.items.empty() || !recording.root.children.empty();
return !recording.matrix_values.empty();
}
void clear_replacements() {
@@ -329,14 +124,26 @@ void clear_replacements() {
namespace dusk::frame_interp {
void ensure_initialized() {
set_enabled(getSettings().game.enableFrameInterpolation);
s_initialized = true;
}
void begin_frame(bool enabled, bool is_sim_frame, float step) {
g_enabled = enabled;
g_is_sim_frame = is_sim_frame;
g_step = std::clamp(step, 0.0f, 1.0f);
if (is_sim_frame) {
s_interpolationCallBackWork.clear();
}
}
bool is_enabled() {
return g_enabled;
}
bool is_sim_frame() {
return g_is_sim_frame;
}
void begin_record() {
ensure_initialized();
@@ -345,7 +152,6 @@ void begin_record() {
g_sync_presentation = false;
g_previous_recording = {};
g_current_recording = {};
g_current_path.clear();
clear_replacements();
s_cam_prev.valid = false;
s_cam_curr.valid = false;
@@ -355,8 +161,6 @@ void begin_record() {
g_sync_presentation = false;
g_previous_recording = std::move(g_current_recording);
g_current_recording = {};
g_current_path.clear();
g_current_path.push_back(&g_current_recording.root);
g_recording = true;
g_interpolating = false;
clear_replacements();
@@ -366,11 +170,6 @@ void begin_record() {
s_cam_prev.valid = false;
s_cam_curr.valid = false;
return;
} else {
copy_view_to_snap(&s_cam_prev, cam->view);
#if WIDESCREEN_SUPPORT
s_cam_prev.wideZoom = s_cam_curr.valid ? s_cam_curr.wideZoom : false;
#endif
}
}
@@ -378,16 +177,20 @@ void end_record() {
g_recording = false;
}
void interpolate(float step) {
void interpolate() {
ensure_initialized();
clear_replacements();
g_step = std::clamp(step, 0.0f, 1.0f);
g_interpolating = g_enabled && !g_recording && !g_sync_presentation && has_recording_data(g_current_recording);
if (!g_interpolating) {
return;
}
const Path& old_root = has_recording_data(g_previous_recording) ? g_previous_recording.root : g_current_recording.root;
interpolate_branch(old_root, g_current_recording.root, g_step);
for (auto const& old : g_previous_recording.matrix_values) {
if (auto it = g_current_recording.matrix_values.find(old.first);
it != g_current_recording.matrix_values.end())
{
lerp_matrix(g_replacements[old.first], old.second, it->second, g_step);
}
}
}
void request_presentation_sync() {
@@ -420,63 +223,30 @@ bool get_ui_tick_pending() {
return g_enabled ? g_ui_tick_pending : true;
}
void open_child(const void* key, int32_t id) {
if (!s_initialized || !g_recording) {
void record_final_mtx(Mtx m, const void* key) {
if (!s_initialized || !g_recording || m == nullptr) {
return;
}
Label label{key, id};
auto& siblings = get_child_bucket(*g_current_path.back(), label).nodes;
Data& data = append_op(Op::OpenChild);
data.child_label = label;
data.child_index = siblings.size();
siblings.emplace_back(std::make_unique<Path>());
Path* const child = siblings.back().get();
child->draw_scope = label;
g_current_path.push_back(child);
auto& it = g_current_recording.matrix_values[reinterpret_cast<uintptr_t>(key)];
MTXCopy(m, it);
}
void close_child() {
if (!s_initialized || !g_recording || g_current_path.size() <= 1) {
return;
}
g_current_path.pop_back();
void record_final_mtx(Mtx m) {
record_final_mtx(m, m);
}
void record_final_mtx_raw(const Mtx* dest, const Mtx src) {
if (!s_initialized || !g_recording || dest == nullptr) {
return;
}
Data& data = append_op(Op::FinalMtx);
data.dest = dest;
data.stable_tag = 0;
copy_matrix(src, data.matrix);
}
void record_final_mtx_raw_tagged(const Mtx* dest, const Mtx src, uint64_t stable_tag) {
if (!s_initialized || !g_recording || dest == nullptr) {
return;
}
Data& data = append_op(Op::FinalMtx);
data.dest = dest;
data.stable_tag = stable_tag;
copy_matrix(src, data.matrix);
}
bool lookup_replacement(const void* source, Mtx out) {
if (presentation_sync_active() || !g_interpolating || source == nullptr) {
bool lookup_replacement(const void* key, Mtx out) {
if (presentation_sync_active() || !g_interpolating || key == nullptr) {
return false;
}
auto it = g_replacements.find(reinterpret_cast<const Mtx*>(source));
auto it = g_replacements.find(reinterpret_cast<uintptr_t>(key));
if (it == g_replacements.end()) {
return false;
}
copy_matrix(it->second.value, out);
MTXCopy(it->second, out);
return true;
}
@@ -493,7 +263,7 @@ bool lookup_concat_replacement(const void* lhs, const void* rhs, Mtx out) {
return false;
}
concat_matrix(*resolved_lhs, *resolved_rhs, out);
MTXConcat(*resolved_lhs, *resolved_rhs, out);
return true;
}
@@ -501,25 +271,62 @@ void record_camera(::camera_process_class* cam, int camera_id) {
if (!g_enabled || camera_id != 0 || cam == nullptr) {
return;
}
s_cam_prev = std::move(s_cam_curr);
copy_view_to_snap(&s_cam_curr, cam->view);
#if WIDESCREEN_SUPPORT
s_cam_curr.wideZoom = mDoGph_gInf_c::isWideZoom();
#endif
}
void interp_view(::view_class* view) {
if (!g_enabled)
return;
if (!s_cam_prev.valid || !s_cam_curr.valid)
return;
const f32 step = get_interpolation_step();
cXyz eye;
cXyz center;
cXyz up;
lerp_xyz(&eye, s_cam_prev.eye, s_cam_curr.eye, step);
lerp_xyz(&center, s_cam_prev.center, s_cam_curr.center, step);
lerp_xyz(&up, s_cam_prev.up, s_cam_curr.up, step);
if (!up.normalizeRS()) {
up = s_cam_curr.up;
up.normalizeRS();
}
view->lookat.eye = eye;
view->lookat.center = center;
view->lookat.up = up;
view->bank = lerp_bank(s_cam_prev.bank, s_cam_curr.bank, step);
view->fovy = s_cam_prev.fovy + (s_cam_curr.fovy - s_cam_prev.fovy) * step;
view->aspect = s_cam_prev.aspect + (s_cam_curr.aspect - s_cam_prev.aspect) * step;
view->near_ = s_cam_prev.near_ + (s_cam_curr.near_ - s_cam_prev.near_) * step;
view->far_ = s_cam_prev.far_ + (s_cam_curr.far_ - s_cam_prev.far_) * step;
// FRAME INTERP TODO: It might be better if I rewired the game to not clear this flag until the
// next sim frame, but I don't care enough to right now
#if WIDESCREEN_SUPPORT
if (mDoGph_gInf_c::isWide() && !mDoGph_gInf_c::isWideZoom() && step >= 0.5f ?
s_cam_curr.wideZoom :
s_cam_prev.wideZoom)
{
mDoGph_gInf_c::onWideZoom();
}
#endif
}
static void run_interpolation_callbacks() {
for (size_t i = 0; i < s_interpolationCallBackWork.size(); i++) {
auto const& work = s_interpolationCallBackWork[i];
work.pCallBack(work.pUserWork);
work.pCallBack(g_is_sim_frame, work.pUserWork);
}
}
void reset_interpolation_callbacks() {
s_interpolationCallBackWork.clear();
}
void add_interpolation_callback(InterpolationCallBack pCallBack, void* pUserWork) {
if (!is_enabled() || s_presentation_depth > 0)
if (!is_enabled() || s_presentation_depth > 0 || !g_is_sim_frame)
return;
s_interpolationCallBackWork.emplace_back(pCallBack, pUserWork);
@@ -544,34 +351,7 @@ void begin_presentation_camera() {
}
std::memcpy(&s_presentation_view_backup, view, sizeof(view_class));
const f32 step = get_interpolation_step();
cXyz eye;
cXyz center;
cXyz up;
lerp_xyz(&eye, s_cam_prev.eye, s_cam_curr.eye, step);
lerp_xyz(&center, s_cam_prev.center, s_cam_curr.center, step);
lerp_xyz(&up, s_cam_prev.up, s_cam_curr.up, step);
if (!up.normalizeRS()) {
up = s_cam_curr.up;
up.normalizeRS();
}
view->lookat.eye = eye;
view->lookat.center = center;
view->lookat.up = up;
view->bank = lerp_bank(s_cam_prev.bank, s_cam_curr.bank, step);
view->fovy = s_cam_prev.fovy + (s_cam_curr.fovy - s_cam_prev.fovy) * step;
view->aspect = s_cam_prev.aspect + (s_cam_curr.aspect - s_cam_prev.aspect) * step;
view->near_ = s_cam_prev.near_ + (s_cam_curr.near_ - s_cam_prev.near_) * step;
view->far_ = s_cam_prev.far_ + (s_cam_curr.far_ - s_cam_prev.far_) * step;
// FRAME INTERP TODO: It might be better if I rewired the game to not clear this flag until the next sim frame, but I don't care enough to right now
#if WIDESCREEN_SUPPORT
if (mDoGph_gInf_c::isWide() && !mDoGph_gInf_c::isWideZoom() && step >= 0.5f ? s_cam_curr.wideZoom : s_cam_prev.wideZoom) {
mDoGph_gInf_c::onWideZoom();
}
#endif
interp_view(view);
// FRAME INTERP TODO: Largely copied from d_camera's camera_draw function from this point, got any better ideas?
C_MTXPerspective(view->projMtx, view->fovy, view->aspect, view->near_, view->far_);
@@ -652,20 +432,4 @@ void end_presentation_camera() {
std::memcpy(view, &s_presentation_view_backup, sizeof(view_class));
}
}
uint64_t alloc_simple_shadow_pair_base() {
if (!s_initialized || !g_recording || g_current_path.size() <= 1) {
return 0;
}
Path* const scope = g_current_path.back();
const uint64_t h = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(scope->draw_scope.key));
const uint32_t lo = scope->simple_shadow_pair_seq;
scope->simple_shadow_pair_seq += 2;
uint64_t tag0 = (h << 17) ^ (static_cast<uint64_t>(lo) << 1u);
if (tag0 == 0) {
tag0 = 2;
}
return tag0;
}
} // namespace dusk::frame_interp
+89 -37
View File
@@ -9,53 +9,109 @@
#include "f_pc/f_pc_layer_iter.h"
#include "f_pc/f_pc_leaf.h"
#include "f_pc/f_pc_node.h"
#include "d/d_debug_viewer.h"
#include "imgui.h"
#include "ImGuiConsole.hpp"
#include "ImGuiMenuTools.hpp"
#include "imgui_internal.h"
namespace dusk {
bool showTreeRecursive;
static bool BeginProcTable() {
static ImGuiTableFlags table_flags =
ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_Resizable |
ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
if (ImGui::BeginTable("proc_table", 7)) {
ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 128);
ImGui::TableSetupColumn("En", ImGuiTableColumnFlags_WidthFixed, 32);
ImGui::TableSetupColumn("Vs", ImGuiTableColumnFlags_WidthFixed, 32);
ImGui::TableSetupColumn("ProcName");
ImGui::TableSetupColumn("Param", ImGuiTableColumnFlags_WidthFixed, 128);
ImGui::TableSetupColumn("Pi", ImGuiTableColumnFlags_WidthFixed, 64);
ImGui::TableSetupColumn("DwPi", ImGuiTableColumnFlags_WidthFixed, 64);
ImGui::TableHeadersRow();
return true;
}
return false;
}
static int ShowProcess(void* p, void*) {
auto proc = static_cast<base_process_class*>(p);
char buf[64];
snprintf(buf, sizeof(buf), "%d", proc->id);
ImGui::TableNextRow();
ImGui::PushID(proc);
bool pending = proc->create_req != nullptr;
if (pending)
ImGui::PushStyleColor(ImGuiCol_Text, {255, 200, 0, 255});
ImGui::TableNextColumn();
ImVec2 avail = ImGui::GetContentRegionAvail();
char id_buf[32];
sprintf(id_buf, "%d", proc->id);
ImVec2 vec = { avail.x, 0 };
if (ImGui::BeginChild(buf, vec, ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
ImGui::Text("[%d] %s", proc->id, GetProcName(proc->profname));
ImGui::Text("init_state: %d, create_phase: %d", proc->state.init_state, proc->state.create_phase);
int flags = ImGuiTreeNodeFlags_SpanAllColumns;
bool isLayer = fpcBs_Is_JustOfType(g_fpcNd_type, proc->subtype);
if (isLayer) {
flags |= ImGuiTreeNodeFlags_DefaultOpen;
} else {
flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen;
}
const char* ofTypeName = "unknown";
if (proc->subtype == g_fpcNd_type) {
ofTypeName = "Node";
}
else if (proc->subtype == g_fpcLf_type) {
ofTypeName = "Leaf";
}
bool open = ImGui::TreeNodeEx(id_buf, flags);
fopAc_ac_c* ac = fopAcM_IsActor(proc) ? (fopAc_ac_c*)proc : nullptr;
if (ac != nullptr && ImGui::IsItemHovered()) {
fopAcM_DrawCullingBox(ac, {0, 255, 255, 255});
}
ImGui::Text("OfType: %d (%s), layer: %d", proc->subtype, ofTypeName, proc->layer_tag.layer->layer_id);
ImGui::TableNextColumn();
bool enable = !fpcM_IsPause(proc, 1);
if (ImGui::Checkbox("##enable", &enable)) {
if (enable)
fpcM_PauseDisable(proc, 1);
else
fpcM_PauseEnable(proc, 1);
}
if (proc->create_req != nullptr) {
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "Pending create request");
}
if (showTreeRecursive) {
if (fpcBs_Is_JustOfType(g_fpcNd_type, proc->subtype)) {
auto procNode = static_cast<process_node_class*>(p);
ImGui::Text("Owns layer %d", procNode->layer.layer_id);
fpcLyIt_OnlyHere(&procNode->layer, ShowProcess, nullptr);
}
ImGui::TableNextColumn();
if (fpcBs_Is_JustOfType(g_fpcLf_type, proc->subtype)) {
leafdraw_class* lf = (leafdraw_class*)proc;
bool vis = lf->unk_0xBC == 0;
if (ImGui::Checkbox("##visible", &vis)) {
if (vis)
lf->unk_0xBC = 0;
else
lf->unk_0xBC = 1;
}
}
ImGui::EndChild();
ImGui::TableNextColumn();
ImGui::Text("%s", ac != nullptr ? fopAcM_getProcNameString(ac) : GetProcName(proc->profname));
ImGui::TableNextColumn();
if (proc->profname == fpcNm_ROOM_SCENE_e) {
ImGui::Text("Room %d", proc->parameters);
} else {
ImGui::Text("%08x", proc->parameters);
}
ImGui::TableNextColumn();
ImGui::Text("%d", proc->priority.current_info.list_id);
ImGui::TableNextColumn();
if (fpcBs_Is_JustOfType(g_fpcLf_type, proc->subtype)) {
ImGui::Text("%d", fpcM_DrawPriority(proc));
} else {
ImGui::Text("--");
}
if (isLayer && open) {
auto procNode = static_cast<process_node_class*>(p);
fpcLyIt_OnlyHere(&procNode->layer, ShowProcess, nullptr);
ImGui::TreePop();
}
if (pending)
ImGui::PopStyleColor(1);
ImGui::PopID();
return 1;
}
@@ -76,15 +132,11 @@ namespace dusk {
if (ImGui::Begin("Processes", &m_showProcessManagement)) {
if (ImGui::BeginTabBar("Tabs")) {
showTreeRecursive = true;
if (ImGui::BeginTabItem("Tree")) {
fpcLyIt_OnlyHere(fpcLy_RootLayer(), ShowProcess, nullptr);
ImGui::EndTabItem();
}
showTreeRecursive = false;
if (ImGui::BeginTabItem("All layers")) {
fpcLyIt_All(ShowProcess, nullptr);
if (BeginProcTable()) {
fpcLyIt_OnlyHere(fpcLy_RootLayer(), ShowProcess, nullptr);
ImGui::EndTable();
}
ImGui::EndTabItem();
}
-6
View File
@@ -26,13 +26,7 @@ int fpcDw_Execute(base_process_class* i_proc) {
}
fpcLy_SetCurrentLayer(i_proc->layer_tag.layer);
#ifdef TARGET_PC
dusk::frame_interp::open_child(i_proc, 0);
#endif
ret = draw_func(i_proc);
#ifdef TARGET_PC
dusk::frame_interp::close_child();
#endif
fpcLy_SetCurrentLayer(save_layer);
return ret;
}
+12
View File
@@ -6,6 +6,10 @@
#include "f_pc/f_pc_leaf.h"
#include "f_pc/f_pc_debug_sv.h"
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
s16 fpcLf_GetPriority(const leafdraw_class* i_leaf) {
return fpcDwPi_Get(&i_leaf->draw_priority);
}
@@ -16,6 +20,11 @@ int fpcLf_DrawMethod(leafdraw_method_class* i_methods, void* i_process) {
int fpcLf_Draw(leafdraw_class* i_leaf) {
int ret = 0;
#if TARGET_PC
if (!i_leaf->draw_interp_frame && !dusk::frame_interp::is_sim_frame()) {
return ret;
}
#endif
if (i_leaf->unk_0xBC == 0) {
ret = fpcLf_DrawMethod(i_leaf->leaf_methods, i_leaf);
}
@@ -56,6 +65,9 @@ int fpcLf_Create(leafdraw_class* i_leaf) {
LEAFDRAW_BASE(i_leaf).subtype = fpcBs_MakeOfType(&g_fpcLf_type);
fpcDwPi_Init(&i_leaf->draw_priority, pprofile->priority);
i_leaf->unk_0xBC = 0;
#if TARGET_PC
i_leaf->draw_interp_frame = false;
#endif
}
int ret = fpcMtd_Create(&i_leaf->leaf_methods->base, i_leaf);
+1 -1
View File
@@ -65,7 +65,7 @@ void fpcM_Management(fpcM_ManagementFunc i_preExecuteFn, fpcM_ManagementFunc i_p
#ifdef TARGET_PC
// FRAME INTERP NOTE: Called in m_Do_main when interp is enabled
if (!dusk::getSettings().game.enableFrameInterpolation || dusk::getTransientSettings().skipFrameRateLimit)
if (!dusk::frame_interp::is_enabled())
#endif
{
cAPIGph_Painter();
+18 -1
View File
@@ -7,6 +7,13 @@
#include "f_pc/f_pc_layer_iter.h"
#include "f_pc/f_pc_debug_sv.h"
#if TARGET_PC
#include "f_op/f_op_draw_iter.h"
#include "f_pc/f_pc_manager.h"
#include "dusk/frame_interpolation.h"
#endif
int fpcNd_DrawMethod(nodedraw_method_class* i_method_class, void* i_data) {
return fpcMtd_Method(i_method_class->draw_method, i_data);
}
@@ -18,7 +25,17 @@ int fpcNd_Draw(process_node_class* i_procNode) {
if (i_procNode->unk_0x1A8 == 0) {
layer_class* save_layer = fpcLy_CurrentLayer();
fpcLy_SetCurrentLayer(&var_r28->layer);
ret = fpcNd_DrawMethod(i_procNode->nodedraw_method, i_procNode);
#if TARGET_PC
if (!i_procNode->draw_interp_frame && !dusk::frame_interp::is_sim_frame()) {
for (create_tag_class* i = fopDwIt_Begin(); i != NULL; i = fopDwIt_Next(i)) {
void* process = i->mpTagData;
fpcM_Draw(process);
}
} else
#endif
{
ret = fpcNd_DrawMethod(i_procNode->nodedraw_method, i_procNode);
}
fpcLy_SetCurrentLayer(save_layer);
}
+6
View File
@@ -25,6 +25,7 @@
#include <cstdio>
#include <cstring>
#include "dusk/logging.h"
#include "dusk/frame_interpolation.h"
u8 mDoExt::CurrentHeapAdjustVerbose;
u8 mDoExt::HeapAdjustVerbose;
@@ -349,6 +350,11 @@ void mDoExt_modelUpdateDL(J3DModel* i_model) {
}
void mDoExt_modelEntryDL(J3DModel* i_model) {
#if TARGET_PC
if (!dusk::frame_interp::is_sim_frame())
return;
#endif
modelMtxErrorCheck(i_model);
J3DModelData* model_data = i_model->getModelData();
+11 -5
View File
@@ -71,6 +71,7 @@
#include "dusk/settings.h"
#include "dusk/imgui/ImGuiConsole.hpp"
#include "tracy/Tracy.hpp"
#include "f_pc/f_pc_draw.h"
// --- GLOBALS ---
s8 mDoMain::developmentMode = -1;
@@ -250,21 +251,26 @@ void main01(void) {
mDoGph_gInf_c::updateRenderSize();
dusk::frame_interp::begin_frame(pacing.is_interpolating, pacing.do_sim_tick, pacing.interpolation_step);
if (pacing.is_interpolating) {
if (pacing.do_sim_tick) {
dusk::frame_interp::reset_interpolation_callbacks();
dusk::frame_interp::set_ui_tick_pending(true);
mDoCPd_c::read();
DuskDebugPad();
dusk::gyro::read(pacing.sim_pace);
fapGm_Execute();
mDoAud_Execute();
dusk::game_clock::reset_accumulator();
}
dusk::frame_interp::interpolate(pacing.interpolation_step);
{
dusk::frame_interp::PresentationCameraScope presentation_camera;
cAPIGph_Painter();
dusk::frame_interp::interpolate();
dusk::frame_interp::begin_presentation_camera();
if (!pacing.do_sim_tick) {
// run draw functions for anything specially marked to handle interp on non-sim
// ticks
fpcM_DrawIterater((fpcM_DrawIteraterFunc)fpcM_Draw);
}
cAPIGph_Painter();
dusk::frame_interp::end_presentation_camera();
dusk::frame_interp::set_ui_tick_pending(false);
} else {
dusk::frame_interp::set_ui_tick_pending(true);