diff --git a/configure.py b/configure.py index 540e2517e..379e69c4d 100644 --- a/configure.py +++ b/configure.py @@ -572,7 +572,7 @@ def MatchingFor(*versions): Object(NonMatching, "SB/Core/x/xParEmitterType.cpp"), Object(Matching, "SB/Core/x/xRenderState.cpp"), Object(NonMatching, "SB/Game/zEntPlayerOOBState.cpp"), - Object(NonMatching, "SB/Core/x/xClumpColl.cpp"), + Object(Equivalent, "SB/Core/x/xClumpColl.cpp"), Object(NonMatching, "SB/Core/x/xEntBoulder.cpp"), Object(NonMatching, "SB/Core/x/xGrid.cpp"), Object(Equivalent, "SB/Core/x/xJSP.cpp"), diff --git a/include/rwsdk/rpcollis.h b/include/rwsdk/rpcollis.h index a7f4d85c5..25c61931e 100644 --- a/include/rwsdk/rpcollis.h +++ b/include/rwsdk/rpcollis.h @@ -47,6 +47,12 @@ typedef RpCollisionTriangle* (*RpIntersectionCallBackWorldTriangle)( RpIntersection* intersection, RpWorldSector* sector, RpCollisionTriangle* collTriangle, RwReal distance, void* data); +typedef RpAtomic* (*RpIntersectionCallBackAtomic) + (RpIntersection* intersection, RpWorldSector* sector, RpAtomic* atomic, RwReal distance, void* data); + +typedef RpWorldSector* (*RpIntersectionCallBackWorldSector) + (RpIntersection* intersection, RpWorldSector* worldSector, void* data); + #ifdef __cplusplus extern "C" { #endif diff --git a/src/SB/Core/x/xClumpColl.cpp b/src/SB/Core/x/xClumpColl.cpp index 046bb9734..c319f0697 100644 --- a/src/SB/Core/x/xClumpColl.cpp +++ b/src/SB/Core/x/xClumpColl.cpp @@ -2,91 +2,889 @@ #include -xClumpCollBSPTree* xClumpColl_StaticBufferInit(void* data, U32 param_2) +U8 xClumpColl_FilterFlags = 0x04; + +union IntersectionCallBack +{ + RpIntersectionCallBackWorldSector sectorCB; + RpIntersectionCallBackWorldTriangle worldCB; + RpIntersectionCallBackAtomic atomicCB; +}; + +struct CallBackParam +{ + RpIntersection* intersection; + IntersectionCallBack u; + void* data; +}; + +struct PolyLineTestParam +{ + RwV3d start; + RpWorldSector* worldSector; + RwV3d delta; + xClumpCollV3dGradient grad; + RwLine line; + CallBackParam* cbParam; +}; + +struct PolyTestParam { - U32* header; // unused + RwBBox bbox; + RpWorldSector* worldSector; + void* leafTestData; + CallBackParam* cbParam; +}; - U32 numBranchNodes = *(U32*)((int)data + 4); - U32 numTriangles = *(U32*)((int)data + 8); +struct TestSphere +{ + RwSphere* sphere; + F32 recipRadius; +}; + +xClumpCollBSPTree* xClumpColl_StaticBufferInit(void* data, U32) +{ + U32* header = (U32*)data; + U32 numBranchNodes = header[1]; + U32 numTriangles = header[2]; + xClumpCollBSPTree* tree = (xClumpCollBSPTree*)RwMalloc(sizeof(xClumpCollBSPTree)); - xClumpCollBSPTree* tree = (xClumpCollBSPTree*)RwMalloc(16); - if (numBranchNodes != 0) + if (numBranchNodes) { - tree->branchNodes = (xClumpCollBSPBranchNode*)((int)data + 12); + tree->branchNodes = (xClumpCollBSPBranchNode*)(header + 3); tree->triangles = (xClumpCollBSPTriangle*)(tree->branchNodes + numBranchNodes); } else { tree->branchNodes = NULL; - tree->triangles = (xClumpCollBSPTriangle*)((int)data + 12); + tree->triangles = (xClumpCollBSPTriangle*)(header + 3); } + tree->numBranchNodes = numBranchNodes; tree->numTriangles = numTriangles; + return tree; } void xClumpColl_InstancePointers(xClumpCollBSPTree* tree, RpClump* clump) { - S32 i; - S32 numAtom; - TempAtomicList* atomicList; - TempAtomicList* iterList; - TempAtomicList* alist; - S32 vertIndex; - S32 numMeshes; - S32 meshIndex; - RpMesh* mesh; + return; +} + +xClumpCollBSPTree* +xClumpColl_ForAllBoxLeafNodeIntersections(xClumpCollBSPTree* tree, RwBBox* box, + xClumpCollIntersectionCallback callBack, void* data) +{ + S32 nStack; + nodeInfo nodeStack[33]; + nodeInfo node; + + node.type = tree->branchNodes ? 2 : 1; + node.index = 0; + nStack = 0; + + while (nStack >= 0) + { + if (node.type == 1) + { + xClumpCollBSPTriangle* tris = tree->triangles + node.index; + if (!callBack(tris, data)) + return NULL; + + node = nodeStack[nStack]; + nStack--; + } + else + { + xClumpCollBSPBranchNode* branch = tree->branchNodes + node.index; + + if (*((RwReal*)((U8*)&box->inf + (branch->leftInfo & 0xC))) < branch->leftValue) + { + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; + + if (*(RwReal*)((U8*)&box->sup + (branch->leftInfo & 0xC)) >= branch->rightValue) + { + nStack++; + nodeStack[nStack].type = branch->rightInfo & 0x3; + nodeStack[nStack].index = branch->rightInfo >> 12; + } + } + else + { + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + } + } + } + + return tree; } -//WIP -xClumpCollBSPTree* xClumpColl_ForAllBoxLeafNodeIntersections(xClumpCollBSPTree* tree, RwBBox* box, - S32 (*callBack)(xClumpCollBSPTriangle*, - void*), - void* data) +xClumpCollBSPTree* +xClumpColl_ForAllLineLeafNodeIntersections(xClumpCollBSPTree* tree, RwLine* line, + xClumpCollV3dGradient* grad, + xClumpCollIntersectionCallback callBack, void* data) { S32 nStack; nodeInfo nodeStack[33]; - xClumpCollBSPBranchNode* branch; - - U32 uVar1; - int iVar2; - int iVar3 = 0; - U32 local_124 = 0; - U32 local_128 = 1 - ((-(int)tree->branchNodes | (int)tree->branchNodes) >> 31); - while (true) + nodeInfo node; + RwLine lineStack[33]; + RwLine currLine; + + node.type = tree->branchNodes ? 2 : 1; + node.index = 0; + currLine = *line; + nStack = 0; + + while (nStack >= 0) { - while (true) + if (node.type == 1) { - if (iVar3 < 0) + xClumpCollBSPTriangle* tris = tree->triangles + node.index; + if (!callBack(tris, data)) + return NULL; + + node = nodeStack[nStack]; + currLine = lineStack[nStack]; + nStack--; + } + else + { + RwSplitBits lStart, lEnd, rStart, rEnd; + xClumpCollBSPBranchNode* branch = tree->branchNodes + node.index; + + lStart.nReal = + *(RwReal*)((U8*)&currLine.start + (branch->leftInfo & 0xC)) - branch->leftValue; + lEnd.nReal = + *(RwReal*)((U8*)&currLine.end + (branch->leftInfo & 0xC)) - branch->leftValue; + rStart.nReal = + *(RwReal*)((U8*)&currLine.start + (branch->leftInfo & 0xC)) - branch->rightValue; + rEnd.nReal = + *(RwReal*)((U8*)&currLine.end + (branch->leftInfo & 0xC)) - branch->rightValue; + + if (rStart.nInt < 0 && rEnd.nInt < 0) { - return tree; + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; } - if (local_128 == 1) - break; - branch = tree->branchNodes + local_124; - uVar1 = branch->leftInfo; - if ((float)branch->leftValue <= *(float*)((int)&(box->inf).x + (uVar1 & 0xc))) + else if (lStart.nInt >= 0 && lEnd.nInt >= 0) { - local_128 = branch->rightInfo & 3; - local_124 = branch->rightInfo >> 0xc; + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + } + else if (!((lStart.nInt ^ lEnd.nInt) & 0x80000000) && + !((rStart.nInt ^ rEnd.nInt) & 0x80000000)) + { + if (rStart.nInt < rEnd.nInt) + { + nStack++; + nodeStack[nStack].type = branch->rightInfo & 0x3; + nodeStack[nStack].index = branch->rightInfo >> 12; + lineStack[nStack].start = currLine.start; + lineStack[nStack].end = currLine.end; + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; + } + else + { + nStack++; + nodeStack[nStack].type = branch->leftInfo & 0x3; + nodeStack[nStack].index = branch->leftInfo >> 12; + lineStack[nStack].start = currLine.start; + lineStack[nStack].end = currLine.end; + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + } + } + else if (((lStart.nInt ^ lEnd.nInt) & 0x80000000) && rStart.nInt >= 0 && rEnd.nInt >= 0) + { + RwV3d vTmp; + F32 delta; + switch (branch->leftInfo & 0xC) + { + case 0: + delta = branch->leftValue - currLine.start.x; + vTmp.x = branch->leftValue; + vTmp.y = currLine.start.y + grad->dydx * delta; + vTmp.z = currLine.start.z + grad->dzdx * delta; + break; + case 4: + delta = branch->leftValue - currLine.start.y; + vTmp.x = currLine.start.x + grad->dxdy * delta; + vTmp.y = branch->leftValue; + vTmp.z = currLine.start.z + grad->dzdy * delta; + break; + case 8: + delta = branch->leftValue - currLine.start.z; + vTmp.x = currLine.start.x + grad->dxdz * delta; + vTmp.y = currLine.start.y + grad->dydz * delta; + vTmp.z = branch->leftValue; + break; + } + if (lStart.nInt < 0) + { + nStack++; + nodeStack[nStack].type = branch->rightInfo & 0x3; + nodeStack[nStack].index = branch->rightInfo >> 12; + lineStack[nStack].start = currLine.start; + lineStack[nStack].end = currLine.end; + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; + currLine.end = vTmp; + } + else + { + nStack++; + nodeStack[nStack].type = branch->leftInfo & 0x3; + nodeStack[nStack].index = branch->leftInfo >> 12; + lineStack[nStack].start = vTmp; + lineStack[nStack].end = currLine.end; + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + } + } + else if (((rStart.nInt ^ rEnd.nInt) & 0x80000000) && lStart.nInt < 0 && lEnd.nInt < 0) + { + RwV3d vTmp; + F32 delta; + switch (branch->leftInfo & 0xC) + { + case 0: + delta = branch->rightValue - currLine.start.x; + vTmp.x = branch->rightValue; + vTmp.y = currLine.start.y + grad->dydx * delta; + vTmp.z = currLine.start.z + grad->dzdx * delta; + break; + case 4: + delta = branch->rightValue - currLine.start.y; + vTmp.x = currLine.start.x + grad->dxdy * delta; + vTmp.y = branch->rightValue; + vTmp.z = currLine.start.z + grad->dzdy * delta; + break; + case 8: + delta = branch->rightValue - currLine.start.z; + vTmp.x = currLine.start.x + grad->dxdz * delta; + vTmp.y = currLine.start.y + grad->dydz * delta; + vTmp.z = branch->rightValue; + break; + } + if (rStart.nInt < 0) + { + nStack++; + nodeStack[nStack].type = branch->rightInfo & 0x3; + nodeStack[nStack].index = branch->rightInfo >> 12; + lineStack[nStack].start = vTmp; + lineStack[nStack].end = currLine.end; + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; + } + else + { + nStack++; + nodeStack[nStack].type = branch->leftInfo & 0x3; + nodeStack[nStack].index = branch->leftInfo >> 12; + lineStack[nStack].start = currLine.start; + lineStack[nStack].end = currLine.end; + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + currLine.end = vTmp; + } } else { - local_128 = uVar1 & 3; - local_124 = uVar1 >> 0xc; - if ((float)branch->rightValue <= *(float*)((int)&(box->sup).x + (uVar1 & 0xc))) + RwV3d vLeft; + RwV3d vRight; + { + F32 delta; + switch (branch->leftInfo & 0xC) + { + case 0: + delta = branch->leftValue - currLine.start.x; + vLeft.x = branch->leftValue; + vLeft.y = currLine.start.y + grad->dydx * delta; + vLeft.z = currLine.start.z + grad->dzdx * delta; + break; + case 4: + delta = branch->leftValue - currLine.start.y; + vLeft.x = currLine.start.x + grad->dxdy * delta; + vLeft.y = branch->leftValue; + vLeft.z = currLine.start.z + grad->dzdy * delta; + break; + case 8: + delta = branch->leftValue - currLine.start.z; + vLeft.x = currLine.start.x + grad->dxdz * delta; + vLeft.y = currLine.start.y + grad->dydz * delta; + vLeft.z = branch->leftValue; + break; + } + } { - iVar3 = iVar3 + 1; - *(int*)&nodeStack[iVar3 * 2] = branch->rightInfo & 3; - *(int*)&nodeStack[iVar3 * 2 + 1] = branch->rightInfo >> 0xc; + F32 delta; + switch (branch->leftInfo & 0xC) + { + case 0: + delta = branch->rightValue - currLine.start.x; + vRight.x = branch->rightValue; + vRight.y = currLine.start.y + grad->dydx * delta; + vRight.z = currLine.start.z + grad->dzdx * delta; + break; + case 4: + delta = branch->rightValue - currLine.start.y; + vRight.x = currLine.start.x + grad->dxdy * delta; + vRight.y = branch->rightValue; + vRight.z = currLine.start.z + grad->dzdy * delta; + break; + case 8: + delta = branch->rightValue - currLine.start.z; + vRight.x = currLine.start.x + grad->dxdz * delta; + vRight.y = currLine.start.y + grad->dydz * delta; + vRight.z = branch->rightValue; + break; + } + } + if (lStart.nInt < 0) + { + nStack++; + nodeStack[nStack].type = branch->rightInfo & 0x3; + nodeStack[nStack].index = branch->rightInfo >> 12; + lineStack[nStack].start = vRight; + lineStack[nStack].end = currLine.end; + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; + currLine.end = vLeft; + } + else + { + nStack++; + nodeStack[nStack].type = branch->leftInfo & 0x3; + nodeStack[nStack].index = branch->leftInfo >> 12; + lineStack[nStack].start = vLeft; + lineStack[nStack].end = currLine.end; + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + currLine.end = vRight; } } } - iVar2 = ((*callBack)(tree->triangles + local_124, data)); - if (iVar2 == 0) - break; - *(U32*)&nodeStack[iVar3 * 2] = local_128; - iVar3--; } - return 0; + + return tree; +} + +xClumpCollBSPTree* +xClumpColl_ForAllCapsuleLeafNodeIntersections(xClumpCollBSPTree* tree, RwLine* line, F32 radius, + xClumpCollV3dGradient* grad, + xClumpCollIntersectionCallback callBack, void* data) +{ + S32 nStack; + nodeInfo nodeStack[33]; + nodeInfo node; + RwLine lineStack[33]; + RwLine currLine; + + node.type = tree->branchNodes ? 2 : 1; + node.index = 0; + currLine = *line; + nStack = 0; + + while (nStack >= 0) + { + if (node.type == 1) + { + xClumpCollBSPTriangle* tris = tree->triangles + node.index; + if (!callBack(tris, data)) + return NULL; + + node = nodeStack[nStack]; + currLine = lineStack[nStack]; + nStack--; + } + else + { + RwSplitBits lStart, lEnd, rStart, rEnd; + xClumpCollBSPBranchNode* branch = tree->branchNodes + node.index; + + lStart.nReal = *(RwReal*)((U8*)&currLine.start + (branch->leftInfo & 0xC)) - + (branch->leftValue + radius); + lEnd.nReal = *(RwReal*)((U8*)&currLine.end + (branch->leftInfo & 0xC)) - + (branch->leftValue + radius); + rStart.nReal = *(RwReal*)((U8*)&currLine.start + (branch->leftInfo & 0xC)) - + (branch->rightValue - radius); + rEnd.nReal = *(RwReal*)((U8*)&currLine.end + (branch->leftInfo & 0xC)) - + (branch->rightValue - radius); + + if (rStart.nInt < 0 && rEnd.nInt < 0) + { + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; + } + else if (lStart.nInt >= 0 && lEnd.nInt >= 0) + { + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + } + else if (!((lStart.nInt ^ lEnd.nInt) & 0x80000000) && + !((rStart.nInt ^ rEnd.nInt) & 0x80000000)) + { + if (rStart.nInt < rEnd.nInt) + { + nStack++; + nodeStack[nStack].type = branch->rightInfo & 0x3; + nodeStack[nStack].index = branch->rightInfo >> 12; + lineStack[nStack].start = currLine.start; + lineStack[nStack].end = currLine.end; + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; + } + else + { + nStack++; + nodeStack[nStack].type = branch->leftInfo & 0x3; + nodeStack[nStack].index = branch->leftInfo >> 12; + lineStack[nStack].start = currLine.start; + lineStack[nStack].end = currLine.end; + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + } + } + else if (((lStart.nInt ^ lEnd.nInt) & 0x80000000) && rStart.nInt >= 0 && rEnd.nInt >= 0) + { + RwV3d vTmp; + F32 delta; + switch (branch->leftInfo & 0xC) + { + case 0: + delta = branch->leftValue - currLine.start.x; + vTmp.x = branch->leftValue; + vTmp.y = currLine.start.y + grad->dydx * delta; + vTmp.z = currLine.start.z + grad->dzdx * delta; + break; + case 4: + delta = branch->leftValue - currLine.start.y; + vTmp.x = currLine.start.x + grad->dxdy * delta; + vTmp.y = branch->leftValue; + vTmp.z = currLine.start.z + grad->dzdy * delta; + break; + case 8: + delta = branch->leftValue - currLine.start.z; + vTmp.x = currLine.start.x + grad->dxdz * delta; + vTmp.y = currLine.start.y + grad->dydz * delta; + vTmp.z = branch->leftValue; + break; + } + if (lStart.nInt < 0) + { + nStack++; + nodeStack[nStack].type = branch->rightInfo & 0x3; + nodeStack[nStack].index = branch->rightInfo >> 12; + lineStack[nStack].start = currLine.start; + lineStack[nStack].end = currLine.end; + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; + currLine.end = vTmp; + } + else + { + nStack++; + nodeStack[nStack].type = branch->leftInfo & 0x3; + nodeStack[nStack].index = branch->leftInfo >> 12; + lineStack[nStack].start = vTmp; + lineStack[nStack].end = currLine.end; + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + } + } + else if (((rStart.nInt ^ rEnd.nInt) & 0x80000000) && lStart.nInt < 0 && lEnd.nInt < 0) + { + RwV3d vTmp; + F32 delta; + switch (branch->leftInfo & 0xC) + { + case 0: + delta = branch->rightValue - currLine.start.x; + vTmp.x = branch->rightValue; + vTmp.y = currLine.start.y + grad->dydx * delta; + vTmp.z = currLine.start.z + grad->dzdx * delta; + break; + case 4: + delta = branch->rightValue - currLine.start.y; + vTmp.x = currLine.start.x + grad->dxdy * delta; + vTmp.y = branch->rightValue; + vTmp.z = currLine.start.z + grad->dzdy * delta; + break; + case 8: + delta = branch->rightValue - currLine.start.z; + vTmp.x = currLine.start.x + grad->dxdz * delta; + vTmp.y = currLine.start.y + grad->dydz * delta; + vTmp.z = branch->rightValue; + break; + } + if (rStart.nInt < 0) + { + nStack++; + nodeStack[nStack].type = branch->rightInfo & 0x3; + nodeStack[nStack].index = branch->rightInfo >> 12; + lineStack[nStack].start = vTmp; + lineStack[nStack].end = currLine.end; + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; + } + else + { + nStack++; + nodeStack[nStack].type = branch->leftInfo & 0x3; + nodeStack[nStack].index = branch->leftInfo >> 12; + lineStack[nStack].start = currLine.start; + lineStack[nStack].end = currLine.end; + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + currLine.end = vTmp; + } + } + else + { + RwV3d vLeft; + RwV3d vRight; + { + F32 delta; + switch (branch->leftInfo & 0xC) + { + case 0: + delta = branch->leftValue - currLine.start.x; + vLeft.x = branch->leftValue; + vLeft.y = currLine.start.y + grad->dydx * delta; + vLeft.z = currLine.start.z + grad->dzdx * delta; + break; + case 4: + delta = branch->leftValue - currLine.start.y; + vLeft.x = currLine.start.x + grad->dxdy * delta; + vLeft.y = branch->leftValue; + vLeft.z = currLine.start.z + grad->dzdy * delta; + break; + case 8: + delta = branch->leftValue - currLine.start.z; + vLeft.x = currLine.start.x + grad->dxdz * delta; + vLeft.y = currLine.start.y + grad->dydz * delta; + vLeft.z = branch->leftValue; + break; + } + } + { + F32 delta; + switch (branch->leftInfo & 0xC) + { + case 0: + delta = branch->rightValue - currLine.start.x; + vRight.x = branch->rightValue; + vRight.y = currLine.start.y + grad->dydx * delta; + vRight.z = currLine.start.z + grad->dzdx * delta; + break; + case 4: + delta = branch->rightValue - currLine.start.y; + vRight.x = currLine.start.x + grad->dxdy * delta; + vRight.y = branch->rightValue; + vRight.z = currLine.start.z + grad->dzdy * delta; + break; + case 8: + delta = branch->rightValue - currLine.start.z; + vRight.x = currLine.start.x + grad->dxdz * delta; + vRight.y = currLine.start.y + grad->dydz * delta; + vRight.z = branch->rightValue; + break; + } + } + if (lStart.nInt < 0) + { + nStack++; + nodeStack[nStack].type = branch->rightInfo & 0x3; + nodeStack[nStack].index = branch->rightInfo >> 12; + lineStack[nStack].start = vRight; + lineStack[nStack].end = currLine.end; + node.type = branch->leftInfo & 0x3; + node.index = branch->leftInfo >> 12; + currLine.end = vLeft; + } + else + { + nStack++; + nodeStack[nStack].type = branch->leftInfo & 0x3; + nodeStack[nStack].index = branch->leftInfo >> 12; + lineStack[nStack].start = vLeft; + lineStack[nStack].end = currLine.end; + node.type = branch->rightInfo & 0x3; + node.index = branch->rightInfo >> 12; + currLine.end = vRight; + } + } + } + } + + return tree; +} + +static S32 LeafNodeLinePolyIntersect(xClumpCollBSPTriangle* triangles, void* data) +{ + PolyLineTestParam* isData = (PolyLineTestParam*)data; + CallBackParam* cbParam = isData->cbParam; + do + { + if (triangles->flags & xClumpColl_FilterFlags) + { + RwV3d *v0, *v1, *v2; + F32 distance; + S32 result; + RwV3d edge1, edge2, tVec, pVec, qVec; + F32 det; + v0 = &triangles->v.p[0]; + if (triangles->flags & 0x2) + { + v1 = &triangles->v.p[2]; + v2 = &triangles->v.p[1]; + } + else + { + v1 = &triangles->v.p[1]; + v2 = &triangles->v.p[2]; + } + RwV3dSubMacro(&edge1, v1, v0); + RwV3dSubMacro(&edge2, v2, v0); + RwV3dCrossProductMacro(&pVec, &isData->delta, &edge2); + det = RwV3dDotProductMacro(&edge1, &pVec); + if (det < -1e-8f) + { + RwV3d edgetmp = edge1; + edge1 = edge2; + edge2 = edgetmp; + RwV3dCrossProductMacro(&pVec, &isData->delta, &edge2); + det = RwV3dDotProductMacro(&edge1, &pVec); + } + result = (det > 1e-8f); + if (result) + { + F32 lo, hi, u, v; + lo = 0.00001f * -det; + hi = det - lo; + RwV3dSubMacro(&tVec, &isData->start, v0); + u = RwV3dDotProductMacro(&tVec, &pVec); + result = (u >= lo && u <= hi); + if (result) + { + RwV3dCrossProductMacro(&qVec, &tVec, &edge1); + v = RwV3dDotProductMacro(&isData->delta, &qVec); + result = (v >= lo && u + v <= hi); + if (result) + { + distance = RwV3dDotProductMacro(&edge2, &qVec); + result = (distance >= lo && distance <= hi); + if (result) + { + distance /= det; + } + } + } + } + if (result) + { + RpCollisionTriangle collisionTri; + RwV3d vTmp, vTmp2; + F32 recipLength, lengthSq; + collisionTri.point = *v0; + collisionTri.index = (RwInt32)triangles; + collisionTri.vertices[0] = v0; + collisionTri.vertices[1] = v1; + collisionTri.vertices[2] = v2; + RwV3dSubMacro(&vTmp, collisionTri.vertices[1], collisionTri.vertices[0]); + RwV3dSubMacro(&vTmp2, collisionTri.vertices[2], collisionTri.vertices[0]); + RwV3dCrossProductMacro(&collisionTri.normal, &vTmp, &vTmp2); + lengthSq = RwV3dDotProductMacro(&collisionTri.normal, &collisionTri.normal); + recipLength = _rwInvSqrt(lengthSq); + RwV3dScaleMacro(&collisionTri.normal, &collisionTri.normal, recipLength); + if (!cbParam->u.worldCB(cbParam->intersection, NULL, &collisionTri, distance, + cbParam->data)) + { + return 0; + } + } + } + } while ((triangles++)->flags & 0x1); + return 1; +} + +static S32 LeafNodeSpherePolyIntersect(xClumpCollBSPTriangle* triangles, void* data) +{ + PolyTestParam* isData = (PolyTestParam*)data; + CallBackParam* cbParam = isData->cbParam; + TestSphere* testSphere = (TestSphere*)isData->leafTestData; + do + { + if (triangles->flags & xClumpColl_FilterFlags) + { + RwV3d *v0, *v1, *v2; + F32 distance; + RpCollisionTriangle collisionTri; + v0 = &triangles->v.p[0]; + if (triangles->flags & 0x2) + { + v1 = &triangles->v.p[2]; + v2 = &triangles->v.p[1]; + } + else + { + v1 = &triangles->v.p[1]; + v2 = &triangles->v.p[2]; + } + if (RtIntersectionSphereTriangle(testSphere->sphere, v0, v1, v2, &collisionTri.normal, + &distance)) + { + collisionTri.point = *v0; + collisionTri.index = (RwInt32)triangles; + collisionTri.vertices[0] = v0; + collisionTri.vertices[1] = v1; + collisionTri.vertices[2] = v2; + distance *= testSphere->recipRadius; + if (!cbParam->u.worldCB(cbParam->intersection, NULL, &collisionTri, distance, + cbParam->data)) + { + return 0; + } + } + } + } while ((triangles++)->flags & 0x1); + return 1; +} + +static S32 LeafNodeBoxPolyIntersect(xClumpCollBSPTriangle* triangles, void* data) +{ + PolyTestParam* isData = (PolyTestParam*)data; + CallBackParam* cbParam = isData->cbParam; + do + { + if (triangles->flags & xClumpColl_FilterFlags) + { + RwV3d *v0, *v1, *v2; + v0 = &triangles->v.p[0]; + if (triangles->flags & 0x2) + { + v1 = &triangles->v.p[2]; + v2 = &triangles->v.p[1]; + } + else + { + v1 = &triangles->v.p[1]; + v2 = &triangles->v.p[2]; + } + if (RtIntersectionBBoxTriangle(&isData->bbox, v0, v1, v2)) + { + RpCollisionTriangle collisionTri; + RwV3d vTmp, vTmp2; + + collisionTri.point = *v0; + collisionTri.index = (RwInt32)triangles; + RwV3dSubMacro(&vTmp, v1, v0); + RwV3dSubMacro(&vTmp2, v2, v0); + RwV3dCrossProductMacro(&collisionTri.normal, &vTmp, &vTmp2); + + F32 lengthSq = RwV3dDotProductMacro(&collisionTri.normal, &collisionTri.normal); + F32 recipLength = _rwInvSqrt(lengthSq); + + RwV3dScaleMacro(&collisionTri.normal, &collisionTri.normal, recipLength); + + collisionTri.vertices[0] = v0; + collisionTri.vertices[1] = v1; + collisionTri.vertices[2] = v2; + + if (!cbParam->u.worldCB(cbParam->intersection, NULL, &collisionTri, 0.0f, + cbParam->data)) + { + return 0; + } + } + } + } while ((triangles++)->flags & 0x1); + return 1; +} + +xClumpCollBSPTree* xClumpColl_ForAllIntersections(xClumpCollBSPTree* tree, + RpIntersection* intersection, + RpIntersectionCallBackWorldTriangle callBack, + void* data) +{ + CallBackParam cbParam; + cbParam.intersection = intersection; + cbParam.u.worldCB = callBack; + cbParam.data = data; + + switch (intersection->type) + { + case rpINTERSECTPOINT: + return NULL; + case rpINTERSECTLINE: + { + PolyLineTestParam isData; + RwLine* line = &intersection->t.line; + F32 recip; + + isData.start = line->start; + RwV3dSubMacro(&isData.delta, &line->end, &line->start); + isData.cbParam = &cbParam; + isData.line = *line; + + recip = (isData.delta.x != 0.0f) ? (1.0f / isData.delta.x) : 0.0f; + isData.grad.dydx = isData.delta.y * recip; + isData.grad.dzdx = isData.delta.z * recip; + + recip = (isData.delta.y != 0.0f) ? (1.0f / isData.delta.y) : 0.0f; + isData.grad.dxdy = isData.delta.x * recip; + isData.grad.dzdy = isData.delta.z * recip; + + recip = (isData.delta.z != 0.0f) ? (1.0f / isData.delta.z) : 0.0f; + isData.grad.dxdz = isData.delta.x * recip; + isData.grad.dydz = isData.delta.y * recip; + + xClumpColl_ForAllLineLeafNodeIntersections(tree, line, &isData.grad, + LeafNodeLinePolyIntersect, &isData); + + return tree; + } + case rpINTERSECTSPHERE: + { + PolyTestParam isData; + TestSphere testSphere; + + isData.bbox.inf = isData.bbox.sup = intersection->t.sphere.center; + isData.bbox.inf.x -= intersection->t.sphere.radius; + isData.bbox.inf.y -= intersection->t.sphere.radius; + isData.bbox.inf.z -= intersection->t.sphere.radius; + isData.bbox.sup.x += intersection->t.sphere.radius; + isData.bbox.sup.y += intersection->t.sphere.radius; + isData.bbox.sup.z += intersection->t.sphere.radius; + + testSphere.sphere = &intersection->t.sphere; + + isData.leafTestData = &testSphere; + isData.cbParam = &cbParam; + + testSphere.recipRadius = 1.0f / testSphere.sphere->radius; + + xClumpColl_ForAllBoxLeafNodeIntersections(tree, &isData.bbox, LeafNodeSpherePolyIntersect, + &isData); + + return tree; + } + case rpINTERSECTBOX: + { + PolyTestParam isData; + + isData.bbox = intersection->t.box; + isData.cbParam = &cbParam; + + xClumpColl_ForAllBoxLeafNodeIntersections(tree, &isData.bbox, LeafNodeBoxPolyIntersect, + &isData); + + return tree; + } + } + + return NULL; } diff --git a/src/SB/Core/x/xClumpColl.h b/src/SB/Core/x/xClumpColl.h index 6073d4921..01edc9c90 100644 --- a/src/SB/Core/x/xClumpColl.h +++ b/src/SB/Core/x/xClumpColl.h @@ -5,6 +5,8 @@ #include #include +#include +#include struct xClumpCollBSPBranchNode { @@ -55,6 +57,7 @@ struct nodeInfo U32 type; U32 index; }; + struct RwMeshCache { U32 lengthOfMeshesArray; @@ -69,20 +72,27 @@ struct TempAtomicList RwMeshCache* meshCache; }; -class RpIntersection; -class RpCollisionTriangle; +typedef S32 (*xClumpCollIntersectionCallback)(xClumpCollBSPTriangle*, void*); typedef RpCollisionTriangle* (*IntersectionCB)(RpIntersection*, RpWorldSector*, RpCollisionTriangle*, float, void*); +xClumpCollBSPTree* xClumpColl_StaticBufferInit(void* data, U32); void xClumpColl_InstancePointers(xClumpCollBSPTree* tree, RpClump* clump); -xClumpCollBSPTree* xClumpColl_StaticBufferInit(void* data, U32 param_2); -void xClumpColl_ForAllCapsuleLeafNodeIntersections(xClumpCollBSPTree* tree, RwLine* line, F32 dist, - xClumpCollV3dGradient* grad, - int (*tri)(xClumpCollBSPTriangle*, void*), - void* data); +xClumpCollBSPTree* +xClumpColl_ForAllBoxLeafNodeIntersections(xClumpCollBSPTree* tree, RwBBox* box, + xClumpCollIntersectionCallback callBack, void* data); +xClumpCollBSPTree* +xClumpColl_ForAllLineLeafNodeIntersections(xClumpCollBSPTree* tree, RwLine* line, + xClumpCollV3dGradient* grad, + xClumpCollIntersectionCallback callBack, void* data); +xClumpCollBSPTree* +xClumpColl_ForAllCapsuleLeafNodeIntersections(xClumpCollBSPTree* tree, RwLine* line, F32 radius, + xClumpCollV3dGradient* grad, + xClumpCollIntersectionCallback callBack, void* data); xClumpCollBSPTree* xClumpColl_ForAllIntersections(xClumpCollBSPTree* tree, RpIntersection* intersection, - IntersectionCB callBack, void* data); + RpIntersectionCallBackWorldTriangle callBack, + void* data); #endif