From a7ff99fa914dc5eb0685ddbcb6b5eb605a77e503 Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Mon, 22 Sep 2025 14:01:53 -0700 Subject: [PATCH 1/8] first function in coll decompiled --- include/ctr/coll.h | 5 +++ include/ctr/gte.h | 61 ++++++++++++++++++++++++++++------- include/ctr/nd.h | 5 ++- include/ctr/test.h | 8 +++++ rewrite/src/exe/coll.c | 39 ++++++++++++++++++++++ rewrite/src/exe/math.c | 10 +++--- rewrite/src/tests/test.c | 1 + rewrite/src/tests/test_coll.c | 14 ++++++++ symbols/gcc-syms-rewrite.txt | 2 +- 9 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 include/ctr/coll.h create mode 100644 rewrite/src/exe/coll.c create mode 100644 rewrite/src/tests/test_coll.c diff --git a/include/ctr/coll.h b/include/ctr/coll.h new file mode 100644 index 000000000..eb2af865e --- /dev/null +++ b/include/ctr/coll.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); \ No newline at end of file diff --git a/include/ctr/gte.h b/include/ctr/gte.h index 7ca41078e..95c83df5d 100644 --- a/include/ctr/gte.h +++ b/include/ctr/gte.h @@ -23,18 +23,32 @@ typedef enum GTE_VECTOR GTE_VECTOR_0, /* SVec */ GTE_VECTOR_1, /* SVec */ GTE_VECTOR_2, /* SVec */ - GTE_VECTOR_IR, /* Vec */ + GTE_VECTOR_IR, /* SVec */ + GTE_VECTOR_MAC, /* Vec */ } GTE_VECTOR; +typedef enum GTE_IR +{ + GTE_IR_0, /* s16 */ + GTE_IR_1, /* s16 */ + GTE_IR_2, /* s16 */ + GTE_IR_3, /* s16 */ +} GTE_IR; + typedef enum GTE_MAC { - GTE_MAC_0, - GTE_MAC_1, - GTE_MAC_2, - GTE_MAC_3, - GTE_MAC_VEC, /* 1-3, Vec */ + GTE_MAC_0, /* s32 */ + GTE_MAC_1, /* s32 */ + GTE_MAC_2, /* s32 */ + GTE_MAC_3, /* s32 */ } GTE_MAC; +typedef enum GTE_INTERPOLATE +{ + GTE_INTERPOLATE_INT, + GTE_INTERPOLATE_FLOATING_POINT, +} GTE_INTERPOLATE; + /* HELPERS */ #define _CAT(a, b) a##b #define CAT(a, b) _CAT(a, b) @@ -44,23 +58,46 @@ typedef enum GTE_MAC #define _gte_loadSVecMatrix_GTE_MATRIX_ROT_GTE_ROW_INDEX_0(v) gte_ldsvrtrow0(v) #define _gte_loadSVecMatrix_GTE_MATRIX_LIGHT_GTE_ROW_INDEX_0(v) gte_ldsvllrow0(v) #define _gte_loadSVecMatrix_GTE_MATRIX_COLOR_GTE_ROW_INDEX_0(v) gte_ldsvlcrow0(v) -#define _gte_loadVec_GTE_VECTOR_0(v) gte_ldv0(v) -#define _gte_loadVec_GTE_VECTOR_1(v) gte_ldv1(v) -#define _gte_loadVec_GTE_VECTOR_2(v) gte_ldv2(v) +#define _gte_loadSVec_GTE_VECTOR_0(v) gte_ldv0(v) +#define _gte_loadSVec_GTE_VECTOR_1(v) gte_ldv1(v) +#define _gte_loadSVec_GTE_VECTOR_2(v) gte_ldv2(v) +#define _gte_loadSVec_GTE_VECTOR_IR(v) gte_ldsv(v) #define _gte_loadVec_GTE_VECTOR_IR(v) gte_ldlvl(v) +#define _gte_loadVec_GTE_VECTOR_MAC(v) __asm__ volatile ( \ + "lwc2 $25, 0( %0 );" \ + "lwc2 $26, 4( %0 );" \ + "lwc2 $27, 8( %0 );" \ + : \ + : "r"( v ) ) #define _gte_readMac_GTE_MAC_0(out) gte_stopz(out) #define _gte_readMac_GTE_MAC_1(out) gte_stlvnl0(out) #define _gte_readMac_GTE_MAC_2(out) gte_stlvnl1(out) #define _gte_readMac_GTE_MAC_3(out) gte_stlvnl2(out) -#define _gte_readMac_GTE_MAC_VEC(out) gte_stlvnl(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_mulMatrixVec(out, matrixType, vecType, shift) gte_mvmva(shift, matrixType, vecType, 3, 0); _gte_readMac_GTE_MAC_VEC(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_leadingZeroes(out, in) __asm__ volatile ( \ + "mtc2 %1, $30;" \ + "nop;" \ + "nop;" \ + "swc2 $31, 0( %0 );" \ + : \ + : "r"( out ), "r"( in ) \ + : "memory" \ + ) /* API */ #define gte_readMac(out, macType) CAT(_gte_readMac_, macType)(out) +#define gte_loadIR(in, irType) CAT(_gte_loadIR_, irType)(in) +#define gte_loadSVec(v, vecType) CAT(_gte_loadSVec_, vecType)(v) #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) \ No newline at end of file +#define gte_dotProduct(out, rowIndex, matrixType, vecType) CAT(_gte_dotProduct_, rowIndex)(out, matrixType, vecType) +#define gte_leadingZeroes(out, in) _gte_leadingZeroes(out, in) +#define gte_interpolate(interpolationType) CAT(_gte_interpolate_, interpolationType)() \ No newline at end of file diff --git a/include/ctr/nd.h b/include/ctr/nd.h index 37bafed0d..8fa28ac9b 100644 --- a/include/ctr/nd.h +++ b/include/ctr/nd.h @@ -23,4 +23,7 @@ void ND_MATH_MatrixMultiplication(Matrix* out, const Matrix* m, const Matrix* n) u32 ND_RNG_Rand(); s32 ND_RNG_RandInt(u32 n); u16 ND_RNG_PseudoRand(u16 n); -u32 ND_RNG_Random(RNGSeed* seed); \ No newline at end of file +u32 ND_RNG_Random(RNGSeed* seed); + +/* COLL */ +void ND_COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); \ No newline at end of file diff --git a/include/ctr/test.h b/include/ctr/test.h index fea8b193b..23e5702c1 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -6,6 +6,7 @@ #include #include #include +#include void LoadTestPatches(); u32 PatchFunction_Beg(u32* index); @@ -17,6 +18,7 @@ u32 PrintMatrixDiff(const char* name, const Matrix* expected, const Matrix* ret, #define TEST_MATH_IMPL #define TEST_RNG_IMPL +#define TEST_COLL_IMPL #ifdef TEST_MATH_IMPL void TEST_MATH_Sin(u32 angle, s32 ret); @@ -52,4 +54,10 @@ u32 PrintMatrixDiff(const char* name, const Matrix* expected, const Matrix* ret, #define TEST_RNG_RandInt(n, ret) #define TEST_RNG_PseudoRand(n, ret) #define TEST_RNG_Random(seed, ret) +#endif + +#ifdef TEST_COLL_IMPL + void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* point, const SVec3* ret); +#else + #define TEST_COLL_ProjectPointToEdge(out, v1, v2, point) #endif \ No newline at end of file diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c new file mode 100644 index 000000000..59dc516b2 --- /dev/null +++ b/rewrite/src/exe/coll.c @@ -0,0 +1,39 @@ +#include +#include +#include + +/* Address: 0x8001ede4 */ +void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point) +{ + const SVec3 edge = { v2->x - v1->x, v2->y - v1->y, v2->z - v1->z }; + const Matrix m = + { + .m[0][0] = edge.x, .m[0][1] = edge.y, .m[0][2] = edge.z, + .m[1][0] = point->x - v1->x, .m[1][1] = point->y - v1->y, .m[1][2] = point->z - v1->z, + }; + 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_readMac(&pointDot, GTE_MAC_2); + s32 leadingZeroes; + gte_leadingZeroes(&leadingZeroes, pointDot); + + const s32 shift = clamp(leadingZeroes - 2, 0, FRACTIONAL_BITS); + if (shift < FRACTIONAL_BITS) { edgeDot >>= (FRACTIONAL_BITS - shift); } + + s32 barycentricFactor = 0; + if (edgeDot != 0) { barycentricFactor = clamp((pointDot << shift) / edgeDot, 0, FP_ONE); } + + const Vec3 V1 = { .x = v1->x, .y = v1->y, .z = v1->z }; + gte_loadIR(barycentricFactor, GTE_IR_0); + gte_loadSVec(edge.v, GTE_VECTOR_IR); + gte_loadVec(V1.v, GTE_VECTOR_MAC); + gte_interpolate(GTE_INTERPOLATE_FLOATING_POINT); + Vec3 coords; + gte_readMac(coords.v, GTE_VECTOR_MAC); + out->x = coords.x; + out->y = coords.y; + out->z = coords.z; + TEST_COLL_ProjectPointToEdge(v1, v2, point, out); +} \ No newline at end of file diff --git a/rewrite/src/exe/math.c b/rewrite/src/exe/math.c index 7af0d019c..ea4387bc6 100644 --- a/rewrite/src/exe/math.c +++ b/rewrite/src/exe/math.c @@ -71,7 +71,7 @@ void MATH_GetInverseMatrixTransformation(Matrix* out, const Matrix* matrix) } const SVec3 t = { .x = (-matrix->t.x) & 0xFFFF, .y = (-matrix->t.y) & 0xFFFF, .z = (-matrix->t.z) & 0xFFFF }; gte_SetRotMatrix(out->m); - gte_loadVec(&t, GTE_VECTOR_0); + gte_loadSVec(&t, GTE_VECTOR_0); gte_mulMatrixVec(out->t.v, GTE_MATRIX_ROT, GTE_VECTOR_0); TEST_MATH_GetInverseMatrixTransformation(matrix, out); } @@ -80,7 +80,7 @@ void MATH_GetInverseMatrixTransformation(Matrix* out, const Matrix* matrix) s32 MATH_VectorLength(const SVec3* vector) { gte_loadRowMatrix(vector, GTE_ROW_INDEX_0, GTE_MATRIX_ROT); - gte_loadVec(vector, GTE_VECTOR_0); + gte_loadSVec(vector, GTE_VECTOR_0); s32 lengthSquared; gte_dotProduct(&lengthSquared, GTE_ROW_INDEX_0, GTE_MATRIX_ROT, GTE_VECTOR_0); const s32 len = ND_SquareRoot0_stub(lengthSquared); @@ -142,11 +142,11 @@ void MATH_MatrixMultiplication(Matrix* out, const Matrix* m, const Matrix* n) const SVec3 v1 = { .x = n->m[0][1], .y = n->m[1][1], .z = n->m[2][1] }; const SVec3 v2 = { .x = n->m[0][2], .y = n->m[1][2], .z = n->m[2][2] }; gte_SetRotMatrix(m->m); - gte_loadVec(&v0, GTE_VECTOR_0); + gte_loadSVec(&v0, GTE_VECTOR_0); gte_mulMatrixVec(res[0].v, GTE_MATRIX_ROT, GTE_VECTOR_0); - gte_loadVec(&v1, GTE_VECTOR_1); + gte_loadSVec(&v1, GTE_VECTOR_1); gte_mulMatrixVec(res[1].v, GTE_MATRIX_ROT, GTE_VECTOR_1); - gte_loadVec(&v2, GTE_VECTOR_2); + gte_loadSVec(&v2, GTE_VECTOR_2); gte_mulMatrixVec(res[2].v, GTE_MATRIX_ROT, GTE_VECTOR_2); out->m[0][0] = res[0].x; out->m[0][1] = res[1].x; out->m[0][2] = res[2].x; out->m[1][0] = res[0].y; out->m[1][1] = res[1].y; out->m[1][2] = res[2].y; diff --git a/rewrite/src/tests/test.c b/rewrite/src/tests/test.c index f4604cd66..90e0485fc 100644 --- a/rewrite/src/tests/test.c +++ b/rewrite/src/tests/test.c @@ -29,6 +29,7 @@ FunctionPatch s_functions[] = TEST_FUNC(RNG_RandInt), TEST_FUNC(RNG_PseudoRand), TEST_FUNC(RNG_Random), + TEST_FUNC(COLL_ProjectPointToEdge), }; void LoadTestPatches() diff --git a/rewrite/src/tests/test_coll.c b/rewrite/src/tests/test_coll.c new file mode 100644 index 000000000..761632a4a --- /dev/null +++ b/rewrite/src/tests/test_coll.c @@ -0,0 +1,14 @@ +#include + +#ifdef TEST_COLL_IMPL + +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)); + SVec3 expected; + ND_COLL_ProjectPointToEdge(&expected, v1, v2, point); + PrintSVectorDiff("COLL_ProjectPointToEdge", &expected, ret); + PatchFunction_End(index); +} + +#endif // TEST_COLL_IMPL \ No newline at end of file diff --git a/symbols/gcc-syms-rewrite.txt b/symbols/gcc-syms-rewrite.txt index 057b69b50..e3448bfad 100644 --- a/symbols/gcc-syms-rewrite.txt +++ b/symbols/gcc-syms-rewrite.txt @@ -61,7 +61,7 @@ ND_COLL_FIXED_BotsSearch = 0x8001d77c; ND_COLL_FIXED_PlayerSearch = 0x8001d944; ND_COLL_SearchBSP_CallbackQUADBLK = 0x8001eb0c; ND_COLL_SearchBSP_CallbackPARAM = 0x8001ebec; -ND_COLL_FIXED_TRIANGL_Barycentrics = 0x8001ede4; +ND_COLL_ProjectPointToEdge = 0x8001ede4; ND_COLL_FIXED_TRIANGL_TestPoint = 0x8001ef50; ND_COLL_FIXED_TRIANGL_GetNormVec = 0x8001f2dc; ND_COLL_FIXED_QUADBLK_TestTriangles = 0x8001f41c; From 9b19ceced0ebd3cc162c32b65098e94933dc619e Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Mon, 22 Sep 2025 14:14:24 -0700 Subject: [PATCH 2/8] better macro --- include/ctr/gte.h | 2 +- rewrite/src/exe/coll.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/ctr/gte.h b/include/ctr/gte.h index 95c83df5d..0797d71e8 100644 --- a/include/ctr/gte.h +++ b/include/ctr/gte.h @@ -100,4 +100,4 @@ typedef enum GTE_INTERPOLATE #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_leadingZeroes(out, in) _gte_leadingZeroes(out, in) -#define gte_interpolate(interpolationType) CAT(_gte_interpolate_, interpolationType)() \ No newline at end of file +#define gte_interpolate(out, interpolationType) CAT(_gte_interpolate_, interpolationType)(); _gte_readMac_GTE_VECTOR_MAC(out) \ No newline at end of file diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index 59dc516b2..b46ff8702 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -29,9 +29,9 @@ void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const gte_loadIR(barycentricFactor, GTE_IR_0); gte_loadSVec(edge.v, GTE_VECTOR_IR); gte_loadVec(V1.v, GTE_VECTOR_MAC); - gte_interpolate(GTE_INTERPOLATE_FLOATING_POINT); + Vec3 coords; - gte_readMac(coords.v, GTE_VECTOR_MAC); + gte_interpolate(coords.v, GTE_INTERPOLATE_FLOATING_POINT); out->x = coords.x; out->y = coords.y; out->z = coords.z; From 48f98bc748a130a7727752c4211dbfbc55d84a10 Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Mon, 22 Sep 2025 20:40:03 -0700 Subject: [PATCH 3/8] COLL_BarycentricTest decompiled --- include/ctr/coll.h | 42 +++++++++++- include/ctr/lev.h | 20 ++++++ include/ctr/nd.h | 4 +- include/ctr/test.h | 2 + rewrite/buildList.txt | 2 +- rewrite/src/exe/coll.c | 105 ++++++++++++++++++++++++++++++ rewrite/src/tests/test.c | 1 + rewrite/src/tests/test_coll.c | 11 ++++ rewrite/src/tests/test_wrappers.s | 41 ++++++++++++ symbols/gcc-syms-rewrite.txt | 1 + 10 files changed, 226 insertions(+), 3 deletions(-) create mode 100644 include/ctr/lev.h create mode 100644 rewrite/src/tests/test_wrappers.s diff --git a/include/ctr/coll.h b/include/ctr/coll.h index eb2af865e..9c6090a0b 100644 --- a/include/ctr/coll.h +++ b/include/ctr/coll.h @@ -1,5 +1,45 @@ #pragma once +#include #include +#include -void COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); \ No newline at end of file +typedef enum Axis +{ + AXIS_Z = 1, + AXIS_X = 2, + AXIS_Y = 3, +} Axis; + +typedef enum BarycentricTest +{ + BARYCENTRIC_TEST_INVALID = -1, + BARYCENTRIC_TEST_SNAP_V1 = 0, + BARYCENTRIC_TEST_EDGE_V1_V2 = 1, + BARYCENTRIC_TEST_SNAP_V2 = 2, + BARYCENTRIC_TEST_EDGE_V2_V3 = 3, + BARYCENTRIC_TEST_SNAP_V3 = 4, + BARYCENTRIC_TEST_EDGE_V1_V3 = 5, + BARYCENTRIC_TEST_INSIDE_TRIANGLE = 6, +} BarycentricTest; + +typedef struct CollVertex +{ + SVec3 pos; + u16 normalDominantAxis; + Vertex* levVertex; + SVec3 triNormal; + u16 planeDist; +} CollVertex; + +typedef struct TestVertex +{ + SVec3 pos; + u16 normalDominantAxis; + SVec3 triNormal; + u16 planeDist; + SVec3 interpolationPoint; +} TestVertex; + +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 new file mode 100644 index 000000000..cc9dd6096 --- /dev/null +++ b/include/ctr/lev.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +typedef struct Color +{ + uint32_t r : 8; + uint32_t g : 8; + uint32_t b : 8; + uint32_t a : 8; +} Color; + +typedef struct Vertex +{ + SVec3 pos; + u16 flags; + Color colorHi; + Color colorLo; +} Vertex; \ No newline at end of file diff --git a/include/ctr/nd.h b/include/ctr/nd.h index 8fa28ac9b..66580d436 100644 --- a/include/ctr/nd.h +++ b/include/ctr/nd.h @@ -3,6 +3,7 @@ #include #include #include +#include void ND_LOAD_XnfFile(char* filename, u32 address, char* dummy); s32 ND_SquareRoot0_stub(s32 n); @@ -26,4 +27,5 @@ u16 ND_RNG_PseudoRand(u16 n); u32 ND_RNG_Random(RNGSeed* seed); /* COLL */ -void ND_COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); \ No newline at end of file +void ND_COLL_ProjectPointToEdge(SVec3* out, const SVec3* v1, const SVec3* v2, const SVec3* point); +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 23e5702c1..a4ec79b2f 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -58,6 +58,8 @@ u32 PrintMatrixDiff(const char* name, const Matrix* expected, const Matrix* ret, #ifdef TEST_COLL_IMPL void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* point, const SVec3* ret); + 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_BarycentricTest(t, v1, v2, v3, pos, ret) #endif \ No newline at end of file diff --git a/rewrite/buildList.txt b/rewrite/buildList.txt index de873b45c..74c0f955c 100644 --- a/rewrite/buildList.txt +++ b/rewrite/buildList.txt @@ -4,4 +4,4 @@ common, header, 0x8000B0B8, 0x0, src/hooks/dll/load_decomp.c // decomp files common, DLL, 0x80200000, 0x0, src/exe/*.c, DECOMP.BIN -common, DLL, 0x80600000, 0x0, src/tests/*.c, TESTS.BIN \ No newline at end of file +common, DLL, 0x80600000, 0x0, src/tests/*.c src/tests/test_wrappers.s, TESTS.BIN \ No newline at end of file diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index b46ff8702..0072fe8f0 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -36,4 +36,109 @@ 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); +} + +/* Address: 0x8001f928 */ +static s32 _COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3) +{ + Vec2 deltaT; + Vec2 deltaTri[2]; + const SVec3* edgeV2; + const SVec3* edgeV3; + u32 firstAxis, secondAxis; + + if (t->normalDominantAxis == AXIS_X) + { + firstAxis = 1; // y + secondAxis = 2; // z + } + else if (t->normalDominantAxis == AXIS_Y) + { + firstAxis = 2; // z + secondAxis = 0; // x + } + else + { + firstAxis = 0; // x + secondAxis = 1; // y + } + + deltaTri[0].x = v2->pos.v[firstAxis] - v1->pos.v[firstAxis]; + deltaTri[0].y = v3->pos.v[firstAxis] - v1->pos.v[firstAxis]; + deltaT.x = t->interpolationPoint.v[firstAxis] - v1->pos.v[firstAxis]; + edgeV2 = &v2->pos; + edgeV3 = &v3->pos; + if (abs(deltaTri[0].x) < abs(deltaTri[0].y)) + { + edgeV2 = &v3->pos; + edgeV3 = &v2->pos; + s32 temp = deltaTri[0].x; + deltaTri[0].x = deltaTri[0].y; + deltaTri[0].y = temp; + } + deltaTri[1].x = edgeV2->v[secondAxis] - v1->pos.v[secondAxis]; + deltaTri[1].y = edgeV3->v[secondAxis] - v1->pos.v[secondAxis]; + deltaT.y = t->interpolationPoint.v[secondAxis] - v1->pos.v[secondAxis]; + + s32 beta = FP(-1); + s32 gamma = FP(-1); + if (deltaTri[0].x != 0) + { + s32 dem = ((deltaTri[1].y * deltaTri[0].x) - (deltaTri[0].y * deltaTri[1].x)) >> 6; + if (dem == 0) { return BARYCENTRIC_TEST_INVALID; } + beta = (((deltaT.y * deltaTri[0].x) - (deltaT.x * deltaTri[1].x)) << 6) / dem; + gamma = ((deltaT.x * FP_ONE) - (beta * deltaTri[0].y)) / deltaTri[0].x; + } + else + { + if (deltaTri[0].y == 0) { return BARYCENTRIC_TEST_INVALID; } + beta = FP_DIV(deltaT.y, deltaTri[0].y); + if (deltaTri[1].x == 0) { return BARYCENTRIC_TEST_INVALID; } + gamma = (deltaT.y * FP_ONE) - (beta * deltaTri[1].y); + } + if (beta == FP(-1) || gamma == FP(-1)) { return BARYCENTRIC_TEST_INVALID; } + + s32 alpha = beta + gamma + FP(-1); + if (gamma < 0) + { + if (beta < 0) + { + t->pos = v1->pos; + return BARYCENTRIC_TEST_SNAP_V1; + } + if (alpha < 0) + { + COLL_ProjectPointToEdge(&t->pos, &v1->pos, edgeV3, &t->interpolationPoint); + return BARYCENTRIC_TEST_EDGE_V1_V3; + } + t->pos = *edgeV3; + return BARYCENTRIC_TEST_SNAP_V3; + } + if (beta < 0) + { + if (alpha < 0) + { + COLL_ProjectPointToEdge(&t->pos, &v1->pos, edgeV2, &t->interpolationPoint); + return BARYCENTRIC_TEST_EDGE_V1_V2; + } + t->pos = *edgeV2; + return BARYCENTRIC_TEST_SNAP_V2; + } + if (alpha > 0) + { + COLL_ProjectPointToEdge(&t->pos, edgeV2, edgeV3, &t->interpolationPoint); + return BARYCENTRIC_TEST_EDGE_V2_V3; + } + t->pos = t->interpolationPoint; + return BARYCENTRIC_TEST_INSIDE_TRIANGLE; +} + +s32 COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3) +{ +#ifdef TEST_COLL_IMPL + TestVertex input = *t; +#endif + const s32 ret = _COLL_BarycentricTest(t, v1, v2, v3); + TEST_COLL_BarycentricTest(&input, v1, v2, v3, &t->pos, ret); + return ret; } \ No newline at end of file diff --git a/rewrite/src/tests/test.c b/rewrite/src/tests/test.c index 90e0485fc..74bc35474 100644 --- a/rewrite/src/tests/test.c +++ b/rewrite/src/tests/test.c @@ -30,6 +30,7 @@ FunctionPatch s_functions[] = TEST_FUNC(RNG_PseudoRand), TEST_FUNC(RNG_Random), TEST_FUNC(COLL_ProjectPointToEdge), + TEST_FUNC(COLL_BarycentricTest), }; void LoadTestPatches() diff --git a/rewrite/src/tests/test_coll.c b/rewrite/src/tests/test_coll.c index 761632a4a..64f1c8c2d 100644 --- a/rewrite/src/tests/test_coll.c +++ b/rewrite/src/tests/test_coll.c @@ -11,4 +11,15 @@ void TEST_COLL_ProjectPointToEdge(const SVec3* v1, const SVec3* v2, const SVec3* PatchFunction_End(index); } +s32 WRAPPER_ND_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3); + +void TEST_COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const CollVertex* v2, const CollVertex* v3, const SVec3* pos, s32 ret) +{ + const u32 index = PatchFunction_Beg((u32*)(&ND_COLL_BarycentricTest)); + const s32 expected = WRAPPER_ND_COLL_BarycentricTest(t, v1, v2, v3); + PrintSVectorDiff("COLL_BarycentricTest", &t->pos, pos); + if (expected != ret) { ND_printf("[COLL_BarycentricTest] Test Failed:\nExpected: %d\nResult: %d\n", expected, ret); } + PatchFunction_End(index); +} + #endif // TEST_COLL_IMPL \ No newline at end of file diff --git a/rewrite/src/tests/test_wrappers.s b/rewrite/src/tests/test_wrappers.s new file mode 100644 index 000000000..d8dc09ea1 --- /dev/null +++ b/rewrite/src/tests/test_wrappers.s @@ -0,0 +1,41 @@ +.set noreorder +.align 2 +.macro SAVE_CONTEXT + addiu $sp, $sp, -44 + sw $s0, 0($sp) + sw $s1, 4($sp) + sw $s2, 8($sp) + sw $s3, 12($sp) + sw $s4, 16($sp) + sw $s5, 20($sp) + sw $s6, 24($sp) + sw $s7, 28($sp) + sw $fp, 32($sp) + sw $gp, 36($sp) + sw $ra, 40($sp) +.endm + +.macro RESTORE_CONTEXT + lw $ra, 40($sp) + lw $gp, 36($sp) + lw $fp, 32($sp) + lw $s7, 28($sp) + lw $s6, 24($sp) + lw $s5, 20($sp) + lw $s4, 16($sp) + lw $s3, 12($sp) + lw $s2, 8($sp) + lw $s1, 4($sp) + lw $s0, 0($sp) + addiu $sp, $sp, 44 +.endm + +.global WRAPPER_ND_COLL_BarycentricTest +.type WRAPPER_ND_COLL_BarycentricTest, @function +WRAPPER_ND_COLL_BarycentricTest: + SAVE_CONTEXT + jal ND_COLL_BarycentricTest + nop + RESTORE_CONTEXT + jr $ra + nop diff --git a/symbols/gcc-syms-rewrite.txt b/symbols/gcc-syms-rewrite.txt index e3448bfad..8bf364f9e 100644 --- a/symbols/gcc-syms-rewrite.txt +++ b/symbols/gcc-syms-rewrite.txt @@ -69,6 +69,7 @@ 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_BarycentricTest = 0x8001f928; ND_COLL_MOVED_TRIANGL_TestPoint = 0x8001fc40; ND_COLL_MOVED_QUADBLK_TestTriangles = 0x80020064; ND_COLL_MOVED_BSPLEAF_TestQuadblocks = 0x800202a8; From 8b825af6ca4c4aab015ad5c938f1614cbdfc1d18 Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Tue, 23 Sep 2025 07:38:57 -0700 Subject: [PATCH 4/8] dont generate code if profiler guard isn't active --- include/ctr/profiler.h | 2 +- rewrite/buildList.txt | 1 - rewrite/src/profiler/benchmark.c | 7 +++++-- rewrite/src/profiler/profiler.c | 28 ++++++++++++++++------------ 4 files changed, 22 insertions(+), 16 deletions(-) diff --git a/include/ctr/profiler.h b/include/ctr/profiler.h index f21f47761..357342106 100644 --- a/include/ctr/profiler.h +++ b/include/ctr/profiler.h @@ -1,4 +1,4 @@ #pragma once -#define REWRITE_PROFILER +//#define REWRITE_PROFILER void LoadProfilerPatches(); diff --git a/rewrite/buildList.txt b/rewrite/buildList.txt index e7adcf8b2..745f83943 100644 --- a/rewrite/buildList.txt +++ b/rewrite/buildList.txt @@ -5,7 +5,6 @@ common, header, 0x8000B0B8, 0x0, src/hooks/dll/load_decomp.c // decomp files common, DLL, 0x80200000, 0x0, src/exe/*.c, DECOMP.BIN common, DLL, 0x80600000, 0x0, src/tests/*.c src/tests/test_wrappers.s, TESTS.BIN -common, DLL, 0x80600000, 0x0, src/tests/*.c, TESTS.BIN // profiler files common, DLL, 0x80500000, 0x0, src/profiler/*.c, PROFILER.BIN diff --git a/rewrite/src/profiler/benchmark.c b/rewrite/src/profiler/benchmark.c index ad8739250..f74563fdd 100644 --- a/rewrite/src/profiler/benchmark.c +++ b/rewrite/src/profiler/benchmark.c @@ -5,6 +5,7 @@ // When running OG functions, // dont forget to undefine these in ctr\test.h: // TEST_MATH_IMPL, TEST_RNG_IMPL, TEST_COLL_IMPL +#ifdef REWRITE_PROFILER void RunBenchmark() { @@ -30,5 +31,7 @@ void RunBenchmark() { ND_COLL_ProjectPointToEdge(&out, &v1, &v2, &point); } - -} \ No newline at end of file + +} + +#endif // REWRITE_PROFILER \ No newline at end of file diff --git a/rewrite/src/profiler/profiler.c b/rewrite/src/profiler/profiler.c index fc9197a5f..133602b4b 100644 --- a/rewrite/src/profiler/profiler.c +++ b/rewrite/src/profiler/profiler.c @@ -1,6 +1,8 @@ #include #include +#ifdef REWRITE_PROFILER + // No Vehicle.h struct MetaPhys { @@ -51,7 +53,7 @@ int Debug_GetPreciseTime() int sysClock = ND_GetRCnt(0xf2000001) + sdata->rcntTotalUnits; - + return sysClock; } @@ -65,35 +67,35 @@ void Hook_DrawOTag(int a) if (timeRed == 0) { timeStart = Debug_GetPreciseTime(); - + void RunBenchmark(); RunBenchmark(); - + timeEnd = Debug_GetPreciseTime(); - + timeRed = timeEnd - timeStart; } - + struct GameTracker* gGT = sdata->gGT; - + if((gGT->gameMode1 & (LOADING|1)) == 0) { // reset depth to CLOSEST gGT->pushBuffer_UI.ptrOT = gGT->otSwapchainDB[gGT->swapchainIndex]; - - + + #ifndef REBUILD_PC char* string = (char*)0x1f800000; #else char string[128]; #endif - + ND_sprintf(string, "RED %d", timeRed); ND_DecalFont_DrawLine(string, 0x14, 0x5C, FONT_SMALL, 0); } - + ND_DrawOTag(a); } @@ -101,6 +103,8 @@ void Hook_DrawOTag(int a) #define JAL(dest) (((unsigned long)dest & 0x3FFFFFF) >> 2 | 0xC000000) void LoadProfilerPatches() -{ +{ *(int*)0x800379b0 = JAL(Hook_DrawOTag); -} \ No newline at end of file +} + +#endif // REWRITE_PROFILER \ No newline at end of file From 79c529581f4a0ee9bb19126c7e39fe2cccf23e1f Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Tue, 23 Sep 2025 14:36:25 -0700 Subject: [PATCH 5/8] fix gamma calculation --- rewrite/src/exe/coll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index 0072fe8f0..34f13867b 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -94,7 +94,7 @@ static s32 _COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const Coll if (deltaTri[0].y == 0) { return BARYCENTRIC_TEST_INVALID; } beta = FP_DIV(deltaT.y, deltaTri[0].y); if (deltaTri[1].x == 0) { return BARYCENTRIC_TEST_INVALID; } - gamma = (deltaT.y * FP_ONE) - (beta * deltaTri[1].y); + gamma = ((deltaT.y * FP_ONE) - (beta * deltaTri[1].y)) / deltaTri[1].x; } if (beta == FP(-1) || gamma == FP(-1)) { return BARYCENTRIC_TEST_INVALID; } From ad008f9681e183d3fc7b4ceb23929295cbadcbd4 Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Tue, 23 Sep 2025 15:07:02 -0700 Subject: [PATCH 6/8] flush cache after modifying instructions --- include/ctr/test.h | 7 +++++++ rewrite/src/tests/test.c | 3 +++ 2 files changed, 10 insertions(+) diff --git a/include/ctr/test.h b/include/ctr/test.h index a4ec79b2f..841198c07 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -14,6 +14,13 @@ void PatchFunction_End(u32 index); u32 PrintSVectorDiff(const char* name, const SVec3* expected, const SVec3* ret); u32 PrintMatrixDiff(const char* name, const Matrix* expected, const Matrix* ret, u32 cmpTrans); +force_inline void FlushCache() +{ + register int n asm("t1") = 0x44; + __asm__ volatile("" : "=r"(n) : "r"(n)); + ((void (*)())0xa0)(); +} + #define BACKUP_ADDR 0x80400000 #define TEST_MATH_IMPL diff --git a/rewrite/src/tests/test.c b/rewrite/src/tests/test.c index 74bc35474..90ef0f713 100644 --- a/rewrite/src/tests/test.c +++ b/rewrite/src/tests/test.c @@ -45,6 +45,7 @@ void LoadTestPatches() *(s_functions[i].address) = s_functions[i].firstNewInst; *(s_functions[i].address + 1) = s_functions[i].secondNewInst; } + FlushCache(); } u32 PatchFunction_Beg(u32* address) @@ -58,6 +59,7 @@ u32 PatchFunction_Beg(u32* address) index = i; *(s_functions[i].address) = s_functions[i].firstInst; *(s_functions[i].address + 1) = s_functions[i].secondInst; + FlushCache(); break; } } @@ -68,6 +70,7 @@ void PatchFunction_End(u32 index) { *(s_functions[index].address) = s_functions[index].firstNewInst; *(s_functions[index].address + 1) = s_functions[index].secondNewInst; + FlushCache(); } u32 PrintSVectorDiff(const char* name, const SVec3* expected, const SVec3* ret) From 70b6106e89bfeb326d51644ef38950d0875e662b Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Tue, 23 Sep 2025 16:22:24 -0700 Subject: [PATCH 7/8] add in naughty dog bug... --- include/ctr/macros.h | 4 +++- include/ctr/profiler.h | 3 ++- rewrite/src/exe/coll.c | 26 ++++++++++++++++++-------- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/include/ctr/macros.h b/include/ctr/macros.h index 89431fe42..6f0a351e5 100644 --- a/include/ctr/macros.h +++ b/include/ctr/macros.h @@ -46,4 +46,6 @@ typedef int8_t s8; #define OFFSETOF(TYPE, ELEMENT) ((unsigned int)&(((TYPE *)0)->ELEMENT)) #define nullptr ((void *) 0) -#define force_inline static inline __attribute__((always_inline)) \ No newline at end of file +#define force_inline static inline __attribute__((always_inline)) + +//#define FIX_CTR_BUGS \ No newline at end of file diff --git a/include/ctr/profiler.h b/include/ctr/profiler.h index 357342106..f6563d4ca 100644 --- a/include/ctr/profiler.h +++ b/include/ctr/profiler.h @@ -1,4 +1,5 @@ #pragma once //#define REWRITE_PROFILER -void LoadProfilerPatches(); + +void LoadProfilerPatches(); \ No newline at end of file diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index 34f13867b..29567781a 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -85,18 +85,28 @@ static s32 _COLL_BarycentricTest(TestVertex* t, const CollVertex* v1, const Coll if (deltaTri[0].x != 0) { s32 dem = ((deltaTri[1].y * deltaTri[0].x) - (deltaTri[0].y * deltaTri[1].x)) >> 6; - if (dem == 0) { return BARYCENTRIC_TEST_INVALID; } - beta = (((deltaT.y * deltaTri[0].x) - (deltaT.x * deltaTri[1].x)) << 6) / dem; - gamma = ((deltaT.x * FP_ONE) - (beta * deltaTri[0].y)) / deltaTri[0].x; + if (dem != 0) + { + beta = (((deltaT.y * deltaTri[0].x) - (deltaT.x * deltaTri[1].x)) << 6) / dem; + gamma = ((deltaT.x * FP_ONE) - (beta * deltaTri[0].y)) / deltaTri[0].x; + } } else { - if (deltaTri[0].y == 0) { return BARYCENTRIC_TEST_INVALID; } - beta = FP_DIV(deltaT.y, deltaTri[0].y); - if (deltaTri[1].x == 0) { return BARYCENTRIC_TEST_INVALID; } - gamma = ((deltaT.y * FP_ONE) - (beta * deltaTri[1].y)) / deltaTri[1].x; + if ((deltaTri[0].y != 0) && (deltaTri[1].x != 0)) + { + beta = FP_DIV(deltaT.y, deltaTri[0].y); + gamma = ((deltaT.y * FP_ONE) - (beta * deltaTri[1].y)) / deltaTri[1].x; + } } - if (beta == FP(-1) || gamma == FP(-1)) { return BARYCENTRIC_TEST_INVALID; } + + /* Naughty Dog bug: their hand written assembly code + forgets to check beta == -1, creating false collisions */ +#ifdef FIX_CTR_BUGS + if ((beta == FP(-1)) || (gamma == FP(-1))) { return BARYCENTRIC_TEST_INVALID; } +#else + if (gamma == FP(-1)) { return BARYCENTRIC_TEST_INVALID; } +#endif s32 alpha = beta + gamma + FP(-1); if (gamma < 0) From b25bbfc43b5e7b1203dc9c3e4d66c10600f302e4 Mon Sep 17 00:00:00 2001 From: mateusfavarin Date: Tue, 23 Sep 2025 16:39:27 -0700 Subject: [PATCH 8/8] address PR review --- include/ctr/lev.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/include/ctr/lev.h b/include/ctr/lev.h index cc9dd6096..407facea3 100644 --- a/include/ctr/lev.h +++ b/include/ctr/lev.h @@ -3,12 +3,16 @@ #include #include -typedef struct Color +typedef union Color { - uint32_t r : 8; - uint32_t g : 8; - uint32_t b : 8; - uint32_t a : 8; + struct + { + u8 r; + u8 g; + u8 b; + u8 a; + }; + u32 color; } Color; typedef struct Vertex