From 1661ab219fd9d27165c5edc4cfd2178274cfb646 Mon Sep 17 00:00:00 2001 From: robojumper Date: Wed, 19 Mar 2025 00:27:22 +0100 Subject: [PATCH] DrawGX almost completely matching --- config/SOUE01/splits.txt | 6 +- config/SOUE01/symbols.txt | 24 +- include/egg/gfx/eggDrawGX.h | 83 +++++- include/egg/gfx/eggGXUtility.h | 15 +- src/egg/gfx/eggDrawGX.cpp | 487 ++++++++++++++++++++++++++++++++- 5 files changed, 594 insertions(+), 21 deletions(-) diff --git a/config/SOUE01/splits.txt b/config/SOUE01/splits.txt index 278dda93..1f60685e 100644 --- a/config/SOUE01/splits.txt +++ b/config/SOUE01/splits.txt @@ -2191,8 +2191,12 @@ egg/gfx/eggCpuTexture.cpp: egg/gfx/eggDrawGX.cpp: .text start:0x8049ECA0 end:0x804A0C24 .ctors start:0x804DB998 end:0x804DB99C + .rodata start:0x804FBA60 end:0x804FBC58 .data start:0x8056EDA0 end:0x8056EE60 - .sdata2 start:0x8057F440 end:0x8057F584 + .sdata start:0x80574F18 end:0x80574F20 + .sbss start:0x80576808 end:0x80576810 + .sdata2 start:0x8057F440 end:0x8057F538 + .bss start:0x80674D68 end:0x80674E48 egg/gfx/eggDrawPathBase.cpp: .text start:0x804A0C30 end:0x804A0E98 diff --git a/config/SOUE01/symbols.txt b/config/SOUE01/symbols.txt index feea3c5c..610e51e7 100644 --- a/config/SOUE01/symbols.txt +++ b/config/SOUE01/symbols.txt @@ -10523,7 +10523,7 @@ __ct__11dStageMgr_cFv = .text:0x80197730; // type:function size:0x39C fn_80197AD0 = .text:0x80197AD0; // type:function size:0x4C fn_80197B20 = .text:0x80197B20; // type:function size:0x54 __dt__Q23EGG6ScreenFv = .text:0x80197B80; // type:function size:0x40 -fn_80197BC0 = .text:0x80197BC0; // type:function size:0x40 +__dt__Q23EGG7FrustumFv = .text:0x80197BC0; // type:function size:0x40 fn_80197C00 = .text:0x80197C00; // type:function size:0x64 fn_80197C70 = .text:0x80197C70; // type:function size:0x5C __dt__22sFPhase<11dStageMgr_c>Fv = .text:0x80197CD0; // type:function size:0x58 @@ -26460,8 +26460,8 @@ BeginDrawLine__Q23EGG6DrawGXFQ33EGG6DrawGX12ColorChannelQ33EGG6DrawGX5ZMode = .t BeginDrawCircleZ__Q23EGG6DrawGXFQ33EGG6DrawGX12ColorChannelQ33EGG6DrawGX5ZMode = .text:0x8049F1C0; // type:function size:0x78 BeginDrawQuad__Q23EGG6DrawGXFQ33EGG6DrawGX12ColorChannelQ33EGG6DrawGX5ZModeQ33EGG6DrawGX5Blendbb = .text:0x8049F240; // type:function size:0xDC BeginDrawScreen__Q23EGG6DrawGXFbbb = .text:0x8049F320; // type:function size:0xE0 -DrawLineStrip__Q23EGG6DrawGXFPCQ23EGG8Vector3fUs7GXColorUc = .text:0x8049F400; // type:function size:0x1EC -DrawLine__Q23EGG6DrawGXFPCQ23EGG8Vector3fUs7GXColorUc = .text:0x8049F5F0; // type:function size:0x1EC +DrawLine__Q23EGG6DrawGXFPCQ23EGG8Vector3fUs8_GXColorUc = .text:0x8049F400; // type:function size:0x1EC +DrawLineStrip__Q23EGG6DrawGXFPCQ23EGG8Vector3fUs8_GXColorUc = .text:0x8049F5F0; // type:function size:0x1EC ClearEfb__Q23EGG6DrawGXFRCQ34nw4r4math5MTX34bbb8_GXColorb = .text:0x8049F7E0; // type:function size:0x264 ResetMaterial__Q23EGG6DrawGXFQ33EGG6DrawGX12ColorChannel = .text:0x8049FA50; // type:function size:0x64 SetMat_ColorChannel__Q23EGG6DrawGXFQ33EGG6DrawGX12ColorChannel = .text:0x8049FAC0; // type:function size:0xD8 @@ -26476,7 +26476,7 @@ CreateDisplayList__Q23EGG6DrawGXFPQ23EGG4Heap = .text:0x804A02E0; // type:functi DrawDL__Q23EGG6DrawGXFQ33EGG6DrawGX2DLRCQ34nw4r4math5MTX348_GXColor = .text:0x804A0AE0; // type:function size:0x88 SetZMode__Q23EGG6DrawGXFQ33EGG6DrawGX5ZMode = .text:0x804A0B70; // type:function size:0x20 SetBlendMode__Q23EGG6DrawGXFQ33EGG6DrawGX5Blend = .text:0x804A0B90; // type:function size:0x24 -DrawDLWorld__Q23EGG6DrawGXFQ33EGG6DrawGX2DLRCQ23EGG9Matrix34f7GXColor = .text:0x804A0BC0; // type:function size:0x5C +DrawDLWorld__Q23EGG6DrawGXFQ33EGG6DrawGX2DLRCQ23EGG9Matrix34f8_GXColor = .text:0x804A0BC0; // type:function size:0x5C __sinit_\eggDrawGX_cpp = .text:0x804A0C20; // type:function size:0x4 scope:local __ct__Q23EGG12DrawPathBaseFv = .text:0x804A0C30; // type:function size:0x58 createScnProc__Q23EGG12DrawPathBaseFP12MEMAllocator = .text:0x804A0C90; // type:function size:0x1B0 @@ -29160,9 +29160,9 @@ gRMO_Ntsc_640x456IntDf_4x3__22@unnamed@eggVideo_cpp@ = .rodata:0x804FB9BC; // ty renderModes__3EGG = .rodata:0x804FB9F8; // type:object size:0x28 scope:local @4804 = .rodata:0x804FBA20; // type:object size:0x10 scope:local data:4byte copyArg2__3EGG = .rodata:0x804FBA30; // type:object size:0x18 -lbl_804FBA60 = .rodata:0x804FBA60; // type:object size:0xD8 -lbl_804FBB38 = .rodata:0x804FBB38; // type:object size:0x30 -lbl_804FBB68 = .rodata:0x804FBB68; // type:object size:0xF0 +sVtxTypes__3EGG = .rodata:0x804FBA60; // type:object size:0x10 +s_ZMode__Q23EGG6DrawGX = .rodata:0x804FBB38; // type:object size:0x30 +s_Blend__Q23EGG6DrawGX = .rodata:0x804FBB68; // type:object size:0xF0 lbl_804FBC58 = .rodata:0x804FBC58; // type:object size:0x18 lbl_804FBC70 = .rodata:0x804FBC70; // type:object size:0xC lbl_804FBC7C = .rodata:0x804FBC7C; // type:object size:0xC @@ -39824,7 +39824,7 @@ sWPADWorkSize__Q23EGG17CoreControllerMgr = .sdata:0x80574EE8; // type:object siz @3877 = .sdata:0x80574F00; // type:object size:0x8 scope:local data:string @3879 = .sdata:0x80574F08; // type:object size:0x8 scope:local data:string @3880 = .sdata:0x80574F10; // type:object size:0x7 scope:local data:string -EGG__DrawGX__sLightMaskDefault = .sdata:0x80574F18; // type:object size:0x8 data:4byte +sLightMaskDefault__Q23EGG6DrawGX = .sdata:0x80574F18; // type:object size:0x4 data:4byte lbl_80574F20 = .sdata:0x80574F20; // type:object size:0x8 lbl_80574F28 = .sdata:0x80574F28; // type:object size:0x4 lbl_80574F2C = .sdata:0x80574F2C; // type:object size:0x4 data:4byte @@ -41148,7 +41148,7 @@ sPtrOverride__Q23EGG6Assert = .sbss:0x80576800; // type:object size:0x4 data:4by sInstantHalt__Q23EGG6Assert = .sbss:0x80576804; // type:object size:0x1 data:byte sAssertOccurred__Q23EGG6Assert = .sbss:0x80576805; // type:object size:0x1 data:byte s_flag__Q23EGG6DrawGX = .sbss:0x80576808; // type:object size:0x4 data:4byte -EGG__DrawGX__sTexMapDefault = .sbss:0x8057680C; // type:object size:0x4 data:4byte +sTexMapDefault__Q23EGG6DrawGX = .sbss:0x8057680C; // type:object size:0x4 data:4byte EGG__Frustum__sGlobalScale = .sbss:0x80576810; // type:object size:0x4 data:float EGG__Frustum__sGlobalOffset = .sbss:0x80576818; // type:object size:0x4 data:float lbl_80576820 = .sbss:0x80576820; // type:object size:0x1 data:byte @@ -48020,7 +48020,7 @@ BLACK__Q23EGG6DrawGX = .sdata2:0x8057F440; // type:object size:0x4 data:4byte WHITE__Q23EGG6DrawGX = .sdata2:0x8057F444; // type:object size:0x4 data:4byte RED__Q23EGG6DrawGX = .sdata2:0x8057F448; // type:object size:0x4 data:4byte GREEN__Q23EGG6DrawGX = .sdata2:0x8057F44C; // type:object size:0x4 data:4byte -BLUE__Q23EGG6DrawGX = .sdata2:0x8057F450; // type:object size:0x8 data:4byte +BLUE__Q23EGG6DrawGX = .sdata2:0x8057F450; // type:object size:0x4 data:4byte lbl_8057F458 = .sdata2:0x8057F458; // type:object size:0x8 data:4byte lbl_8057F460 = .sdata2:0x8057F460; // type:object size:0x4 data:float lbl_8057F464 = .sdata2:0x8057F464; // type:object size:0x4 data:float @@ -49798,8 +49798,8 @@ ey__Q23EGG8Vector3f = .bss:0x80674C48; // type:object size:0xC data:float ez__Q23EGG8Vector3f = .bss:0x80674C54; // type:object size:0xC data:float buf__Q23EGG6Assert = .bss:0x80674C60; // type:object size:0x104 s_DL__Q23EGG6DrawGX = .bss:0x80674D68; // type:object size:0x90 -sCameraMtx = .bss:0x80674DF8; // type:object size:0x30 data:float -lbl_80674E28 = .bss:0x80674E28; // type:object size:0x20 +s_cameraMtx__Q23EGG6DrawGX = .bss:0x80674DF8; // type:object size:0x30 data:float +sDummyTexObj__Q23EGG6DrawGX = .bss:0x80674E28; // type:object size:0x20 sMtx__Q23EGG15GlobalDrawState = .bss:0x80674E48; // type:object size:0x30 CPU_TEX_ARR = .bss:0x80674E78; // type:object size:0x48 data:4byte sMtx__3EGG = .bss:0x80674EC0; // type:object size:0x30 data:float diff --git a/include/egg/gfx/eggDrawGX.h b/include/egg/gfx/eggDrawGX.h index b7a4d10c..6854ab50 100644 --- a/include/egg/gfx/eggDrawGX.h +++ b/include/egg/gfx/eggDrawGX.h @@ -5,6 +5,10 @@ #include "egg/core/eggHeap.h" #include "egg/gfx/eggTexture.h" #include "egg/math/eggMatrix.h" +#include "nw4r/g3d/res/g3d_restex.h" +#include "nw4r/math/math_types.h" +#include "rvl/GX/GXTexture.h" +#include "rvl/GX/GXTypes.h" #include "rvl/GX.h" // IWYU pragma: export @@ -12,12 +16,28 @@ namespace EGG { class DrawGX { public: + DrawGX() {} // made up struct DLData { u8 *mpList; u32 mLen; }; + // made up, stride 0xC + struct ZModeConfig { + bool mTest; + GXCompare mCompare; + bool mUpdate; + }; + + // made up, stride 0x10 + struct BlendModeConfig { + GXBlendMode mBlendMode; + GXBlendFactor mBlendFactorSrc; + GXBlendFactor mBlendFactorDst; + GXLogicOp mLogicOp; + }; + enum DL { DL_0, DL_1, @@ -78,21 +98,78 @@ public: BLEND_MAX }; + enum ZMode { + ZMODE_0, + ZMODE_1, + ZMODE_2, + ZMODE_3, + + ZMODE_MAX, + }; + + enum TevSetting { + TEV_0, + TEV_1, + TEV_2, + }; + + enum TexGen { + TEXGEN_0, + TEXGEN_1, + }; + + enum ColorChannel { + COLORCHAN_0, + COLORCHAN_1, + }; + static void Initialize(Heap *); static GXTexMapID GetTexMapDefault(); - static void LoadTexture(const EGG::ResTIMG *, GXTexMapID); + static GXLightID GetLightMaskDefault(); + + static void BeginDrawLine(ColorChannel, ZMode); + static void BeginDrawCircleZ(ColorChannel, ZMode); + static void BeginDrawQuad(ColorChannel, ZMode, Blend, bool, bool); static void BeginDrawScreen(bool, bool, bool); - static void CreateDisplayList(EGG::Heap*); + + static void DrawLineStrip(const EGG::Vector3f *, u16, GXColor, u8); + static void DrawLine(const EGG::Vector3f *, u16, GXColor, u8); + static void ClearEfb(const nw4r::math::MTX34 &, bool, bool, bool, GXColor, bool); + static void ResetMaterial(enum ColorChannel); + static void SetMat_ColorChannel(enum ColorChannel); + static void SetMat_TexGen(enum TexGen); + static void SetMat_Ind(); + static void SetMat_Tev(GXTevStageID, enum TevSetting); + static void SetMat_PE(enum ZMode, enum Blend); + + static void LoadTexture(const EGG::ResTIMG *, GXTexMapID); + static void LoadTexture(nw4r::g3d::ResTex, GXTexMapID); + + static void CreateDisplayList(EGG::Heap *); static void DrawDL(enum DL, const nw4r::math::MTX34 &, GXColor); static void SetVtxState(enum VtxType); + static void SetZMode(enum ZMode); static void SetBlendMode(enum Blend); + static void DrawDLWorld(DL dl, const EGG::Matrix34f& mtx, GXColor color); // TODO MORE + // not sure static DLData s_DL[DL_MAX]; + static const DL s_DL0; + static const DL s_DL7; + static const DL s_DL8; - static Matrix34f s_cameraMtx; + static const ZModeConfig s_ZMode[ZMODE_MAX]; + static const BlendModeConfig s_Blend[BLEND_MAX]; + static GXTexObj sDummyTexObj; + // not sure end + + static GXTexMapID sTexMapDefault; + static GXLightID sLightMaskDefault; + + static nw4r::math::MTX34 s_cameraMtx; static u32 s_flag; diff --git a/include/egg/gfx/eggGXUtility.h b/include/egg/gfx/eggGXUtility.h index d36dfff1..daf49239 100644 --- a/include/egg/gfx/eggGXUtility.h +++ b/include/egg/gfx/eggGXUtility.h @@ -1,6 +1,19 @@ #ifndef EGG_GX_UTILITY_H #define EGG_GX_UTILITY_H -namespace EGG {} // namespace EGG +#include "egg/gfx/eggTexture.h" +#include "nw4r/g3d/res/g3d_restex.h" +#include "rvl/GX/GXTexture.h" + +namespace EGG { + +class GXUtility { +public: + static int getTexMtxID(int); + static void getTexObj(GXTexObj *, const EGG::ResTIMG &); + static void getTexObj(_GXTexObj *, nw4r::g3d::ResTex, GXTexWrapMode, GXTexWrapMode, GXTexFilter, GXTexFilter); +}; + +} // namespace EGG #endif diff --git a/src/egg/gfx/eggDrawGX.cpp b/src/egg/gfx/eggDrawGX.cpp index d575781c..5b80bb56 100644 --- a/src/egg/gfx/eggDrawGX.cpp +++ b/src/egg/gfx/eggDrawGX.cpp @@ -1,13 +1,21 @@ #include "egg/gfx/eggDrawGX.h" #include "common.h" +#include "egg/gfx/eggGXUtility.h" +#include "egg/gfx/eggStateGX.h" #include "math.h" +#include "nw4r/g3d/res/g3d_restex.h" #include "nw4r/math/math_triangular.h" #include "nw4r/math/math_types.h" +#include "rvl/GX/GXAttr.h" +#include "rvl/GX/GXBump.h" #include "rvl/GX/GXDisplayList.h" #include "rvl/GX/GXDraw.h" #include "rvl/GX/GXGeometry.h" #include "rvl/GX/GXLight.h" +#include "rvl/GX/GXPixel.h" +#include "rvl/GX/GXTev.h" +#include "rvl/GX/GXTexture.h" #include "rvl/GX/GXTransform.h" #include "rvl/GX/GXTypes.h" #include "rvl/GX/GXVert.h" @@ -16,6 +24,29 @@ #include "rvl/MTX/vec.h" #include "rvl/OS/OSCache.h" +namespace EGG { + +const GXColor DrawGX::BLACK = {0x00, 0x00, 0x00, 0xFF}; +const GXColor DrawGX::WHITE = {0xFF, 0xFF, 0xFF, 0xFF}; +const GXColor DrawGX::RED = {0xFF, 0x00, 0x00, 0xFF}; +const GXColor DrawGX::GREEN = {0x00, 0xFF, 0x00, 0xFF}; +const GXColor DrawGX::BLUE = {0x00, 0x00, 0xFF, 0xFF}; + +const DrawGX::DL DrawGX::s_DL0 = DrawGX::DL_0; +const DrawGX::DL DrawGX::s_DL7 = DrawGX::DL_7; +const DrawGX::DL DrawGX::s_DL8 = DrawGX::DL_8; + +GXTexMapID DrawGX::sTexMapDefault; +GXLightID DrawGX::sLightMaskDefault = GX_LIGHT0; + +nw4r::math::MTX34 DrawGX::s_cameraMtx; +DrawGX::DLData DrawGX::s_DL[DL_MAX]; +GXTexObj DrawGX::sDummyTexObj; + +u32 DrawGX::s_flag; + +}; // namespace EGG + namespace { static void DrawQuadNormal(u8 x1, u8 x2, u8 x3, u8 x4, u8 y) { @@ -35,10 +66,10 @@ static void DrawQuadLineStripNormal(u8 x1, u8 x2, u8 x3, u8 x4, u8 y) { } static void DrawCircleYPolygonFan(const nw4r::math::MTX34 &mtx, f32 f, u16 numSegments) { + f32 stepSize = (2.0f * M_PI / numSegments); nw4r::math::VEC3 v1(0.0f, 1.0f, 0.0f); nw4r::math::VEC3 v2(0.0f, f, 0.0f); - f32 stepSize = (2.0f * M_PI / numSegments); int seg = numSegments + 1; PSMTXMultVec(mtx, v1, v1); @@ -70,8 +101,8 @@ static void DrawCircleYPolygonFan(const nw4r::math::MTX34 &mtx, f32 f, u16 numSe PSMTXMultVec(mtx, v4, v4); PSMTXMultVec(mtx, v5, v5); - v4 -= v2; - v5 -= v2; + nw4r::math::VEC3Sub(&v4, &v4, &v2); + nw4r::math::VEC3Sub(&v5, &v5, &v2); nw4r::math::VEC3 v6; PSVECCrossProduct(v5, v4, v6); @@ -85,7 +116,413 @@ static void DrawCircleYPolygonFan(const nw4r::math::MTX34 &mtx, f32 f, u16 numSe namespace EGG { -u8 sDetailLevels[] = {10, 20}; +static DrawGX sDrawGX; + +static u8 DummyTextureData[64] = { + // clang-format off +0x00, 0xFF, 0x00, 0xFF, +0x00, 0xFF, 0x00, 0xFF, +0x00, 0xFF, 0x00, 0xFF, +0x00, 0xFF, 0x00, 0xFF, +0x00, 0xFF, 0x00, 0xFF, +0x00, 0xFF, 0x00, 0xFF, +0x00, 0xFF, 0x00, 0xFF, +0x00, 0xFF, 0x00, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, +0xFF, 0xFF, 0xFF, 0xFF, + // clang-format on +}; + +void DrawGX::Initialize(Heap *pHeap_) { + 2.0f; // cool + Heap *pHeap = pHeap_ == nullptr ? Heap::getCurrentHeap() : pHeap_; + + GXInitTexObj(&sDummyTexObj, DummyTextureData, 4, 4, GX_TF_Z24X8, GX_REPEAT, GX_REPEAT, false); + GXInitTexObjLOD(&sDummyTexObj, GX_NEAR, GX_NEAR, 0.0, 0.0, 0.0, 0, 0, GX_ANISO_1); + PSMTXIdentity(s_cameraMtx.m); + CreateDisplayList(pHeap); +} + +GXTexMapID DrawGX::GetTexMapDefault() { + return sTexMapDefault; +} +GXLightID DrawGX::GetLightMaskDefault() { + return sLightMaskDefault; +} + +void DrawGX::BeginDrawLine(ColorChannel chan, ZMode zMode) { + SetMat_ColorChannel(chan); + SetMat_TexGen(TEXGEN_0); + SetMat_Ind(); + GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + GXSetNumTevStages(1); + SetMat_Tev(GX_TEVSTAGE0, TEV_0); + SetMat_PE(zMode, BLEND_0); + SetVtxState(VTX_TYPE_1); +} + +void DrawGX::BeginDrawCircleZ(ColorChannel chan, ZMode zMode) { + SetMat_ColorChannel(chan); + SetMat_TexGen(TEXGEN_0); + SetMat_Ind(); + GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + GXSetNumTevStages(1); + SetMat_Tev(GX_TEVSTAGE0, TEV_0); + SetMat_PE(zMode, BLEND_0); + SetVtxState(VTX_TYPE_4); +} + +void DrawGX::BeginDrawQuad(ColorChannel chan, ZMode zMode, Blend blendMode, bool b1, bool b2) { + SetMat_ColorChannel(chan); + SetMat_TexGen(b1 ? TEXGEN_1 : TEXGEN_0); + SetMat_Ind(); + GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + GXSetNumTevStages(1); + SetMat_Tev(GX_TEVSTAGE0, b1 ? TEV_2 : TEV_0); + if (b2) { + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA); + } + SetMat_PE(zMode, blendMode); + SetVtxState(b1 ? VTX_TYPE_7 : VTX_TYPE_8); +} + +static const DrawGX::VtxType sVtxTypes[2][2] = { + {DrawGX::VTX_TYPE_10, DrawGX::VTX_TYPE_12}, + {DrawGX::VTX_TYPE_11, DrawGX::VTX_TYPE_13}, +}; + +void DrawGX::BeginDrawScreen(bool b1, bool b2, bool b3) { + SetMat_ColorChannel(COLORCHAN_1); + SetMat_TexGen(b2 ? TEXGEN_1 : TEXGEN_0); + SetMat_Ind(); + GXSetNumTevStages(1); + GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + SetMat_Tev(GX_TEVSTAGE0, b2 ? TEV_2 : TEV_0); + if (b3) { + GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA); + } + SetMat_PE(ZMODE_0, BLEND_0); + SetVtxState(sVtxTypes[b1 ? 1 : 0][b2 ? 0 : 1]); +} + +void DrawGX::DrawLine(const EGG::Vector3f *pPoints, u16 numPoints, GXColor color, u8 thickness) { + GXLoadPosMtxImm(s_cameraMtx.m, 0); + GXSetChanMatColor(GX_COLOR0A0, color); + GXSetLineWidth(thickness, 0); + GXBegin(GX_LINES, GX_VTXFMT0, numPoints); + for (int i = 0; i < numPoints; i++) { + GXPosition3f32(pPoints[i].x, pPoints[i].y, pPoints[i].z); + } +} + +void DrawGX::DrawLineStrip(const EGG::Vector3f *pPoints, u16 numPoints, GXColor color, u8 thickness) { + GXLoadPosMtxImm(s_cameraMtx.m, 0); + GXSetChanMatColor(GX_COLOR0A0, color); + GXSetLineWidth(thickness, 0); + GXBegin(GX_LINESTRIP, GX_VTXFMT0, numPoints); + for (int i = 0; i < numPoints; i++) { + GXPosition3f32(pPoints[i].x, pPoints[i].y, pPoints[i].z); + } +} + +void DrawGX::ClearEfb( + const nw4r::math::MTX34 &mat, bool bColorUpdate, bool bAlphaUpdate, bool b3, GXColor clr, bool b4 +) { + StateGX::ScopedColor colorUpdate(bColorUpdate); + StateGX::ScopedAlpha alphaUpdate(bAlphaUpdate); + SetMat_ColorChannel(COLORCHAN_1); + GXSetCullMode(GX_CULL_NONE); + if (b3) { + SetMat_TexGen(TEXGEN_1); + GXLoadTexObj(&sDummyTexObj, sTexMapDefault); + } else { + SetMat_TexGen(TEXGEN_0); + } + + SetMat_Ind(); + GXSetNumTevStages(1); + GXSetTevDirect(GX_TEVSTAGE0); + GXSetTevColor(GX_TEVREG0, clr); + GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0); + GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + if (b3) { + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, sTexMapDefault, GX_COLOR_NULL); + } else { + GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); + } + GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_C0); + 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_A0); + GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV); + GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + SetBlendMode(BLEND_14); + if (b3) { + GXSetZTexture(2, GX_TF_Z24X8, 0); + SetZMode(ZMODE_3); + GXSetZCompLoc(0); + SetVtxState(b4 ? VTX_TYPE_11 : VTX_TYPE_10); + GXLoadPosMtxImm(mat, 0); + GXCallDisplayList(s_DL[DL_16].mpList, s_DL[DL_16].mLen); + GXSetZTexture(0, GX_TF_Z24X8, 0); + GXSetZCompLoc(1); + } else { + SetZMode(ZMODE_0); + SetVtxState(b4 ? VTX_TYPE_13 : VTX_TYPE_12); + GXLoadPosMtxImm(mat, 0); + GXCallDisplayList(s_DL[DL_17].mpList, s_DL[DL_17].mLen); + } +} + +void DrawGX::ResetMaterial(enum ColorChannel chan) { + SetMat_ColorChannel(chan); + SetMat_TexGen(TEXGEN_0); + SetMat_Ind(); + GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); + GXSetNumTevStages(1); + SetMat_Tev(GX_TEVSTAGE0, TEV_0); + SetMat_PE(ZMODE_1, BLEND_0); +} + +void DrawGX::SetMat_ColorChannel(enum ColorChannel chan) { + switch (chan) { + case COLORCHAN_0: + GXSetNumChans(1); + GXSetCullMode(GX_CULL_BACK); + GXSetChanCtrl(GX_COLOR0A0, true, GX_SRC_REG, GX_SRC_REG, GetLightMaskDefault(), GX_DF_CLAMP, GX_AF_SPOT); + GXSetChanCtrl(GX_COLOR1A1, false, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + break; + case COLORCHAN_1: + GXSetNumChans(1); + GXSetCullMode(GX_CULL_BACK); + GXSetChanCtrl(GX_COLOR0A0, false, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_SPOT); + GXSetChanCtrl(GX_COLOR1A1, false, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); + break; + } +} + +void DrawGX::SetMat_TexGen(enum TexGen texGen) { + switch (texGen) { + case TEXGEN_0: + GXSetNumTexGens(0); + GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3c, 0, 0x7d); + break; + case TEXGEN_1: + GXSetNumTexGens(1); + GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3c, 0, 0x7d); + break; + } +} + +void DrawGX::SetMat_Ind() { + GXSetNumIndStages(0); +} + +void DrawGX::SetMat_Tev(GXTevStageID stageId, enum TevSetting setting) { + switch (setting) { + case TEV_0: + GXSetTevDirect(stageId); + GXSetTevOrder(stageId, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); + GXSetTevSwapMode(stageId, GX_TEV_SWAP0, GX_TEV_SWAP0); + GXSetTevColorIn(stageId, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC); + GXSetTevColorOp(stageId, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GXSetTevAlphaIn(stageId, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_RASA); + GXSetTevAlphaOp(stageId, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV); + break; + case TEV_2: + GXSetTevDirect(stageId); + GXSetTevOrder(stageId, GX_TEXCOORD0, sTexMapDefault, GX_COLOR0A0); + GXSetTevSwapMode(stageId, GX_TEV_SWAP0, GX_TEV_SWAP0); + GXSetTevColorIn(stageId, GX_CC_ZERO, GX_CC_TEXC, GX_CC_RASC, GX_CC_ZERO); + GXSetTevColorOp(stageId, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GXSetTevAlphaIn(stageId, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO); + GXSetTevAlphaOp(stageId, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV); + break; + case TEV_1: + GXSetTevDirect(stageId); + GXSetTevOrder(stageId, GX_TEXCOORD0, sTexMapDefault, GX_COLOR0A0); + GXSetTevSwapMode(stageId, GX_TEV_SWAP0, GX_TEV_SWAP0); + GXSetTevColorIn(stageId, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC); + GXSetTevColorOp(stageId, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, 1, GX_TEVPREV); + GXSetTevAlphaIn(stageId, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA); + GXSetTevAlphaOp(stageId, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, true, GX_TEVPREV); + break; + } +} + +void DrawGX::SetMat_PE(enum ZMode zMode, enum Blend blendMode) { + GXSetZCompLoc(true); + GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); + SetZMode(zMode); + SetBlendMode(blendMode); +} + +void DrawGX::LoadTexture(const EGG::ResTIMG *tex, GXTexMapID texMapId) { + GXTexObj obj; + GXUtility::getTexObj(&obj, *tex); + GXLoadTexObj(&obj, texMapId); +} + +void DrawGX::LoadTexture(nw4r::g3d::ResTex tex, GXTexMapID texMapId) { + GXTexObj obj; + GXUtility::getTexObj(&obj, tex, GX_CLAMP, GX_CLAMP, GX_LINEAR, GX_LINEAR); + GXLoadTexObj(&obj, texMapId); +} + +void DrawGX::SetVtxState(EGG::DrawGX::VtxType type) { + GXClearVtxDesc(); + switch (type) { + case VTX_TYPE_0: + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_RGBA4, 0xe); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_CLR_RGB, GX_RGBA4, 0xe); + // clang-format off + static const ALIGN_DECL(32) u8 sVtxDataType0[] = { + 0xE0, 0x00, 0x20, 0x00, + 0xE0, 0x00, 0xE0, 0x00, + 0x20, 0x00, 0x20, 0x00, + 0x20, 0x00, 0x20, 0x00, + 0x20, 0x00, 0x20, 0x00, + 0x20, 0x00, 0xE0, 0x00, + 0xE0, 0x00, 0xE0, 0x00, + 0xE0, 0x00, 0xE0, 0x00, + 0xE0, 0x00, 0x20, 0x00, + 0x20, 0x00, 0xE0, 0x00, + 0x20, 0x00, 0x20, 0x00, + 0xE0, 0x00, 0xE0, 0x00, + }; + static const ALIGN_DECL(32) u8 sNrmDataType0[] = { + 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xC0, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x00, + }; + // clang-format on + GXSetArray(GX_VA_POS, sVtxDataType0, 6); + GXSetArray(GX_VA_NRM, sNrmDataType0, 6); + GXSetVtxDesc(GX_VA_POS, GX_INDEX8); + GXSetVtxDesc(GX_VA_NRM, GX_INDEX8); + break; + case VTX_TYPE_2: + case VTX_TYPE_3: + case VTX_TYPE_4: + case VTX_TYPE_5: + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_NRM, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_CLR_RGB, GX_F32, 0); + break; + case VTX_TYPE_6: + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxDesc(GX_VA_NRM, GX_DIRECT); + GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_CLR_RGB, GX_F32, 0); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); + break; + case VTX_TYPE_1: + GXSetVtxDesc(GX_VA_POS, GX_DIRECT); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_F32, 0); + break; + case VTX_TYPE_7: + case VTX_TYPE_8: + // clang-format off + static const ALIGN_DECL(32) u8 sVtxDataType7[] = { + 0xE0, 0x00, 0x20, 0x00, + 0x20, 0x00, 0x20, 0x00, + 0x20, 0x00, 0xE0, 0x00, + 0xE0, 0x00, 0xE0, 0x00, + }; + static const ALIGN_DECL(32) u8 sNrmDataType7[] = { + 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, + }; + static const ALIGN_DECL(32) u8 sTexDataType7[] = { + 0x00, 0x00, 0x01, 0x00, + 0x01, 0x01, 0x00, 0x01, + }; + // clang-format on + GXSetVtxDesc(GX_VA_POS, GX_INDEX8); + GXSetVtxDesc(GX_VA_NRM, GX_INDEX8); + if (type == VTX_TYPE_7) { + GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8); + } + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBA4, 0xe); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_CLR_RGB, GX_RGBA4, 0xe); + if (type == VTX_TYPE_7) { + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGB565, 0); + } + GXSetArray(GX_VA_POS, sVtxDataType7, 4); + GXSetArray(GX_VA_NRM, sNrmDataType7, 6); + if (type == VTX_TYPE_7) { + GXSetArray(GX_VA_TEX0, sTexDataType7, 2); + } + break; + case VTX_TYPE_9: + // clang-format off + static const ALIGN_DECL(32) u8 sVtxDataType9[] = { + 0xE0, 0x00, 0x00, 0x00, + 0xE0, 0x00, 0x20, 0x00, + 0x00, 0x00, 0xE0, 0x00, + 0x20, 0x00, 0x00, 0x00, + 0x20, 0x00, 0xE0, 0x00, + 0x00, 0x00, 0x20, 0x00, + }; + static const ALIGN_DECL(32) u8 sNrmDataType9[] = { + 0x00, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, + }; + // clang-format on + GXSetVtxDesc(GX_VA_POS, GX_INDEX8); + GXSetVtxDesc(GX_VA_NRM, GX_INDEX8); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGBA, GX_RGBA4, 0xe); + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_CLR_RGB, GX_RGBA4, 0xe); + GXSetArray(GX_VA_POS, sVtxDataType9, 6); + GXSetArray(GX_VA_NRM, sNrmDataType9, 6); + break; + case VTX_TYPE_10: + case VTX_TYPE_11: + case VTX_TYPE_12: + case VTX_TYPE_13: { + // clang-format off + static const ALIGN_DECL(32) u8 sPosDataType10[] = { + 0x00, 0x01, 0x01, 0x01, + 0x01, 0x00, 0x00, 0x00, + }; + static const ALIGN_DECL(32) u8 sTexDataType10[] = { + 0x00, 0x00, 0x01, 0x00, + 0x01, 0x01, 0x00, 0x01, + }; + // clang-format on + bool bVar1 = type == VTX_TYPE_11 || type == VTX_TYPE_13; + bool bVar2 = type == VTX_TYPE_10 || type == VTX_TYPE_11; + GXSetVtxDesc(GX_VA_POS, GX_INDEX8); + if (bVar2) { + GXSetVtxDesc(GX_VA_TEX0, GX_INDEX8); + } + GXSetArray(GX_VA_POS, bVar1 ? sTexDataType10 : sPosDataType10, 2); + if (bVar2) { + GXSetArray(GX_VA_TEX0, sTexDataType10, 2); + } + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGB565, 0); + if (bVar2) { + GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGB565, 0); + } + break; + } + } +} + +const u8 sDetailLevels[] = {0x10, 0x20}; void DrawGX::CreateDisplayList(EGG::Heap *pHeap) { u8 ALIGN_DECL(32) tmpDisplayList[16 * 1024]; @@ -251,4 +688,46 @@ void DrawGX::DrawDL(enum DL dl, const nw4r::math::MTX34 &mtx, GXColor clr) { GXCallDisplayList(s_DL[dl].mpList, s_DL[dl].mLen); } +const DrawGX::ZModeConfig DrawGX::s_ZMode[ZMODE_MAX] = { + {false, GX_ALWAYS, false}, + { true, GX_LEQUAL, true}, + { true, GX_LEQUAL, false}, + { true, GX_ALWAYS, true}, +}; + +void DrawGX::SetZMode(enum ZMode mode) { + GXSetZMode(s_ZMode[mode].mTest, s_ZMode[mode].mCompare, s_ZMode[mode].mUpdate); +} + +const DrawGX::BlendModeConfig DrawGX::s_Blend[BLEND_MAX] = { + { GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_INVSRCALPHA, GX_BL_SRCALPHA, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_ONE, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_SRCCLR, GX_BL_ONE, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_INVSRCCLR, GX_BL_ONE, GX_LO_CLEAR}, + {GX_BM_SUBTRACT, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_ZERO, GX_BL_SRCCLR, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_ZERO, GX_BL_INVSRCCLR, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_ONE, GX_BL_ZERO, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_DSTALPHA, GX_BL_INVDSTALPHA, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_INVDSTALPHA, GX_BL_DSTALPHA, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_DSTALPHA, GX_BL_ONE, GX_LO_CLEAR}, + { GX_BM_BLEND, GX_BL_INVDSTALPHA, GX_BL_ONE, GX_LO_CLEAR}, + { GX_BM_NONE, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR}, +}; + +void DrawGX::SetBlendMode(enum Blend mode) { + GXSetBlendMode( + s_Blend[mode].mBlendMode, s_Blend[mode].mBlendFactorSrc, s_Blend[mode].mBlendFactorDst, s_Blend[mode].mLogicOp + ); +} + +void DrawGX::DrawDLWorld(DL dl, const EGG::Matrix34f &mtx, GXColor color) { + nw4r::math::MTX34 resMtx; + + PSMTXConcat(s_cameraMtx.m, mtx.m, resMtx.m); + DrawDL(dl, resMtx, color); +} + } // namespace EGG