mirror of
https://github.com/PrimeDecomp/prime.git
synced 2025-12-10 03:47:40 +00:00
Halfway match CAABox; continue CBallCamera
This commit is contained in:
@@ -1,6 +1,196 @@
|
||||
#include "Kyoto/Math/CAABox.hpp"
|
||||
|
||||
#include "Kyoto/Math/CLineSeg.hpp"
|
||||
#include "Kyoto/Math/CMath.hpp"
|
||||
#include "Kyoto/Math/CTransform4f.hpp"
|
||||
#include "Kyoto/Math/CTri.hpp"
|
||||
#include "Kyoto/Streams/CInputStream.hpp"
|
||||
|
||||
#include "float.h"
|
||||
|
||||
CAABox CAABox::mskInvertedBox(FLT_MIN, FLT_MIN, FLT_MIN, FLT_MAX, FLT_MAX, FLT_MAX);
|
||||
CAABox CAABox::mskNullBox(0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
|
||||
|
||||
CAABox::CAABox(CInputStream& in) : min(in), max(in) {}
|
||||
|
||||
CAABox::CAABox(const CVector3f& min, const CVector3f& max) : min(min), max(max) {}
|
||||
|
||||
CLineSeg CAABox::GetEdge(EBoxEdgeId id) const {
|
||||
switch (id) {
|
||||
case kE_Z0:
|
||||
return CLineSeg(CVector3f(min.GetX(), min.GetY(), max.GetZ()),
|
||||
CVector3f(min.GetX(), min.GetY(), min.GetZ()));
|
||||
case kE_Y0:
|
||||
return CLineSeg(CVector3f(min.GetX(), min.GetY(), max.GetZ()),
|
||||
CVector3f(min.GetX(), max.GetY(), max.GetZ()));
|
||||
case kE_X0:
|
||||
return CLineSeg(CVector3f(min.GetX(), min.GetY(), min.GetZ()),
|
||||
CVector3f(max.GetX(), min.GetY(), min.GetZ()));
|
||||
case kE_Y1:
|
||||
return CLineSeg(CVector3f(min.GetX(), min.GetY(), min.GetZ()),
|
||||
CVector3f(min.GetX(), max.GetY(), min.GetZ()));
|
||||
case kE_Z1:
|
||||
return CLineSeg(CVector3f(max.GetX(), min.GetY(), min.GetZ()),
|
||||
CVector3f(max.GetX(), min.GetY(), max.GetZ()));
|
||||
case kE_Y2:
|
||||
return CLineSeg(CVector3f(max.GetX(), min.GetY(), min.GetZ()),
|
||||
CVector3f(max.GetX(), max.GetY(), min.GetZ()));
|
||||
case kE_X1:
|
||||
return CLineSeg(CVector3f(max.GetX(), min.GetY(), max.GetZ()),
|
||||
CVector3f(min.GetX(), min.GetY(), max.GetZ()));
|
||||
case kE_Y3:
|
||||
return CLineSeg(CVector3f(max.GetX(), min.GetY(), max.GetZ()),
|
||||
CVector3f(max.GetX(), max.GetY(), max.GetZ()));
|
||||
case kE_Z2:
|
||||
return CLineSeg(CVector3f(max.GetX(), max.GetY(), max.GetZ()),
|
||||
CVector3f(max.GetX(), max.GetY(), min.GetZ()));
|
||||
case kE_X2:
|
||||
return CLineSeg(CVector3f(max.GetX(), max.GetY(), min.GetZ()),
|
||||
CVector3f(min.GetX(), max.GetY(), min.GetZ()));
|
||||
case kE_Z3:
|
||||
return CLineSeg(CVector3f(min.GetX(), max.GetY(), min.GetZ()),
|
||||
CVector3f(min.GetX(), max.GetY(), max.GetZ()));
|
||||
case kE_X3:
|
||||
return CLineSeg(CVector3f(min.GetX(), max.GetY(), max.GetZ()),
|
||||
CVector3f(max.GetX(), max.GetY(), max.GetZ()));
|
||||
default:
|
||||
return CLineSeg(CVector3f(min.GetX(), min.GetY(), max.GetZ()),
|
||||
CVector3f(min.GetX(), min.GetY(), min.GetZ()));
|
||||
}
|
||||
}
|
||||
|
||||
CTri CAABox::GetTri(EBoxFaceId face, int windOffset) const {
|
||||
CVector3f verts[4] = {
|
||||
CVector3f(min.GetX(), min.GetY(), max.GetZ()),
|
||||
CVector3f(min.GetX(), min.GetY(), min.GetZ()),
|
||||
CVector3f(max.GetX(), min.GetY(), min.GetZ()),
|
||||
CVector3f(max.GetX(), min.GetY(), max.GetZ()),
|
||||
};
|
||||
switch (face) {
|
||||
case kF_YMin:
|
||||
default:
|
||||
verts[0] = CVector3f(min.GetX(), min.GetY(), max.GetZ());
|
||||
verts[1] = CVector3f(max.GetX(), min.GetY(), max.GetZ());
|
||||
verts[2] = CVector3f(max.GetX(), min.GetY(), min.GetZ());
|
||||
verts[3] = CVector3f(min.GetX(), min.GetY(), min.GetZ());
|
||||
break;
|
||||
case kF_YMax:
|
||||
verts[0] = CVector3f(max.GetX(), max.GetY(), max.GetZ());
|
||||
verts[1] = CVector3f(min.GetX(), max.GetY(), max.GetZ());
|
||||
verts[2] = CVector3f(min.GetX(), max.GetY(), min.GetZ());
|
||||
verts[3] = CVector3f(max.GetX(), max.GetY(), min.GetZ());
|
||||
break;
|
||||
case kF_XMin:
|
||||
verts[0] = CVector3f(min.GetX(), max.GetY(), max.GetZ());
|
||||
verts[1] = CVector3f(min.GetX(), min.GetY(), max.GetZ());
|
||||
verts[2] = CVector3f(min.GetX(), min.GetY(), min.GetZ());
|
||||
verts[3] = CVector3f(min.GetX(), max.GetY(), min.GetZ());
|
||||
break;
|
||||
case kF_XMax:
|
||||
verts[0] = CVector3f(max.GetX(), min.GetY(), max.GetZ());
|
||||
verts[1] = CVector3f(max.GetX(), max.GetY(), max.GetZ());
|
||||
verts[2] = CVector3f(max.GetX(), max.GetY(), min.GetZ());
|
||||
verts[3] = CVector3f(max.GetX(), min.GetY(), min.GetZ());
|
||||
break;
|
||||
case kF_ZMax:
|
||||
verts[0] = CVector3f(min.GetX(), max.GetY(), max.GetZ());
|
||||
verts[1] = CVector3f(max.GetX(), max.GetY(), max.GetZ());
|
||||
verts[2] = CVector3f(max.GetX(), min.GetY(), max.GetZ());
|
||||
verts[3] = CVector3f(min.GetX(), min.GetY(), max.GetZ());
|
||||
break;
|
||||
case kF_ZMin:
|
||||
verts[0] = min;
|
||||
verts[1] = CVector3f(max.GetX(), min.GetY(), min.GetZ());
|
||||
verts[2] = CVector3f(max.GetX(), max.GetY(), min.GetZ());
|
||||
verts[3] = CVector3f(min.GetX(), max.GetY(), min.GetZ());
|
||||
break;
|
||||
}
|
||||
return CTri(verts[windOffset], verts[(windOffset + 1) % 4], verts[(windOffset + 2) % 4]);
|
||||
}
|
||||
|
||||
bool CAABox::DoBoundsOverlap(const CAABox& other) const {
|
||||
if (other.min.GetX() > max.GetX() || min.GetX() > other.max.GetX() ||
|
||||
other.min.GetY() > max.GetY() || min.GetY() > other.max.GetY() ||
|
||||
other.min.GetZ() > max.GetZ() || min.GetZ() > other.max.GetZ()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CAABox::AccumulateBounds(const CVector3f& other) {
|
||||
if (other.GetX() < min.GetX()) {
|
||||
min.SetX(other.GetX());
|
||||
}
|
||||
if (other.GetY() < min.GetY()) {
|
||||
min.SetY(other.GetY());
|
||||
}
|
||||
if (other.GetZ() < min.GetZ()) {
|
||||
min.SetZ(other.GetZ());
|
||||
}
|
||||
if (other.GetX() > max.GetX()) {
|
||||
max.SetX(other.GetX());
|
||||
}
|
||||
if (other.GetY() > max.GetY()) {
|
||||
max.SetY(other.GetY());
|
||||
}
|
||||
if (other.GetZ() > max.GetZ()) {
|
||||
max.SetZ(other.GetZ());
|
||||
}
|
||||
}
|
||||
|
||||
bool CAABox::Inside(const CAABox& other) const {
|
||||
if (min.GetX() >= other.min.GetX() && max.GetX() <= other.max.GetX() &&
|
||||
min.GetY() >= other.min.GetY() && max.GetY() <= other.max.GetY() &&
|
||||
min.GetZ() >= other.min.GetZ() && max.GetZ() <= other.max.GetZ()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CAABox::InsidePlane(const CPlane& plane) const {
|
||||
CVector3f vec(CMath::FastFSel(plane.GetNormal().GetX(), min.GetX(), max.GetX()),
|
||||
CMath::FastFSel(plane.GetNormal().GetY(), min.GetY(), max.GetY()),
|
||||
CMath::FastFSel(plane.GetNormal().GetZ(), min.GetZ(), max.GetZ()));
|
||||
return !(CVector3f::Dot(plane.GetNormal(), vec) >= plane.GetConstant());
|
||||
}
|
||||
|
||||
// TODO non-matching
|
||||
CAABox CAABox::GetTransformedAABox(const CTransform4f& xf) const {
|
||||
if (&xf == &CTransform4f::Identity()) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
CVector3f newMin = xf.GetTranslation();
|
||||
CVector3f newMax = xf.GetTranslation();
|
||||
for (int x = 0; x < 3; ++x) {
|
||||
for (int y = 0; y < 3; ++y) {
|
||||
f32 mul = xf.GetRow(x)[y];
|
||||
f32 minMul = mul * GetMinPoint()[y];
|
||||
f32 maxMul = mul * GetMaxPoint()[y];
|
||||
if (minMul < maxMul) {
|
||||
newMin[x] += maxMul;
|
||||
newMax[x] += minMul;
|
||||
} else {
|
||||
newMin[x] += minMul;
|
||||
newMax[x] += maxMul;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CAABox(newMin, newMax);
|
||||
}
|
||||
|
||||
CVector3f CAABox::ClampToBox(const CVector3f& vec) const {
|
||||
return CVector3f(
|
||||
vec.GetX() < min.GetX() ? min.GetX() : (vec.GetX() > max.GetX() ? max.GetX() : vec.GetX()),
|
||||
vec.GetY() < min.GetY() ? min.GetY() : (vec.GetY() > max.GetY() ? max.GetY() : vec.GetY()),
|
||||
vec.GetZ() < min.GetZ() ? min.GetZ() : (vec.GetZ() > max.GetZ() ? max.GetZ() : vec.GetZ()));
|
||||
}
|
||||
|
||||
CVector3f CAABox::FurthestPointAlongVector(const CVector3f& vec) const {
|
||||
return CVector3f(CMath::FastFSel(vec.GetX(), max.GetX(), min.GetX()),
|
||||
CMath::FastFSel(vec.GetY(), max.GetY(), min.GetY()),
|
||||
CMath::FastFSel(vec.GetZ(), max.GetZ(), min.GetZ()));
|
||||
}
|
||||
|
||||
CVector3f CAABox::ClosestPointAlongVector(const CVector3f& vec) const {
|
||||
return CVector3f(CMath::FastFSel(vec.GetX(), min.GetX(), max.GetX()),
|
||||
|
||||
@@ -2,14 +2,19 @@
|
||||
|
||||
#include "math.h"
|
||||
|
||||
#include "Collision/CCollidableSphere.hpp"
|
||||
#include "Collision/CCollisionInfo.hpp"
|
||||
#include "Collision/CRayCastResult.hpp"
|
||||
|
||||
#include "MetroidPrime/CCollisionActor.hpp"
|
||||
#include "MetroidPrime/CGameCollision.hpp"
|
||||
#include "MetroidPrime/Cameras/CCameraManager.hpp"
|
||||
#include "MetroidPrime/Player/CPlayer.hpp"
|
||||
#include "MetroidPrime/Tweaks/CTweakBall.hpp"
|
||||
#include "MetroidPrime/Tweaks/CTweakPlayer.hpp"
|
||||
|
||||
#include "WorldFormat/CMetroidAreaCollider.hpp"
|
||||
|
||||
static CMaterialList kLineOfSightIncludeList = CMaterialList(kMT_Solid);
|
||||
static CMaterialList kLineOfSightExcludeList =
|
||||
CMaterialList(kMT_ProjectilePassthrough, kMT_Player, kMT_Character, kMT_CameraPassthrough);
|
||||
@@ -354,3 +359,231 @@ void CBallCamera::UpdateColliders(const CTransform4f& xf,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO non-matching regswaps
|
||||
CVector3f
|
||||
CBallCamera::CalculateCollidersCentroid(const rstl::vector< CCameraCollider >& colliderList,
|
||||
int numObscured) const {
|
||||
if (colliderList.size() < 3) {
|
||||
return CVector3f(0.f, 1.f, 0.f);
|
||||
}
|
||||
|
||||
int clearColliders = 0;
|
||||
int prevCol = colliderList.size() - 1;
|
||||
f32 accumCross = 0.f;
|
||||
f32 accumX = 0.f;
|
||||
f32 accumZ = 0.f;
|
||||
for (int i = 0; i < colliderList.size(); ++i) {
|
||||
if (colliderList[prevCol].GetOcclusionCount() < 2 && colliderList[i].GetOcclusionCount() < 2) {
|
||||
f32 scale = colliderList[prevCol].GetScale();
|
||||
f32 z0 = scale * colliderList[prevCol].GetPosition().GetZ();
|
||||
f32 x0 = scale * colliderList[prevCol].GetPosition().GetX();
|
||||
f32 x1 = scale * colliderList[i].GetPosition().GetX();
|
||||
f32 z1 = scale * colliderList[i].GetPosition().GetZ();
|
||||
|
||||
f32 cross = x0 * z1 - x1 * z0;
|
||||
accumCross += cross;
|
||||
accumX += cross * (x1 + x0);
|
||||
accumZ += cross * (z1 + z0);
|
||||
} else {
|
||||
clearColliders += 1;
|
||||
}
|
||||
prevCol = i;
|
||||
}
|
||||
|
||||
if (static_cast< f32 >(clearColliders) / static_cast< f32 >(colliderList.size()) <=
|
||||
x330_clearColliderThreshold) {
|
||||
return CVector3f(0.f, 1.f, 0.f);
|
||||
}
|
||||
|
||||
if (accumCross != 0.f) {
|
||||
f32 baryCross = 3.f * accumCross;
|
||||
return CVector3f(accumX / baryCross, 0.f, accumZ / baryCross);
|
||||
}
|
||||
|
||||
return CVector3f(0.f, 2.f, 0.f);
|
||||
}
|
||||
|
||||
CVector3f CBallCamera::ApplyColliders() {
|
||||
CVector3f smallCentroid =
|
||||
CalculateCollidersCentroid(x264_smallColliders, x2c4_smallCollidersObsCount);
|
||||
CVector3f mediumCentroid =
|
||||
CalculateCollidersCentroid(x274_mediumColliders, x2c8_mediumCollidersObsCount);
|
||||
CVector3f largeCentroid =
|
||||
CalculateCollidersCentroid(x284_largeColliders, x2cc_largeCollidersObsCount);
|
||||
|
||||
if (smallCentroid.GetY() == 0.f) {
|
||||
x2a0_smallCentroid = smallCentroid;
|
||||
} else {
|
||||
x2a0_smallCentroid = CVector3f::Zero();
|
||||
}
|
||||
|
||||
float centroidX = x2a0_smallCentroid.GetX();
|
||||
float centroidZ = x2a0_smallCentroid.GetZ();
|
||||
|
||||
if (mediumCentroid.GetY() == 0.f) {
|
||||
x2ac_mediumCentroid = mediumCentroid;
|
||||
} else {
|
||||
x2ac_mediumCentroid = CVector3f::Zero();
|
||||
}
|
||||
|
||||
centroidX += x2ac_mediumCentroid.GetX();
|
||||
centroidZ += x2ac_mediumCentroid.GetZ();
|
||||
|
||||
if (largeCentroid.GetY() == 0.f) {
|
||||
x2b8_largeCentroid = largeCentroid;
|
||||
} else {
|
||||
x2b8_largeCentroid = CVector3f::Zero();
|
||||
}
|
||||
|
||||
centroidX += x2b8_largeCentroid.GetX();
|
||||
centroidZ += x2b8_largeCentroid.GetZ();
|
||||
|
||||
if (x18c_31_clearLOS) {
|
||||
centroidX /= 1.5f;
|
||||
}
|
||||
centroidZ /= 3.f;
|
||||
|
||||
if (!x18c_31_clearLOS && x368_obscuringObjectId == kInvalidUniqueId) {
|
||||
float xMul = 1.5f;
|
||||
float zMul = 1.f;
|
||||
if (x350_obscuringMaterial.HasMaterial(kMT_Floor)) {
|
||||
zMul += 2.f * x358_unobscureMag;
|
||||
}
|
||||
if (x350_obscuringMaterial.HasMaterial(kMT_Wall)) {
|
||||
xMul += 3.f * CMath::Clamp(0.f, x358_unobscureMag - 0.25f, 1.f);
|
||||
}
|
||||
centroidX *= xMul;
|
||||
centroidZ *= zMul;
|
||||
}
|
||||
|
||||
if (!x18c_28_volumeCollider) {
|
||||
return CVector3f::Zero();
|
||||
}
|
||||
|
||||
if (fabsf(centroidX) < 0.05f) {
|
||||
centroidX = 0.f;
|
||||
}
|
||||
if (fabsf(centroidZ) < 0.05f) {
|
||||
centroidZ = 0.f;
|
||||
}
|
||||
|
||||
if (x18c_31_clearLOS) {
|
||||
centroidZ *= 0.5f;
|
||||
}
|
||||
|
||||
return CVector3f(centroidX, 0.f, centroidZ);
|
||||
}
|
||||
|
||||
int CBallCamera::CountObscuredColliders(const rstl::vector< CCameraCollider >& colliderList) const {
|
||||
int ret = 0;
|
||||
for (int i = 0; i < colliderList.size(); i++) {
|
||||
if (colliderList[i].GetOcclusionCount() >= 2) {
|
||||
++ret;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CAABox
|
||||
CBallCamera::CalculateCollidersBoundingBox(const rstl::vector< CCameraCollider >& colliderList,
|
||||
const CStateManager& mgr) const {
|
||||
CAABox aabb = CAABox::MakeMaxInvertedBox();
|
||||
for (int i = 0; i < colliderList.size(); i++) {
|
||||
aabb.AccumulateBounds(colliderList[i].GetRealPosition());
|
||||
}
|
||||
aabb.AccumulateBounds(mgr.GetPlayer()->GetTranslation());
|
||||
return aabb;
|
||||
}
|
||||
|
||||
CVector3f CBallCamera::AvoidGeometryFull(const CTransform4f& xf, const TEntityList& nearList,
|
||||
f32 dt, CStateManager& mgr) {
|
||||
UpdateColliders(xf, x264_smallColliders, x2d0_smallColliderIt, x264_smallColliders.size(), 4.f,
|
||||
nearList, dt, mgr);
|
||||
UpdateColliders(xf, x274_mediumColliders, x2d4_mediumColliderIt, x274_mediumColliders.size(), 4.f,
|
||||
nearList, dt, mgr);
|
||||
UpdateColliders(xf, x284_largeColliders, x2d8_largeColliderIt, x284_largeColliders.size(), 4.f,
|
||||
nearList, dt, mgr);
|
||||
return ApplyColliders();
|
||||
}
|
||||
|
||||
CVector3f CBallCamera::AvoidGeometry(const CTransform4f& xf, const TEntityList& nearList, f32 dt,
|
||||
CStateManager& mgr) {
|
||||
switch (x328_avoidGeomCycle) {
|
||||
case 0:
|
||||
UpdateColliders(xf, x264_smallColliders, x2d0_smallColliderIt, 1, 4.f, nearList, dt, mgr);
|
||||
break;
|
||||
case 1:
|
||||
UpdateColliders(xf, x274_mediumColliders, x2d4_mediumColliderIt, 3, 4.f, nearList, dt, mgr);
|
||||
break;
|
||||
case 2:
|
||||
UpdateColliders(xf, x284_largeColliders, x2d8_largeColliderIt, 4, 4.f, nearList, dt, mgr);
|
||||
break;
|
||||
case 3:
|
||||
UpdateColliders(xf, x284_largeColliders, x2d8_largeColliderIt, 4, 4.f, nearList, dt, mgr);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
int newCycle = x328_avoidGeomCycle + 1;
|
||||
x328_avoidGeomCycle = newCycle;
|
||||
if (newCycle >= 4) {
|
||||
x328_avoidGeomCycle = 0;
|
||||
}
|
||||
|
||||
return ApplyColliders();
|
||||
}
|
||||
|
||||
// TODO non-matching regswaps
|
||||
bool CBallCamera::DetectCollision(const CVector3f& from, const CVector3f& to, f32 radius, f32& d,
|
||||
CStateManager& mgr) {
|
||||
CVector3f delta = to - from;
|
||||
f32 deltaMag = delta.Magnitude();
|
||||
CVector3f deltaNorm = delta * (1.f / deltaMag);
|
||||
bool clear = true;
|
||||
|
||||
if (deltaMag > 0.000001f) {
|
||||
f32 margin = 2.f * radius;
|
||||
CAABox aabb = CAABox::MakeMaxInvertedBox();
|
||||
aabb.AccumulateBounds(from);
|
||||
aabb.AccumulateBounds(to);
|
||||
aabb = CAABox(aabb.GetMinPoint() - CVector3f(margin, margin, margin),
|
||||
aabb.GetMaxPoint() + CVector3f(margin, margin, margin));
|
||||
TEntityList nearList;
|
||||
mgr.BuildColliderList(nearList, *mgr.GetPlayer(), aabb);
|
||||
CAreaCollisionCache cache(aabb);
|
||||
CGameCollision::BuildAreaCollisionCache(mgr, cache);
|
||||
if (cache.HasCacheOverflowed()) {
|
||||
clear = false;
|
||||
}
|
||||
if (CGameCollision::DetectCollisionBoolean_Cached(
|
||||
mgr, cache,
|
||||
CCollidableSphere(CSphere(CVector3f::Zero(), radius), CMaterialList(kMT_Solid)),
|
||||
CTransform4f::Translate(from),
|
||||
CMaterialFilter::MakeIncludeExclude(
|
||||
CMaterialList(kMT_Solid), CMaterialList(kMT_ProjectilePassthrough, kMT_Player,
|
||||
kMT_Character, kMT_CameraPassthrough)),
|
||||
nearList)) {
|
||||
d = -1.f;
|
||||
return true;
|
||||
}
|
||||
if (clear) {
|
||||
TUniqueId intersectId = kInvalidUniqueId;
|
||||
CCollisionInfo info;
|
||||
f64 dTmp = deltaMag;
|
||||
if (CGameCollision::DetectCollision_Cached_Moving(
|
||||
mgr, cache,
|
||||
CCollidableSphere(CSphere(CVector3f::Zero(), radius), CMaterialList(kMT_Solid)),
|
||||
CTransform4f::Translate(from),
|
||||
CMaterialFilter::MakeIncludeExclude(
|
||||
CMaterialList(kMT_Solid), CMaterialList(kMT_ProjectilePassthrough, kMT_Player,
|
||||
kMT_Character, kMT_CameraPassthrough)),
|
||||
nearList, deltaNorm, intersectId, info, dTmp)) {
|
||||
d = static_cast< f32 >(dTmp);
|
||||
clear = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return !clear;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user