Actually add CMetroidAreaColliderg

This commit is contained in:
Luke Street 2022-10-20 20:27:39 -04:00
parent 71ff684be4
commit f535084540
1 changed files with 194 additions and 0 deletions

View File

@ -0,0 +1,194 @@
#include "WorldFormat/CMetroidAreaCollider.hpp"
#include "Collision/CollisionUtil.hpp"
#include <string.h>
static uint gCalledClip = 0;
static uint gRejectedByClip = 0;
static uint gTrianglesProcessed = 0;
static uint gDupTrianglesProcessed = 0;
ushort CMetroidAreaCollider::sDupPrimitiveCheckCount = 0;
ushort CMetroidAreaCollider::sDupVertexList[0x2800];
ushort CMetroidAreaCollider::sDupEdgeList[0x6000];
ushort CMetroidAreaCollider::sDupTriangleList[0x4000];
static inline CVector3f ClipRayToPlane(const CVector3f& a, const CVector3f& b,
const CPlane& plane) {
float f = -plane.GetHeight(a) / CVector3f::Dot(b - a, plane.GetNormal());
return (a - b) * (1.f - f);
}
bool CMetroidAreaCollider::ConvexPolyCollision(const CPlane* planes, const CVector3f* verts,
CAABox& aabb) {
typedef rstl::reserved_vector< CVector3f, 20 > ClipVec;
++gCalledClip;
++gRejectedByClip;
ClipVec vecs[2];
int vecIdx = 0;
int otherVecIdx = 1;
vecs[0].push_back(verts[0]);
vecs[0].push_back(verts[1]);
vecs[0].push_back(verts[2]);
for (int i = 0; i < 6; ++i) {
ClipVec& vec = vecs[vecIdx];
ClipVec& otherVec = vecs[otherVecIdx];
otherVec.clear();
bool inFrontOf = planes[i].GetHeight(vec.front()) >= 0.f;
for (int j = 0; j < vec.size(); ++j) {
const CVector3f& b = vec[j == vec.size() - 1 ? 0 : j + 1];
if (inFrontOf) {
otherVec.push_back(vec[j]);
}
bool nextInFrontOf = planes[i].GetHeight(b) >= 0.f;
if (nextInFrontOf ^ inFrontOf) {
otherVec.push_back(ClipRayToPlane(vec[j], b, planes[i]) + b);
}
inFrontOf = nextInFrontOf;
}
if (otherVec.empty()) {
return false;
}
otherVecIdx ^= 1;
vecIdx ^= 1;
}
ClipVec& accumVec = vecs[otherVecIdx ^ 1];
for (ClipVec::const_iterator it = accumVec.begin(); it != accumVec.end(); ++it) {
aabb.AccumulateBounds(*it);
}
--gRejectedByClip;
return true;
}
void CMetroidAreaCollider::ResetInternalCounters() {
gCalledClip = 0;
gRejectedByClip = 0;
gTrianglesProcessed = 0;
gDupTrianglesProcessed = 0;
if (sDupPrimitiveCheckCount == 0xffff) {
memset(sDupVertexList, 0, sizeof(sDupVertexList));
memset(sDupEdgeList, 0, sizeof(sDupEdgeList));
memset(sDupTriangleList, 0, sizeof(sDupTriangleList));
++sDupPrimitiveCheckCount;
}
++sDupPrimitiveCheckCount;
}
bool CMetroidAreaCollider::AABoxCollisionCheck_Internal(const CAreaOctTree::Node& node,
CAABoxAreaCache& cache) {
bool ret = false;
switch (node.GetTreeType()) {
case CAreaOctTree::Node::kTT_Invalid:
return false;
case CAreaOctTree::Node::kTT_Branch: {
for (int i = 0; i < 8; ++i) {
CAreaOctTree::Node ch = node.GetChild(i);
CAABox box = ch.GetBoundingBox();
if (box.DoBoundsOverlap(cache.x0_aabb))
if (AABoxCollisionCheck_Internal(ch, cache))
ret = true;
}
break;
}
case CAreaOctTree::Node::kTT_Leaf: {
CAreaOctTree::TriListReference list = node.GetTriangleArray();
const CAreaOctTree& owner = node.GetOwner();
const CMaterialFilter& filter = cache.x8_filter;
const CPlane* planes = cache.x4_planes;
for (int j = 0; j < list.GetSize(); ++j) {
++gTrianglesProcessed;
ushort triIdx = list.GetAt(j);
if (sDupPrimitiveCheckCount == sDupTriangleList[triIdx]) {
++gDupTrianglesProcessed;
} else {
sDupTriangleList[triIdx] = sDupPrimitiveCheckCount;
const CCollisionSurface& surf = owner.GetMasterListTriangle(triIdx);
CMaterialList material(surf.GetSurfaceFlags());
if (filter.Passes(material)) {
if (CollisionUtil::TriBoxOverlap(cache.x14_center, cache.x20_halfExtent, surf.GetVert(0),
surf.GetVert(1), surf.GetVert(2)) == true) {
CAABox aabb = CAABox::MakeMaxInvertedBox();
if (ConvexPolyCollision(planes, &surf.GetVert(0), aabb)) {
CPlane plane = surf.GetPlane();
CCollisionInfo collision(aabb, cache.xc_material, material, plane.GetNormal(),
-plane.GetNormal());
cache.x10_collisionList.Add(collision, false);
ret = true;
}
}
}
}
}
break;
}
default:
break;
}
return ret;
}
bool CMetroidAreaCollider::AABoxCollisionCheck_Cached(const COctreeLeafCache& leafCache,
const CAABox& aabb,
const CMaterialFilter& filter,
const CMaterialList& matList,
CCollisionInfoList& list) {
bool ret = false;
const CUnitVector3f right(1.f, 0.f, 0.f, CUnitVector3f::kN_No);
const CUnitVector3f forward(0.f, 1.f, 0.f, CUnitVector3f::kN_No);
const CUnitVector3f up(0.f, 0.f, 1.f, CUnitVector3f::kN_No);
const CPlane planes[6] = {
CPlane(aabb.GetMinPoint(), right),
CPlane(aabb.GetMaxPoint(), -right),
CPlane(aabb.GetMinPoint(), forward),
CPlane(aabb.GetMaxPoint(), -forward),
CPlane(aabb.GetMinPoint(), up),
CPlane(aabb.GetMaxPoint(), -up),
};
ResetInternalCounters();
CVector3f center = aabb.GetCenterPoint();
CVector3f halfExtent = aabb.GetHalfExtent();
for (int i = 0; i < leafCache.GetNumLeaves(); ++i) {
const CAreaOctTree::Node& node = leafCache.GetLeaf(i);
if (aabb.DoBoundsOverlap(node.GetBoundingBox())) {
CAreaOctTree::TriListReference listRef = node.GetTriangleArray();
for (int j = 0; j < listRef.GetSize(); ++j) {
++gTrianglesProcessed;
ushort triIdx = listRef.GetAt(j);
if (sDupPrimitiveCheckCount == sDupTriangleList[triIdx]) {
++gDupTrianglesProcessed;
} else {
sDupTriangleList[triIdx] = sDupPrimitiveCheckCount;
const CCollisionSurface& surf = node.GetOwner().GetMasterListTriangle(triIdx);
CMaterialList material(surf.GetSurfaceFlags());
if (filter.Passes(material)) {
if (CollisionUtil::TriBoxOverlap(center, halfExtent, surf.GetVert(0), surf.GetVert(1),
surf.GetVert(2)) == true) {
CAABox aabb2 = CAABox::MakeMaxInvertedBox();
if (ConvexPolyCollision(planes, &surf.GetVert(0), aabb2)) {
CPlane plane = surf.GetPlane();
CCollisionInfo collision(aabb2, matList, material, plane.GetNormal(),
-plane.GetNormal());
list.Add(collision, false);
ret = true;
}
}
}
}
}
}
}
return ret;
}