From 87b0252267c2571e0b7380d3f0a4d7bd0a427d5b Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Thu, 25 Sep 2025 11:54:41 -0700 Subject: [PATCH 1/6] porting data types --- include/ctr/coll.h | 62 ++++++++++++++++++++++++++++ include/ctr/lev.h | 94 +++++++++++++++++++++++++++++++++++++++++- include/ctr/math.h | 9 +++- include/ctr/prim.h | 12 +++--- rewrite/src/exe/coll.c | 2 + 5 files changed, 170 insertions(+), 9 deletions(-) diff --git a/include/ctr/coll.h b/include/ctr/coll.h index 9c6090a0b..fca6ed5ef 100644 --- a/include/ctr/coll.h +++ b/include/ctr/coll.h @@ -41,5 +41,67 @@ typedef struct TestVertex SVec3 interpolationPoint; } TestVertex; +typedef struct DriverQuadblockCollData +{ + SVec3 driverPos; + s16 driverHitRadius; + s32 driverHitRadiusSquared; + SVec3 driverNextPos; + u16 collFlags; + u16 searchFlags; + s16 unk0; + u32 skipCollNoQuadFlagsMatch; +} DriverQuadblockCollData; + +typedef union CollInputData +{ + DriverQuadblockCollData quadblock; +} CollInputData; + +typedef struct CollDCache +{ + SVec3 inputNextPos; + s16 inputHitRadius; + s32 inputHitRadiusSquared; + s16 unk0; + s16 unk1; + CollInputData collInput; + MeshInfo* meshInfo; + BoundingBox bbox; + s16 numVerticesTested; + s16 numTrianglesTouched; + s16 unk2; + s16 numInstancesCollided; + u32 unk3; + BSPNode* bspNodes; + TestVertex collIntersection; + u8 unk4; + u8 currTriangleIndex; + Quadblock* currQuadblock; + SVec3 collPos; + u16 normalDominantAxis_TriCollided; + SVec3 normalTriCollided; + s16 unk5; + SVec3 interpolationPoint; + u8 barycentricTest; + u8 collidedTriangleIndex; + Quadblock* collidedQuadblock; + s32 speedScale; + u8 unk6[0x44]; + Vertex* collidedVertices[NUM_VERTICES_TRIANGLE]; + CollVertex* currTestVertices[NUM_VERTICES_TRIANGLE]; + SVec3 distInterpolationIntersection; + s16 unk7; + u16 quadblockThirdIndex; + u16 quadblockFouthIndex; + CollVertex quadblockCollVertices[NUM_VERTICES_QUADBLOCK]; + u32 stepFlags; + s16 normalScale; + u8 normalBitshift; + u8 lodShift; +} CollDCache; + +#define DCACHE_COLL (*(CollDCache*) 0x1f800000) + void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); s32 COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); \ No newline at end of file diff --git a/include/ctr/lev.h b/include/ctr/lev.h index 407facea3..ab154f0f4 100644 --- a/include/ctr/lev.h +++ b/include/ctr/lev.h @@ -2,6 +2,10 @@ #include #include +#include + +#define NUM_VERTICES_QUADBLOCK 9 +#define NUM_VERTICES_TRIANGLE 3 typedef union Color { @@ -15,10 +19,98 @@ typedef union Color u32 color; } Color; +typedef struct TextureLayout +{ + UV uv0; + CLUT clut; + UV uv1; + PolyTexpage texpage; + UV uv2; + UV uv3; +} TextureLayout; + +typedef struct TextureGroup +{ + TextureLayout far; + TextureLayout middle; + TextureLayout near; + TextureLayout mosaic; +} TextureGroup; + typedef struct Vertex { SVec3 pos; u16 flags; Color colorHi; Color colorLo; -} Vertex; \ No newline at end of file +} Vertex; + +typedef struct VisibleSet +{ + u32* visibleBSPNodes; + u32* visibleQuadblocks; + u32* visibleInstances; + u32* visibleExtra; +} VisibleSet; + +typedef struct Quadblock +{ + u16 index[NUM_VERTICES_QUADBLOCK]; // 0x0 + u16 flags; // 0x12 + u32 drawOrderLow; // 0x14 + u32 drawOrderHigh; // 0x18 + u32 offMidTextures[4]; // 0x1C + BoundingBox bbox; // 0x2C + u8 terrain; // 0x38 + u8 weatherIntensity; // 0x39 + u8 weatherVanishRate; // 0x3A + s8 speedImpact; // 0x3B + u16 id; // 0x3C + u8 checkpointIndex; // 0x3E + u8 triNormalVecBitshift; // 0x3F + u32 offLowTexture; // 0x40 + VisibleSet visibleSet; // 0x44 + u16 triNormalVecDividend[NUM_VERTICES_QUADBLOCK + 1]; // 0x48 +} Quadblock; + +typedef struct BSPBranch +{ + u16 flags; // 0x0 + u16 id; // 0x2 + BoundingBox bbox; // 0x4 + SVec3 axis; // 0x10 + u16 likelyPadding; // 0x16 + u16 leftChildID; // 0x18 + u16 rightChildID; // 0x1A + u16 unk1; // 0x1C + u16 unk2; // 0x1E +} BSPBranch; + +typedef struct BSPLeaf +{ + u16 flags; // 0x0 + u16 id; // 0x2 + BoundingBox bbox; // 0x4 + u32 likelyPadding; // 0x10 + u32 offHitbox; // 0x14 + u32 numQuads; // 0x18 + Quadblock* quadblocks; // 0x1C +} BSPLeaf; + +typedef union BSPNode +{ + BSPBranch branch; + BSPLeaf leaf; +} BSPNode; + +typedef struct MeshInfo +{ + u32 numQuadblocks; // 0x0 + u32 numVertices; // 0x4 + u32 unk1; // 0x8 + Quadblock* quadblocks; // 0xC + Vertex* vertices; // 0x10 + u32 unk2; // 0x14 + BSPNode* bspNodes; // 0x18 + u32 numBSPNodes; // 0x1C +} MeshInfo; \ No newline at end of file diff --git a/include/ctr/math.h b/include/ctr/math.h index 2a307a28d..7139d083a 100644 --- a/include/ctr/math.h +++ b/include/ctr/math.h @@ -69,11 +69,18 @@ typedef union Vec4 s32 v[4]; } Vec4; -typedef struct Matrix { +typedef struct Matrix +{ s16 m[3][3]; Vec3 t; } Matrix; +typedef struct BoundingBox +{ + SVec3 min; + SVec3 max; +} BoundingBox; + typedef struct TrigTable { s16 sin; diff --git a/include/ctr/prim.h b/include/ctr/prim.h index 727781a61..44715e453 100644 --- a/include/ctr/prim.h +++ b/include/ctr/prim.h @@ -2,13 +2,13 @@ #include -enum VertexCount +typedef enum VertexCount { VertexCount_Point = 1, VertexCount_Line = 2, VertexCount_Tri = 3, VertexCount_Quad = 4, -}; +} VertexCount; typedef union Tag { @@ -41,18 +41,18 @@ typedef union Texpage u32 self; } Texpage; -typedef struct +typedef struct TPage { Tag tag; Texpage texpage; } TPage; -enum RenderCode +typedef enum RenderCode { RenderCode_Polygon = 1, RenderCode_Line = 2, RenderCode_Rectangle = 3, -}; +} RenderCode; typedef union PrimCode { @@ -100,8 +100,6 @@ typedef union ColorCode u32 self; } ColorCode; -typedef ColorCode Color; - #define MakeColorCode(red, green, blue, renderCode) (ColorCode) { .r = red, .g = green, .b = blue, .code = renderCode } #define MakeColor(red, green, blue) (Color) { .r = red, .g = green, .b = blue } diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index f8ddb0654..043a0d2ab 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -37,6 +37,8 @@ void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const out->z = coords.z; TEST_COLL_ProjectPointToEdge(v1, v2, point, out); #ifdef TEST_COLL_IMPL + /* This is a hand written assembly function that breaks the ABI, + and some callers expect the argument registers to be untouched*/ __asm__ volatile("move $a0, %0" : : "r"((u32)out)); __asm__ volatile("move $a1, %0" : : "r"((u32)v1)); __asm__ volatile("move $a2, %0" : : "r"((u32)v2)); From 64d289cb080bc4e09abc1f04a0c085312a92979b Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Thu, 25 Sep 2025 13:43:59 -0700 Subject: [PATCH 2/6] load vertice data decompiled --- include/ctr/coll.h | 5 +++-- include/ctr/nd.h | 1 + include/ctr/test.h | 2 ++ rewrite/src/exe/coll.c | 23 +++++++++++++++++++++-- rewrite/src/tests/test.c | 1 + rewrite/src/tests/test_coll.c | 31 +++++++++++++++++++++++++++++++ symbols/gcc-syms-rewrite.txt | 2 +- 7 files changed, 60 insertions(+), 5 deletions(-) diff --git a/include/ctr/coll.h b/include/ctr/coll.h index fca6ed5ef..375730c21 100644 --- a/include/ctr/coll.h +++ b/include/ctr/coll.h @@ -27,7 +27,7 @@ typedef struct CollVertex { SVec3 pos; u16 normalDominantAxis; - Vertex* levVertex; + const Vertex* levVertex; SVec3 triNormal; u16 planeDist; } CollVertex; @@ -93,7 +93,7 @@ typedef struct CollDCache SVec3 distInterpolationIntersection; s16 unk7; u16 quadblockThirdIndex; - u16 quadblockFouthIndex; + u16 quadblockFourthIndex; CollVertex quadblockCollVertices[NUM_VERTICES_QUADBLOCK]; u32 stepFlags; s16 normalScale; @@ -104,4 +104,5 @@ typedef struct CollDCache #define DCACHE_COLL (*(CollDCache*) 0x1f800000) void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); +void COLL_LoadVerticeData(CollDCache* cache); s32 COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); \ No newline at end of file diff --git a/include/ctr/nd.h b/include/ctr/nd.h index 0b139cf99..96d074abb 100644 --- a/include/ctr/nd.h +++ b/include/ctr/nd.h @@ -29,4 +29,5 @@ u32 ND_RNG_Random(RNGSeed* seed); /* COLL */ void ND_COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); +void ND_COLL_LoadVerticeData(CollDCache* cache); s32 ND_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); \ No newline at end of file diff --git a/include/ctr/test.h b/include/ctr/test.h index 50468a11c..a3b5cee00 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -66,8 +66,10 @@ force_inline void FlushCache() #ifdef TEST_COLL_IMPL void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* point, const SVec3* ret); + void TEST_COLL_LoadVerticeData(CollDCache* cache); void TEST_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const SVec3* pos, s32 ret); #else #define TEST_COLL_ProjectPointToEdge(out, v1, v2, point) + #define TEST_COLL_LoadVerticeData(cache) #define TEST_COLL_BarycentricTest(t, v1, v2, v3, pos, ret) #endif \ No newline at end of file diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index 043a0d2ab..fcf5e884a 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -36,14 +36,33 @@ void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const out->y = coords.y; out->z = coords.z; TEST_COLL_ProjectPointToEdge(v1, v2, point, out); -#ifdef TEST_COLL_IMPL /* This is a hand written assembly function that breaks the ABI, and some callers expect the argument registers to be untouched*/ __asm__ volatile("move $a0, %0" : : "r"((u32)out)); __asm__ volatile("move $a1, %0" : : "r"((u32)v1)); __asm__ volatile("move $a2, %0" : : "r"((u32)v2)); __asm__ volatile("move $a3, %0" : : "r"((u32)point)); -#endif +} + +/* Address: 0x8001f7f0 */ +void COLL_LoadVerticeData(CollDCache* cache) +{ + const Quadblock* quadblock = cache->currQuadblock; + const Vertex* vertices = cache->meshInfo->vertices; + for (u32 i = 0; i < NUM_VERTICES_QUADBLOCK; i++) + { + u16 index = quadblock->index[i]; + const Vertex* vertex = &vertices[index]; + cache->quadblockCollVertices[i].pos = vertex->pos; + cache->quadblockCollVertices[i].levVertex = vertex; + } + cache->quadblockThirdIndex = quadblock->index[2]; + cache->quadblockFourthIndex = quadblock->index[3]; + TEST_COLL_LoadVerticeData(cache); + /* This is a hand written assembly function that breaks the ABI, + and some callers expect the argument registers to be untouched*/ + __asm__ volatile("move $a0, %0" : : "r"((u32)cache)); + __asm__ volatile("move $t9, %0" : : "r"((u32)quadblock)); } /* Address: 0x8001f928 */ diff --git a/rewrite/src/tests/test.c b/rewrite/src/tests/test.c index 56eb7b08b..979eb76ea 100644 --- a/rewrite/src/tests/test.c +++ b/rewrite/src/tests/test.c @@ -31,6 +31,7 @@ FunctionPatch s_functions[] = TEST_FUNC(RNG_Random), TEST_FUNC(COLL_ProjectPointToEdge), TEST_FUNC(COLL_BarycentricTest), + TEST_FUNC(COLL_LoadVerticeData), }; void LoadTestPatches() diff --git a/rewrite/src/tests/test_coll.c b/rewrite/src/tests/test_coll.c index c45abcfe3..efc255a5e 100644 --- a/rewrite/src/tests/test_coll.c +++ b/rewrite/src/tests/test_coll.c @@ -13,6 +13,37 @@ void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* PatchFunction_End(index); } +void TEST_COLL_LoadVerticeData(CollDCache* cache) +{ + CollVertex vertices[NUM_VERTICES_QUADBLOCK]; + for (u32 i = 0; i < NUM_VERTICES_QUADBLOCK; i++) + { + vertices[i] = cache->quadblockCollVertices[i]; + } + const u16 thirdIndex = cache->quadblockThirdIndex; + const u16 fourthIndex = cache->quadblockFourthIndex; + const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_LoadVerticeData)); + + const u32 quadblock = (u32) cache->currQuadblock; + const u32 levVertices = (u32) cache->meshInfo->vertices; + __asm__ volatile("move $t9, %0" : : "r"(quadblock)); + __asm__ volatile("move $t8, %0" : : "r"(levVertices)); + + typedef void (*Func)(CollDCache* cache); + Func func = (Func) TEST_WRAPPER; + func(cache); + for (u32 i = 0; i < NUM_VERTICES_QUADBLOCK; i++) + { + PrintSVectorDiff("COLL_LoadVerticeData", &cache->quadblockCollVertices[i].pos, &vertices[i].pos); + if (cache->quadblockCollVertices[i].levVertex != vertices[i].levVertex) + { + ND_printf("[COLL_LoadVerticeData] Test Failed: levVertex at index %d\n", i); + } + } + if (cache->quadblockThirdIndex != thirdIndex) { ND_printf("[COLL_LoadVerticeData] Test Failed:\nthirdIndex: %d\nResult:%d\n", cache->quadblockThirdIndex, thirdIndex); } + if (cache->quadblockFourthIndex != fourthIndex) { ND_printf("[COLL_LoadVerticeData] Test Failed:\nfourthIndex: %d\nResult:%d\n", cache->quadblockFourthIndex, fourthIndex);} + PatchFunction_End(index); +} void TEST_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const SVec3* pos, s32 ret) { diff --git a/symbols/gcc-syms-rewrite.txt b/symbols/gcc-syms-rewrite.txt index 8bf364f9e..c26690caf 100644 --- a/symbols/gcc-syms-rewrite.txt +++ b/symbols/gcc-syms-rewrite.txt @@ -68,7 +68,7 @@ ND_COLL_FIXED_QUADBLK_TestTriangles = 0x8001f41c; ND_COLL_FIXED_BSPLEAF_TestQuadblocks = 0x8001f5f0; ND_COLL_FIXED_QUADBLK_GetNormVecs_LoLOD = 0x8001f67c; ND_COLL_FIXED_QUADBLK_GetNormVecs_HiLOD = 0x8001f6f0; -ND_COLL_FIXED_QUADBLK_LoadScratchpadVerts = 0x8001f7f0; +ND_COLL_LoadVerticeData = 0x8001f7f0; ND_COLL_BarycentricTest = 0x8001f928; ND_COLL_MOVED_TRIANGL_TestPoint = 0x8001fc40; ND_COLL_MOVED_QUADBLK_TestTriangles = 0x80020064; From 26dbbece5ce57468af65e12390f0a97f9d299dd5 Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Thu, 25 Sep 2025 14:57:59 -0700 Subject: [PATCH 3/6] decompile CalculateTrianglePlane --- include/ctr/coll.h | 1 + include/ctr/gte.h | 26 +++++++++++++---------- include/ctr/nd.h | 4 +++- include/ctr/test.h | 1 + rewrite/src/exe/coll.c | 40 +++++++++++++++++++++++++++++++---- rewrite/src/exe/math.c | 2 +- rewrite/src/tests/test.c | 1 + rewrite/src/tests/test_coll.c | 12 +++++++++++ symbols/gcc-syms-rewrite.txt | 4 ++-- 9 files changed, 72 insertions(+), 19 deletions(-) diff --git a/include/ctr/coll.h b/include/ctr/coll.h index 375730c21..23fa7019f 100644 --- a/include/ctr/coll.h +++ b/include/ctr/coll.h @@ -104,5 +104,6 @@ typedef struct CollDCache #define DCACHE_COLL (*(CollDCache*) 0x1f800000) void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); +void COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3); void COLL_LoadVerticeData(CollDCache* cache); s32 COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); \ No newline at end of file diff --git a/include/ctr/gte.h b/include/ctr/gte.h index 0797d71e8..f100d1667 100644 --- a/include/ctr/gte.h +++ b/include/ctr/gte.h @@ -43,11 +43,11 @@ typedef enum GTE_MAC GTE_MAC_3, /* s32 */ } GTE_MAC; -typedef enum GTE_INTERPOLATE +typedef enum GTE_CALC { - GTE_INTERPOLATE_INT, - GTE_INTERPOLATE_FLOATING_POINT, -} GTE_INTERPOLATE; + GTE_CALC_INT, + GTE_CALC_FLOATING_POINT, +} GTE_CALC; /* HELPERS */ #define _CAT(a, b) a##b @@ -75,12 +75,15 @@ typedef enum GTE_INTERPOLATE #define _gte_readMac_GTE_MAC_3(out) gte_stlvnl2(out) #define _gte_readMac_GTE_VECTOR_MAC(out) gte_stlvnl(out) #define _gte_loadIR_GTE_IR_0(in) gte_lddp(in) -#define _gte_dotProduct_GTE_ROW_INDEX_0(out, matrixType, vecType) gte_mvmva(0, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_1(out) -#define _gte_dotProduct_GTE_ROW_INDEX_1(out, matrixType, vecType) gte_mvmva(0, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_2(out) -#define _gte_dotProduct_GTE_ROW_INDEX_2(out, matrixType, vecType) gte_mvmva(0, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_3(out) +#define _gte_dotProduct_GTE_ROW_INDEX_0_GTE_CALC_INT(out, matrixType, vecType) gte_mvmva(0, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_1(out) +#define _gte_dotProduct_GTE_ROW_INDEX_1_GTE_CALC_INT(out, matrixType, vecType) gte_mvmva(0, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_2(out) +#define _gte_dotProduct_GTE_ROW_INDEX_2_GTE_CALC_INT(out, matrixType, vecType) gte_mvmva(0, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_3(out) +#define _gte_dotProduct_GTE_ROW_INDEX_0_GTE_CALC_FLOATING_POINT(out, matrixType, vecType) gte_mvmva(1, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_1(out) +#define _gte_dotProduct_GTE_ROW_INDEX_1_GTE_CALC_FLOATING_POINT(out, matrixType, vecType) gte_mvmva(1, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_2(out) +#define _gte_dotProduct_GTE_ROW_INDEX_2_GTE_CALC_FLOATING_POINT(out, matrixType, vecType) gte_mvmva(1, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_3(out) #define _gte_mulMatrixVec(out, matrixType, vecType, shift) gte_mvmva(shift, matrixType, vecType, 3, 0); _gte_readMac_GTE_VECTOR_MAC(out) -#define _gte_interpolate_GTE_INTERPOLATE_INT() gte_gpl0() -#define _gte_interpolate_GTE_INTERPOLATE_FLOATING_POINT() gte_gpl12() +#define _gte_interpolate_GTE_CALC_INT() gte_gpl0() +#define _gte_interpolate_GTE_CALC_FLOATING_POINT() gte_gpl12() #define _gte_leadingZeroes(out, in) __asm__ volatile ( \ "mtc2 %1, $30;" \ "nop;" \ @@ -98,6 +101,7 @@ typedef enum GTE_INTERPOLATE #define gte_loadVec(v, vecType) CAT(_gte_loadVec_, vecType)(v) #define gte_loadRowMatrix(v, rowIndex, matrixType) CAT3(_gte_loadSVecMatrix_, matrixType, _##rowIndex)(v) #define gte_mulMatrixVec(out, matrixType, vecType) _gte_mulMatrixVec(out, matrixType, vecType, 1) -#define gte_dotProduct(out, rowIndex, matrixType, vecType) CAT(_gte_dotProduct_, rowIndex)(out, matrixType, vecType) +#define gte_dotProduct(out, rowIndex, matrixType, vecType, calcType) CAT3(_gte_dotProduct_, rowIndex, _##calcType)(out, matrixType, vecType) #define gte_leadingZeroes(out, in) _gte_leadingZeroes(out, in) -#define gte_interpolate(out, interpolationType) CAT(_gte_interpolate_, interpolationType)(); _gte_readMac_GTE_VECTOR_MAC(out) \ No newline at end of file +#define gte_interpolate(out, calcType) CAT(_gte_interpolate_, calcType)(); _gte_readMac_GTE_VECTOR_MAC(out) +#define gte_crossProduct(out, matrix, vector) gte_SetRotMatrix(matrix); gte_loadSVec(vector, GTE_VECTOR_IR); gte_op0(); gte_readMac(out, GTE_VECTOR_MAC) \ No newline at end of file diff --git a/include/ctr/nd.h b/include/ctr/nd.h index 96d074abb..c97586346 100644 --- a/include/ctr/nd.h +++ b/include/ctr/nd.h @@ -6,10 +6,11 @@ #include void ND_LOAD_XnfFile(char* filename, u32 address, char* dummy); +void ND_LOAD_InitCD(); + s32 ND_SquareRoot0_stub(s32 n); int ND_printf(const char* format, ...); int ND_sprintf(const char* outStr, const char* format, ...); -void ND_LOAD_InitCD(); /* MATH */ s32 ND_MATH_Sin(u32 angle); @@ -29,5 +30,6 @@ u32 ND_RNG_Random(RNGSeed* seed); /* COLL */ void ND_COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); +void ND_COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3); void ND_COLL_LoadVerticeData(CollDCache* cache); s32 ND_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); \ No newline at end of file diff --git a/include/ctr/test.h b/include/ctr/test.h index a3b5cee00..cd5b81fe8 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -66,6 +66,7 @@ force_inline void FlushCache() #ifdef TEST_COLL_IMPL void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* point, const SVec3* ret); + void TEST_COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const CollVertex* ret); void TEST_COLL_LoadVerticeData(CollDCache* cache); void TEST_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const SVec3* pos, s32 ret); #else diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index fcf5e884a..df3c17d47 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -14,7 +14,7 @@ void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const gte_SetRotMatrix(m.m); gte_loadSVec(edge.v, GTE_VECTOR_0); s32 edgeDot, pointDot; - gte_dotProduct(&edgeDot, GTE_ROW_INDEX_0, GTE_MATRIX_ROT, GTE_VECTOR_0); + gte_dotProduct(&edgeDot, GTE_ROW_INDEX_0, GTE_MATRIX_ROT, GTE_VECTOR_0, GTE_CALC_INT); gte_readMac(&pointDot, GTE_MAC_2); s32 leadingZeroes; gte_leadingZeroes(&leadingZeroes, pointDot); @@ -31,19 +31,51 @@ void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const gte_loadVec(V1.v, GTE_VECTOR_MAC); Vec3 coords; - gte_interpolate(coords.v, GTE_INTERPOLATE_FLOATING_POINT); + gte_interpolate(coords.v, GTE_CALC_FLOATING_POINT); out->x = coords.x; out->y = coords.y; out->z = coords.z; TEST_COLL_ProjectPointToEdge(v1, v2, point, out); /* This is a hand written assembly function that breaks the ABI, - and some callers expect the argument registers to be untouched*/ + and some callers expect the argument registers to be untouched */ __asm__ volatile("move $a0, %0" : : "r"((u32)out)); __asm__ volatile("move $a1, %0" : : "r"((u32)v1)); __asm__ volatile("move $a2, %0" : : "r"((u32)v2)); __asm__ volatile("move $a3, %0" : : "r"((u32)point)); } +/* Address: 0x8001f2dc */ +void COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3) +{ +#ifdef TEST_COLL_IMPL + CollVertex input = *v1; +#endif + Vec3 cross; + const Matrix m = { .m[0][0] = v3->pos.x - v1->pos.x, .m[1][1] = v3->pos.y - v1->pos.y, .m[2][2] = v3->pos.z - v1->pos.z }; + const SVec3 v = { .x = v2->pos.x - v1->pos.x, .y = v2->pos.y - v1->pos.y, .z = v2->pos.z - v1->pos.z }; + gte_crossProduct(cross.v, m.m, v.v); + v1->triNormal.x = ((cross.x >> cache->lodShift) * cache->normalScale) >> cache->normalBitshift; + v1->triNormal.y = ((cross.y >> cache->lodShift) * cache->normalScale) >> cache->normalBitshift; + v1->triNormal.z = ((cross.z >> cache->lodShift) * cache->normalScale) >> cache->normalBitshift; + + s32 dot; + gte_loadRowMatrix(v1->pos.v, GTE_ROW_INDEX_0, GTE_MATRIX_ROT); + gte_loadSVec(v1->triNormal.v, GTE_VECTOR_IR); + gte_dotProduct(&dot, GTE_ROW_INDEX_0, GTE_MATRIX_ROT, GTE_VECTOR_IR, GTE_CALC_FLOATING_POINT); + v1->planeDist = dot >> 1; + + Vec3 absNormal = { .x = abs(v1->triNormal.x), .y = abs(v1->triNormal.y), .z = abs(v1->triNormal.z) }; + const s32 magnitude = max(max(absNormal.x, absNormal.y), absNormal.z); + if (magnitude == absNormal.x) { v1->normalDominantAxis = AXIS_X; } + else if (magnitude == absNormal.y) { v1->normalDominantAxis = AXIS_Y; } + else { v1->normalDominantAxis = AXIS_Z; } + TEST_COLL_CalculateTrianglePlane(cache, &input, v2, v3, v1); + /* This is a hand written assembly function that breaks the ABI, + and some callers expect the argument registers to be untouched */ + __asm__ volatile("move $a0, %0" : : "r"((u32)cache)); + __asm__ volatile("move $t9, %0" : : "r"((u32)cache->currQuadblock)); +} + /* Address: 0x8001f7f0 */ void COLL_LoadVerticeData(CollDCache* cache) { @@ -60,7 +92,7 @@ void COLL_LoadVerticeData(CollDCache* cache) cache->quadblockFourthIndex = quadblock->index[3]; TEST_COLL_LoadVerticeData(cache); /* This is a hand written assembly function that breaks the ABI, - and some callers expect the argument registers to be untouched*/ + and some callers expect the argument registers to be untouched */ __asm__ volatile("move $a0, %0" : : "r"((u32)cache)); __asm__ volatile("move $t9, %0" : : "r"((u32)quadblock)); } diff --git a/rewrite/src/exe/math.c b/rewrite/src/exe/math.c index ea4387bc6..38ee459b6 100644 --- a/rewrite/src/exe/math.c +++ b/rewrite/src/exe/math.c @@ -82,7 +82,7 @@ s32 MATH_VectorLength(const SVec3* vector) gte_loadRowMatrix(vector, GTE_ROW_INDEX_0, GTE_MATRIX_ROT); gte_loadSVec(vector, GTE_VECTOR_0); s32 lengthSquared; - gte_dotProduct(&lengthSquared, GTE_ROW_INDEX_0, GTE_MATRIX_ROT, GTE_VECTOR_0); + gte_dotProduct(&lengthSquared, GTE_ROW_INDEX_0, GTE_MATRIX_ROT, GTE_VECTOR_0, GTE_CALC_INT); const s32 len = ND_SquareRoot0_stub(lengthSquared); TEST_MATH_VectorLength(vector, len); return len; diff --git a/rewrite/src/tests/test.c b/rewrite/src/tests/test.c index 979eb76ea..a7eed37c0 100644 --- a/rewrite/src/tests/test.c +++ b/rewrite/src/tests/test.c @@ -32,6 +32,7 @@ FunctionPatch s_functions[] = TEST_FUNC(COLL_ProjectPointToEdge), TEST_FUNC(COLL_BarycentricTest), TEST_FUNC(COLL_LoadVerticeData), + TEST_FUNC(COLL_CalculateTrianglePlane), }; void LoadTestPatches() diff --git a/rewrite/src/tests/test_coll.c b/rewrite/src/tests/test_coll.c index efc255a5e..852b70576 100644 --- a/rewrite/src/tests/test_coll.c +++ b/rewrite/src/tests/test_coll.c @@ -13,6 +13,18 @@ void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* PatchFunction_End(index); } +void TEST_COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const CollVertex* ret) +{ + const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_CalculateTrianglePlane)); + typedef void (*Func)(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3); + Func func = (Func) TEST_WRAPPER; + func(cache, v1, v2, v3); + PrintSVectorDiff("COLL_CalculateTrianglePlane", &v1->triNormal, &ret->triNormal); + if (v1->planeDist != ret->planeDist) { ND_printf("[COLL_CalculateTrianglePlane] Test Failed:\nDist: %d\nResult: %d\n", v1->planeDist, ret->planeDist); } + if (v1->normalDominantAxis != ret->normalDominantAxis) { ND_printf("[COLL_CalculateTrianglePlane] Test Failed:\nAxis: %d\nResult: %d\n", v1->normalDominantAxis, ret->normalDominantAxis); } + PatchFunction_End(index); +} + void TEST_COLL_LoadVerticeData(CollDCache* cache) { CollVertex vertices[NUM_VERTICES_QUADBLOCK]; diff --git a/symbols/gcc-syms-rewrite.txt b/symbols/gcc-syms-rewrite.txt index c26690caf..22beb1ee9 100644 --- a/symbols/gcc-syms-rewrite.txt +++ b/symbols/gcc-syms-rewrite.txt @@ -63,7 +63,7 @@ ND_COLL_SearchBSP_CallbackQUADBLK = 0x8001eb0c; ND_COLL_SearchBSP_CallbackPARAM = 0x8001ebec; ND_COLL_ProjectPointToEdge = 0x8001ede4; ND_COLL_FIXED_TRIANGL_TestPoint = 0x8001ef50; -ND_COLL_FIXED_TRIANGL_GetNormVec = 0x8001f2dc; +ND_COLL_CalculateTrianglePlane = 0x8001f2dc; ND_COLL_FIXED_QUADBLK_TestTriangles = 0x8001f41c; ND_COLL_FIXED_BSPLEAF_TestQuadblocks = 0x8001f5f0; ND_COLL_FIXED_QUADBLK_GetNormVecs_LoLOD = 0x8001f67c; @@ -851,7 +851,7 @@ ND_ThTick_SetAndExec = 0x800716ec; ND_ThTick_Set = 0x80071704; ND_RotTrans = 0x8007170c; ND_ratan2 = 0x8007173c; -ND_memset = 0x800718bc; +memset = 0x800718bc; ND_strcmp = 0x800718cc; ND_SetTransMatrix = 0x800718dc; ND_SetRotMatrix = 0x800718fc; From 1a7b523664269ef5704aefee789be63a6bfa76d1 Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Thu, 25 Sep 2025 17:51:55 -0700 Subject: [PATCH 4/6] two more functions --- include/ctr/coll.h | 4 +-- include/ctr/lev.h | 4 +-- include/ctr/nd.h | 2 ++ rewrite/src/exe/coll.c | 54 ++++++++++++++++++++++++++++++++---- rewrite/src/tests/test.c | 4 +-- symbols/gcc-syms-rewrite.txt | 4 +-- 6 files changed, 58 insertions(+), 14 deletions(-) diff --git a/include/ctr/coll.h b/include/ctr/coll.h index 23fa7019f..cc0732b6c 100644 --- a/include/ctr/coll.h +++ b/include/ctr/coll.h @@ -104,6 +104,6 @@ typedef struct CollDCache #define DCACHE_COLL (*(CollDCache*) 0x1f800000) void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); -void COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3); -void COLL_LoadVerticeData(CollDCache* cache); +void COLL_LoadQuadblockData_LowLOD(CollDCache* cache, Quadblock* quadblock); +void COLL_LoadQuadblockData_HighLOD(CollDCache* cache, Quadblock* quadblock); s32 COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); \ No newline at end of file diff --git a/include/ctr/lev.h b/include/ctr/lev.h index ab154f0f4..840d810e1 100644 --- a/include/ctr/lev.h +++ b/include/ctr/lev.h @@ -69,8 +69,8 @@ typedef struct Quadblock u8 checkpointIndex; // 0x3E u8 triNormalVecBitshift; // 0x3F u32 offLowTexture; // 0x40 - VisibleSet visibleSet; // 0x44 - u16 triNormalVecDividend[NUM_VERTICES_QUADBLOCK + 1]; // 0x48 + VisibleSet* visibleSet; // 0x44 + s16 triNormalVecDividend[NUM_VERTICES_QUADBLOCK + 1]; // 0x48 } Quadblock; typedef struct BSPBranch diff --git a/include/ctr/nd.h b/include/ctr/nd.h index c97586346..7f5e63ebb 100644 --- a/include/ctr/nd.h +++ b/include/ctr/nd.h @@ -30,6 +30,8 @@ u32 ND_RNG_Random(RNGSeed* seed); /* COLL */ void ND_COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); +void ND_COLL_LoadQuadblockData_LowLOD(CollDCache* cache, Quadblock* quadblock); +void ND_COLL_LoadQuadblockData_HighLOD(CollDCache* cache, Quadblock* quadblock); void ND_COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3); void ND_COLL_LoadVerticeData(CollDCache* cache); s32 ND_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); \ No newline at end of file diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index df3c17d47..f106cab99 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -45,7 +45,7 @@ void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const } /* Address: 0x8001f2dc */ -void COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3) +static void COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3) { #ifdef TEST_COLL_IMPL CollVertex input = *v1; @@ -70,14 +70,10 @@ void COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const else if (magnitude == absNormal.y) { v1->normalDominantAxis = AXIS_Y; } else { v1->normalDominantAxis = AXIS_Z; } TEST_COLL_CalculateTrianglePlane(cache, &input, v2, v3, v1); - /* This is a hand written assembly function that breaks the ABI, - and some callers expect the argument registers to be untouched */ - __asm__ volatile("move $a0, %0" : : "r"((u32)cache)); - __asm__ volatile("move $t9, %0" : : "r"((u32)cache->currQuadblock)); } /* Address: 0x8001f7f0 */ -void COLL_LoadVerticeData(CollDCache* cache) +static void COLL_LoadVerticeData(CollDCache* cache) { const Quadblock* quadblock = cache->currQuadblock; const Vertex* vertices = cache->meshInfo->vertices; @@ -91,6 +87,52 @@ void COLL_LoadVerticeData(CollDCache* cache) cache->quadblockThirdIndex = quadblock->index[2]; cache->quadblockFourthIndex = quadblock->index[3]; TEST_COLL_LoadVerticeData(cache); +} + +/* Address: 0x8001f67c */ +void COLL_LoadQuadblockData_LowLOD(CollDCache* cache, Quadblock* quadblock) +{ + COLL_LoadVerticeData(cache); + cache->lodShift = 2; + cache->normalBitshift = quadblock->triNormalVecBitshift; + if (cache->quadblockThirdIndex != cache->quadblockFourthIndex) + { + cache->normalScale = quadblock->triNormalVecDividend[9]; + COLL_CalculateTrianglePlane(cache, &cache->quadblockCollVertices[1], &cache->quadblockCollVertices[3], &cache->quadblockCollVertices[2]); + } + cache->normalScale = quadblock->triNormalVecDividend[8]; + COLL_CalculateTrianglePlane(cache, &cache->quadblockCollVertices[0], &cache->quadblockCollVertices[1], &cache->quadblockCollVertices[2]); + /* This is a hand written assembly function that breaks the ABI, + and some callers expect the argument registers to be untouched */ + __asm__ volatile("move $a0, %0" : : "r"((u32)cache)); + __asm__ volatile("move $t9, %0" : : "r"((u32)quadblock)); +} + +/* Address: 0x8001f6f0 */ +void COLL_LoadQuadblockData_HighLOD(CollDCache* cache, Quadblock* quadblock) +{ + COLL_LoadVerticeData(cache); + cache->lodShift = 0; + cache->normalBitshift = quadblock->triNormalVecBitshift; + if (cache->quadblockThirdIndex != cache->quadblockFourthIndex) + { + cache->normalScale = quadblock->triNormalVecDividend[4]; + COLL_CalculateTrianglePlane(cache, &cache->quadblockCollVertices[8], &cache->quadblockCollVertices[6], &cache->quadblockCollVertices[7]); + cache->normalScale = quadblock->triNormalVecDividend[5]; + COLL_CalculateTrianglePlane(cache, &cache->quadblockCollVertices[7], &cache->quadblockCollVertices[3], &cache->quadblockCollVertices[8]); + cache->normalScale = quadblock->triNormalVecDividend[6]; + COLL_CalculateTrianglePlane(cache, &cache->quadblockCollVertices[1], &cache->quadblockCollVertices[7], &cache->quadblockCollVertices[6]); + cache->normalScale = quadblock->triNormalVecDividend[7]; + COLL_CalculateTrianglePlane(cache, &cache->quadblockCollVertices[2], &cache->quadblockCollVertices[6], &cache->quadblockCollVertices[8]); + } + cache->normalScale = quadblock->triNormalVecDividend[0]; + COLL_CalculateTrianglePlane(cache, &cache->quadblockCollVertices[0], &cache->quadblockCollVertices[4], &cache->quadblockCollVertices[5]); + cache->normalScale = quadblock->triNormalVecDividend[1]; + COLL_CalculateTrianglePlane(cache, &cache->quadblockCollVertices[4], &cache->quadblockCollVertices[6], &cache->quadblockCollVertices[5]); + cache->normalScale = quadblock->triNormalVecDividend[2]; + COLL_CalculateTrianglePlane(cache, &cache->quadblockCollVertices[6], &cache->quadblockCollVertices[4], &cache->quadblockCollVertices[1]); + cache->normalScale = quadblock->triNormalVecDividend[3]; + COLL_CalculateTrianglePlane(cache, &cache->quadblockCollVertices[5], &cache->quadblockCollVertices[6], &cache->quadblockCollVertices[2]); /* This is a hand written assembly function that breaks the ABI, and some callers expect the argument registers to be untouched */ __asm__ volatile("move $a0, %0" : : "r"((u32)cache)); diff --git a/rewrite/src/tests/test.c b/rewrite/src/tests/test.c index a7eed37c0..ba75b6e65 100644 --- a/rewrite/src/tests/test.c +++ b/rewrite/src/tests/test.c @@ -31,8 +31,8 @@ FunctionPatch s_functions[] = TEST_FUNC(RNG_Random), TEST_FUNC(COLL_ProjectPointToEdge), TEST_FUNC(COLL_BarycentricTest), - TEST_FUNC(COLL_LoadVerticeData), - TEST_FUNC(COLL_CalculateTrianglePlane), + TEST_FUNC(COLL_LoadQuadblockData_LowLOD), + TEST_FUNC(COLL_LoadQuadblockData_HighLOD), }; void LoadTestPatches() diff --git a/symbols/gcc-syms-rewrite.txt b/symbols/gcc-syms-rewrite.txt index 22beb1ee9..1d5edad33 100644 --- a/symbols/gcc-syms-rewrite.txt +++ b/symbols/gcc-syms-rewrite.txt @@ -66,8 +66,8 @@ ND_COLL_FIXED_TRIANGL_TestPoint = 0x8001ef50; ND_COLL_CalculateTrianglePlane = 0x8001f2dc; ND_COLL_FIXED_QUADBLK_TestTriangles = 0x8001f41c; ND_COLL_FIXED_BSPLEAF_TestQuadblocks = 0x8001f5f0; -ND_COLL_FIXED_QUADBLK_GetNormVecs_LoLOD = 0x8001f67c; -ND_COLL_FIXED_QUADBLK_GetNormVecs_HiLOD = 0x8001f6f0; +ND_COLL_LoadQuadblockData_LowLOD = 0x8001f67c; +ND_COLL_LoadQuadblockData_HighLOD = 0x8001f6f0; ND_COLL_LoadVerticeData = 0x8001f7f0; ND_COLL_BarycentricTest = 0x8001f928; ND_COLL_MOVED_TRIANGL_TestPoint = 0x8001fc40; From 9d527b4a688dcf167196708416a98d60879bc09a Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Thu, 25 Sep 2025 17:55:10 -0700 Subject: [PATCH 5/6] missing def --- include/ctr/test.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/ctr/test.h b/include/ctr/test.h index cd5b81fe8..b7207b394 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -24,9 +24,9 @@ force_inline void FlushCache() #define BACKUP_ADDR 0x80400000 -#define TEST_MATH_IMPL -#define TEST_RNG_IMPL -#define TEST_COLL_IMPL +//#define TEST_MATH_IMPL +//#define TEST_RNG_IMPL +//#define TEST_COLL_IMPL #ifdef TEST_MATH_IMPL void TEST_MATH_Sin(u32 angle, s32 ret); @@ -71,6 +71,7 @@ force_inline void FlushCache() void TEST_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const SVec3* pos, s32 ret); #else #define TEST_COLL_ProjectPointToEdge(out, v1, v2, point) + #define TEST_COLL_CalculateTrianglePlane(cache, v1, v2, v3, ret) #define TEST_COLL_LoadVerticeData(cache) #define TEST_COLL_BarycentricTest(t, v1, v2, v3, pos, ret) #endif \ No newline at end of file From 20e4b41804783b45f5d9ccc67040b05f5505b995 Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Fri, 26 Sep 2025 16:02:54 -0700 Subject: [PATCH 6/6] decompile TestTriangle --- include/ctr/coll.h | 32 ++++---- include/ctr/driver.h | 8 ++ include/ctr/gte.h | 7 +- include/ctr/lev.h | 37 ++++++++- include/ctr/nd.h | 3 +- include/ctr/test.h | 4 +- rewrite/src/exe/coll.c | 143 ++++++++++++++++++++++++++++++++- rewrite/src/tests/test.c | 2 +- rewrite/src/tests/test_coll.c | 23 ++++++ symbols/gcc-extern-rewrite.txt | 3 +- symbols/gcc-syms-rewrite.txt | 2 +- 11 files changed, 237 insertions(+), 27 deletions(-) create mode 100644 include/ctr/driver.h diff --git a/include/ctr/coll.h b/include/ctr/coll.h index cc0732b6c..7b7bf997e 100644 --- a/include/ctr/coll.h +++ b/include/ctr/coll.h @@ -29,7 +29,7 @@ typedef struct CollVertex u16 normalDominantAxis; const Vertex* levVertex; SVec3 triNormal; - u16 planeDist; + s16 planeDist; } CollVertex; typedef struct TestVertex @@ -37,7 +37,7 @@ typedef struct TestVertex SVec3 pos; u16 normalDominantAxis; SVec3 triNormal; - u16 planeDist; + s16 planeDist; SVec3 interpolationPoint; } TestVertex; @@ -66,31 +66,27 @@ typedef struct CollDCache s16 unk0; s16 unk1; CollInputData collInput; - MeshInfo* meshInfo; + const MeshInfo* meshInfo; BoundingBox bbox; s16 numVerticesTested; - s16 numTrianglesTouched; + s16 numTrianglesCollided; s16 unk2; s16 numInstancesCollided; u32 unk3; - BSPNode* bspNodes; + const BSPNode* bspNodes; TestVertex collIntersection; u8 unk4; u8 currTriangleIndex; - Quadblock* currQuadblock; - SVec3 collPos; - u16 normalDominantAxis_TriCollided; - SVec3 normalTriCollided; - s16 unk5; - SVec3 interpolationPoint; - u8 barycentricTest; + const Quadblock* currQuadblock; + TestVertex coll; + s8 barycentricTest; u8 collidedTriangleIndex; - Quadblock* collidedQuadblock; + const Quadblock* collidedQuadblock; s32 speedScale; u8 unk6[0x44]; - Vertex* collidedVertices[NUM_VERTICES_TRIANGLE]; - CollVertex* currTestVertices[NUM_VERTICES_TRIANGLE]; - SVec3 distInterpolationIntersection; + const Vertex* collidedVertices[NUM_VERTICES_TRIANGLE]; + const CollVertex* currTestVertices[NUM_VERTICES_TRIANGLE]; + SVec3 deltaInterpolationIntersection; s16 unk7; u16 quadblockThirdIndex; u16 quadblockFourthIndex; @@ -106,4 +102,6 @@ typedef struct CollDCache void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); void COLL_LoadQuadblockData_LowLOD(CollDCache* cache, Quadblock* quadblock); void COLL_LoadQuadblockData_HighLOD(CollDCache* cache, Quadblock* quadblock); -s32 COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); \ No newline at end of file +void COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); + +extern u32 e_ignoreCollisionDoorFlagTerrain; // 0x8008d728 \ No newline at end of file diff --git a/include/ctr/driver.h b/include/ctr/driver.h new file mode 100644 index 000000000..c16a9d0eb --- /dev/null +++ b/include/ctr/driver.h @@ -0,0 +1,8 @@ +#pragma once + +#include + +typedef enum StepFlags +{ + STEPFLAGS_OUT_OF_BOUNDS = 0x4000, +} StepFlags; \ No newline at end of file diff --git a/include/ctr/gte.h b/include/ctr/gte.h index f100d1667..7d138f3fd 100644 --- a/include/ctr/gte.h +++ b/include/ctr/gte.h @@ -82,8 +82,10 @@ typedef enum GTE_CALC #define _gte_dotProduct_GTE_ROW_INDEX_1_GTE_CALC_FLOATING_POINT(out, matrixType, vecType) gte_mvmva(1, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_2(out) #define _gte_dotProduct_GTE_ROW_INDEX_2_GTE_CALC_FLOATING_POINT(out, matrixType, vecType) gte_mvmva(1, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_3(out) #define _gte_mulMatrixVec(out, matrixType, vecType, shift) gte_mvmva(shift, matrixType, vecType, 3, 0); _gte_readMac_GTE_VECTOR_MAC(out) -#define _gte_interpolate_GTE_CALC_INT() gte_gpl0() -#define _gte_interpolate_GTE_CALC_FLOATING_POINT() gte_gpl12() +#define _gte_interpolate_GTE_CALC_INT() gte_gpf0() +#define _gte_interpolate_GTE_CALC_FLOATING_POINT() gte_gpf12() +#define _gte_interpolateBase_GTE_CALC_INT() gte_gpl0() +#define _gte_interpolateBase_GTE_CALC_FLOATING_POINT() gte_gpl12() #define _gte_leadingZeroes(out, in) __asm__ volatile ( \ "mtc2 %1, $30;" \ "nop;" \ @@ -104,4 +106,5 @@ typedef enum GTE_CALC #define gte_dotProduct(out, rowIndex, matrixType, vecType, calcType) CAT3(_gte_dotProduct_, rowIndex, _##calcType)(out, matrixType, vecType) #define gte_leadingZeroes(out, in) _gte_leadingZeroes(out, in) #define gte_interpolate(out, calcType) CAT(_gte_interpolate_, calcType)(); _gte_readMac_GTE_VECTOR_MAC(out) +#define gte_interpolateBase(out, calcType) CAT(_gte_interpolateBase_, calcType)(); _gte_readMac_GTE_VECTOR_MAC(out) #define gte_crossProduct(out, matrix, vector) gte_SetRotMatrix(matrix); gte_loadSVec(vector, GTE_VECTOR_IR); gte_op0(); gte_readMac(out, GTE_VECTOR_MAC) \ No newline at end of file diff --git a/include/ctr/lev.h b/include/ctr/lev.h index 840d810e1..1a74801d5 100644 --- a/include/ctr/lev.h +++ b/include/ctr/lev.h @@ -53,11 +53,46 @@ typedef struct VisibleSet u32* visibleExtra; } VisibleSet; +typedef enum QuadFlags +{ + QUADFLAGS_INVISIBLE = 1 << 0, + QUADFLAGS_MOON_GRAVITY = 1 << 1, + QUADFLAGS_REFLECTION = 1 << 2, + QUADFLAGS_KICKERS = 1 << 3, + QUADFLAGS_OUT_OF_BOUNDS = 1 << 4, + QUADFLAGS_NEVER_USED = 1 << 5, + QUADFLAGS_TRIGGER_SCRIPT = 1 << 6, + QUADFLAGS_REVERB = 1 << 7, + QUADFLAGS_KICKERS_TWO = 1 << 8, + QUADFLAGS_MASK_GRAB = 1 << 9, + QUADFLAGS_TIGER_TEMPLE_DOOR = 1 << 10, + QUADFLAGS_COLLISION_TRIGGER = 1 << 11, + QUADFLAGS_GROUND = 1 << 12, + QUADFLAGS_WALL = 1 << 13, + QUADFLAGS_NO_COLLISION = 1 << 14, + QUADFLAGS_INVISIBLE_TRIGGER = 1 << 15, +} QuadFlags; + +typedef struct DrawOrder +{ + u32 drawOrder : 8; + u32 rotFlipFace0 : 3; + u32 drawModeFace0 : 2; + u32 rotFlipFace1 : 3; + u32 drawModeFace1 : 2; + u32 rotFlipFace2 : 3; + u32 drawModeFace2 : 2; + u32 rotFlipFace3 : 3; + u32 drawModeFace3 : 2; + u32 unk : 3; + u32 doubleSided : 1; +} DrawOrder; + typedef struct Quadblock { u16 index[NUM_VERTICES_QUADBLOCK]; // 0x0 u16 flags; // 0x12 - u32 drawOrderLow; // 0x14 + DrawOrder drawOrderLow; // 0x14 u32 drawOrderHigh; // 0x18 u32 offMidTextures[4]; // 0x1C BoundingBox bbox; // 0x2C diff --git a/include/ctr/nd.h b/include/ctr/nd.h index 7f5e63ebb..513741644 100644 --- a/include/ctr/nd.h +++ b/include/ctr/nd.h @@ -34,4 +34,5 @@ void ND_COLL_LoadQuadblockData_LowLOD(CollDCache* cache, Quadblock* quadblock); void ND_COLL_LoadQuadblockData_HighLOD(CollDCache* cache, Quadblock* quadblock); void ND_COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3); void ND_COLL_LoadVerticeData(CollDCache* cache); -s32 ND_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); \ No newline at end of file +s32 ND_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); +void ND_COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); \ No newline at end of file diff --git a/include/ctr/test.h b/include/ctr/test.h index b7207b394..2b20e2ecb 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -26,7 +26,7 @@ force_inline void FlushCache() //#define TEST_MATH_IMPL //#define TEST_RNG_IMPL -//#define TEST_COLL_IMPL +#define TEST_COLL_IMPL #ifdef TEST_MATH_IMPL void TEST_MATH_Sin(u32 angle, s32 ret); @@ -69,9 +69,11 @@ force_inline void FlushCache() void TEST_COLL_CalculateTrianglePlane(const CollDCache* cache, CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const CollVertex* ret); void TEST_COLL_LoadVerticeData(CollDCache* cache); void TEST_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const SVec3* pos, s32 ret); + void TEST_COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const CollDCache* ret); #else #define TEST_COLL_ProjectPointToEdge(out, v1, v2, point) #define TEST_COLL_CalculateTrianglePlane(cache, v1, v2, v3, ret) #define TEST_COLL_LoadVerticeData(cache) #define TEST_COLL_BarycentricTest(t, v1, v2, v3, pos, ret) + #define TEST_COLL_TestTriangle(cache, v1, v2, v3, ret) #endif \ No newline at end of file diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index f106cab99..e0b0c497c 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -1,5 +1,6 @@ #include #include +#include #include /* Address: 0x8001ede4 */ @@ -31,7 +32,7 @@ void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const gte_loadVec(V1.v, GTE_VECTOR_MAC); Vec3 coords; - gte_interpolate(coords.v, GTE_CALC_FLOATING_POINT); + gte_interpolateBase(coords.v, GTE_CALC_FLOATING_POINT); out->x = coords.x; out->y = coords.y; out->z = coords.z; @@ -244,7 +245,7 @@ static s32 _COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const Coll return BARYCENTRIC_TEST_INSIDE_TRIANGLE; } -s32 COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3) +static s32 COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3) { #ifdef TEST_COLL_IMPL TestVertex input = *t; @@ -252,4 +253,142 @@ s32 COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* const s32 ret = _COLL_BarycentricTest(t, v1, v2, v3); TEST_COLL_BarycentricTest(&input, v1, v2, v3, &t->pos, ret); return ret; +} + +static void _COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3) +{ + cache->numVerticesTested++; + cache->collIntersection.triNormal = v1->triNormal; + cache->collIntersection.planeDist = v1->planeDist; + cache->collIntersection.normalDominantAxis = v1->normalDominantAxis; + + const u16 quadFlags = cache->currQuadblock->flags; + if ((quadFlags & QUADFLAGS_TIGER_TEMPLE_DOOR) && (cache->currQuadblock->terrain & e_ignoreCollisionDoorFlagTerrain)) { return; } + + const u32 triggerScript = quadFlags & QUADFLAGS_TRIGGER_SCRIPT; + const Matrix m = { + .m[0][0] = cache->inputNextPos.x, .m[0][1] = cache->inputNextPos.y, .m[0][2] = cache->inputNextPos.z, + .m[1][0] = cache->collInput.quadblock.driverPos.x, .m[1][1] = cache->collInput.quadblock.driverPos.y, .m[1][2] = cache->collInput.quadblock.driverPos.z, + }; + s32 distTriNextPos, distTriCurrPos; + gte_SetRotMatrix(m.m); + gte_loadSVec(cache->collIntersection.triNormal.v, GTE_VECTOR_0); + gte_dotProduct(&distTriNextPos, GTE_ROW_INDEX_0, GTE_MATRIX_ROT, GTE_VECTOR_0, GTE_CALC_FLOATING_POINT); + gte_readMac(&distTriCurrPos, GTE_MAC_2); + distTriNextPos = distTriNextPos + (cache->collIntersection.planeDist * -2); + distTriCurrPos = distTriCurrPos + (cache->collIntersection.planeDist * -2); + cache->numVerticesTested++; + if (distTriCurrPos < 0) + { + if ((!triggerScript) && (cache->currQuadblock->drawOrderLow.doubleSided == 0)) { return; } + distTriCurrPos = -distTriCurrPos; + distTriNextPos = -distTriNextPos; + cache->collIntersection.triNormal.x = -cache->collIntersection.triNormal.x; + cache->collIntersection.triNormal.y = -cache->collIntersection.triNormal.y; + cache->collIntersection.triNormal.z = -cache->collIntersection.triNormal.z; + cache->collIntersection.planeDist = -cache->collIntersection.planeDist; + } + if ((distTriNextPos >= cache->inputHitRadius) || ((!triggerScript) && (distTriNextPos > distTriCurrPos))) { return; } + + u32 crossedPlane = false; + const SVec3 deltaPos = { + .x = cache->inputNextPos.x - cache->collInput.quadblock.driverPos.x, + .y = cache->inputNextPos.y - cache->collInput.quadblock.driverPos.y, + .z = cache->inputNextPos.z - cache->collInput.quadblock.driverPos.z + }; + if (distTriNextPos < 0) + { + const s32 interpolationFactor = FP_DIV(-distTriNextPos, distTriCurrPos - distTriNextPos); + gte_loadSVec(deltaPos.v, GTE_VECTOR_IR); + gte_loadIR(interpolationFactor, GTE_IR_0); + crossedPlane = true; + } + else + { + gte_loadSVec(cache->collIntersection.triNormal.v, GTE_VECTOR_IR); + gte_loadIR(distTriNextPos, GTE_IR_0); + } + Vec3 interpolation; + gte_interpolate(interpolation.v, GTE_CALC_FLOATING_POINT); + cache->collIntersection.interpolationPoint.x = cache->inputNextPos.x - interpolation.x; + cache->collIntersection.interpolationPoint.y = cache->inputNextPos.y - interpolation.y; + cache->collIntersection.interpolationPoint.z = cache->inputNextPos.z - interpolation.z; + cache->currTestVertices[0] = v1; + cache->currTestVertices[1] = v2; + cache->currTestVertices[2] = v3; + const s32 barycentricTest = COLL_BarycentricTest(&cache->collIntersection, v1, v2, v3); + if (barycentricTest == BARYCENTRIC_TEST_INVALID) { return; } + + if (crossedPlane) + { + cache->deltaInterpolationIntersection.x = cache->collIntersection.interpolationPoint.x - cache->collIntersection.pos.x; + cache->deltaInterpolationIntersection.y = cache->collIntersection.interpolationPoint.y - cache->collIntersection.pos.y; + cache->deltaInterpolationIntersection.z = cache->collIntersection.interpolationPoint.z - cache->collIntersection.pos.z; + } + else + { + cache->deltaInterpolationIntersection.x = cache->inputNextPos.x - cache->collIntersection.pos.x; + cache->deltaInterpolationIntersection.y = cache->inputNextPos.y - cache->collIntersection.pos.y; + cache->deltaInterpolationIntersection.z = cache->inputNextPos.z - cache->collIntersection.pos.z; + } + s32 distSquaredInterpolationIntersection; + gte_loadRowMatrix(cache->deltaInterpolationIntersection.v, GTE_ROW_INDEX_0, GTE_MATRIX_ROT); + gte_loadSVec(cache->deltaInterpolationIntersection.v, GTE_VECTOR_0); + gte_dotProduct(&distSquaredInterpolationIntersection, GTE_ROW_INDEX_0, GTE_MATRIX_ROT, GTE_VECTOR_0, GTE_CALC_INT); + if (distSquaredInterpolationIntersection > cache->inputHitRadiusSquared) { return; } + + if (triggerScript) + { + const u32 skip = (distTriNextPos >= 0) && (distTriNextPos >= cache->inputHitRadius) && (distTriCurrPos >= cache->inputHitRadius); + if (!skip) { cache->stepFlags |= cache->currQuadblock->terrain; return; } + } + + s32 deltaDist = distTriCurrPos - distTriNextPos; + if (deltaDist != 0) { deltaDist = FP_ONE - FP_DIV(cache->inputHitRadius - distTriNextPos, deltaDist); } + if (deltaDist >= cache->speedScale) { return; } + + if (quadFlags & QUADFLAGS_OUT_OF_BOUNDS) + { + if ((quadFlags & QUADFLAGS_MASK_GRAB) == 0) { return; } + cache->stepFlags |= STEPFLAGS_OUT_OF_BOUNDS; + return; + } + + cache->speedScale = deltaDist; + cache->collidedVertices[0] = cache->currTestVertices[0]->levVertex; + cache->collidedVertices[1] = cache->currTestVertices[1]->levVertex; + cache->collidedVertices[2] = cache->currTestVertices[2]->levVertex; + cache->coll.pos = cache->collIntersection.pos; + cache->coll.normalDominantAxis = cache->collIntersection.normalDominantAxis; + cache->coll.triNormal = cache->collIntersection.triNormal; + cache->coll.planeDist = cache->collIntersection.planeDist; + cache->coll.interpolationPoint = cache->collIntersection.interpolationPoint; + cache->collidedQuadblock = cache->currQuadblock; + cache->collidedTriangleIndex = cache->currTriangleIndex; + cache->barycentricTest = barycentricTest; + if (deltaDist > 0) + { + Vec3 nextPos; + gte_loadSVec(deltaPos.v, GTE_VECTOR_IR); + gte_loadIR(deltaDist, GTE_IR_0); + gte_interpolate(nextPos.v, GTE_CALC_FLOATING_POINT); + cache->collInput.quadblock.driverNextPos.x = cache->collInput.quadblock.driverPos.x + nextPos.x; + cache->collInput.quadblock.driverNextPos.y = cache->collInput.quadblock.driverPos.y + nextPos.y; + cache->collInput.quadblock.driverNextPos.z = cache->collInput.quadblock.driverPos.z + nextPos.z; + } + else { cache->collInput.quadblock.driverNextPos = cache->collInput.quadblock.driverPos; } + cache->numTrianglesCollided++; +} + +void COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3) +{ +#ifdef TEST_COLL_IMPL + *(CollDCache*)(BACKUP_ADDR) = *cache; +#endif + _COLL_TestTriangle(cache, v1, v2, v3); + TEST_COLL_TestTriangle((CollDCache*)(BACKUP_ADDR), v1, v2, v3, cache); + /* This is a hand written assembly function that breaks the ABI, + and some callers expect the argument registers to be untouched */ + __asm__ volatile("move $a0, %0" : : "r"((u32)cache)); + __asm__ volatile("move $t9, %0" : : "r"((u32)cache->currQuadblock)); } \ No newline at end of file diff --git a/rewrite/src/tests/test.c b/rewrite/src/tests/test.c index ba75b6e65..90b82d9e8 100644 --- a/rewrite/src/tests/test.c +++ b/rewrite/src/tests/test.c @@ -30,9 +30,9 @@ FunctionPatch s_functions[] = TEST_FUNC(RNG_PseudoRand), TEST_FUNC(RNG_Random), TEST_FUNC(COLL_ProjectPointToEdge), - TEST_FUNC(COLL_BarycentricTest), TEST_FUNC(COLL_LoadQuadblockData_LowLOD), TEST_FUNC(COLL_LoadQuadblockData_HighLOD), + TEST_FUNC(COLL_TestTriangle), }; void LoadTestPatches() diff --git a/rewrite/src/tests/test_coll.c b/rewrite/src/tests/test_coll.c index 852b70576..41f0c8b34 100644 --- a/rewrite/src/tests/test_coll.c +++ b/rewrite/src/tests/test_coll.c @@ -2,6 +2,19 @@ #ifdef TEST_COLL_IMPL +static u32 PrintDCacheDiff(const char* name, const CollDCache* expected, const CollDCache* ret) +{ + u32 failed = false; + const u8* pExpected = (const u8*) expected; + const u8* pRet = (const u8*) ret; + const u32 len = sizeof(CollDCache); + for (u32 i = 0; i < len; i++) + { + if (pExpected[i] != pRet[i]) { ND_printf("[%s] Test Failed:\nOffset %x: %d, got: %d\n", name, i, (u32) pExpected[i], (u32) pRet[i]); failed = true; } + } + return failed; +} + void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* point, const SVec3* ret) { const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_ProjectPointToEdge)); @@ -68,4 +81,14 @@ void TEST_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVe PatchFunction_End(index); } +void TEST_COLL_TestTriangle(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const CollDCache* ret) +{ + const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_TestTriangle)); + typedef void (*Func)(CollDCache* cache, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); + Func func = (Func) TEST_WRAPPER; + func(cache, v1, v2, v3); + PrintDCacheDiff("COLL_TestTriangle", cache, ret); + PatchFunction_End(index); +} + #endif // TEST_COLL_IMPL \ No newline at end of file diff --git a/symbols/gcc-extern-rewrite.txt b/symbols/gcc-extern-rewrite.txt index bb9ba8de6..04133297a 100644 --- a/symbols/gcc-extern-rewrite.txt +++ b/symbols/gcc-extern-rewrite.txt @@ -1,2 +1,3 @@ e_gameTracker = 0x8008d2ac; -e_seed = 0x8008d424; \ No newline at end of file +e_seed = 0x8008d424; +e_ignoreCollisionDoorFlagTerrain = 0x8008d728; \ No newline at end of file diff --git a/symbols/gcc-syms-rewrite.txt b/symbols/gcc-syms-rewrite.txt index 1d5edad33..759d14ff9 100644 --- a/symbols/gcc-syms-rewrite.txt +++ b/symbols/gcc-syms-rewrite.txt @@ -70,7 +70,7 @@ ND_COLL_LoadQuadblockData_LowLOD = 0x8001f67c; ND_COLL_LoadQuadblockData_HighLOD = 0x8001f6f0; ND_COLL_LoadVerticeData = 0x8001f7f0; ND_COLL_BarycentricTest = 0x8001f928; -ND_COLL_MOVED_TRIANGL_TestPoint = 0x8001fc40; +ND_COLL_TestTriangle = 0x8001fc40; ND_COLL_MOVED_QUADBLK_TestTriangles = 0x80020064; ND_COLL_MOVED_BSPLEAF_TestQuadblocks = 0x800202a8; ND_COLL_MOVED_PlayerSearch = 0x80020410;