diff --git a/config/SOUE01/splits.txt b/config/SOUE01/splits.txt index 37df5819..bfa130a3 100644 --- a/config/SOUE01/splits.txt +++ b/config/SOUE01/splits.txt @@ -369,6 +369,14 @@ m/m3d/m_scnleaf.cpp: .text start:0x802EBBD0 end:0x802EBFF8 .data start:0x80542708 end:0x8054272C +m/m3d/m_shadow.cpp: + .text start:0x802EC000 end:0x802EDF2C + .ctors start:0x804DB8C8 end:0x804DB8CC + .data start:0x80542730 end:0x805427EC + .sdata start:0x80573FC8 end:0x80573FCC + .sbss start:0x80575BF0 end:0x80575C04 + .sdata2 start:0x8057CD68 end:0x8057CD90 + m/m3d/m_smdl.cpp: .text start:0x802EDF30 end:0x802EE094 .data start:0x805427F0 end:0x80542820 diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index 9df5e7aa..ba54a606 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -17655,40 +17655,40 @@ calc__Q23m3d9scnLeaf_cFb = .text:0x802EBE20; // type:function size:0x78 calcVtx__Q23m3d9scnLeaf_cFb = .text:0x802EBEA0; // type:function size:0x78 calcView__Q23m3d9scnLeaf_cFPvb = .text:0x802EBF20; // type:function size:0x84 setPriorityDraw__Q23m3d9scnLeaf_cFii = .text:0x802EBFB0; // type:function size:0x48 -fn_802EC000 = .text:0x802EC000; // type:function size:0x88 -fn_802EC090 = .text:0x802EC090; // type:function size:0x7C -fn_802EC110 = .text:0x802EC110; // type:function size:0x1E8 -fn_802EC300 = .text:0x802EC300; // type:function size:0x2C -fn_802EC330 = .text:0x802EC330; // type:function size:0xD4 -fn_802EC410 = .text:0x802EC410; // type:function size:0x8C -fn_802EC4A0 = .text:0x802EC4A0; // type:function size:0x1DC -fn_802EC680 = .text:0x802EC680; // type:function size:0x9C -fn_802EC720 = .text:0x802EC720; // type:function size:0x24 -fn_802EC750 = .text:0x802EC750; // type:function size:0x28 -fn_802EC780 = .text:0x802EC780; // type:function size:0xA4 -fn_802EC830 = .text:0x802EC830; // type:function size:0x368 -fn_802ECBA0 = .text:0x802ECBA0; // type:function size:0x170 -fn_802ECD10 = .text:0x802ECD10; // type:function size:0x3E4 -fn_802ED100 = .text:0x802ED100; // type:function size:0xE8 -fn_802ED1F0 = .text:0x802ED1F0; // type:function size:0x20 -fn_802ED210 = .text:0x802ED210; // type:function size:0x20 -fn_802ED230 = .text:0x802ED230; // type:function size:0x20 -fn_802ED250 = .text:0x802ED250; // type:function size:0x78 -fn_802ED2D0 = .text:0x802ED2D0; // type:function size:0x60 -fn_802ED330 = .text:0x802ED330; // type:function size:0x9C -fn_802ED3D0 = .text:0x802ED3D0; // type:function size:0x7C -fn_802ED450 = .text:0x802ED450; // type:function size:0x40 -fn_802ED490 = .text:0x802ED490; // type:function size:0x16C -fn_802ED600 = .text:0x802ED600; // type:function size:0xF8 -fn_802ED700 = .text:0x802ED700; // type:function size:0x148 -fn_802ED850 = .text:0x802ED850; // type:function size:0x24C -fn_802EDAA0 = .text:0x802EDAA0; // type:function size:0x108 -fn_802EDBB0 = .text:0x802EDBB0; // type:function size:0x68 -fn_802EDC20 = .text:0x802EDC20; // type:function size:0x58 -fn_802EDC80 = .text:0x802EDC80; // type:function size:0x8 -fn_802EDC90 = .text:0x802EDC90; // type:function size:0x17C -fn_802EDE10 = .text:0x802EDE10; // type:function size:0x10C -fn_802EDF20 = .text:0x802EDF20; // type:function size:0xC +__dt__Q23m3d9mShadow_cFv = .text:0x802EC000; // type:function size:0x88 +drawOpa__Q23m3d9mShadow_cFv = .text:0x802EC090; // type:function size:0x7C +create__Q23m3d9mShadow_cFiUciUsUlQ34nw4r3g3d6ResMdlUl = .text:0x802EC110; // type:function size:0x1E8 +__ct__Q23m3d14mShadowChild_cFv = .text:0x802EC300; // type:function size:0x2C +remove__Q23m3d9mShadow_cFv = .text:0x802EC330; // type:function size:0xD4 +reset__Q23m3d9mShadow_cFv = .text:0x802EC410; // type:function size:0x8C +addCircle__Q23m3d9mShadow_cFPQ23m3d15mShadowCircle_cUlUl = .text:0x802EC4A0; // type:function size:0x1DC +drawMdl__Q23m3d9mShadow_cFPQ23m3d15mShadowCircle_cUlRQ23m3d9scnLeaf_cRC7mQuat_cR7mVec3_c6mColorUlf = .text:0x802EC680; // type:function size:0x9C +addMdlToCircle__Q23m3d9mShadow_cFPQ23m3d15mShadowCircle_cRQ23m3d9scnLeaf_cRC7mQuat_c = .text:0x802EC720; // type:function size:0x24 +removeCircle__Q23m3d9mShadow_cFPQ23m3d15mShadowCircle_c = .text:0x802EC750; // type:function size:0x28 +drawTexObj__Q23m3d9mShadow_cFPQ23m3d15mShadowCircle_cUlPC9_GXTexObjRC6mMtx_cRC7mQuat_cR7mVec3_c6mColorUlf = .text:0x802EC780; // type:function size:0xA4 +drawSub2__3m3dFPvUc = .text:0x802EC830; // type:function size:0x368 scope:local +drawSub1__3m3dFPvUc = .text:0x802ECBA0; // type:function size:0x170 scope:local +drawAllShadows__Q23m3d9mShadow_cFv = .text:0x802ECD10; // type:function size:0x3E4 +create__Q23m3d9mShadow_cFPCQ23m3d19mShadowCircleConfigQ34nw4r3g3d6ResMdlPQ23EGG4Heap = .text:0x802ED100; // type:function size:0xE8 +beforeDraw__Q23m3d9mShadow_cFv = .text:0x802ED1F0; // type:function size:0x20 +draw__Q23m3d9mShadow_cFRC6mMtx_cUl = .text:0x802ED210; // type:function size:0x20 +afterDraw__Q23m3d9mShadow_cFv = .text:0x802ED230; // type:function size:0x20 +swapHeaps__Q23m3d9mShadow_cFv = .text:0x802ED250; // type:function size:0x78 +destroy__Q23m3d9mShadow_cFv = .text:0x802ED2D0; // type:function size:0x60 +__dt__Q23m3d14mShadowChild_cFv = .text:0x802ED330; // type:function size:0x9C +create__Q23m3d14mShadowChild_cFUcPQ23EGG4Heap = .text:0x802ED3D0; // type:function size:0x7C +set__Q23m3d14mShadowChild_cFRC7mVec3_cf6mColor = .text:0x802ED450; // type:function size:0x40 +addMdl__Q23m3d14mShadowChild_cFRQ23m3d9scnLeaf_cRC7mQuat_c = .text:0x802ED490; // type:function size:0x16C +setGeom__Q23m3d14mShadowChild_cFPC9_GXTexObjRC6mMtx_cRC7mQuat_c = .text:0x802ED600; // type:function size:0xF8 +updateMtx__Q23m3d14mShadowChild_cFv = .text:0x802ED700; // type:function size:0x148 +drawMdl__Q23m3d14mShadowChild_cFv = .text:0x802ED850; // type:function size:0x24C +draw__Q23m3d14mShadowChild_cFv = .text:0x802EDAA0; // type:function size:0x108 +__dt__Q23m3d15mShadowCircle_cFv = .text:0x802EDBB0; // type:function size:0x68 +__dt__Q23m3d15mCustomShadow_cFv = .text:0x802EDC20; // type:function size:0x58 +getType__Q23m3d15mCustomShadow_cCFv = .text:0x802EDC80; // type:function size:0x8 +draw__Q23m3d15mCustomShadow_cFRC6mMtx_c = .text:0x802EDC90; // type:function size:0x17C +calc__Q23m3d15mCustomShadow_cF6mMtx_cR6mMtx_c = .text:0x802EDE10; // type:function size:0x10C +__sinit_\m_shadow_cpp = .text:0x802EDF20; // type:function size:0xC scope:local __ct__Q23m3d6smdl_cFv = .text:0x802EDF30; // type:function size:0x4C __dt__Q23m3d6smdl_cFv = .text:0x802EDF80; // type:function size:0x58 create__Q23m3d6smdl_cFQ34nw4r3g3d6ResMdlP12mAllocator_cUliPUl = .text:0x802EDFE0; // type:function size:0xB4 @@ -17865,7 +17865,7 @@ __arraydtor$4414 = .text:0x802F2310; // type:function size:0x1C fn_802F2330 = .text:0x802F2330; // type:function size:0x120 fn_802F2450 = .text:0x802F2450; // type:function size:0x18C fn_802F25E0 = .text:0x802F25E0; // type:function size:0x19C -fn_802F2780 = .text:0x802F2780; // type:function size:0x198 +fn_802F2780__7mQuat_cFRC7mQuat_c = .text:0x802F2780; // type:function size:0x198 fn_802F2920 = .text:0x802F2920; // type:function size:0x48 fn_802F2970 = .text:0x802F2970; // type:function size:0x110 fn_802F2A80 = .text:0x802F2A80; // type:function size:0xF0 @@ -24732,7 +24732,7 @@ fn_8044E680 = .text:0x8044E680; // type:function size:0x50 fn_8044E6D0 = .text:0x8044E6D0; // type:function size:0x16C fn_8044E840 = .text:0x8044E840; // type:function size:0x270 fn_8044EAB0 = .text:0x8044EAB0; // type:function size:0x494 -fn_8044EF50 = .text:0x8044EF50; // type:function size:0x8A4 +Draw1Mat1ShpDirectly__Q24nw4r3g3dFQ34nw4r3g3d6ResMatQ34nw4r3g3d6ResShpPCQ34nw4r4math5MTX34PCQ34nw4r4math5MTX34UlPQ34nw4r3g3d16Draw1Mat1ShpSwapPQ44nw4r3g3d8G3DState8IndMtxOp = .text:0x8044EF50; // type:function size:0x8A4 fn_8044F800 = .text:0x8044F800; // type:function size:0xC0 fn_8044F8C0 = .text:0x8044F8C0; // type:function size:0xD8 fn_8044F9A0 = .text:0x8044F9A0; // type:function size:0x260 @@ -26234,8 +26234,8 @@ resizeForMBlock__Q23EGG7FrmHeapFPvUl = .text:0x804962B0; // type:function size:0 getTotalFreeSize__Q23EGG7FrmHeapFv = .text:0x804962C0; // type:function size:0x14 getAllocatableSize__Q23EGG7FrmHeapFl = .text:0x804962E0; // type:function size:0x8 adjust__Q23EGG7FrmHeapFv = .text:0x804962F0; // type:function size:0x78 -FUN_80496370 = .text:0x80496370; // type:function size:0x8 -FUN_80496380 = .text:0x80496380; // type:function size:0x8 +recordState__Q23EGG7FrmHeapFUl = .text:0x80496370; // type:function size:0x8 +freeState__Q23EGG7FrmHeapFUl = .text:0x80496380; // type:function size:0x8 getHeapKind__Q23EGG7FrmHeapCFv = .text:0x80496390; // type:function size:0x8 __ct__Q23EGG10AssertHeapFP12MEMiHeapHead = .text:0x804963A0; // type:function size:0x3C __dt__Q23EGG10AssertHeapFv = .text:0x804963E0; // type:function size:0x74 @@ -35707,14 +35707,14 @@ __vt__Q23m3d6fanm_c = .data:0x805426A8; // type:object size:0x18 __vt__Q23m3d5mdl_c = .data:0x805426C0; // type:object size:0x2C __vt__Q33m3d5mdl_c13mdlCallback_c = .data:0x805426F0; // type:object size:0x18 __vt__Q23m3d9scnLeaf_c = .data:0x80542708; // type:object size:0x24 -lbl_80542730 = .data:0x80542730; // type:object size:0x10 -lbl_80542740 = .data:0x80542740; // type:object size:0x20 -lbl_80542760 = .data:0x80542760; // type:object size:0x10 -lbl_80542770 = .data:0x80542770; // type:object size:0x10 -lbl_80542780 = .data:0x80542780; // type:object size:0x28 -lbl_805427A8 = .data:0x805427A8; // type:object size:0x2C -lbl_805427D4 = .data:0x805427D4; // type:object size:0xC -lbl_805427E0 = .data:0x805427E0; // type:object size:0x10 +lbl_80542730 = .data:0x80542730; // type:object size:0xA scope:local data:string +sTexMtx__3m3d = .data:0x80542740; // type:object size:0x20 scope:local +sColors__3m3d = .data:0x80542760; // type:object size:0x10 scope:local +sChans__3m3d = .data:0x80542770; // type:object size:0x10 scope:local +__vt__Q23m3d15mCustomShadow_c = .data:0x80542780; // type:object size:0x28 +__vt__Q23m3d9mShadow_c = .data:0x805427A8; // type:object size:0x2C +__vt__Q23m3d15mShadowCircle_c = .data:0x805427D4; // type:object size:0xC +__vt__Q23m3d14mShadowChild_c = .data:0x805427E0; // type:object size:0xC __vt__Q23m3d6smdl_c = .data:0x805427F0; // type:object size:0x2C __vt__16mHeapAllocator_c = .data:0x80542820; // type:object size:0x14 __vt__12mAllocator_c = .data:0x80542834; // type:object size:0x14 @@ -39073,7 +39073,7 @@ lbl_80573FB0 = .sdata:0x80573FB0; // type:object size:0x4 data:4byte lbl_80573FB4 = .sdata:0x80573FB4; // type:object size:0x4 data:4byte m_rootUniqueID__7fBase_c = .sdata:0x80573FB8; // type:object size:0x4 data:4byte m_nowLoopProc__10fManager_c = .sdata:0x80573FC0; // type:object size:0x4 data:4byte -lbl_80573FC8 = .sdata:0x80573FC8; // type:object size:0x8 data:4byte +STEP__3m3d = .sdata:0x80573FC8; // type:object size:0x4 data:4byte lbl_80573FD0 = .sdata:0x80573FD0; // type:object size:0x4 lbl_80573FD4 = .sdata:0x80573FD4; // type:object size:0x1 data:byte lbl_80573FD8 = .sdata:0x80573FD8; // type:object size:0x4 data:4byte @@ -40303,11 +40303,11 @@ l_lightMgr_pp__Q23m3d8internal = .sbss:0x80575BDC; // type:object size:0x4 data: l_numFogMgr__Q23m3d8internal = .sbss:0x80575BE0; // type:object size:0x4 data:4byte l_fogMgr_pp__Q23m3d8internal = .sbss:0x80575BE4; // type:object size:0x4 data:4byte l_alignment__Q23m3d8internal = .sbss:0x80575BE8; // type:object size:0x4 data:4byte -lbl_80575BF0 = .sbss:0x80575BF0; // type:object size:0x4 data:4byte -lbl_80575BF4 = .sbss:0x80575BF4; // type:object size:0x4 data:4byte -lbl_80575BF8 = .sbss:0x80575BF8; // type:object size:0x4 data:4byte -lbl_80575BFC = .sbss:0x80575BFC; // type:object size:0x1 data:byte -lbl_80575C00 = .sbss:0x80575C00; // type:object size:0x8 data:4byte +sInstance__Q23m3d9mShadow_c = .sbss:0x80575BF0; // type:object size:0x4 data:4byte +sTexObj__Q23m3d9mShadow_c = .sbss:0x80575BF4; // type:object size:0x4 data:4byte +sResShp__Q23m3d9mShadow_c = .sbss:0x80575BF8; // type:object size:0x4 data:4byte +@GUARD@draw__Q23m3d15mCustomShadow_cFRC6mMtx_c@nullMat = .sbss:0x80575BFC; // type:object size:0x1 data:byte +@LOCAL@draw__Q23m3d15mCustomShadow_cFRC6mMtx_c@nullMat = .sbss:0x80575C00; // type:object size:0x4 data:4byte Zero__7mAng3_c = .sbss:0x80575C08; // type:object size:0x6 data:2byte somePtr__4mDvd = .sbss:0x80575C10; // type:object size:0x4 data:4byte someNumber__4mDvd = .sbss:0x80575C14; // type:object size:0x4 data:4byte @@ -49129,7 +49129,7 @@ l_param__4mDvd = .bss:0x805CAF68; // type:object size:0x30 lbl_805CAF98 = .bss:0x805CAF98; // type:object size:0xC @LOCAL@loadToMainRAM__4mDvdFiPcPQ23EGG4HeapQ33EGG9DvdRipper15EAllocDirectionlPUlPUlUl@DvdFile = .bss:0x805CAFA8; // type:object size:0xD0 g_gameHeaps__5mHeap = .bss:0x805CB078; // type:object size:0x10 data:4byte -lbl_805CB088 = .bss:0x805CB088; // type:object size:0x30 data:4byte +Identity__6mMtx_c = .bss:0x805CB088; // type:object size:0x30 data:4byte g_core__4mPad = .bss:0x805CB0B8; // type:object size:0x10 data:4byte lbl_805CB0C8 = .bss:0x805CB0C8; // type:object size:0xC g_PadAdditionalData__4mPad = .bss:0x805CB0D8; // type:object size:0x60 data:float diff --git a/configure.py b/configure.py index 0c3ee490..639fac8c 100644 --- a/configure.py +++ b/configure.py @@ -364,6 +364,7 @@ def nw4rLib(lib_name, objects, extra_cflags=[]): Object(Matching, "m/m3d/m_calc_ratio.cpp"), Object(Matching, "m/m3d/m_fanm.cpp"), Object(Matching, "m/m3d/m_mdl.cpp"), + Object(NonMatching, "m/m3d/m_shadow.cpp"), Object(Matching, "m/m3d/m_scnleaf.cpp"), Object(Matching, "m/m3d/m_smdl.cpp"), Object(Matching, "m/m_allocator.cpp"), diff --git a/include/egg/math/eggQuat.h b/include/egg/math/eggQuat.h index 8cfc10af..687ff74d 100644 --- a/include/egg/math/eggQuat.h +++ b/include/egg/math/eggQuat.h @@ -6,10 +6,9 @@ namespace EGG { -struct Quatf : Vector3f { +struct Quatf : public Vector3f { Quatf() {} Quatf(f32 f, Vector3f v) : w(f), Vector3f(v) {} - ~Quatf() {} friend Quatf operator*(const Quatf &q, const Vector3f &vec) { diff --git a/include/m/m3d/m_scnleaf.h b/include/m/m3d/m_scnleaf.h index 18e9db9c..fd224768 100644 --- a/include/m/m3d/m_scnleaf.h +++ b/include/m/m3d/m_scnleaf.h @@ -49,8 +49,12 @@ class scnLeaf_c : UnkClass, EGG::Disposer { void setPriorityDraw(int, int); + inline nw4r::g3d::ScnLeaf *getG3dObject() { + return mpScnLeaf; + } + protected: - nw4r::g3d::ScnLeaf *mpScnLeaf; + /* 0x14 */ nw4r::g3d::ScnLeaf *mpScnLeaf; }; } // namespace m3d diff --git a/include/m/m3d/m_shadow.h b/include/m/m3d/m_shadow.h new file mode 100644 index 00000000..9f0b70d1 --- /dev/null +++ b/include/m/m3d/m_shadow.h @@ -0,0 +1,187 @@ +#ifndef M3D_M_SHADOW_H +#define M3D_M_SHADOW_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace m3d { + +/** + * A configuration struct for our global shadow manager. + * The game uses one for most rooms and one for the Koloktos boss fight. + */ +struct mShadowCircleConfig { + u32 heapSize; + u8 count; + u8 unk1; + u8 unk2; + u8 texBufferSize; + u8 drawOpaPriority; +}; + +/** + * A callback that allows the stage manager to customize parts of + * the shadow pipeline. + */ +class mShadowCallback_c { +public: + virtual ~mShadowCallback_c() {} + virtual void beforeDraw() = 0; + virtual void draw(const mMtx_c &, u32) = 0; + virtual void afterDraw() = 0; +}; + +class mShadowCircle_c; + +/** + * Represents an internal shadow circle. + */ +class mShadowChild_c { + friend class mShadow_c; + +public: + nw4r::ut::Node mNode; + + mShadowChild_c() : mpCircle(nullptr), mpLeaves(nullptr), field_0x154(0), mNumLeaves(0) {} + /* vt at 0x08 */ + virtual ~mShadowChild_c(); + + bool create(u8, EGG::Heap *); + void set(const mVec3_c &pos, f32 dist, mColor color); + bool setGeom(const GXTexObj *texObj, const mMtx_c &mtx, const mQuat_c &quat); + void draw(); + void updateMtx(); + void drawMdl(); + + bool addMdl(scnLeaf_c &mdl, const mQuat_c &quat); + + void set0x154(UNKWORD arg) { + field_0x154 = arg; + } + +private: + /* 0x00C */ EGG::Heap *mpHeap; + /* 0x010 */ mShadowCircle_c *mpCircle; + /* 0x014 */ u32 mPriorityMaybe; + /* 0x018 */ GXTexObj mTexObj; + /* 0x038 */ mColor mShadowColor; + /* 0x03C */ mQuat_c mQuat; + /* 0x04C */ mFrustum_c mFrustum; + /* 0x13C */ f32 field_0x13C; + /* 0x140 */ scnLeaf_c **mpLeaves; + /* 0x144 */ mVec3_c mPositionMaybe; + /* 0x150 */ f32 mOffsetMaybe; + /* 0x154 */ UNKWORD field_0x154; + /* 0x158 */ u8 mMaxNumLeaves; + /* 0x159 */ u8 mNumLeaves; + /* 0x15A */ u8 mColorChanIdx; +}; + +/** + * An RAII handle to a shadow circle. + */ +class mShadowCircle_c { + friend class mShadow_c; + friend class mShadowChild_c; + +public: + mShadowCircle_c() : mpChild(nullptr) {} + virtual ~mShadowCircle_c(); + +private: + mShadowChild_c *mpChild; +}; + +/** + * The global shadow circle manager. + */ +class mShadow_c : public proc_c { + friend class mShadowCircle_c; + friend class mShadowChild_c; + +public: + mShadow_c(EGG::Heap *heap) + : mpHeap(heap), mpCurrentHeap(nullptr), mpChilds(nullptr), mpTexBuf(nullptr), mpCallback(nullptr), + mCurrentHeapIdx(0), mFreeChildIdx(0), field_0x66(true) { + nw4r::ut::List_Init(&mList, 0); + } + virtual ~mShadow_c(); + virtual void remove() override; + virtual void drawOpa() override; + + bool drawMdl(mShadowCircle_c *circle, u32 priority, scnLeaf_c &mdl, const mQuat_c &quat, mVec3_c &pos, mColor color, + u32 param9, f32 dist); + bool drawTexObj(mShadowCircle_c *circle, u32 priority, const GXTexObj *texObj, const mMtx_c &mtx, + const mQuat_c &quat, mVec3_c &pos, mColor color, u32 param9, f32 dist); + + bool addMdlToCircle(mShadowCircle_c *circle, scnLeaf_c &mdl, const mQuat_c &quat); + + void beforeDraw(); + void draw(const mMtx_c &, u32); + void afterDraw(); + + EGG::FrmHeap *changeHeap(int index) { + mCurrentHeapIdx = index % 2; + mpCurrentHeap = mpFrmHeaps[mCurrentHeapIdx]; + } + void swapHeaps(); + void create(int count, u8 unk1, int unk2, u16 texBufferSize, u32 drawOpaPriority, nw4r::g3d::ResMdl mdl, + u32 heapSize); + void reset(); + + bool addCircle(mShadowCircle_c *circle, u32 priority, u32 unk); + void removeCircle(mShadowCircle_c *circle); + + void drawAllShadows(); + + static void create(const mShadowCircleConfig *, nw4r::g3d::ResMdl mdl, EGG::Heap *heap); + static void destroy(); + + static mShadow_c *sInstance; + +private: + /* 0x18 */ EGG::Heap *mpHeap; + /* 0x1C */ mAllocator_c mAllocator; + /* 0x38 */ EGG::FrmHeap *mpFrmHeaps[2]; + /* 0x40 */ EGG::FrmHeap *mpCurrentHeap; + /* 0x44 */ nw4r::ut::List mList; + /* 0x50 */ mShadowChild_c *mpChilds; + /* 0x54 */ void *mpTexBuf; + /* 0x58 */ u32 mTexBufferSize; + /* 0x5C */ mShadowCallback_c *mpCallback; + /* 0x60 */ u8 mCurrentHeapIdx; + /* 0x61 */ u8 mChildCount; + /* 0x62 */ u8 mFreeChildIdx; + /* 0x63 */ u8 mNumTexBuffers; + /* 0x64 */ u8 mFreeTexIdx; + /* 0x65 */ u8 mTexSize; + /* 0x66 */ bool field_0x66; + +public: + static GXTexObj *sTexObj; + static nw4r::g3d::ResShp sResShp; +}; + +class mCustomShadow_c : public scnLeaf_c { +public: + virtual ~mCustomShadow_c(); + virtual int getType() const override; + /* 0x24 */ virtual void draw(const mMtx_c &); + + void calc(mMtx_c, mMtx_c &); + + /* 0x18 */ mMtx_c mMtx; + /* 0x48 */ f32 field_0x48; + /* 0x4C */ f32 field_0x4C; +}; + +} // namespace m3d + +#endif diff --git a/include/m/m_frustum.h b/include/m/m_frustum.h index 0b629468..f4ae5c4a 100644 --- a/include/m/m_frustum.h +++ b/include/m/m_frustum.h @@ -2,7 +2,27 @@ #define M_FRUSTUM_H #include +#include +#include -class mFrustum_c {}; +// Bunch of untested assumptions in here +class mFrustum_c { +public: + void set(f32, f32, f32, f32, f32 near, f32 far, const mMtx_c &mtx, bool); + /* 0x00 */ mMtx_c mView; + /* 0x30 */ nw4r::math::PLANE mPlane_0x30; + /* 0x40 */ nw4r::math::PLANE mPlane_0x40; + /* 0x50 */ nw4r::math::PLANE mPlane_0x50; + /* 0x60 */ nw4r::math::PLANE mPlane_0x60; + /* 0x70 */ f32 mNear; + /* 0x74 */ f32 mFar; + /* 0x78 */ nw4r::math::AABB mAabb; + /* 0x90 */ nw4r::math::PLANE mPlane_0x90; + /* 0xA0 */ nw4r::math::PLANE mPlane_0xA0; + /* 0xB0 */ nw4r::math::PLANE mPlane_0xB0; + /* 0xC0 */ nw4r::math::PLANE mPlane_0xC0; + /* 0xD0 */ nw4r::math::PLANE mPlane_0xD0; + /* 0xE0 */ nw4r::math::PLANE mPlane_0xE0; +}; #endif diff --git a/include/m/m_mtx.h b/include/m/m_mtx.h index 879e62cf..1a57307b 100644 --- a/include/m/m_mtx.h +++ b/include/m/m_mtx.h @@ -11,11 +11,45 @@ #pragma push #pragma warning off(10402) class mMtx_c { + typedef f32 (*MtxRef)[4]; + typedef const f32 (*MtxRefConst)[4]; + public: mMtx_c(){}; /* 802f1660 */ mMtx_c(f32 xx, f32 xy, f32 xz, f32 xw, f32 yx, f32 yy, f32 yz, f32 yw, f32 zx, f32 zy, f32 zz, f32 zw); + // not sure if this breaks anything but we need a matrix type + // with an inline copy assignment operator + mMtx_c &operator=(const mMtx_c &r) { + xx = r.xx; + xy = r.xy; + xz = r.xz; + xw = r.xw; + + yx = r.yx; + yy = r.yy; + yz = r.yz; + yw = r.yw; + + zx = r.zx; + zy = r.zy; + zz = r.zz; + zw = r.zw; + + return *this; + } + + inline operator MtxRef() { + return m; + } + inline operator MtxRefConst() const { + return m; + } + operator nw4r::math::MTX34 *() { + return &nw4rm; + } + /* 802f16b0 */ void XrotS(const mAng &angle); ///< Generates a rotation matrix for the X axis with the given angle. /* 802f1770 */ void XrotM(const mAng &angle); ///< Rotates the matrix on the X axis by the given angle. /* 802f17c0 */ void YrotS(const mAng &angle); ///< Generates a rotation matrix for the Y axis with the given angle. @@ -40,10 +74,6 @@ class mMtx_c { /* 802f1c40 */ void rot(int, int); // does some werrd operation to rotate the matrix /* 802f1e60 */ bool quatRelated(); - operator nw4r::math::MTX34 *() { - return &nw4rm; - } - public: union { EGG::Matrix34f mat; diff --git a/include/m/m_quat.h b/include/m/m_quat.h index e69de29b..a2a1f28a 100644 --- a/include/m/m_quat.h +++ b/include/m/m_quat.h @@ -0,0 +1,12 @@ +#ifndef M_QUAT_H +#define M_QUAT_H + +#include +#include + +class mQuat_c : public EGG::Quatf { +public: + void fn_802F2780(const mQuat_c &other); +}; + +#endif diff --git a/include/nw4r/g3d/g3d_calcview.h b/include/nw4r/g3d/g3d_calcview.h index 3c9a43cf..e79a18d4 100644 --- a/include/nw4r/g3d/g3d_calcview.h +++ b/include/nw4r/g3d/g3d_calcview.h @@ -5,8 +5,9 @@ namespace nw4r { namespace g3d { -void CalcView(math::MTX34 *, math::MTX33 *, const math::MTX34 *, const u32 *, u32, const math::MTX34 *, ResMdl, - math::MTX34 *); +void CalcView(math::MTX34 *pViewPosArray, math::MTX33 *pViewNrmArray, const math::MTX34 *pModelMtxArray, + const u32 *pModelMtxAttribArray, u32 numMtx, const math::MTX34 *pView, ResMdl resMdl, + math::MTX34 *pVewTexMtxArray); } } // namespace nw4r diff --git a/include/nw4r/g3d/g3d_draw.h b/include/nw4r/g3d/g3d_draw.h index 3501607e..8a1a7585 100644 --- a/include/nw4r/g3d/g3d_draw.h +++ b/include/nw4r/g3d/g3d_draw.h @@ -7,8 +7,8 @@ namespace nw4r { namespace g3d { struct DrawResMdlReplacement {}; -void DrawResMdlDirectly(ResMdl, const math::MTX34 *, const math::MTX33 *, const math::MTX34 *, const u8 *, const u8 *, - DrawResMdlReplacement *, u32); +void DrawResMdlDirectly(ResMdl mdl, const math::MTX34 *pViewPos, const math::MTX33 *pViewNrm, + const math::MTX34 *pViewEnv, const u8 *pOpa, const u8 *pXlu, DrawResMdlReplacement *pRep, u32 resMdlDrawMode); } // namespace g3d } // namespace nw4r diff --git a/include/nw4r/g3d/g3d_resmat.h b/include/nw4r/g3d/g3d_resmat.h index 7c26d9e9..4946b707 100644 --- a/include/nw4r/g3d/g3d_resmat.h +++ b/include/nw4r/g3d/g3d_resmat.h @@ -123,6 +123,15 @@ struct ResGenMode : public ResCommon { void GXSetCullMode(GXCullMode); }; +struct ResTexObjData {}; + +struct ResTexObj { + ResCommon mTexObj; + inline ResTexObj(void *vptr) : mTexObj(vptr) {} + + GXTexObj *GetTexObj(GXTexMapID); +}; + struct ResMatData { u32 size; // offset 0x0, size 0x4 s32 toResMdlData; // offset 0x4, size 0x4 @@ -144,6 +153,8 @@ struct ResMatData { }; struct ResMat : public ResCommon { + ResMat(void *ptr) : ResCommon(ptr) {} + ResMatTevColor GetResMatTevColor() { return ResMatTevColor(&ofs_to_ptr(ref().toResMatDLData)->dlTevColor); } @@ -160,6 +171,10 @@ struct ResMat : public ResCommon { return ResTexSrt(&ref().texSrtData); } + ResTexObj GetResTexObj() { + return ResTexObj(&ref().texObjData); + } + ResMatTexCoordGen GetResMatTexCoordGen() { return ResMatTexCoordGen(&ofs_to_ptr(ref().toResMatDLData)->dlTexCoordGen); } diff --git a/include/nw4r/g3d/g3d_resmdl.h b/include/nw4r/g3d/g3d_resmdl.h index 6a7b4c4f..5cf68da7 100644 --- a/include/nw4r/g3d/g3d_resmdl.h +++ b/include/nw4r/g3d/g3d_resmdl.h @@ -7,6 +7,20 @@ namespace nw4r { namespace g3d { + +enum ResMdlDrawMode { + RESMDL_DRAWMODE_SORT_OPA_NONE = 0, + RESMDL_DRAWMODE_SORT_OPA_Z = 1, + RESMDL_DRAWMODE_SORT_XLU_NONE = 0, + RESMDL_DRAWMODE_SORT_XLU_Z = 2, + RESMDL_DRAWMODE_IGNORE_MATERIAL = 4, + RESMDL_DRAWMODE_FORCE_LIGHTOFF = 8, + RESMDL_DRAWMODE_NOPPCSYNC = 16, + RESMDL_DRAWMODE_DEFAULT = 2, + REDMDL_DRAWMODE_SORT_NONE = 0, + RESMDL_DRAWMODE_SORT_Z = 3, +}; + struct ResMdlData { char mMagic[4]; // "MDL0" u32 INT_0x4; diff --git a/include/nw4r/g3d/g3d_resshp.h b/include/nw4r/g3d/g3d_resshp.h index eadb88f6..2dc41239 100644 --- a/include/nw4r/g3d/g3d_resshp.h +++ b/include/nw4r/g3d/g3d_resshp.h @@ -3,7 +3,8 @@ #include "nw4r/g3d/g3d_rescommon.h" #include "nw4r/g3d/g3d_resmdl.h" #include "nw4r/g3d/g3d_resvtx.h" -#include #include "common.h" +#include +#include "common.h" namespace nw4r { @@ -70,7 +71,7 @@ struct ResShpPrePrim { struct ResShp { ResCommon mShp; - + inline ResShp() : mShp((void*)nullptr) {} inline ResShp(void *vptr) : mShp(vptr) {} bool IsValid() const { return mShp.IsValid(); diff --git a/include/nw4r/g3d/g3d_resvtx.h b/include/nw4r/g3d/g3d_resvtx.h index 448eaedd..ab1e1d11 100644 --- a/include/nw4r/g3d/g3d_resvtx.h +++ b/include/nw4r/g3d/g3d_resvtx.h @@ -1,6 +1,6 @@ #ifndef NW4R_G3D_RESVTX_H #define NW4R_G3D_RESVTX_H -#include +#include #include "nw4r/g3d/g3d_rescommon.h" namespace nw4r diff --git a/include/nw4r/g3d/g3d_scnmdl.h b/include/nw4r/g3d/g3d_scnmdl.h index d453a01e..c2ab9ff0 100644 --- a/include/nw4r/g3d/g3d_scnmdl.h +++ b/include/nw4r/g3d/g3d_scnmdl.h @@ -35,7 +35,7 @@ class ScnMdl : public ScnMdlSimple { } private: - char UNK_0x118[0x144 - 0x118]; + char UNK_0x120[0x144 - 0x120]; DrawResMdlReplacement mDrawMdlReplace; // at 0x144 NW4R_G3D_TYPE_OBJ_DECL(ScnMdl); diff --git a/include/nw4r/math/math_triangular.h b/include/nw4r/math/math_triangular.h index 4d27959d..ff450d87 100644 --- a/include/nw4r/math/math_triangular.h +++ b/include/nw4r/math/math_triangular.h @@ -41,6 +41,10 @@ inline f32 SinRad(f32 rad) { */ f32 CosFIdx(f32 fidx); +inline f32 CosIdx(u16 idx) { + return CosFIdx(NW4R_MATH_IDX_TO_FIDX(U16ToF32(idx))); +} + inline f32 CosDeg(f32 deg) { return CosFIdx(NW4R_MATH_DEG_TO_FIDX(deg)); } diff --git a/include/rvl/GX/GXFrameBuf.h b/include/rvl/GX/GXFrameBuf.h index 7e8592b5..4b5814ca 100644 --- a/include/rvl/GX/GXFrameBuf.h +++ b/include/rvl/GX/GXFrameBuf.h @@ -30,6 +30,13 @@ void GXSetDispCopyDst(u16 width, u16 height); u32 GXSetDispCopyYScale(f32 scale); void GXCopyDisp(void *data, GXBool bUpdate); +void GXSetTexCopySrc(u16 left, u16 top, u16 width, u16 height); +void GXSetTexCopyDst(u16 left, u16 top, GXTexFmt fmt, u8 mipmap); +void GXCopyTex(void *data, GXBool bUpdate); + +// Not sure where this belongs +void GXPixModeSync(); + extern GXRenderModeObj GXNtsc480IntDf; extern GXRenderModeObj GXMpal480IntDf; extern GXRenderModeObj GXPal528IntDf; diff --git a/include/rvl/GX/GXTexture.h b/include/rvl/GX/GXTexture.h index fa82a9e4..6b758649 100644 --- a/include/rvl/GX/GXTexture.h +++ b/include/rvl/GX/GXTexture.h @@ -27,6 +27,8 @@ void GXGetTexObjAll(const GXTexObj *pTexObj, void **pImage, u16 *width, u16 *hei void GXGetTexObjLODAll(const GXTexObj *pTexObj, GXTexFilter *minFilter, GXTexFilter *magFilter, f32 *minLOD, f32 *maxLOD, f32 *LODBias, u8 *biasClampEnable, u8 *edgeLODEnable, GXAnisotropy *anisotropy); u32 GXGetTexObjTlut(GXTexObj *); +u32 GXGetTexBufferSize(u16 width, u16 height, u32 format, GXBool arg3, u8 arg4); +void GXInvalidateTexAll(); #ifdef __cplusplus } diff --git a/include/rvl/GX/GXTransform.h b/include/rvl/GX/GXTransform.h index 780af102..6a9ed39a 100644 --- a/include/rvl/GX/GXTransform.h +++ b/include/rvl/GX/GXTransform.h @@ -15,7 +15,7 @@ void GXLoadPosMtxIndx(u16 index, u32 id); void GXLoadNrmMtxImm(const Mtx mtx, u32 id); void GXLoadNrmMtxIndx3x3(u16 index, u32 id); void GXSetCurrentMtx(u32 id); -void GXLoadTexMtxImm(const Mtx mtx, u32 id, GXMtxType type); +void GXLoadTexMtxImm(const f32 mtx[][4], u32 id, GXMtxType type); void GXSetViewportJitter(f32 ox, f32 oy, f32 sx, f32 sy, f32 near, f32 far, u32 nextField); void GXSetViewport(f32 ox, f32 oy, f32 sx, f32 sy, f32 near, f32 far); void GXGetViewportv(f32 view[6]); diff --git a/src/m/m3d/m_shadow.cpp b/src/m/m3d/m_shadow.cpp new file mode 100644 index 00000000..649337aa --- /dev/null +++ b/src/m/m3d/m_shadow.cpp @@ -0,0 +1,615 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// All of this is completely made up, as we don't have symbols for this TU +// (contrary to the rest of m3d and most of nw4r::g3d) + +#define FRM_HEAP_STATE 'tag0' + +namespace m3d { + +mShadow_c *mShadow_c::sInstance; + +GXTexObj *mShadow_c::sTexObj; +nw4r::g3d::ResShp mShadow_c::sResShp; + +mShadow_c::~mShadow_c() { + remove(); +} + +void mShadow_c::drawOpa() { + if (field_0x66) { + beforeDraw(); + mShadowChild_c *child = static_cast(nw4r::ut::List_GetFirst(&mList)); + while (child != nullptr) { + child->draw(); + child = static_cast(nw4r::ut::List_GetNext(&mList, child)); + } + afterDraw(); + } +} + +void mShadow_c::create(int count, u8 unk1, int unk2, u16 texSize, u32 drawOpaPriority, nw4r::g3d::ResMdl mdl, + u32 heapSize) { + // Regswaps + mAllocator.attach(mpHeap, 0x20); + proc_c::create(&mAllocator, nullptr); + u32 bufSize = GXGetTexBufferSize(texSize, texSize, GX_TF_RGB565, false, 0); + mTexBufferSize = bufSize; + u32 numTexBuffers = (unk2 + 2) / 3; + mpTexBuf = mpHeap->alloc(bufSize * numTexBuffers, 0x20); + + // Maybe an Inline? + EGG::FrmHeap **heap = mpFrmHeaps; + for (int i = 0; i < 2; i++) { + heap[0] = mHeap::createFrmHeap(heapSize, mpHeap, "ShadowTmp", 0x4, 0); + heap[0]->recordState(FRM_HEAP_STATE); + heap++; + } + swapHeaps(); + + mShadowChild_c *childs = new (mpHeap, 0x04) mShadowChild_c[count]; + mpChilds = childs; + for (int i = 0; i < count; i++) { + childs->create(unk1, mpHeap); + childs++; + } + + setPriorityDraw(drawOpaPriority, 0); + setOption(/* DISABLE_DRAW_XLU */ 0x07, 1); + + mChildCount = count; + mFreeChildIdx = 0; + mNumTexBuffers = numTexBuffers * 3; + mFreeTexIdx = 0; + mTexSize = texSize; + + nw4r::g3d::ResMat mat = mdl.GetResMat(0); + sResShp = mdl.GetResShp(0); + sTexObj = mat.GetResTexObj().GetTexObj(GX_TEXMAP0); +} + +void mShadow_c::remove() { + if (mpHeap != nullptr) { + if (mpChilds != nullptr) { + delete[] mpChilds; + mpChilds = nullptr; + } + + EGG::FrmHeap **heap = mpFrmHeaps; + for (int i = 0; i < 2; i++) { + if (heap[i] != nullptr) { + mHeap::destroyFrmHeap(heap[i]); + heap[i] = nullptr; + } + } + + if (mpTexBuf != nullptr) { + mpHeap->free(mpTexBuf); + mpTexBuf = nullptr; + } + + scnLeaf_c::remove(); + mpHeap = nullptr; + } +} + +void mShadow_c::reset() { + mShadowChild_c *iter = static_cast(nw4r::ut::List_GetFirst(&mList)); + while (iter != nullptr) { + iter->mNumLeaves = 0; + mShadowCircle_c *circle = iter->mpCircle; + iter->mpCircle = nullptr; + circle->mpChild = nullptr; + iter = static_cast(nw4r::ut::List_GetNext(&mList, iter)); + } + mFreeChildIdx = 0; + mFreeTexIdx = 0; + nw4r::ut::List_Init(&mList, 0); + swapHeaps(); +} + +bool mShadow_c::addCircle(mShadowCircle_c *circle, u32 priority, u32 isMdl) { + if (circle->mpChild != nullptr) { + // Already linked, OK + return true; + } + + mShadowChild_c *childPtr; + if (mFreeChildIdx < mChildCount && (!isMdl || mFreeTexIdx < mNumTexBuffers)) { + // There are free entries in our buffer, so just add a new child + childPtr = &mpChilds[mFreeChildIdx]; + if (mFreeChildIdx++ == 0) { + entry(); + } + + if (isMdl) { + mFreeTexIdx++; + } + } else { + // There are no free entries in our buffer, so replace an existing entry? + childPtr = static_cast(nw4r::ut::List_GetLast(&mList)); + if (priority >= childPtr->mPriorityMaybe) { + return false; + } + + if (isMdl) { + if (mFreeTexIdx >= mNumTexBuffers) { + while (childPtr->mNumLeaves == 0) { + childPtr = static_cast(nw4r::ut::List_GetPrev(&mList, childPtr)); + if (priority >= childPtr->mPriorityMaybe) { + return false; + } + } + } else { + mFreeTexIdx++; + } + } + childPtr->mNumLeaves = 0; + childPtr->mpCircle->mpChild = nullptr; + nw4r::ut::List_Remove(&mList, childPtr); + } + + circle->mpChild = childPtr; + childPtr->mpCircle = circle; + childPtr->mPriorityMaybe = priority; + mShadowChild_c *iter = static_cast(nw4r::ut::List_GetFirst(&mList)); + if (iter == nullptr) { + nw4r::ut::List_Append(&mList, childPtr); + return true; + } else { + do { + if (childPtr->mPriorityMaybe < iter->mPriorityMaybe) { + nw4r::ut::List_Insert(&mList, iter, childPtr); + return true; + } + iter = static_cast(nw4r::ut::List_GetNext(&mList, iter)); + } while (iter != nullptr); + nw4r::ut::List_Append(&mList, childPtr); + } + + return true; +} + +bool mShadow_c::drawMdl(mShadowCircle_c *circle, u32 priority, scnLeaf_c &mdl, const mQuat_c &quat, mVec3_c &pos, + mColor color, u32 param9, f32 dist) { + if (!addCircle(circle, priority, 1)) { + return false; + } + + mShadowChild_c *child = circle->mpChild; + child->set(pos, dist, color); + child->set0x154(param9); + return child->addMdl(mdl, quat); +} + +bool mShadow_c::addMdlToCircle(mShadowCircle_c *circle, scnLeaf_c &mdl, const mQuat_c &quat) { + if (circle->mpChild == nullptr) { + return false; + } + return circle->mpChild->addMdl(mdl, quat); +} + +void mShadow_c::removeCircle(mShadowCircle_c *circle) { + mShadowChild_c *child = circle->mpChild; + if (child == nullptr) { + return; + } + circle->mpChild = nullptr; + child->mpCircle = nullptr; + nw4r::ut::List_Remove(&mList, child); +} + +static f32 sTexMtx[2][4] = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}}; + +static u32 STEP = 0x2492; + +static GXColor sColors[] = { + {0xFF, 0x00, 0x00, 0x00}, + {0x00, 0xFF, 0x00, 0x00}, + {0x00, 0x00, 0xFF, 0x00}, + {0x00, 0x00, 0x00, 0x00}, +}; + +bool mShadow_c::drawTexObj(mShadowCircle_c *circle, u32 priority, const GXTexObj *texObj, const mMtx_c &mtx, + const mQuat_c &quat, mVec3_c &pos, mColor color, u32 param9, f32 dist) { + if (!addCircle(circle, priority, 0)) { + return false; + } + + mShadowChild_c *child = circle->mpChild; + child->set(pos, dist, color); + child->set0x154(param9); + return child->setGeom(texObj, mtx, quat); +} + +static void drawSub2(void *data, u8 i) { + s16 ang; + u32 wid = i * 2; + GXSetTexCopySrc(0, 0, wid, wid); + GXSetTexCopyDst(i, i, GX_TF_RGB565, 1); + GXCopyTex(data, false); + GXPixModeSync(); + GXInvalidateTexAll(); + GXTexObj obj; + GXInitTexObj(&obj, data, i, i, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, 0); + GXInitTexObjLOD(&obj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1); + GXLoadTexObj(&obj, GX_TEXMAP0); + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBX8, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U8, 0); + GXSetNumChans(0); + GXSetNumTexGens(8); + GXSetNumTevStages(8); + GXSetTevColor(GX_TEVREG1, nw4r::ut::Color(0, 0, 0, 0x20)); + ang = 0; + for (int id = GX_TEXCOORD0, idx = GX_TEXMTX0; id < GX_MAX_TEXCOORD; + id += 1, idx += (GX_TEXMTX1 - GX_TEXMTX0), ang += STEP) { + GXSetTexCoordGen2((GXTexCoordID)id, GX_TG_MTX2x4, GX_TG_TEX0, idx, FALSE, GX_DUALMTX_IDENT); + sTexMtx[0][3] = 0.01f * nw4r::math::CosIdx(ang); + sTexMtx[1][3] = 0.01f * nw4r::math::SinIdx(ang); + GXLoadTexMtxImm(sTexMtx, idx, GX_MTX_2x4); + } + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_A0, GX_CC_ZERO); + + for (int id = GX_TEVSTAGE1; id < GX_TEVSTAGE8; id++) { + GXSetTevSwapMode((GXTevStageID)id, GX_TEV_SWAP0, GX_TEV_SWAP0); + GXSetTevOrder((GXTevStageID)id, (GXTexCoordID)id, GX_TEXMAP0, GX_COLOR_NULL); + GXSetTevColorIn((GXTevStageID)id, GX_CC_ZERO, GX_CC_TEXC, GX_CC_A1, GX_CC_CPREV); + GXSetTevColorOp((GXTevStageID)id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GXSetTevAlphaIn((GXTevStageID)id, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO); + GXSetTevAlphaOp((GXTevStageID)id, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + } + GXSetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_SET); + GXLoadPosMtxImm(mMtx_c::Identity, 0); + GXSetCurrentMtx(0); + + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + + GXPosition2u16(0, 0); + GXPosition2u8(0, 0); + + GXPosition2u16(wid, 0); + GXPosition2u8(1, 0); + + GXPosition2u16(wid, wid); + GXPosition2u8(1, 1); + + GXPosition2u16(0, wid); + GXPosition2u8(0, 1); + // GXEnd(); +} + +static void drawSub1(void *data, u8 i) { + Mtx44 mtx; + u16 wid = i * 2; + f32 wid2 = i * 2; + C_MTXOrtho(mtx, 0.0f, wid2, 0.0f, wid2, 0.0f, 1.0f); + GXSetProjection(mtx, GX_ORTHOGRAPHIC); + drawSub2(data, i); + GXSetNumChans(1); + GXSetNumTexGens(0); + GXSetNumTevStages(1); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO); + + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + + GXBegin(GX_LINESTRIP, GX_VTXFMT0, 5); + GXPosition2u16(0, 0); + GXPosition2u16(wid, 0); + GXPosition2u16(wid, wid); + GXPosition2u16(0, wid); + GXPosition2u16(0, 0); + // GXEnd(); + + GXSetZMode(true, GX_ALWAYS, true); + GXSetTexCopySrc(0, 0, wid, wid); + GXSetTexCopyDst(i, i, GX_TF_RGB565, 1); + GXCopyTex(data, true); + GXPixModeSync(); + GXInvalidateTexAll(); +} + +void mShadow_c::drawAllShadows() { + mShadowChild_c *iter = static_cast(nw4r::ut::List_GetFirst(&mList)); + if (iter != nullptr) { + f32 wid = mTexSize * 2; + u16 wid2 = mTexSize * 2; + GXSetViewport(0.0f, 0.0f, wid, wid, 0.0f, 1.0f); + GXSetScissor(0, 0, wid2, wid2); + GXSetScissorBoxOffset(0, 0); + GXLoadTexObj(mShadow_c::sTexObj, GX_TEXMAP1); + GXSetNumChans(1); + GXSetChanCtrl(GX_COLOR0A0, false, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + GXSetNumTexGens(0); + GXSetNumTevStages(1); + GXSetNumIndStages(0); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO); + GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO); + GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GXSetZCompLoc(1); + GXSetBlendMode(GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_SET); + GXSetZMode(false, GX_ALWAYS, false); + GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0); + GXColor clr = {0}; + GXSetFog(GX_FOG_NONE, clr, 0.0f, 0.0f, 0.0f, 0.0f); + GXSetFogRangeAdj(0, 0, 0); + GXSetCullMode(GX_CULL_BACK); + GXSetDither(0); + GXSetClipMode(GX_CLIP_DISABLE); + GXLoadPosMtxImm(mMtx_c::Identity.m, 0); + GXSetCurrentMtx(0); + Mtx44 mtx; + C_MTXOrtho(mtx, 0.0f, wid, 0.0f, wid, 0.0f, 1.0f); + GXSetProjection(mtx, GX_ORTHOGRAPHIC); + GXSetLineWidth(0x18, 0); + int i = 0; + void *imgData = mpTexBuf; + do { + iter->updateMtx(); + if (iter->mNumLeaves != 0) { + if (i == 0) { + GXClearVtxDesc(); + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_U16, 0); + GXBegin(GX_QUADS, GX_VTXFMT0, 4); + GXPosition2u16(0, 0); + GXPosition2u16(wid2, 0); + GXPosition2u16(wid2, wid2); + GXPosition2u16(0, wid2); + // GXEnd(); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0); + GXSetBlendMode(GX_BM_LOGIC, GX_BL_ONE, GX_BL_ONE, GX_LO_OR); + } + iter->mColorChanIdx = i; + GXInitTexObj(&iter->mTexObj, imgData, mTexSize, mTexSize, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, false); + GXInitTexObjLOD(&iter->mTexObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1); + iter->drawMdl(); + i = (i + 1) % 3; + if (i == 0) { + drawSub1(imgData, mTexSize); + imgData = (void *)((u8 *)imgData + mTexBufferSize); + } + } + iter = static_cast(nw4r::ut::List_GetNext(&mList, iter)); + } while (iter != nullptr); + + if (i != 0) { + drawSub1(imgData, mTexSize); + } + + GXSetClipMode(GX_CLIP_ENABLE); + GXSetDither(true); + nw4r::g3d::G3DState::Invalidate(0x7FF); + } +} + +void mShadow_c::create(const mShadowCircleConfig *config, nw4r::g3d::ResMdl mdl, EGG::Heap *heap) { + mShadow_c::sInstance = new (heap, 0x04) mShadow_c(heap); + mShadow_c::sInstance->create(config->count, config->unk1, config->unk2, config->texBufferSize, + config->drawOpaPriority, mdl, config->heapSize); +} + +void mShadow_c::beforeDraw() { + if (mpCallback != nullptr) { + mpCallback->beforeDraw(); + } +} + +void mShadow_c::draw(const mMtx_c &mtx, u32 unk) { + if (mpCallback != nullptr) { + mpCallback->draw(mtx, unk); + } +} + +void mShadow_c::afterDraw() { + if (mpCallback != nullptr) { + mpCallback->afterDraw(); + } +} + +void mShadow_c::swapHeaps() { + changeHeap(mCurrentHeapIdx + 1); + mpCurrentHeap->freeState(FRM_HEAP_STATE); + mpCurrentHeap->recordState(FRM_HEAP_STATE); +} + +void mShadow_c::destroy() { + if (mShadow_c::sInstance != nullptr) { + mShadow_c::sInstance->remove(); + delete mShadow_c::sInstance; + mShadow_c::sInstance = nullptr; + } +} + +mShadowChild_c::~mShadowChild_c() { + if (mpCircle != nullptr) { + mpCircle->mpChild = nullptr; + mpCircle = nullptr; + } + + if (mpLeaves != nullptr) { + mpHeap->free(mpLeaves); + mpLeaves = nullptr; + } +} + +bool mShadowChild_c::create(u8 maxNum, EGG::Heap *heap) { + if ((mpLeaves = static_cast(heap->alloc(maxNum * sizeof(scnLeaf_c *), 0x04))) == nullptr) { + return false; + } + mpHeap = heap; + mMaxNumLeaves = maxNum; + return true; +} + +void mShadowChild_c::set(const mVec3_c &pos, f32 dist, mColor color) { + mPositionMaybe = pos; + mOffsetMaybe = dist; + mShadowColor = color; +} + +bool mShadowChild_c::addMdl(scnLeaf_c &mdl, const mQuat_c &quat) { + if (!(mNumLeaves < mMaxNumLeaves)) { + return false; + } + + mMtx_c mtx; + if (mdl.getType() == 0) { + mdl.getLocalMtx(mtx); + } else { + mtx = static_cast(mdl).mMtx; + } + + // TODO this copy is a bit weird (reads members in a different order) + mQuat_c q = quat; + PSMTXMultVec(mtx.m, q, q); + + if (mNumLeaves == 0) { + mQuat = q; + } else { + mQuat.fn_802F2780(q); + } + mpLeaves[mNumLeaves++] = &mdl; + return true; +} + +bool mShadowChild_c::setGeom(const GXTexObj *texObj, const mMtx_c &mtx, const mQuat_c &quat) { + mQuat = quat; + PSMTXMultVec(mtx.m, mQuat, mQuat); + if (texObj == nullptr) { + mTexObj = *mShadow_c::sTexObj; + } else { + mTexObj = *texObj; + } + return true; +} + +void mShadowChild_c::updateMtx() { + // TODO all of this is broken + mVec3_c a = *(mVec3_c *)(&mQuat) + mPositionMaybe * mOffsetMaybe; + mVec3_c b = *(mVec3_c *)(&mQuat) - mPositionMaybe * field_0x13C; + mMtx_c mtx; + C_MTXLookAt(mtx.m, b, + *(fabsf((a.x - b.x) * (a.x - b.x) + (a.z - b.z) * (a.z - b.z)) <= FLT_EPSILON ? &mVec3_c::Ez : + &mVec3_c::Ey), + a); + f32 f = field_0x13C; + mFrustum.set(f, -f, -f, f, f, f + mOffsetMaybe, mtx, true); +} + +void mShadowChild_c::drawMdl() { + // TODO maybe roughly equivalent + using namespace nw4r; + mMtx_c mtx; + GXSetTevColor(GX_TEVREG0, sColors[mColorChanIdx]); + C_MTXOrtho(mtx.m, field_0x13C, -field_0x13C, -field_0x13C, field_0x13C, 0.0f, 100.0f + (-mFrustum.mFar)); + GXSetProjection(mtx.m, GX_ORTHOGRAPHIC); + g3d::G3DState::Invalidate(0x7FF); + + for (scnLeaf_c **leaf = &mpLeaves[mNumLeaves - 1]; leaf >= &mpLeaves[0]; leaf--) { + scnLeaf_c *lf = *leaf; + if (lf->getType() == 0 /* Model */) { + g3d::ScnMdlSimple *mdl = g3d::G3dObj::DynamicCast(lf->getG3dObject()); + + u32 bufSize = mdl->GetNumViewMtx() * sizeof(math::MTX34); + math::MTX34 *viewPosArray = static_cast(mShadow_c::sInstance->mpHeap->alloc(bufSize, 0x20)); + + g3d::CalcView(viewPosArray, nullptr, mdl->GetWldMtxArray(), mdl->GetWldMtxAttribArray(), + mdl->GetNumViewMtx(), mFrustum.mView, mdl->GetResMdl(), nullptr); + DCStoreRange(viewPosArray, bufSize); + + g3d::ScnMdl *mdl2 = g3d::G3dObj::DynamicCast(lf->getG3dObject()); + + g3d::DrawResMdlReplacement *pRep = mdl2 ? mdl2->GetDrawResMdlReplacement() : nullptr; + + g3d::DrawResMdlDirectly(mdl->GetResMdl(), viewPosArray, nullptr, nullptr, + mdl2->GetByteCode(g3d::ScnMdlSimple::BYTE_CODE_DRAW_OPA), nullptr, pRep, + g3d::RESMDL_DRAWMODE_FORCE_LIGHTOFF | g3d::RESMDL_DRAWMODE_IGNORE_MATERIAL); + GXInvalidateVtxCache(); + } else { + // this happens with bomb bag, and goes to 0x802EDC90 (mCustomShadow_c::draw) + static_cast(lf)->draw(mFrustum.mView); + } + } +} + +static GXTevColorChan sChans[] = {GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA}; + +void mShadowChild_c::draw() { + if (mNumLeaves != 0) { + GXTevColorChan chan = sChans[mColorChanIdx]; + GXSetTevSwapModeTable(GX_TEV_SWAP0, chan, chan, chan, chan); + } else { + GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + } + GXLoadTexObj(&mTexObj, GX_TEXMAP0); + GXSetTevColor(GX_TEVREG0, mShadowColor); + Mtx mtx; + C_MTXLightOrtho(mtx, field_0x13C, -field_0x13C, -field_0x13C, field_0x13C, 0.5f, -0.5f, 0.5f, 0.5f); + PSMTXConcat(mtx, mFrustum.mView.m, mtx); + GXLoadTexMtxImm(mtx, GX_TEXMTX0, GX_MTX_3x4); + mShadow_c::sInstance->draw(mFrustum.mView, field_0x154); + GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); +} + +mShadowCircle_c::~mShadowCircle_c() { + mShadow_c::sInstance->removeCircle(this); +} + +mCustomShadow_c::~mCustomShadow_c() {} + +int mCustomShadow_c::getType() const { + return 0x2; +} + +void mCustomShadow_c::draw(const mMtx_c &arg) { + nw4r::g3d::G3DState::Invalidate(0x7FF); + GXSetNumTexGens(1); + GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3C, false, 0x7D); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP1, GX_COLOR_NULL); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_C0, GX_CC_TEXC, GX_CC_ZERO); + + mMtx_c result; + calc(arg, result); + static nw4r::g3d::ResMat nullMat(nullptr); + + nw4r::g3d::Draw1Mat1ShpDirectly(nullMat, mShadow_c::sResShp, result, result, 0x18, nullptr, nullptr); + GXSetNumTexGens(0); + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0); +} + +void mCustomShadow_c::calc(mMtx_c mtx, mMtx_c &mtx2) { + // TODO some shuffles + + mVec3_c trans; + mtx2 = mMtx; + mVec3_c offset(0.0f, 0.0f, 0.0f); + offset.y = field_0x48; + PSMTXMultVec(mtx2, offset, trans); + PSMTXMultVec(mtx, trans, trans); + + PSMTXTrans(mtx2, trans.x, trans.y, trans.z); + + mMtx_c scaleMtx; + PSMTXScale(scaleMtx, field_0x4C, field_0x4C, field_0x4C); + PSMTXConcat(mtx2, scaleMtx, mtx2); +} + +} // namespace m3d