From a1938ffd13bcd3f94ef5b101a8d3822dc848ac22 Mon Sep 17 00:00:00 2001 From: Irastris Date: Sat, 12 Sep 2026 22:08:00 -0400 Subject: [PATCH] Create material interp module, drop various per-actor callbacks --- files.cmake | 1 + include/d/actor/d_a_npc_zra.h | 3 - include/d/actor/d_a_obj_lv8Lift.h | 3 - include/m_Do/m_Do_ext.h | 16 +- .../JSystem/J3DGraphAnimator/J3DAnimation.h | 66 +- .../JSystem/J3DGraphAnimator/J3DMaterialAnm.h | 32 + .../JSystem/J3DGraphAnimator/J3DModel.h | 1 - .../src/J3DGraphAnimator/J3DAnimation.cpp | 70 +++ .../src/J3DGraphAnimator/J3DMaterialAnm.cpp | 45 ++ .../JSystem/src/J3DGraphAnimator/J3DModel.cpp | 20 +- libs/JSystem/src/J3DGraphBase/J3DMaterial.cpp | 7 + src/d/actor/d_a_e_sm2.cpp | 57 -- src/d/actor/d_a_npc_zra.cpp | 69 --- src/d/actor/d_a_obj_groundwater.cpp | 12 +- src/d/actor/d_a_obj_item.cpp | 29 - src/d/actor/d_a_obj_lv8Lift.cpp | 41 -- src/d/actor/d_a_obj_lv8OptiLift.cpp | 41 -- src/d/d_kankyo.cpp | 2 + src/dusk/interp/frame_interpolation.cpp | 12 + src/dusk/interp/frame_interpolation.h | 2 + src/dusk/interp/material.cpp | 577 ++++++++++++++++++ src/dusk/interp/material.h | 104 ++++ src/m_Do/m_Do_ext.cpp | 19 + 23 files changed, 967 insertions(+), 262 deletions(-) create mode 100644 src/dusk/interp/material.cpp create mode 100644 src/dusk/interp/material.h diff --git a/files.cmake b/files.cmake index 71353a19b8..8962ee2cb8 100644 --- a/files.cmake +++ b/files.cmake @@ -1467,6 +1467,7 @@ set(DUSK_FILES src/dusk/interp/camera.cpp src/dusk/interp/frame_interpolation.cpp src/dusk/interp/line.cpp + src/dusk/interp/material.cpp src/dusk/interp/particle.cpp src/dusk/interp/samples.cpp src/dusk/interp/vertex.cpp diff --git a/include/d/actor/d_a_npc_zra.h b/include/d/actor/d_a_npc_zra.h index 825076e192..ee786522f9 100644 --- a/include/d/actor/d_a_npc_zra.h +++ b/include/d/actor/d_a_npc_zra.h @@ -370,9 +370,6 @@ public: u32 getAngleNoFromParam() { return (u8)(fopAcM_GetParam(this) >> 8); } void setBlastFlag(u8 i_flag) { mBlastFlag = i_flag; } MtxP getHeadMtx() { return mAnm_p->getModel()->getAnmMtx(4); } -#if TARGET_PC - friend void daNpc_zrA_interp_callback(void* pUserWork); -#endif /* 0x0B48 */ Z2Creature mCreatureSound; /* 0x0BD8 */ J3DModel* mpObjectModel[3]; diff --git a/include/d/actor/d_a_obj_lv8Lift.h b/include/d/actor/d_a_obj_lv8Lift.h index 4f243d0906..1fa4d4b7f6 100644 --- a/include/d/actor/d_a_obj_lv8Lift.h +++ b/include/d/actor/d_a_obj_lv8Lift.h @@ -58,9 +58,6 @@ public: void setNextPoint(); int Draw(); int Delete(); -#if TARGET_PC - friend void daL8Lift_interp_callback(void* pUserWork); -#endif u8 getPthID() { return fopAcM_GetParamBit(this, 0, 8); } u8 getMoveSpeed() { return fopAcM_GetParamBit(this, 8, 4); } diff --git a/include/m_Do/m_Do_ext.h b/include/m_Do/m_Do_ext.h index 4c1ceeb997..83a6a78230 100644 --- a/include/m_Do/m_Do_ext.h +++ b/include/m_Do/m_Do_ext.h @@ -80,7 +80,13 @@ public: int remove(J3DModelData* i_modelData) { return i_modelData->removeTexMtxAnimator(mpAnm); } void entryFrame() { entryFrame(getFrame()); } - void entryFrame(f32 frame) { mpAnm->setFrame(frame); } +#if TARGET_PC + void entryFrame(f32 frame); +#else + void entryFrame(f32 frame) { + mpAnm->setFrame(frame); + } +#endif J3DAnmTextureSRTKey* getBtkAnm() const { return mpAnm; } @@ -110,7 +116,13 @@ public: int remove(J3DModelData* i_modelData) { return i_modelData->removeTevRegAnimator(mpAnm); } void entryFrame() { entryFrame(getFrame()); } - void entryFrame(f32 frame) { mpAnm->setFrame(frame); } +#if TARGET_PC + void entryFrame(f32 frame); +#else + void entryFrame(f32 frame) { + mpAnm->setFrame(frame); + } +#endif J3DAnmTevRegKey* getBrkAnm() const { return mpAnm; } diff --git a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DAnimation.h b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DAnimation.h index f006183d07..80af43182b 100644 --- a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DAnimation.h +++ b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DAnimation.h @@ -6,9 +6,9 @@ #include #include "global.h" +#if TARGET_PC #include "helpers/endian.h" -#if TARGET_PC #define OFFSET_PTR_V0 BE(u32) #else #define OFFSET_PTR_V0 void* @@ -478,27 +478,45 @@ struct J3DAnmClusterFullTable { */ class J3DAnmBase { public: +#if TARGET_PC + J3DAnmBase(); +#else J3DAnmBase() { mAttribute = 0; field_0x5 = 0; mFrameMax = 0; mFrame = 0.0f; } +#endif +#if TARGET_PC + J3DAnmBase(s16 frameMax); +#else J3DAnmBase(s16 frameMax) { mAttribute = 0; field_0x5 = 0; mFrameMax = frameMax; mFrame = 0.0f; } +#endif +#if TARGET_PC + virtual ~J3DAnmBase(); +#else virtual ~J3DAnmBase() {} +#endif virtual s32 getKind() const = 0; u8 getAttribute() const { return mAttribute; } s16 getFrameMax() const { return mFrameMax; } f32 getFrame() const { return mFrame; } - void setFrame(f32 frame) { mFrame = frame; } +#if TARGET_PC + void setFrame(f32 frame); +#else + void setFrame(f32 frame) { + mFrame = frame; + } +#endif /* 0x4 */ u8 mAttribute; /* 0x5 */ u8 field_0x5; @@ -960,30 +978,66 @@ public: void init(int endFrame) { init((s16)endFrame); } BOOL checkPass(f32); void update(); +#if TARGET_PC + virtual ~J3DFrameCtrl(); +#else virtual ~J3DFrameCtrl() {} +#endif u8 getAttribute() const { return mAttribute; } - void setAttribute(u8 attr) { mAttribute = attr; } +#if TARGET_PC + void setAttribute(u8 attr); +#else + void setAttribute(u8 attr) { + mAttribute = attr; + } +#endif u8 getState() const { return mState; } bool checkState(u8 state) const { return mState & state ? true : false; } s16 getStart() const { return mStart; } +#if TARGET_PC + void setStart(s16 start); +#else void setStart(s16 start) { mStart = start; mFrame = start; } +#endif s16 getEnd() const { return mEnd; } - void setEnd(s16 end) { mEnd = end; } +#if TARGET_PC + void setEnd(s16 end); +#else + void setEnd(s16 end) { + mEnd = end; + } +#endif s16 getLoop() const { return mLoop; } - void setLoop(s16 loop) { mLoop = loop; } +#if TARGET_PC + void setLoop(s16 loop); +#else + void setLoop(s16 loop) { + mLoop = loop; + } +#endif f32 getRate() const { return mRate; } void setRate(f32 rate) { mRate = rate; } f32 getFrame() const { return mFrame; } - void setFrame(f32 frame) { mFrame = frame; } +#if TARGET_PC + void setFrame(f32 frame); +#else + void setFrame(f32 frame) { + mFrame = frame; + } +#endif +#if TARGET_PC + void reset(); +#else void reset() { mFrame = mStart; mRate = 1.0f; mState = 0; } +#endif /* 0x04 */ u8 mAttribute; /* 0x05 */ u8 mState; diff --git a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DMaterialAnm.h b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DMaterialAnm.h index 4c3f0f75bb..94d3315d2e 100644 --- a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DMaterialAnm.h +++ b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DMaterialAnm.h @@ -31,10 +31,15 @@ public: void setAnmFlag(bool flag) { mAnmFlag = flag; } bool getAnmFlag() const { return mAnmFlag; } +#if TARGET_PC + void calc(GXColor* pColor) const; + J3DAnmColor* getAnimation() const { return mAnmColor; } +#else void calc(GXColor* pColor) const { J3D_ASSERT_NULLPTR(507, pColor != NULL); mAnmColor->getColor(field_0x0, pColor); } +#endif private: /* 0x0 */ u16 field_0x0; @@ -66,10 +71,15 @@ public: void setAnmFlag(bool flag) { mAnmFlag = flag; } +#if TARGET_PC + void calc(J3DTextureSRTInfo* pSRTInfo) const; + J3DAnmTextureSRTKey* getAnimation() const { return mAnmTransform; } +#else void calc(J3DTextureSRTInfo* pSRTInfo) const { J3D_ASSERT_NULLPTR(519, pSRTInfo != NULL); mAnmTransform->getTransform(field_0x0, pSRTInfo); } +#endif bool getAnmFlag() const { return mAnmFlag; } @@ -108,6 +118,9 @@ public: void setAnmFlag(bool flag) { mAnmFlag = flag; } bool getAnmFlag() const { return mAnmFlag; } +#if TARGET_PC + J3DAnmTexPattern* getAnimation() const { return mAnmTexPattern; } +#endif J3DAnmTexPattern* getAnmTexPattern() { return mAnmTexPattern; } private: @@ -141,10 +154,15 @@ public: void setAnmFlag(bool flag) { mAnmFlag = flag; } bool getAnmFlag() const { return mAnmFlag; } +#if TARGET_PC + void calc(GXColorS10* pColor) const; + J3DAnmTevRegKey* getAnimation() const { return mAnmTevReg; } +#else void calc(GXColorS10* pColor) const { J3D_ASSERT_NULLPTR(545, pColor != NULL); mAnmTevReg->getTevColorReg(field_0x0, pColor); } +#endif private: /* 0x0 */ u16 field_0x0; @@ -177,10 +195,15 @@ public: void setAnmFlag(bool flag) { mAnmFlag = flag; } bool getAnmFlag() const { return mAnmFlag; } +#if TARGET_PC + void calc(GXColor* pColor) const; + J3DAnmTevRegKey* getAnimation() const { return mAnmTevReg; } +#else void calc(GXColor* pColor) const { J3D_ASSERT_NULLPTR(558, pColor != NULL); mAnmTevReg->getTevKonstReg(field_0x0, pColor); } +#endif private: /* 0x0 */ u16 field_0x0; @@ -197,6 +220,9 @@ public: J3DMaterialAnm() { initialize(); } void initialize(); +#if TARGET_PC + bool hasMaterialAnimation() const; +#endif void setMatColorAnm(int, J3DMatColorAnm*); void setTexMtxAnm(int, J3DTexMtxAnm*); void setTexNoAnm(int, J3DTexNoAnm*); @@ -207,6 +233,12 @@ public: virtual void calc(J3DMaterial*) const; const J3DTexMtxAnm& getTexMtxAnm(int i) const { return mTexMtxAnm[i]; } +#if TARGET_PC + const J3DMatColorAnm& getMatColorAnm(int i) const { return mMatColorAnm[i]; } + const J3DTexNoAnm& getTexNoAnm(int i) const { return mTexNoAnm[i]; } + const J3DTevColorAnm& getTevColorAnm(int i) const { return mTevColorAnm[i]; } + const J3DTevKColorAnm& getTevKColorAnm(int i) const { return mTevKColorAnm[i]; } +#endif private: /* 0x04 */ J3DMatColorAnm mMatColorAnm[2]; diff --git a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModel.h b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModel.h index 430e223016..042dc81dd3 100644 --- a/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModel.h +++ b/libs/JSystem/include/JSystem/J3DGraphAnimator/J3DModel.h @@ -79,7 +79,6 @@ public: virtual ~J3DModel() {} #if TARGET_PC - static void interp_callback(void* pUserWork); void calc_presentation_base_mtx(); void prepare_presentation_view(); #endif diff --git a/libs/JSystem/src/J3DGraphAnimator/J3DAnimation.cpp b/libs/JSystem/src/J3DGraphAnimator/J3DAnimation.cpp index 8bbdc68204..3ad9093ff8 100644 --- a/libs/JSystem/src/J3DGraphAnimator/J3DAnimation.cpp +++ b/libs/JSystem/src/J3DGraphAnimator/J3DAnimation.cpp @@ -5,7 +5,12 @@ #include "JSystem/J3DGraphBase/J3DStruct.h" #include "JSystem/JMath/JMath.h" +#if TARGET_PC +#include "dusk/interp/material.h" +#endif + void J3DFrameCtrl::init(s16 endFrame) { + IF_DUSK(dusk::interp::material::reset(this)); mAttribute = EMode_LOOP; mState = 0; mStart = 0; @@ -134,6 +139,7 @@ int J3DFrameCtrl::checkPass(f32 passFrame) { void J3DFrameCtrl::update() { + IF_DUSK(dusk::interp::material::Update materialUpdate(*this)); mState = 0; mFrame += mRate; @@ -1456,3 +1462,67 @@ void J3DAnmTevRegKey::searchUpdateMaterialID(J3DModelData* pModelData) { J3D_ASSERT_NULLPTR(2119, pModelData != NULL); searchUpdateMaterialID(&pModelData->getMaterialTable()); } + +#if TARGET_PC +J3DAnmBase::J3DAnmBase() { + dusk::interp::material::reset(this); + mAttribute = 0; + field_0x5 = 0; + mFrameMax = 0; + mFrame = 0.0f; +} + +J3DAnmBase::J3DAnmBase(s16 frameMax) { + dusk::interp::material::reset(this); + mAttribute = 0; + field_0x5 = 0; + mFrameMax = frameMax; + mFrame = 0.0f; +} + +J3DAnmBase::~J3DAnmBase() { + dusk::interp::material::reset(this); +} + +void J3DAnmBase::setFrame(f32 frame) { + dusk::interp::material::reset(this); + mFrame = frame; +} + +J3DFrameCtrl::~J3DFrameCtrl() { + dusk::interp::material::reset(this); +} + +void J3DFrameCtrl::setAttribute(u8 attr) { + dusk::interp::material::reset(this); + mAttribute = attr; +} + +void J3DFrameCtrl::setStart(s16 start) { + dusk::interp::material::reset(this); + mStart = start; + mFrame = start; +} + +void J3DFrameCtrl::setEnd(s16 end) { + dusk::interp::material::reset(this); + mEnd = end; +} + +void J3DFrameCtrl::setLoop(s16 loop) { + dusk::interp::material::reset(this); + mLoop = loop; +} + +void J3DFrameCtrl::setFrame(f32 frame) { + dusk::interp::material::reset(this); + mFrame = frame; +} + +void J3DFrameCtrl::reset() { + dusk::interp::material::reset(this); + mFrame = mStart; + mRate = 1.0f; + mState = 0; +} +#endif diff --git a/libs/JSystem/src/J3DGraphAnimator/J3DMaterialAnm.cpp b/libs/JSystem/src/J3DGraphAnimator/J3DMaterialAnm.cpp index f280a1583e..cd18d9ec82 100644 --- a/libs/JSystem/src/J3DGraphAnimator/J3DMaterialAnm.cpp +++ b/libs/JSystem/src/J3DGraphAnimator/J3DMaterialAnm.cpp @@ -3,6 +3,10 @@ #include "JSystem/J3DGraphAnimator/J3DMaterialAnm.h" #include "JSystem/J3DGraphBase/J3DMaterial.h" +#if TARGET_PC +#include "dusk/interp/material.h" +#endif + void J3DMaterialAnm::initialize() { for (int i = 0; i < ARRAY_SIZE(mMatColorAnm); i++) { mMatColorAnm[i].setAnmFlag(false); @@ -114,3 +118,44 @@ void J3DMaterialAnm::setTevKColorAnm(int idx, J3DTevKColorAnm* pTevKColorAnm) { mTevKColorAnm[idx] = *pTevKColorAnm; } } + +#if TARGET_PC +bool J3DMaterialAnm::hasMaterialAnimation() const { + for (const auto& track : mMatColorAnm) { + if (track.getAnmFlag()) return true; + } + for (const auto& track : mTexMtxAnm) { + if (track.getAnmFlag()) return true; + } + for (const auto& track : mTevColorAnm) { + if (track.getAnmFlag()) return true; + } + for (const auto& track : mTevKColorAnm) { + if (track.getAnmFlag()) return true; + } + return false; +} + +void J3DMatColorAnm::calc(GXColor* pColor) const { + J3D_ASSERT_NULLPTR(507, pColor != NULL); + dusk::interp::material::Sample materialSample(mAnmColor); + mAnmColor->getColor(field_0x0, pColor); +} + +void J3DTexMtxAnm::calc(J3DTextureSRTInfo* pSRTInfo) const { + J3D_ASSERT_NULLPTR(519, pSRTInfo != NULL); + dusk::interp::material::sample_texture(mAnmTransform, field_0x0, pSRTInfo); +} + +void J3DTevColorAnm::calc(GXColorS10* pColor) const { + J3D_ASSERT_NULLPTR(545, pColor != NULL); + dusk::interp::material::Sample materialSample(mAnmTevReg); + mAnmTevReg->getTevColorReg(field_0x0, pColor); +} + +void J3DTevKColorAnm::calc(GXColor* pColor) const { + J3D_ASSERT_NULLPTR(558, pColor != NULL); + dusk::interp::material::Sample materialSample(mAnmTevReg); + mAnmTevReg->getTevKonstReg(field_0x0, pColor); +} +#endif diff --git a/libs/JSystem/src/J3DGraphAnimator/J3DModel.cpp b/libs/JSystem/src/J3DGraphAnimator/J3DModel.cpp index 7408e399cb..7f7c999832 100644 --- a/libs/JSystem/src/J3DGraphAnimator/J3DModel.cpp +++ b/libs/JSystem/src/J3DGraphAnimator/J3DModel.cpp @@ -11,6 +11,7 @@ #if TARGET_PC #include "dusk/interp/frame_interpolation.h" +#include "dusk/interp/material.h" #include "dusk/interp/vertex.h" #endif @@ -103,12 +104,6 @@ s32 J3DModel::entryModelData(J3DModelData* pModelData, u32 mdlFlags, u32 mtxNum) } #if TARGET_PC -void J3DModel::interp_callback(void* pUserWork) { - J3DModel* i_this = static_cast(pUserWork); - i_this->calcMaterial(); - i_this->diff(); -} - void J3DModel::calc_presentation_base_mtx() { Mtx identity; MTXIdentity(identity); @@ -327,7 +322,16 @@ void J3DModel::calcMaterial() { material->getMaterialAnm()->calc(material); } - material->calc(getAnmMtx(material->getJoint()->getJntNo())); + MtxP jointMtx = getAnmMtx(material->getJoint()->getJntNo()); +#if TARGET_PC + Mtx presentedJoint; + if (dusk::interp::is_presentation_active() && + dusk::interp::lookup_replacement(jointMtx, presentedJoint)) + { + jointMtx = presentedJoint; + } +#endif + material->calc(jointMtx); } } @@ -536,7 +540,7 @@ void J3DModel::entry() { #if TARGET_PC if (mModelData->needsInterpCallBack()) { - dusk::interp::add_interpolation_callback(&J3DModel::interp_callback, this); + dusk::interp::material::record_model(this); } #endif } diff --git a/libs/JSystem/src/J3DGraphBase/J3DMaterial.cpp b/libs/JSystem/src/J3DGraphBase/J3DMaterial.cpp index 27043184ee..7f59692bc0 100644 --- a/libs/JSystem/src/J3DGraphBase/J3DMaterial.cpp +++ b/libs/JSystem/src/J3DGraphBase/J3DMaterial.cpp @@ -4,6 +4,10 @@ #include "JSystem/J3DGraphBase/J3DMaterial.h" #include "JSystem/JKernel/JKRHeap.h" +#if TARGET_PC +#include "JSystem/J3DGraphAnimator/J3DMaterialAnm.h" +#endif + J3DColorBlock* J3DMaterial::createColorBlock(u32 flags) { J3DColorBlock* rv = NULL; switch (flags) { @@ -367,6 +371,9 @@ s32 J3DMaterial::newSingleSharedDisplayList(u32 dlSize) { #if TARGET_PC bool J3DMaterial::needsInterpCallBack() const { + if (mMaterialAnm != nullptr && mMaterialAnm->hasMaterialAnimation()) { + return true; + } for (int i = 0, n = getTexGenNum(); i < n; i++) { J3DTexMtx* pTexMtx = mTexGenBlock->getTexMtx(i); if (pTexMtx != NULL) { diff --git a/src/d/actor/d_a_e_sm2.cpp b/src/d/actor/d_a_e_sm2.cpp index 96f718ce0b..5c0d9838ea 100644 --- a/src/d/actor/d_a_e_sm2.cpp +++ b/src/d/actor/d_a_e_sm2.cpp @@ -14,10 +14,6 @@ #include "f_op/f_op_camera_mng.h" #include -#if TARGET_PC -#include "dusk/interp/frame_interpolation.h" -#endif - class daE_SM2_HIO_c : public fOpAcm_HIO_entry_c { public: daE_SM2_HIO_c(); @@ -80,62 +76,9 @@ static int nodeCallBack(J3DJoint* i_joint, int param_1) { return 1; } -#if TARGET_PC -static void daE_SM2_interp_callback(void* pUserWork) { - e_sm2_class* i_this = static_cast(pUserWork); - if (i_this == NULL) { - return; - } - - fopAc_ac_c* actor = (fopAc_ac_c*)&i_this->enemy; - g_env_light.settingTevStruct(0, &actor->current.pos, &actor->tevStr); - - if (!i_this->isPiece) { - if (i_this->modelMorf == NULL) { - return; - } - J3DModel* model = i_this->modelMorf->getModel(); - if (model == NULL) { - return; - } - g_env_light.setLightTevColorType_MAJI(model, &actor->tevStr); - - J3DMaterial* material = model->getModelData()->getMaterialNodePointer(0); - material->getTevKColor(1)->r = i_this->color_R; - material->getTevKColor(1)->g = i_this->color_G; - material->getTevKColor(1)->b = i_this->color_B; - material->getTevKColor(1)->a = 217.0f * i_this->color_alpha; - - if (i_this->pbtk != NULL) { - i_this->pbtk->entry(model->getModelData()); - } - } else { - if (i_this->pieceModelMorf == NULL) { - return; - } - J3DModel* model = i_this->pieceModelMorf->getModel(); - if (model == NULL) { - return; - } - - J3DMaterial* material = model->getModelData()->getMaterialNodePointer(0); - material->getTevKColor(1)->r = i_this->color_R; - material->getTevKColor(1)->g = i_this->color_G; - material->getTevKColor(1)->b = i_this->color_B; - material->getTevKColor(1)->a = 217.0f * i_this->color_alpha; - - g_env_light.setLightTevColorType_MAJI(model, &actor->tevStr); - } -} -#endif - static int daE_SM2_Draw(e_sm2_class* i_this) { fopAc_ac_c* actor = (fopAc_ac_c*)&i_this->enemy; -#if TARGET_PC - dusk::interp::add_interpolation_callback(&daE_SM2_interp_callback, i_this); -#endif - g_env_light.settingTevStruct(0, &actor->current.pos, &actor->tevStr); J3DModel* model; diff --git a/src/d/actor/d_a_npc_zra.cpp b/src/d/actor/d_a_npc_zra.cpp index f77200c514..9d97a3ac2c 100644 --- a/src/d/actor/d_a_npc_zra.cpp +++ b/src/d/actor/d_a_npc_zra.cpp @@ -20,10 +20,6 @@ #include "d/actor/d_a_obj_zraMark.h" #include -#if TARGET_PC -#include "dusk/interp/frame_interpolation.h" -#endif - static NPC_ZRA_HIO_CLASS l_HIO; DUSK_GAME_DATA daNpc_zrA_HIOParam const daNpc_zrA_Param_c::m = { @@ -690,69 +686,6 @@ int daNpc_zrA_c::Execute() { return execute(); } -#if TARGET_PC -void daNpc_zrA_interp_callback(void* pUserWork) { - daNpc_zrA_c* i_this = static_cast(pUserWork); - if (i_this == NULL || i_this->mAnm_p == NULL || i_this->checkHide()) { - return; - } - - J3DModel* model = i_this->mAnm_p->getModel(); - if (model == NULL) { - return; - } - - J3DModelData* model_data = model->getModelData(); - model_data->getMaterialNodePointer(1)->setMaterialAnm(i_this->mpMatAnm); - - if (i_this->mTwilight) { - g_env_light.settingTevStruct(4, &i_this->current.pos, &i_this->tevStr); - } else { - g_env_light.settingTevStruct(0, &i_this->current.pos, &i_this->tevStr); - } - g_env_light.setLightTevColorType_MAJI(model, &i_this->tevStr); - - if (i_this->mWaterAnmFlags & daNpcF_c::ANM_PLAY_BTK) { - i_this->mWaterBtkAnm.entry(model_data); - } - if (i_this->mWaterAnmFlags & daNpcF_c::ANM_PLAY_BPK) { - i_this->mWaterBpkAnm.entry(model_data); - } - if (i_this->mAnmFlags & daNpcF_c::ANM_PLAY_BTP) { - i_this->mBtpAnm.entry(model_data); - } - if (i_this->mAnmFlags & daNpcF_c::ANM_PLAY_BTK) { - i_this->mBtkAnm.entry(model_data); - } - if (i_this->mAnmFlags & daNpcF_c::ANM_PLAY_BRK) { - i_this->mBrkAnm.entry(model_data); - } - - if (!i_this->mHide && !i_this->mTwilight) { - fopAcM_setEffectMtx(i_this, model_data); - } - - model->calcMaterial(); - model->diff(); - - if (i_this->mAnmFlags & daNpcF_c::ANM_PLAY_BTP) { - i_this->mBtpAnm.remove(model_data); - } - if (i_this->mAnmFlags & daNpcF_c::ANM_PLAY_BTK) { - i_this->mBtkAnm.remove(model_data); - } - if (i_this->mAnmFlags & daNpcF_c::ANM_PLAY_BRK) { - i_this->mBrkAnm.remove(model_data); - } - if (i_this->mWaterAnmFlags & daNpcF_c::ANM_PLAY_BPK) { - i_this->mWaterBpkAnm.remove(model_data); - } - if (i_this->mWaterAnmFlags & daNpcF_c::ANM_PLAY_BTK) { - i_this->mWaterBtkAnm.remove(model_data); - } -} -#endif - int daNpc_zrA_c::Draw() { BOOL bvar2 = false; J3DModel* model = mAnm_p->getModel(); @@ -804,8 +737,6 @@ int daNpc_zrA_c::Draw() { mAnm_p->entryDL(); } - IF_DUSK(dusk::interp::add_interpolation_callback(&daNpc_zrA_interp_callback, this)); - if (mAnmFlags & ANM_PLAY_BTP) { mBtpAnm.remove(model_data); } diff --git a/src/d/actor/d_a_obj_groundwater.cpp b/src/d/actor/d_a_obj_groundwater.cpp index 59f310678d..5877de3b80 100644 --- a/src/d/actor/d_a_obj_groundwater.cpp +++ b/src/d/actor/d_a_obj_groundwater.cpp @@ -9,6 +9,10 @@ #include "d/d_com_inf_game.h" #include "m_Do/m_Do_graphic.h" +#if TARGET_PC +#include "dusk/interp/material.h" +#endif + static daGrdWater_HIO_c l_HIO; static daGrdWater_c::modeFunc l_mode_func[5] = { @@ -299,13 +303,17 @@ int daGrdWater_c::Draw() { if (material->getTexGenBlock()->getTexMtx(0) != NULL) { J3DTexMtxInfo* mtxInfo = &material->getTexGenBlock()->getTexMtx(0)->getTexMtxInfo(); if (mtxInfo != NULL) { +#if TARGET_PC + dusk::interp::material::set_view_projection(mtxInfo, 1.0f, 1.0f, -0.01f, 0.0f); +#else Mtx afStack_50; C_MTXLightPerspective(afStack_50, dComIfGd_getView()->fovy, dComIfGd_getView()->aspect, 1.0f, 1.0f, -0.01f, 0.0f); - #if WIDESCREEN_SUPPORT +#if WIDESCREEN_SUPPORT mDoGph_gInf_c::setWideZoomLightProjection(afStack_50); - #endif +#endif mtxInfo->setEffectMtx(afStack_50); +#endif modelData2->simpleCalcMaterial(0, (MtxP)j3dDefaultMtx); } } diff --git a/src/d/actor/d_a_obj_item.cpp b/src/d/actor/d_a_obj_item.cpp index cfd7963207..1c9cc1d5a8 100644 --- a/src/d/actor/d_a_obj_item.cpp +++ b/src/d/actor/d_a_obj_item.cpp @@ -16,10 +16,6 @@ #include "f_op/f_op_camera_mng.h" #include "m_Do/m_Do_mtx.h" -#if TARGET_PC -#include "dusk/interp/frame_interpolation.h" -#endif - static f32 Reflect(cXyz* i_vec, cBgS_PolyInfo const& i_polyinfo, f32 i_scale) { cM3dGPla plane; @@ -35,27 +31,6 @@ static f32 Reflect(cXyz* i_vec, cBgS_PolyInfo const& i_polyinfo, f32 i_scale) { return 0.0f; } -#if TARGET_PC -static void d_a_obj_item_interp_callback(void* pUserWork) { - daItem_c* item = static_cast(pUserWork); - if (item == NULL || item->mpModel == NULL || !item->chkDraw()) { - return; - } - item->setTevStr(); - if (item->mpBrkAnm != NULL) { - s8 tevFrm = item->getTevFrm(); - if (tevFrm != -1) { - item->mpBrkAnm->entry(item->mpModel->getModelData(), tevFrm); - } else { - item->mpBrkAnm->entry(item->mpModel->getModelData()); - } - } - if (item->chkFlag(4)) { - fopAcM_setEffectMtx(item, item->mpModel->getModelData()); - } -} -#endif - const daItemBase_data& daItemBase_c::getData() { return m_data; } @@ -411,10 +386,6 @@ int daItem_c::_daItem_draw() { return 1; } -#if TARGET_PC - dusk::interp::add_interpolation_callback(&d_a_obj_item_interp_callback, this); -#endif - if (chkDraw()) { return DrawBase(); } diff --git a/src/d/actor/d_a_obj_lv8Lift.cpp b/src/d/actor/d_a_obj_lv8Lift.cpp index b77e098487..38809bbfee 100644 --- a/src/d/actor/d_a_obj_lv8Lift.cpp +++ b/src/d/actor/d_a_obj_lv8Lift.cpp @@ -10,10 +10,6 @@ #include "d/d_path.h" #include "d/d_bg_w.h" -#if TARGET_PC -#include "dusk/interp/frame_interpolation.h" -#endif - daL8Lift_HIO_c::daL8Lift_HIO_c() { mStopDisappearTime = 30; mStartMoveTime = 60; @@ -384,44 +380,7 @@ void daL8Lift_c::setNextPoint() { mCurrentPoint = next_point; } -#if TARGET_PC -void daL8Lift_interp_callback(void* pUserWork) { - daL8Lift_c* lift = static_cast(pUserWork); - if (lift == NULL || lift->mpModel == NULL) { - return; - } - - g_env_light.settingTevStruct(0x10, &lift->current.pos, &lift->tevStr); - g_env_light.setLightTevColorType_MAJI(lift->mpModel, &lift->tevStr); - - J3DModelData* modelData = lift->mpModel->getModelData(); - J3DMaterial* materialp = modelData->getMaterialNodePointer(0); - - if (materialp->getTexGenBlock()->getTexMtx(1) != NULL) { - J3DTexMtxInfo* mtx_info = &materialp->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo(); - if (mtx_info != NULL) { - Mtx m; - C_MTXLightOrtho(m, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f); - mDoMtx_stack_c::XrotS(0x4000); - mDoMtx_stack_c::transM(-lift->current.pos.x, -lift->current.pos.y, -lift->current.pos.z); - cMtx_concat(m, mDoMtx_stack_c::get(), mtx_info->mEffectMtx); - } - } - - lift->mBtk.entry(modelData); - - J3DGXColor* color = materialp->getTevKColor(1); - color->r = l_HIO.mColorR; - color->g = l_HIO.mColorG; - color->b = l_HIO.mColorB; -} -#endif - int daL8Lift_c::Draw() { -#if TARGET_PC - dusk::interp::add_interpolation_callback(&daL8Lift_interp_callback, this); -#endif - g_env_light.settingTevStruct(16, ¤t.pos, &tevStr); g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr); J3DModelData* modelData = mpModel->getModelData(); diff --git a/src/d/actor/d_a_obj_lv8OptiLift.cpp b/src/d/actor/d_a_obj_lv8OptiLift.cpp index b63b0979f8..dc49f3f69b 100644 --- a/src/d/actor/d_a_obj_lv8OptiLift.cpp +++ b/src/d/actor/d_a_obj_lv8OptiLift.cpp @@ -11,10 +11,6 @@ #include "d/d_com_inf_game.h" #include "d/d_path.h" -#if TARGET_PC -#include "dusk/interp/frame_interpolation.h" -#endif - daOptiLift_HIO_c::daOptiLift_HIO_c() { mStopDisappearTime = 30; mStartMoveTime = 30; @@ -416,44 +412,7 @@ void daOptiLift_c::setNextPoint() { mCurrentPoint = next_point; } -#if TARGET_PC -static void daOptiLift_interp_callback(void* pUserWork) { - daOptiLift_c* lift = static_cast(pUserWork); - if (lift == NULL || lift->mpModel == NULL) { - return; - } - - g_env_light.settingTevStruct(0x10, &lift->current.pos, &lift->tevStr); - g_env_light.setLightTevColorType_MAJI(lift->mpModel, &lift->tevStr); - - J3DModelData* modelData = lift->mpModel->getModelData(); - J3DMaterial* materialp = modelData->getMaterialNodePointer(0); - - if (materialp->getTexGenBlock()->getTexMtx(1) != NULL) { - J3DTexMtxInfo* mtx_info = &materialp->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo(); - if (mtx_info != NULL) { - Mtx m; - C_MTXLightOrtho(m, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f); - mDoMtx_stack_c::XrotS(0x4000); - mDoMtx_stack_c::transM(-lift->current.pos.x, -lift->current.pos.y, -lift->current.pos.z); - cMtx_concat(m, mDoMtx_stack_c::get(), mtx_info->mEffectMtx); - } - } - - lift->mBtk.entry(modelData); - - J3DGXColor* color = materialp->getTevKColor(1); - color->r = l_HIO.mColorR; - color->g = l_HIO.mColorG; - color->b = l_HIO.mColorB; -} -#endif - int daOptiLift_c::Draw() { -#if TARGET_PC - dusk::interp::add_interpolation_callback(&daOptiLift_interp_callback, this); -#endif - g_env_light.settingTevStruct(0x10, ¤t.pos, &tevStr); g_env_light.setLightTevColorType_MAJI(mpModel, &tevStr); diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index cefa3430ad..3b7f4d9ad4 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -35,6 +35,7 @@ #if TARGET_PC #include "dusk/game_clock.h" +#include "dusk/interp/material.h" #include "dusk/imgui/ImGuiBloomWindow.hpp" static f32 timeScale = 1.0f; #endif @@ -4479,6 +4480,7 @@ static void setLightTevColorType_MAJI_sub(J3DMaterial* material_p, dKy_tevstr_c* } } } + IF_DUSK(dusk::interp::material::record_light_view(material_p)); } } diff --git a/src/dusk/interp/frame_interpolation.cpp b/src/dusk/interp/frame_interpolation.cpp index 229217281b..598ddfb272 100644 --- a/src/dusk/interp/frame_interpolation.cpp +++ b/src/dusk/interp/frame_interpolation.cpp @@ -2,6 +2,7 @@ #include "dusk/game_clock.h" #include "dusk/interp/lerp.h" +#include "dusk/interp/material.h" #include "dusk/interp/particle.h" #include "dusk/interp/samples.h" #include "dusk/interp/vertex.h" @@ -84,6 +85,7 @@ void interpolate_replacements() { struct InterpolationCallBackWork { dusk::interp::InterpolationCallBack pCallBack; void* pUserWork; + std::shared_ptr owner; }; std::vector s_interpolationCallBackWork; @@ -111,6 +113,7 @@ void clear_interpolation_history() { dusk::interp::camera_invalidate_snapshots(); dusk::interp::clear_owned_samples(); dusk::interp::clear_weather_samples(); + dusk::interp::material::clear(); dusk::interp::particle::clear(); dusk::interp::vertex::clear(); s_presentationDepth = 0; @@ -129,6 +132,7 @@ void begin_sim_tick() { clear_callbacks(); camera_on_sim_tick(); ++s_simTickSeq; + material::prune(); particle::prune(); vertex::prune(); } @@ -297,4 +301,12 @@ void add_interpolation_callback(InterpolationCallBack pCallBack, void* pUserWork s_interpolationCallBackWork.push_back({pCallBack, pUserWork}); } +void add_interpolation_callback(InterpolationCallBack pCallBack, void* pUserWork, + std::shared_ptr owner) { + if (!should_capture() || is_presentation_active() || pCallBack == nullptr) { + return; + } + s_interpolationCallBackWork.push_back({pCallBack, pUserWork, std::move(owner)}); +} + } // namespace dusk::interp diff --git a/src/dusk/interp/frame_interpolation.h b/src/dusk/interp/frame_interpolation.h index 9a73c9af52..028a111c3e 100644 --- a/src/dusk/interp/frame_interpolation.h +++ b/src/dusk/interp/frame_interpolation.h @@ -3,6 +3,7 @@ #include #include +#include #ifdef __cplusplus namespace dusk::interp { @@ -35,6 +36,7 @@ bool is_presentation_active(); typedef void (*InterpolationCallBack)(void* pUserWork); void add_interpolation_callback(InterpolationCallBack pCallBack, void* pUserWork); +void add_interpolation_callback(InterpolationCallBack pCallBack, void* pUserWork, std::shared_ptr owner); } // namespace dusk::interp #endif diff --git a/src/dusk/interp/material.cpp b/src/dusk/interp/material.cpp new file mode 100644 index 0000000000..f8a16162a3 --- /dev/null +++ b/src/dusk/interp/material.cpp @@ -0,0 +1,577 @@ +#include "material.h" + +#include "frame_interpolation.h" + +#include "dusk/game_clock.h" + +#include "d/d_com_inf_game.h" +#include "m_Do/m_Do_graphic.h" + +#include "JSystem/J3DGraphAnimator/J3DAnimation.h" +#include "JSystem/J3DGraphAnimator/J3DModel.h" +#include "JSystem/J3DGraphAnimator/J3DModelData.h" +#include "JSystem/J3DGraphBase/J3DMaterial.h" + +#include +#include +#include +#include +#include +#include + +namespace dusk::interp::material { + +namespace { +struct ViewProjection { + f32 scaleS, scaleT, transS, transT; + + void apply(J3DTexMtxInfo* info) const { + Mtx projection; + const auto* view = dComIfGd_getView(); + C_MTXLightPerspective(projection, view->fovy, view->aspect, scaleS, scaleT, transS, transT); +#if WIDESCREEN_SUPPORT + mDoGph_gInf_c::setWideZoomLightProjection(projection); +#endif + info->setEffectMtx(projection); + } +}; + +struct LightView { + Mtx inverse; + + void apply(J3DLightInfo* light, bool rotateDirection) const { + Mtx changeOfView; + MTXConcat(j3dSys.getViewMtx(), inverse, changeOfView); + MTXMultVec(changeOfView, &light->mLightPosition, &light->mLightPosition); + if (rotateDirection) { + MTXMultVecSR(changeOfView, &light->mLightDirection, &light->mLightDirection); + } + } +}; + +struct Tables { + std::unordered_map controllers; + std::unordered_map resources; + std::unordered_map projections; + std::unordered_map lightViews; +}; + +Tables& tables() { + static Tables stored; + return stored; +} + +template +Frames lookup(const Map& map, Key key) { + auto it = map.find(key); + return it == map.end() ? Frames{} : it->second; +} + +f32 sample_texture_translation(const J3DAnmKeyTableBase& table, const BE(f32)* values, f32 frame, f32 evaluated) { + if (table.mMaxFrame < 2 || table.mType != 1) { + return evaluated; + } + + const auto* keys = values + table.mOffset; + for (u16 i = 1; i < table.mMaxFrame; ++i) { + const auto* left = keys + (i - 1) * 4; + const auto* right = left + 4; + if ((f32)left[0] >= frame) { + break; + } + if ((f32)right[0] <= frame || (f32)right[0] - (f32)left[0] != 1.0f) { + continue; + } + const f32 slope = left[2]; + const f32 jump = (f32)right[1] - (f32)left[1] - slope; + const f32 tiles = std::round(jump); + if (std::abs((f32)right[3] - slope) < 0.0001f && std::abs(tiles) >= 1.0f && + std::abs(jump - tiles) < 0.0001f) + { + return (f32)left[1] + slope * (frame - (f32)left[0]); + } + } + + return evaluated; +} +} // namespace + +Frames get_frames(const J3DFrameCtrl* controller) { + return lookup(tables().controllers, controller); +} + +Frames get_frames(const J3DAnmBase* resource) { + return lookup(tables().resources, resource); +} + +void reset(const J3DFrameCtrl* controller) { + tables().controllers.erase(controller); +} + +void reset(const J3DAnmBase* resource) { + tables().resources.erase(resource); +} + +void bind(J3DAnmBase* resource, const J3DFrameCtrl* controller) { + Frames frames = get_frames(controller); + if (frames.valid && frames.tick == sim_tick_seq() && + frames.epoch == game_clock::g_frameTiming.presentationEpoch) + { + tables().resources[resource] = frames; + } else { + reset(resource); + } +} + +void swap_frames(J3DAnmBase* resource, Frames& frames) { + Frames saved = get_frames(resource); + if (frames.valid) { + tables().resources[resource] = frames; + } else { + reset(resource); + } + frames = saved; +} + +void clear() { + tables().controllers.clear(); + tables().resources.clear(); + tables().projections.clear(); + tables().lightViews.clear(); +} + +void prune() { + tables().projections.clear(); + tables().lightViews.clear(); + const uint64_t tick = sim_tick_seq(); + const uint64_t epoch = game_clock::g_frameTiming.presentationEpoch; + auto stale = [=](const auto& entry) { + return entry.second.epoch != epoch || entry.second.tick < tick - (tick != 0); + }; + std::erase_if(tables().controllers, stale); + std::erase_if(tables().resources, stale); +} + +f32 Frames::read(f32 requested) const { + if (!valid || !smooth || !is_enabled() || !is_presentation_active() || tick != sim_tick_seq() || + epoch != game_clock::g_frameTiming.presentationEpoch || requested != current) + { + return requested; + } + + const f32 step = get_interpolation_step(); + if (step <= 0.0f) { + return previous; + } + if (step >= 1.0f) { + return current; + } + + f32 frame = previous + (loop ? travel : current - previous) * step; + if (loop && (frame < loopStart || frame >= loopEnd)) { + if ((travel > 0.0f && frame >= loopEnd) || (travel < 0.0f && frame < loopStart)) { + const f32 length = loopEnd - loopStart; + frame = loopStart + std::fmod(frame - loopStart, length); + if (frame < loopStart) { + frame += length; + } + } + } + + return frame; +} + +Update::Update(J3DFrameCtrl& controller) : m_controller(controller), m_before(controller.getFrame()), m_continuous(true) { + m_travel = controller.getRate(); + const f32 next = m_before + m_travel; + const f32 start = controller.getStart(); + const f32 end = controller.getEnd(); + m_continuous = std::isfinite(m_before) && std::isfinite(next) && end > start; + switch (controller.getAttribute()) { + case J3DFrameCtrl::EMode_NONE: + break; + case J3DFrameCtrl::EMode_RESET: + m_continuous &= next < end; + break; + case J3DFrameCtrl::EMode_LOOP: + m_continuous &= end - start > 1.0f; + m_loopStart = m_travel < 0.0f ? start : controller.getLoop(); + m_loopEnd = m_travel < 0.0f ? controller.getLoop() : end; + if (m_loopEnd > m_loopStart && controller.getLoop() >= start && controller.getLoop() <= end) { + m_continuous &= m_before >= start && m_before < end; + } else { + m_loopStart = m_loopEnd = 0.0f; + m_continuous &= next >= start && next < end; + } + break; + case J3DFrameCtrl::EMode_REVERSE: + m_continuous &= next >= start && next < end; + break; + case J3DFrameCtrl::EMode_LOOP_REVERSE: + m_continuous &= next >= start && next < end - 1.0f; + break; + default: + m_continuous = false; + break; + } +} + +Update::~Update() { + auto& stored = tables().controllers; + Frames frames = get_frames(&m_controller); + if (!should_capture() || is_presentation_active()) { + reset(&m_controller); + return; + } + const uint64_t tick = sim_tick_seq(); + const uint64_t epoch = game_clock::g_frameTiming.presentationEpoch; + const bool same_tick = frames.tick == tick && frames.epoch == epoch && frames.valid; + const f32 current = m_controller.getFrame(); + const bool loop = m_loopEnd > m_loopStart; + const bool compatible = !same_tick || + (frames.loop == loop && (!loop || (frames.loopStart == m_loopStart && + frames.loopEnd == m_loopEnd && frames.travel * m_travel >= 0.0f))); + const bool continuous = compatible && m_continuous && std::isfinite(current) && + (!same_tick || (frames.smooth && frames.current == m_before)); + const f32 previous = same_tick ? frames.previous : m_before; + Frames captured{continuous ? previous : current, current, tick, epoch, true, continuous}; + captured.loop = continuous && loop; + captured.travel = same_tick ? frames.travel + m_travel : m_travel; + captured.loopStart = m_loopStart; + captured.loopEnd = m_loopEnd; + stored[&m_controller] = captured; +} + +Sample::Sample(J3DAnmBase* animation) : m_animation(animation), m_frame(animation->getFrame()) { + animation->mFrame = get_frames(animation).read(m_frame); +} + +Sample::~Sample() { + m_animation->mFrame = m_frame; +} + +void sample_texture(const J3DAnmTextureSRTKey* animation, u16 track, J3DTextureSRTInfo* result) { + const Frames frames = get_frames(animation); + const f32 current = animation->getFrame(); + const f32 sampled = frames.read(current); + animation->calcTransform(sampled, track, result); + + if (!is_enabled() || !is_presentation_active() || sampled == current) { + return; + } + + const auto* table = animation->mAnmTable + track * 3; + result->mTranslationX = sample_texture_translation(table[0].mTranslateInfo, animation->mTransData, + sampled, result->mTranslationX); + result->mTranslationY = sample_texture_translation(table[1].mTranslateInfo, animation->mTransData, + sampled, result->mTranslationY); +} + +namespace { +template +struct Values { + struct Entry { + T* target; + T captured; + T saved; + }; + std::vector entries; + + bool capture(T* target) { + if (target == nullptr || std::any_of(entries.begin(), entries.end(), + [=](const Entry& entry) { + return entry.target == target; + })) + { + return false; + } + entries.push_back({target, *target, *target}); + return true; + } + + void apply() { + for (auto& entry : entries) { + entry.saved = *entry.target; + *entry.target = entry.captured; + } + } + + void restore() { + for (auto& entry : entries) { + *entry.target = entry.saved; + } + } +}; + +template +bool same_color(const Color& a, const Color& b) { + return a.r == b.r && a.g == b.g && a.b == b.b && a.a == b.a; +} +} // namespace + +struct ModelBindings::State { + std::tuple, + Values, Values, Values, + Values, Values, Values, + Values, Values, Values, + Values, Values, Values, + Values, Values, Values, + Values, Values, Values> values; + + struct Animation { + J3DMaterial* material; + J3DMaterialAnm tracks; + }; + + struct Resource { + J3DAnmBase* target; + f32 frame; + Frames frames; + f32 savedFrame; + Frames savedFrames; + }; + + struct Projection { + J3DTexMtxInfo* target; + ViewProjection recipe; + }; + + struct Light { + J3DLightInfo* target; + LightView view; + bool rotateDirection; + }; + + std::vector animations; + std::vector resources; + std::vector projections; + std::vector lights; + + template + bool capture(T* target) { + return std::get>(values).capture(target); + } +}; + +ModelBindings::ModelBindings() : m_state(std::make_unique()) {} +ModelBindings::~ModelBindings() = default; + +void ModelBindings::capture(J3DMaterial* material) { + auto& state = *m_state; + if (!state.capture(material)) { + return; + } + + auto* color = material->getColorBlock(); + switch (color->getType()) { + case 'CLOF': state.capture(static_cast(color)); break; + case 'CLAB': state.capture(static_cast(color)); break; + case 'CLON': state.capture(static_cast(color)); break; + } + + auto* texgen = material->getTexGenBlock(); + switch (texgen->getType()) { + case 'TGPT': state.capture(static_cast(texgen)); break; + case 'TGB4': state.capture(static_cast(texgen)); break; + case 'TGBC': state.capture(static_cast(texgen)); break; + } + + auto* tev = material->getTevBlock(); + switch (tev->getType()) { + case 'TVPT': state.capture(static_cast(tev)); break; + case 'TVB1': state.capture(static_cast(tev)); break; + case 'TVB2': state.capture(static_cast(tev)); break; + case 'TVB4': state.capture(static_cast(tev)); break; + case 'TV16': state.capture(static_cast(tev)); break; + } + + auto* indirect = material->getIndBlock(); + if (indirect->getType() == 'IBLF') { + state.capture(static_cast(indirect)); + } + + auto* pe = material->getPEBlock(); + switch (pe->getType()) { + case 'PEFG': state.capture(static_cast(pe)); break; + case 'PEFL': state.capture(static_cast(pe)); break; + } + + for (int i = 0; i < 8; ++i) { + if (auto* light = color->getLight(i)) { + if (state.capture(light->getLightInfo())) { + if (auto it = tables().lightViews.find(material); i != 1 && it != tables().lightViews.end()) { + state.lights.push_back({light->getLightInfo(), it->second, i >= 2}); + } + } + state.capture(&light->mLightObj); + } + if (auto* coord = texgen->getTexCoord(i)) { + state.capture(&coord->mTexMtxReg); + } + if (auto* matrix = texgen->getTexMtx(i); state.capture(matrix)) { + auto* info = &matrix->getTexMtxInfo(); + if (auto it = tables().projections.find(info); it != tables().projections.end()) { + state.projections.push_back({info, it->second}); + } + } + } + + auto* animation = material->getMaterialAnm(); + if (animation == nullptr) { + return; + } + + auto& tracks = state.animations.emplace_back(State::Animation{material, *animation}).tracks; + for (int i = 0; i < 2; ++i) { + const auto& track = tracks.getMatColorAnm(i); + if (!track.getAnmFlag()) { + continue; + } + capture(track.getAnimation()); + GXColor evaluated; + track.calc(&evaluated); + if (!same_color(*material->getMatColor(i), evaluated)) { + tracks.setMatColorAnm(i, nullptr); + } + } + for (int i = 0; i < 8; ++i) { + const auto& track = tracks.getTexNoAnm(i); + if (!track.getAnmFlag()) { + continue; + } + capture(track.getAnimation()); + u16 evaluated; + track.calc(&evaluated); + if (material->getTexNo(i) != evaluated) { + tracks.setTexNoAnm(i, nullptr); + } + } + for (int i = 0; i < 8; ++i) { + const auto& track = tracks.getTexMtxAnm(i); + if (!track.getAnmFlag()) { + continue; + } + capture(track.getAnimation()); + J3DTextureSRTInfo evaluated; + track.calc(&evaluated); + if (!material->getTexMtx(i)->getTexMtxInfo().mSRT.operator==(evaluated)) { + tracks.setTexMtxAnm(i, nullptr); + } + } + for (int i = 0; i < 3; ++i) { + const auto& track = tracks.getTevColorAnm(i); + if (!track.getAnmFlag()) { + continue; + } + capture(track.getAnimation()); + GXColorS10 evaluated; + track.calc(&evaluated); + if (!same_color(*material->getTevColor(i), evaluated)) { + tracks.setTevColorAnm(i, nullptr); + } + } + for (int i = 0; i < 4; ++i) { + const auto& track = tracks.getTevKColorAnm(i); + if (!track.getAnmFlag()) { + continue; + } + capture(track.getAnimation()); + GXColor evaluated; + track.calc(&evaluated); + if (!same_color(*material->getTevKColor(i), evaluated)) { + tracks.setTevKColorAnm(i, nullptr); + } + } +} + +void ModelBindings::capture(J3DAnmBase* resource) { + if (resource == nullptr) { + return; + } + + for (const auto& entry : m_state->resources) { + if (entry.target == resource) { + return; + } + } + + m_state->resources.push_back({resource, resource->getFrame(), get_frames(resource)}); +} + +void ModelBindings::apply() { + std::apply([](auto&... values) { (values.apply(), ...); }, m_state->values); + + for (auto& entry : m_state->animations) { + entry.material->setMaterialAnm(&entry.tracks); + } + + for (auto& entry : m_state->resources) { + entry.savedFrame = entry.target->mFrame; + entry.target->mFrame = entry.frame; + entry.savedFrames = entry.frames; + swap_frames(entry.target, entry.savedFrames); + } + + for (const auto& entry : m_state->projections) { + entry.recipe.apply(entry.target); + } + + for (const auto& entry : m_state->lights) { + entry.view.apply(entry.target, entry.rotateDirection); + } +} + +void ModelBindings::restore() { + for (auto& entry : m_state->resources) { + entry.target->mFrame = entry.savedFrame; + swap_frames(entry.target, entry.savedFrames); + } + + std::apply([](auto&... values) { (values.restore(), ...); }, m_state->values); +} + +void record_model(J3DModel* model) { + if (!should_capture() || is_presentation_active()) { + return; + } + + struct Recording { + J3DModel* model; + ModelBindings bindings; + }; + + auto recording = std::make_shared(); + recording->model = model; + J3DModelData* data = model->getModelData(); + for (u16 i = 0; i < data->getMaterialNum(); ++i) { + recording->bindings.capture(data->getMaterialNodePointer(i)); + } + + add_interpolation_callback([](void* work) { + auto& recording = *static_cast(work); + ModelScope scope(recording.bindings); + recording.model->calcMaterial(); + recording.model->diff(); + }, recording.get(), recording); +} + +void set_view_projection(J3DTexMtxInfo* info, f32 scaleS, f32 scaleT, f32 transS, f32 transT) { + ViewProjection recipe{scaleS, scaleT, transS, transT}; + recipe.apply(info); + if (should_capture() && !is_presentation_active()) { + tables().projections.insert_or_assign(info, recipe); + } +} + +void record_light_view(J3DMaterial* material) { + if (!should_capture() || is_presentation_active()) { + return; + } + + LightView view; + if (MTXInverse(j3dSys.getViewMtx(), view.inverse)) { + tables().lightViews.insert_or_assign(material, view); + } +} + +} // namespace dusk::interp::material diff --git a/src/dusk/interp/material.h b/src/dusk/interp/material.h new file mode 100644 index 0000000000..cfd7f5abc7 --- /dev/null +++ b/src/dusk/interp/material.h @@ -0,0 +1,104 @@ +#pragma once + +#include "JSystem/J3DGraphAnimator/J3DMaterialAnm.h" +#include "JSystem/J3DGraphBase/J3DMatBlock.h" + +#include +#include +#include + +class J3DAnmBase; +class J3DFrameCtrl; +class J3DModel; + +namespace dusk::interp::material { + +class ModelBindings; + +struct Frames { + f32 previous = 0.0f; + f32 current = 0.0f; + uint64_t tick = 0; + uint64_t epoch = 0; + bool valid = false; + bool smooth = false; + + bool loop = false; + f32 travel = 0.0f; + f32 loopStart = 0.0f; + f32 loopEnd = 0.0f; + + f32 read(f32 requested) const; +}; + +class Update { +public: + explicit Update(J3DFrameCtrl& controller); + ~Update(); + Update(const Update&) = delete; + Update& operator=(const Update&) = delete; + +private: + J3DFrameCtrl& m_controller; + f32 m_before; + bool m_continuous; + f32 m_travel = 0.0f; + f32 m_loopStart = 0.0f; + f32 m_loopEnd = 0.0f; +}; + +class Sample { +public: + explicit Sample(J3DAnmBase* animation); + ~Sample(); + Sample(const Sample&) = delete; + Sample& operator=(const Sample&) = delete; + +private: + J3DAnmBase* m_animation; + f32 m_frame; +}; + +class ModelBindings { +public: + ModelBindings(); + ~ModelBindings(); + ModelBindings(const ModelBindings&) = delete; + ModelBindings& operator=(const ModelBindings&) = delete; + void capture(J3DMaterial* material); + void apply(); + void restore(); + +private: + void capture(J3DAnmBase* resource); + struct State; + std::unique_ptr m_state; +}; + +class ModelScope { +public: + explicit ModelScope(ModelBindings& bindings) : m_bindings(bindings) { m_bindings.apply(); } + ~ModelScope() { m_bindings.restore(); } + ModelScope(const ModelScope&) = delete; + ModelScope& operator=(const ModelScope&) = delete; +private: + ModelBindings& m_bindings; +}; + +void record_model(J3DModel* model); + +void set_view_projection(J3DTexMtxInfo* info, f32 scaleS, f32 scaleT, f32 transS, f32 transT); +void record_light_view(J3DMaterial* material); + +void sample_texture(const J3DAnmTextureSRTKey* animation, u16 track, J3DTextureSRTInfo* result); + +Frames get_frames(const J3DFrameCtrl* controller); +Frames get_frames(const J3DAnmBase* resource); +void reset(const J3DFrameCtrl* controller); +void reset(const J3DAnmBase* resource); +void bind(J3DAnmBase* resource, const J3DFrameCtrl* controller); +void swap_frames(J3DAnmBase* resource, Frames& frames); +void prune(); +void clear(); + +} // namespace dusk::interp::material diff --git a/src/m_Do/m_Do_ext.cpp b/src/m_Do/m_Do_ext.cpp index a53275b7fb..f2f4216ffc 100644 --- a/src/m_Do/m_Do_ext.cpp +++ b/src/m_Do/m_Do_ext.cpp @@ -29,6 +29,7 @@ #include "dusk/game_clock.h" #include "dusk/interp/frame_interpolation.h" #include "dusk/interp/line.h" +#include "dusk/interp/material.h" #include "dusk/logging.h" #include "dusk/version.hpp" #endif @@ -147,6 +148,7 @@ int mDoExt_bpkAnm::init(J3DMaterialTable* i_matTable, J3DAnmColor* i_bpk, int i_ int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF) { JUT_ASSERT(371, (i_anmPlay == FALSE || getFrameCtrl() != NULL || isCurrentSolidHeap()) && i_matTable != NULL && i_bpk != NULL); + IF_DUSK(dusk::interp::material::reset(getFrameCtrl())); mpAnm = i_bpk; mpAnm->searchUpdateMaterialID(i_matTable); @@ -160,6 +162,7 @@ int mDoExt_bpkAnm::init(J3DMaterialTable* i_matTable, J3DAnmColor* i_bpk, int i_ void mDoExt_bpkAnm::entry(J3DMaterialTable* i_matTable, f32 i_frame) { mpAnm->setFrame(i_frame); + IF_DUSK(dusk::interp::material::bind(mpAnm, getFrameCtrl())); i_matTable->entryMatColorAnimator(mpAnm); } @@ -186,6 +189,7 @@ int mDoExt_btkAnm::init(J3DMaterialTable* i_matTable, J3DAnmTextureSRTKey* i_btk int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF) { JUT_ASSERT(468, (i_anmPlay == FALSE || getFrameCtrl() != NULL || isCurrentSolidHeap()) && i_matTable != NULL && i_btk != NULL); + IF_DUSK(dusk::interp::material::reset(getFrameCtrl())); mpAnm = i_btk; mpAnm->searchUpdateMaterialID(i_matTable); @@ -198,6 +202,7 @@ int mDoExt_btkAnm::init(J3DMaterialTable* i_matTable, J3DAnmTextureSRTKey* i_btk void mDoExt_btkAnm::entry(J3DMaterialTable* i_matTable, f32 i_frame) { mpAnm->setFrame(i_frame); + IF_DUSK(dusk::interp::material::bind(mpAnm, getFrameCtrl())); i_matTable->entryTexMtxAnimator(mpAnm); } @@ -205,6 +210,7 @@ int mDoExt_brkAnm::init(J3DMaterialTable* i_matTable, J3DAnmTevRegKey* i_brk, in int i_attribute, f32 i_rate, s16 i_startF, s16 i_endF) { JUT_ASSERT(516, (i_anmPlay == FALSE || getFrameCtrl() != NULL || isCurrentSolidHeap()) && i_matTable != NULL && i_brk != NULL); + IF_DUSK(dusk::interp::material::reset(getFrameCtrl())); mpAnm = i_brk; mpAnm->searchUpdateMaterialID(i_matTable); @@ -217,6 +223,7 @@ int mDoExt_brkAnm::init(J3DMaterialTable* i_matTable, J3DAnmTevRegKey* i_brk, in void mDoExt_brkAnm::entry(J3DMaterialTable* i_matTable, f32 i_frame) { mpAnm->setFrame(i_frame); + IF_DUSK(dusk::interp::material::bind(mpAnm, getFrameCtrl())); i_matTable->entryTevRegAnimator(mpAnm); } @@ -4052,3 +4059,15 @@ static void dummy() { { J3DFog temp; temp = temp; J3DFog temp2(temp); } { J3DTexMtx temp; temp = temp; J3DTexMtx temp2(temp); } } + +#if TARGET_PC +void mDoExt_btkAnm::entryFrame(f32 frame) { + mpAnm->setFrame(frame); + IF_DUSK(dusk::interp::material::bind(mpAnm, getFrameCtrl())); +} + +void mDoExt_brkAnm::entryFrame(f32 frame) { + mpAnm->setFrame(frame); + IF_DUSK(dusk::interp::material::bind(mpAnm, getFrameCtrl())); +} +#endif