diff --git a/include/ctr/coll.h b/include/ctr/coll.h index 9c6090a0b..7b7bf997e 100644 --- a/include/ctr/coll.h +++ b/include/ctr/coll.h @@ -27,9 +27,9 @@ typedef struct CollVertex { SVec3 pos; u16 normalDominantAxis; - Vertex* levVertex; + const Vertex* levVertex; SVec3 triNormal; - u16 planeDist; + s16 planeDist; } CollVertex; typedef struct TestVertex @@ -37,9 +37,71 @@ typedef struct TestVertex SVec3 pos; u16 normalDominantAxis; SVec3 triNormal; - u16 planeDist; + s16 planeDist; 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; + const MeshInfo* meshInfo; + BoundingBox bbox; + s16 numVerticesTested; + s16 numTrianglesCollided; + s16 unk2; + s16 numInstancesCollided; + u32 unk3; + const BSPNode* bspNodes; + TestVertex collIntersection; + u8 unk4; + u8 currTriangleIndex; + const Quadblock* currQuadblock; + TestVertex coll; + s8 barycentricTest; + u8 collidedTriangleIndex; + const Quadblock* collidedQuadblock; + s32 speedScale; + u8 unk6[0x44]; + const Vertex* collidedVertices[NUM_VERTICES_TRIANGLE]; + const CollVertex* currTestVertices[NUM_VERTICES_TRIANGLE]; + SVec3 deltaInterpolationIntersection; + s16 unk7; + u16 quadblockThirdIndex; + u16 quadblockFourthIndex; + 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 +void COLL_LoadQuadblockData_LowLOD(CollDCache* cache, Quadblock* quadblock); +void COLL_LoadQuadblockData_HighLOD(CollDCache* cache, Quadblock* quadblock); +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 0797d71e8..7d138f3fd 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,17 @@ 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_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;" \ @@ -98,6 +103,8 @@ 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_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 407facea3..1a74801d5 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,133 @@ 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 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 + DrawOrder 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 + s16 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/nd.h b/include/ctr/nd.h index 0b139cf99..513741644 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,4 +30,9 @@ u32 ND_RNG_Random(RNGSeed* seed); /* COLL */ 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 +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); +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/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/include/ctr/test.h b/include/ctr/test.h index 50468a11c..2b20e2ecb 100644 --- a/include/ctr/test.h +++ b/include/ctr/test.h @@ -24,8 +24,8 @@ force_inline void FlushCache() #define BACKUP_ADDR 0x80400000 -#define TEST_MATH_IMPL -#define TEST_RNG_IMPL +//#define TEST_MATH_IMPL +//#define TEST_RNG_IMPL #define TEST_COLL_IMPL #ifdef TEST_MATH_IMPL @@ -66,8 +66,14 @@ 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); + 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 f8ddb0654..e0b0c497c 100644 --- a/rewrite/src/exe/coll.c +++ b/rewrite/src/exe/coll.c @@ -1,5 +1,6 @@ #include #include +#include #include /* Address: 0x8001ede4 */ @@ -14,7 +15,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,17 +32,112 @@ 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_interpolateBase(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); -#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)); +} + +/* Address: 0x8001f2dc */ +static 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); +} + +/* Address: 0x8001f7f0 */ +static 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); +} + +/* 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)); + __asm__ volatile("move $t9, %0" : : "r"((u32)quadblock)); } /* Address: 0x8001f928 */ @@ -149,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; @@ -157,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/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 56eb7b08b..90b82d9e8 100644 --- a/rewrite/src/tests/test.c +++ b/rewrite/src/tests/test.c @@ -30,7 +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 c45abcfe3..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)); @@ -13,6 +26,49 @@ 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]; + 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) { @@ -25,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 8bf364f9e..759d14ff9 100644 --- a/symbols/gcc-syms-rewrite.txt +++ b/symbols/gcc-syms-rewrite.txt @@ -63,14 +63,14 @@ 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; -ND_COLL_FIXED_QUADBLK_GetNormVecs_HiLOD = 0x8001f6f0; -ND_COLL_FIXED_QUADBLK_LoadScratchpadVerts = 0x8001f7f0; +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; @@ -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;