From c153cdff5b3d772baeb79fd4546f1b2a8df141de Mon Sep 17 00:00:00 2001 From: Aiden <86704247+vabold@users.noreply.github.com> Date: Wed, 24 Jan 2024 20:05:22 -0500 Subject: [PATCH] WIP --- source/game/field/RKGndCol.cc | 248 +++++++++++++++++++++++----------- source/game/field/RKGndCol.hh | 2 +- 2 files changed, 169 insertions(+), 81 deletions(-) diff --git a/source/game/field/RKGndCol.cc b/source/game/field/RKGndCol.cc index 6633e619..e454711e 100644 --- a/source/game/field/RKGndCol.cc +++ b/source/game/field/RKGndCol.cc @@ -56,7 +56,9 @@ RKGndCol::RKGndCol(const void *file) { // TODO: This makes an assumption that m_blockData is allocated immediately after // m_prisms=m_prismData+1 - m_prismCount = ((uintptr_t)m_blockData - (uintptr_t)m_prisms) / sizeof(KCollisionPrism); + m_prismCount = + (reinterpret_cast(m_blockData) - reinterpret_cast(m_prisms + 1)) / + sizeof(KCollisionPrism); computeBBox(); } @@ -69,14 +71,13 @@ void RKGndCol::computeBBox() { const KCollisionPrism prism = getPrism(i); const EGG::Vector3f fnrm = getNrm(prism.fnrm_i); - // TODO: Why are the variables backwards? - const EGG::Vector3f enrm3 = getNrm(prism.enrm1_i); + const EGG::Vector3f enrm1 = getNrm(prism.enrm1_i); const EGG::Vector3f enrm2 = getNrm(prism.enrm2_i); - const EGG::Vector3f enrm1 = getNrm(prism.enrm3_i); + const EGG::Vector3f enrm3 = getNrm(prism.enrm3_i); const EGG::Vector3f vtx1 = getPos(prism.pos_i); - const EGG::Vector3f vtx3 = GetVertex(prism.height, vtx1, fnrm, enrm1, enrm3); - const EGG::Vector3f vtx2 = GetVertex(prism.height, vtx1, fnrm, enrm1, enrm2); + const EGG::Vector3f vtx3 = GetVertex(prism.height, vtx1, fnrm, enrm3, enrm1); + const EGG::Vector3f vtx2 = GetVertex(prism.height, vtx1, fnrm, enrm3, enrm2); m_bbox.mMin = m_bbox.mMin.minimize(vtx1); m_bbox.mMin = m_bbox.mMin.minimize(vtx2); @@ -158,12 +159,9 @@ const u16 *RKGndCol::searchBlock(const EGG::Vector3f &point) { /* 807c2410 - checkCollision */ bool RKGndCol::checkSphereCollision(float *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut) { - if (std::isfinite(m_prevPos.y)) { - ; // return checkSphereMovement(distOut, fnrmOut, flagsOut); - } else { - return checkSphere(distOut, fnrmOut, flagsOut); - } - return false; + return std::isfinite(m_prevPos.y) ? + false /* checkSphereMovement(distOut, fnrmOut, flagsOut) */ : + checkSphere(distOut, fnrmOut, flagsOut); } /*bool RKGndCol::LAB_807c19ec(float &planeDist, f32 real_sq_dist) { @@ -212,8 +210,9 @@ bool RKGndCol::scaleNormalsAndUpdatePlaneDist(f32 dot, f32 dist1, f32 dist2, return LAB_807c19d0(planeDist, sq_dist); }*/ -bool RKGndCol::checkTriCollision(const KCollisionPrism &prism, f32 *distOut, EGG::Vector3f *fnrmOut, - u16 *flagsOut) { +// Returns whether or not there are still triangles to check +bool RKGndCol::checkSphereTriCollision(const KCollisionPrism &prism, f32 *distOut, + EGG::Vector3f *fnrmOut, u16 *flagsOut) { // Responsible for updating the output params auto out = [&](float dist) { if (distOut) { @@ -236,9 +235,10 @@ bool RKGndCol::checkTriCollision(const KCollisionPrism &prism, f32 *distOut, EGG const EGG::Vector3f vert = m_pos - getPos(prism.pos_i); + // Edge normals point outside the triangle const EGG::Vector3f enrm1 = getNrm(prism.enrm1_i); - f32 dist_ac = vert.ps_dot(enrm1); - if (m_radius <= dist_ac) { + f32 dist_ca = vert.ps_dot(enrm1); + if (m_radius <= dist_ca) { return false; } @@ -261,17 +261,95 @@ bool RKGndCol::checkTriCollision(const KCollisionPrism &prism, f32 *distOut, EGG return false; } - auto LAB_807c19ec = [&](f32 real_sq_dist) { + // Originally part of the edge searching, but moved out for simplicity + // If these are all zero, then we're inside the triangle + if (dist_ab <= 0.0f && dist_bc <= 0.0f && dist_ca <= 0.0f) { + return out(dist_in_plane); + } + + EGG::Vector3f edge_nor, other_edge_nor; + f32 edge_dist, other_edge_dist; + // NOTE (vabold): > means further, < means closer, = means same distance + if (dist_ab >= dist_ca && dist_ab > dist_bc) { + // AB is the furthest edge + edge_nor = enrm2; + edge_dist = dist_ab; + if (dist_ca >= dist_bc) { + // CA is the second furthest edge + other_edge_nor = enrm1; + other_edge_dist = dist_ca; + } else { + // BC is the second furthest edge + other_edge_nor = enrm3; + other_edge_dist = dist_bc; + } + } else if (dist_bc >= dist_ca) { + // BC is the furthest edge + edge_nor = enrm3; + edge_dist = dist_bc; + if (dist_ab >= dist_ca) { + // AB is the second furthest edge + other_edge_nor = enrm2; + other_edge_dist = dist_ab; + } else { + // CA is the second furthest edge + other_edge_nor = enrm1; + other_edge_dist = dist_ca; + } + } else { + // CA is the furthest edge + edge_nor = enrm1; + edge_dist = dist_ca; + if (dist_bc >= dist_ab) { + // BC is the second furthest edge + other_edge_nor = enrm3; + other_edge_dist = dist_bc; + } else { + // AB is the second furthest edge + other_edge_nor = enrm2; + other_edge_dist = dist_ab; + } + } + + f32 cos = edge_nor.ps_dot(other_edge_nor); + f32 sq_dist; + if (cos * edge_dist > other_edge_dist) { + if (edge_dist > plane_dist) { + return false; + } + + sq_dist = m_radius * m_radius - edge_dist * edge_dist; + } else { + f32 t = (cos * edge_dist - other_edge_dist) / (cos * cos - 1.0f); + f32 s = edge_dist - t * cos; + const EGG::Vector3f corner_pos = edge_nor * s + other_edge_nor * t; + f32 corner_sq_dist = corner_pos.dot(); + + if (corner_sq_dist > plane_dist * plane_dist) { + return false; + } + + sq_dist = m_radius * m_radius - corner_sq_dist; + } + + if (sq_dist < plane_dist * plane_dist || sq_dist < 0.0f) { + return false; + } + + f32 dist = EGG::Mathf::sqrt(sq_dist) - plane_dist; + if (dist <= 0.0f) { + return false; + } + + return out(dist); + + /*auto LAB_807c19ec = [&](f32 real_sq_dist) { u32 temp = (((0 <= real_sq_dist) << 1) << 0x1c) >> 0x1d; if (real_sq_dist < plane_dist * plane_dist || temp == 0) { return false; } - f32 distToPlanePlusRadius = 0.0f; - if (real_sq_dist > 0) { - distToPlanePlusRadius = EGG::Mathf::frsqrt(real_sq_dist) * real_sq_dist; - } - distToPlanePlusRadius -= plane_dist; + f32 distToPlanePlusRadius = EGG::Mathf::sqrt(real_sq_dist) - plane_dist; if (distToPlanePlusRadius <= 0) { return false; } @@ -288,11 +366,11 @@ bool RKGndCol::checkTriCollision(const KCollisionPrism &prism, f32 *distOut, EGG return LAB_807c19ec(real_sq_dist); }; - auto scaleAndCombineNormals = [&](f32 dot, f32 dist1, f32 dist2, const EGG::Vector3f &nrm1, + auto scaleAndCombineNormals = [&](f32 cos, f32 dist1, f32 dist2, const EGG::Vector3f &nrm1, const EGG::Vector3f &nrm2) { - f32 dVar7 = (dot * dist1 - dist2) / (dot * dot - 1); - f32 fVar1 = dist1 - dVar7 * dot; - EGG::Vector3f combined = nrm1 * dVar7 + nrm2 * fVar1; + f32 t = (cos * dist1 - dist2) / (cos * cos - 1); + f32 s = dist1 - t * cos; + EGG::Vector3f combined = nrm1 * s + nrm2 * t; return LAB_807c19d0(combined.ps_dot(combined)); }; @@ -301,38 +379,38 @@ bool RKGndCol::checkTriCollision(const KCollisionPrism &prism, f32 *distOut, EGG bool bDotCheck; auto dotAndScale = [&](const EGG::Vector3f &vec1, const EGG::Vector3f &vec2, f32 dist1, - f32 dist2) { + f32 dist2) -> bool { f32 dot = vec1.ps_dot(vec2); bDotCheck = dot * dist1 <= dist2; return bDotCheck ? scaleAndCombineNormals(dot, dist1, dist2, vec1, vec2) : false; }; - f32 radius_sq = m_radius * m_radius; + EGG::Vector3f vec1, vec2; + f32 dist1, dist2; - if (dist_ac <= dist_ab) { + if (dist_ca <= dist_ab) { if (dist_ab <= dist_bc) { - if (dist_bc <= 0) { - return out(dist_in_plane); - } - bool bRet = dotAndScale(enrm2, enrm3, dist_bc, dist_ab); - if (bDotCheck) { - return bRet; - } - } - if (dist_ab <= 0) { - return out(dist_in_plane); - } - if (dist_bc <= dist_ac) { - bool bRet = dotAndScale(enrm1, enrm2, dist_ab, dist_ac); - if (bDotCheck) { - return bRet; - } + vec1 = enrm2; + vec2 = enrm3; + dist1 = dist_bc; + dist2 = dist_ab; + } else if (dist_bc <= dist_ca) { + vec1 = enrm1; + vec2 = enrm2; + dist1 = dist_ab; + dist2 = dist_ca; } else { - bool bRet = dotAndScale(enrm2, enrm3, dist_ab, dist_bc); - if (bDotCheck) { - return bRet; - } + vec1 = enrm2; + vec2 = enrm3; + dist1 = dist_ab; + dist2 = dist_bc; + } + + bool bRet = dotAndScale(vec1, vec2, dist1, dist2); + if (bDotCheck) { + return bRet; } + if (plane_dist < dist_ab) { return false; } @@ -341,66 +419,76 @@ bool RKGndCol::checkTriCollision(const KCollisionPrism &prism, f32 *distOut, EGG return LAB_807c19ec(real_sq_dist); } - if (dist_ac <= dist_bc) { - if (dist_bc <= 0.0f) { - return out(dist_in_plane); - } - if (dist_ac <= dist_ab) { - bool bRet = dotAndScale(enrm2, enrm3, dist_bc, dist_ab); - if (bDotCheck) { - return bRet; - } + if (dist_ca <= dist_bc) { + bool bScale = false; + if (dist_ca <= dist_ab) { + vec1 = enrm2; + vec2 = enrm3; + dist1 = dist_bc; + dist2 = dist_ab; } else { - bool bRet = dotAndScale(enrm3, enrm1, dist_ac, dist_bc); - if (bDotCheck) { - return bRet; - } + vec1 = enrm3; + vec2 = enrm1; + dist1 = dist_ca; + dist2 = dist_bc; } + + bool bRet = dotAndScale(vec1, vec2, dist1, dist2); + if (bDotCheck) { + return bRet; + } + if (plane_dist < dist_bc) { return false; } + f32 real_sq_dist = radius_sq - dist_bc * dist_bc; return LAB_807c19ec(real_sq_dist); } - if (dist_ac <= 0.0f) { - return out(dist_in_plane); - } + // LAB_807c170c if (dist_ab <= dist_bc) { f32 dot = enrm1.ps_dot(enrm3); - if (dist_bc < dot * dist_ac) { - if (dist_ac <= dist_in_plane) { - f32 real_sq_dist = radius_sq - dist_ac * dist_ac; - return LAB_807c19ec(real_sq_dist); + if (dist_bc < dot * dist_ca) { + + // GOTO LAB_807c1830 + if (dist_in_plane < dist_ca) { + return false; } - return false; - } else { - return scaleAndCombineNormals(dot, dist_ac, dist_bc, enrm3, enrm1); + + f32 real_sq_dist = radius_sq - dist_ca * dist_ca; + return LAB_807c19ec(real_sq_dist); } + return scaleAndCombineNormals(dot, dist_ca, dist_bc, enrm3, enrm1); } else { f32 dot = enrm1.ps_dot(enrm2); - if (dist_ab < dot * dist_ac) { - if (dist_ac <= plane_dist) { - f32 real_sq_dist = radius_sq - dist_ac * dist_ac; + if (dist_ab < dot * dist_ca) { + if (dist_ca <= plane_dist) { + f32 real_sq_dist = radius_sq - dist_ca * dist_ca; return LAB_807c19ec(real_sq_dist); } return false; } - return scaleAndCombineNormals(dot, dist_ab, dist_ac, enrm1, enrm2); - } + return scaleAndCombineNormals(dot, dist_ab, dist_ca, enrm1, enrm2); + }*/ } -bool RKGndCol::checkSphere(float *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut) { +bool RKGndCol::checkSphere(f32 *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut) { + // If there's no list of triangles to check, there's no collision if (!m_prismIter) { return false; } + // Check collision for all triangles, and continuously call the function until we're out while (*++m_prismIter != 0) { - KCollisionPrism prism = getPrism(*m_prismIter); - if (checkTriCollision(prism, distOut, fnrmOut, flagsOut)) { + const KCollisionPrism prism = getPrism(*m_prismIter); + if (checkSphereTriCollision(prism, distOut, fnrmOut, flagsOut)) { return true; } } + + // We're out of triangles to check - another list must be prepared for subsequent calls + m_prismIter = nullptr; return false; } diff --git a/source/game/field/RKGndCol.hh b/source/game/field/RKGndCol.hh index a287a448..e4c2a7d5 100644 --- a/source/game/field/RKGndCol.hh +++ b/source/game/field/RKGndCol.hh @@ -45,7 +45,7 @@ public: KCollisionPrism getPrism(u16 prismIdx) const; private: - bool checkTriCollision(const KCollisionPrism &prism, float *distOut, EGG::Vector3f *fnrmOut, + bool checkSphereTriCollision(const KCollisionPrism &prism, float *distOut, EGG::Vector3f *fnrmOut, u16 *flagsOut); /*bool LAB_807c19d0(float &planeDist, f32 sq_dist); bool LAB_807c19ec(float &planeDist, f32 real_sq_dist);