mirror of https://github.com/PrimeDecomp/prime.git
Actually add CMetroidAreaColliderg
This commit is contained in:
parent
71ff684be4
commit
f535084540
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue