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..407facea3 --- /dev/null +++ b/include/ctr/lev.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +typedef union Color +{ + struct + { + u8 r; + u8 g; + u8 b; + u8 a; + }; + u32 color; +} Color; + +typedef struct Vertex +{ + SVec3 pos; + u16 flags; + Color colorHi; + Color colorLo; +} Vertex; \ No newline at end of file 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/nd.h b/include/ctr/nd.h index 467f914ed..0b139cf99 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); @@ -27,4 +28,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/profiler.h b/include/ctr/profiler.h index f21f47761..f6563d4ca 100644 --- a/include/ctr/profiler.h +++ b/include/ctr/profiler.h @@ -1,4 +1,5 @@ #pragma once -#define REWRITE_PROFILER -void LoadProfilerPatches(); +//#define REWRITE_PROFILER + +void LoadProfilerPatches(); \ No newline at end of file diff --git a/include/ctr/test.h b/include/ctr/test.h index fc4561b0a..841198c07 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -14,11 +14,18 @@ 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 -//#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); @@ -58,6 +65,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 d138895ac..745f83943 100644 --- a/rewrite/buildList.txt +++ b/rewrite/buildList.txt @@ -4,7 +4,7 @@ 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 +common, DLL, 0x80600000, 0x0, src/tests/*.c src/tests/test_wrappers.s, TESTS.BIN // profiler files -common, DLL, 0x80500000, 0x0, src/profiler/*.c, PROFILER.BIN \ No newline at end of file +common, DLL, 0x80500000, 0x0, src/profiler/*.c, PROFILER.BIN diff --git a/rewrite/src/exe/coll.c b/rewrite/src/exe/coll.c index b46ff8702..29567781a 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -36,4 +36,119 @@ 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) + { + 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) && (deltaTri[1].x != 0)) + { + beta = FP_DIV(deltaT.y, deltaTri[0].y); + gamma = ((deltaT.y * FP_ONE) - (beta * deltaTri[1].y)) / deltaTri[1].x; + } + } + + /* 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) + { + 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/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 diff --git a/rewrite/src/tests/test.c b/rewrite/src/tests/test.c index 90e0485fc..90ef0f713 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() @@ -44,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) @@ -57,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; } } @@ -67,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) 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;