summaryrefslogtreecommitdiff
path: root/src/code
diff options
context:
space:
mode:
authormzxrules <mzxrules@gmail.com>2021-11-23 11:29:18 -0500
committerGitHub <noreply@github.com>2021-11-23 13:29:18 -0300
commit6b493d3f9d79dd2546e833998f3b9ba8a747223a (patch)
treebde8720d11cca4fec61b4493e709342e27519706 /src/code
parent837eb1c80687fe9b57a3c7b841547c33feeed6c7 (diff)
z_bgcheck.c (#357)
* first few functions * two more almost matching functions * Rebase to NBS, get it to compile * BgCheck_RaycastFloorStaticList OK, fix-up some functions * BgCheck_SphVsStaticWall OK! and a few others * more z_bgcheck NON_MATCHINGS * OK more functions, reorganize external reference #defines * More functions OK, more struct fixes * More OKs * Decomp all the way to the end of bgcheck * All functions attempted * Rename functions * formatting, data migration * Give names to unk structs, rename some structs, fix some non-equivalent functions * WaterBox_GetSurfaceImpl OK * BgCheck_ResetPolyCheckTbl OK, improve WaterBox_GetSurface2 codegen, eliminate warnings and clean up source. * BcCheck3_BgActorInit ->BgCheck3_BgActorInit, fix warnings * pr change requests * fix crc maybe * implement more changes * implement alf's changes
Diffstat (limited to 'src/code')
-rw-r--r--src/code/sys_math3d.c50
-rw-r--r--src/code/z_bg_collect.c48
-rw-r--r--src/code/z_bg_item.c20
-rw-r--r--src/code/z_bgcheck.c4715
-rw-r--r--src/code/z_collision_check.c6
-rw-r--r--src/code/z_fireobj.c6
-rw-r--r--src/code/z_quake.c5
-rw-r--r--src/code/z_scene.c2
-rw-r--r--src/code/z_scene_proc.c4
-rw-r--r--src/code/z_snap.c7
10 files changed, 4577 insertions, 286 deletions
diff --git a/src/code/sys_math3d.c b/src/code/sys_math3d.c
index f607295c1..50fd1211e 100644
--- a/src/code/sys_math3d.c
+++ b/src/code/sys_math3d.c
@@ -2,7 +2,7 @@
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_Normalize.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_80179678.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_PlaneVsLineSegClosestPoint.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_80179798.s")
@@ -46,7 +46,7 @@
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_Vec3fMagnitude.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_DistanceSquared.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_Vec3fDistSq.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_Distance.s")
@@ -60,15 +60,15 @@
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_CrossProduct.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_NormalVector.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_SurfaceNorm.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017A954.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_PointRelativeToCubeFaces.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017AA0C.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_PointRelativeToCubeEdges.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017ABBC.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_PointRelativeToCubeVertices.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017AD38.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_LineVsCube.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017B68C.s")
@@ -80,51 +80,51 @@
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017B9D8.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_NormalizedDistanceFromPlane.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_UDistPlaneToPos.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_NormalizedSignedDistanceFromPlane.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_DistPlaneToPos.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017BAD0.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkPointParaYDist.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017BD98.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017BDE0.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017BE30.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkPointParaYIntersectDist.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017BEE0.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkPointParaYIntersectInsideTri.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017BF8C.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017C008.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkLineSegParaYIntersect.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017C17C.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017C1F0.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017C494.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkPointParaYIntersectInsideTri2.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017C540.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkPointParaXDist.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017C808.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017C850.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkPointParaXIntersect.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017C904.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017C980.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkLineSegParaXIntersect.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017CB08.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017CB7C.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkLineSegParaZDist.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017CEA8.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017CEF0.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkPointParaZIntersect.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017CFA4.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017D020.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_TriChkLineSegParaZIntersect.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017D1AC.s")
@@ -148,7 +148,7 @@
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017DA24.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_ColSphereLineSeg.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_LineVsSph.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017DD34.s")
@@ -162,7 +162,7 @@
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017F1A0.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_ColSphereSphere.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_SphVsSph.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_ColSphereSphereIntersect.s")
@@ -178,11 +178,11 @@
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3d_ColTriTri.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017F9C0.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_XZInSphere.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017FA34.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_XYInSphere.s")
-#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017FAA8.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/Math3D_YZInSphere.s")
#pragma GLOBAL_ASM("asm/non_matchings/code/sys_math3d/func_8017FB1C.s")
diff --git a/src/code/z_bg_collect.c b/src/code/z_bg_collect.c
index 706c4b80a..0d4f4a21f 100644
--- a/src/code/z_bg_collect.c
+++ b/src/code/z_bg_collect.c
@@ -1,33 +1,33 @@
#include "global.h"
-void BgCheck2_UpdateActorPosition(CollisionContext* colCtx, s32 index, Actor* actor) {
+void BgCheck2_UpdateActorPosition(CollisionContext* colCtx, s32 bgId, Actor* actor) {
MtxF prevMatrix;
MtxF prevMatrixInv;
MtxF currMatrix;
Vec3f newPos;
Vec3f posWithInv;
- if (BgCheck_IsActorMeshIndexValid(index) == 0) {
+ if (!DynaPoly_IsBgIdBgActor(bgId)) {
return;
}
SkinMatrix_SetScaleRotateYRPTranslate(
- &prevMatrix, colCtx->dyna.bgActors[index].prevTransform.scale.x,
- colCtx->dyna.bgActors[index].prevTransform.scale.y, colCtx->dyna.bgActors[index].prevTransform.scale.z,
- colCtx->dyna.bgActors[index].prevTransform.rot.x, colCtx->dyna.bgActors[index].prevTransform.rot.y,
- colCtx->dyna.bgActors[index].prevTransform.rot.z, colCtx->dyna.bgActors[index].prevTransform.pos.x,
- colCtx->dyna.bgActors[index].prevTransform.pos.y, colCtx->dyna.bgActors[index].prevTransform.pos.z);
+ &prevMatrix, colCtx->dyna.bgActors[bgId].prevTransform.scale.x,
+ colCtx->dyna.bgActors[bgId].prevTransform.scale.y, colCtx->dyna.bgActors[bgId].prevTransform.scale.z,
+ colCtx->dyna.bgActors[bgId].prevTransform.rot.x, colCtx->dyna.bgActors[bgId].prevTransform.rot.y,
+ colCtx->dyna.bgActors[bgId].prevTransform.rot.z, colCtx->dyna.bgActors[bgId].prevTransform.pos.x,
+ colCtx->dyna.bgActors[bgId].prevTransform.pos.y, colCtx->dyna.bgActors[bgId].prevTransform.pos.z);
if (SkinMatrix_Invert(&prevMatrix, &prevMatrixInv) == 2) {
return;
}
SkinMatrix_SetScaleRotateYRPTranslate(
- &currMatrix, colCtx->dyna.bgActors[index].curTransform.scale.x,
- colCtx->dyna.bgActors[index].curTransform.scale.y, colCtx->dyna.bgActors[index].curTransform.scale.z,
- colCtx->dyna.bgActors[index].curTransform.rot.x, colCtx->dyna.bgActors[index].curTransform.rot.y,
- colCtx->dyna.bgActors[index].curTransform.rot.z, colCtx->dyna.bgActors[index].curTransform.pos.x,
- colCtx->dyna.bgActors[index].curTransform.pos.y, colCtx->dyna.bgActors[index].curTransform.pos.z);
+ &currMatrix, colCtx->dyna.bgActors[bgId].curTransform.scale.x, colCtx->dyna.bgActors[bgId].curTransform.scale.y,
+ colCtx->dyna.bgActors[bgId].curTransform.scale.z, colCtx->dyna.bgActors[bgId].curTransform.rot.x,
+ colCtx->dyna.bgActors[bgId].curTransform.rot.y, colCtx->dyna.bgActors[bgId].curTransform.rot.z,
+ colCtx->dyna.bgActors[bgId].curTransform.pos.x, colCtx->dyna.bgActors[bgId].curTransform.pos.y,
+ colCtx->dyna.bgActors[bgId].curTransform.pos.z);
SkinMatrix_Vec3fMtxFMultXYZ(&prevMatrixInv, &actor->world.pos, &posWithInv);
SkinMatrix_Vec3fMtxFMultXYZ(&currMatrix, &posWithInv, &newPos);
@@ -35,14 +35,14 @@ void BgCheck2_UpdateActorPosition(CollisionContext* colCtx, s32 index, Actor* ac
actor->world.pos = newPos;
}
-void BgCheck2_UpdateActorYRotation(CollisionContext* colCtx, s32 index, Actor* actor) {
+void BgCheck2_UpdateActorYRotation(CollisionContext* colCtx, s32 bgId, Actor* actor) {
s16 angleChange;
- if (BgCheck_IsActorMeshIndexValid(index) == 0) {
+ if (!DynaPoly_IsBgIdBgActor(bgId)) {
return;
}
- angleChange = colCtx->dyna.bgActors[index].curTransform.rot.y - colCtx->dyna.bgActors[index].prevTransform.rot.y;
+ angleChange = colCtx->dyna.bgActors[bgId].curTransform.rot.y - colCtx->dyna.bgActors[bgId].prevTransform.rot.y;
if (actor->id == 0) {
((Player*)actor)->currentYaw += angleChange;
@@ -52,14 +52,14 @@ void BgCheck2_UpdateActorYRotation(CollisionContext* colCtx, s32 index, Actor* a
actor->world.rot.y += angleChange;
}
-void BgCheck2_AttachToMesh(CollisionContext* colCtx, Actor* actor, s32 index) {
+void BgCheck2_AttachToMesh(CollisionContext* colCtx, Actor* actor, s32 bgId) {
DynaPolyActor* meshActor;
- if (BgCheck_IsActorMeshIndexValid(index) == 0) {
+ if (!DynaPoly_IsBgIdBgActor(bgId)) {
return;
}
- meshActor = BgCheck_GetActorOfMesh(colCtx, index);
+ meshActor = DynaPoly_GetActor(colCtx, bgId);
if (meshActor != NULL) {
DynaPolyActor_SetRidingFallingState(meshActor);
@@ -72,31 +72,31 @@ void BgCheck2_AttachToMesh(CollisionContext* colCtx, Actor* actor, s32 index) {
}
}
-u32 BgCheck2_UpdateActorAttachedToMesh(CollisionContext* colCtx, s32 index, Actor* actor) {
+u32 BgCheck2_UpdateActorAttachedToMesh(CollisionContext* colCtx, s32 bgId, Actor* actor) {
u32 wasUpdated = 0;
DynaPolyActor* meshActor;
- if (BgCheck_IsActorMeshIndexValid(index) == 0) {
+ if (!DynaPoly_IsBgIdBgActor(bgId)) {
return 0;
}
- if (colCtx->dyna.bgActorFlags[index] & 2 || !(colCtx->dyna.bgActorFlags[index] & 1)) {
+ if (colCtx->dyna.bgActorFlags[bgId] & 2 || !(colCtx->dyna.bgActorFlags[bgId] & 1)) {
return 0;
}
- meshActor = BgCheck_GetActorOfMesh(colCtx, index);
+ meshActor = DynaPoly_GetActor(colCtx, bgId);
if (meshActor == NULL) {
return 0;
}
if (meshActor->flags & 1) {
- BgCheck2_UpdateActorPosition(colCtx, index, actor);
+ BgCheck2_UpdateActorPosition(colCtx, bgId, actor);
wasUpdated = 1;
}
if (meshActor->flags & 2) {
- BgCheck2_UpdateActorYRotation(colCtx, index, actor);
+ BgCheck2_UpdateActorYRotation(colCtx, bgId, actor);
wasUpdated = 1;
}
diff --git a/src/code/z_bg_item.c b/src/code/z_bg_item.c
index 92a300e43..74adbe695 100644
--- a/src/code/z_bg_item.c
+++ b/src/code/z_bg_item.c
@@ -18,8 +18,8 @@ void DynaPolyActor_Init(DynaPolyActor* dynaActor, s32 flags) {
void DynaPolyActor_LoadMesh(GlobalContext* globalCtx, DynaPolyActor* dynaActor, CollisionHeader* meshHeader) {
CollisionHeader* header = NULL;
- BgCheck_RelocateMeshHeader(meshHeader, &header);
- dynaActor->bgId = BgCheck_AddActorMesh(globalCtx, &globalCtx->colCtx.dyna, dynaActor, header);
+ CollisionHeader_GetVirtual(meshHeader, &header);
+ dynaActor->bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &dynaActor->actor, header);
}
void DynaPolyActor_ResetState(DynaPolyActor* dynaActor) {
@@ -34,8 +34,8 @@ void DynaPolyActor_SetRidingMovingState(DynaPolyActor* dynaActor) {
dynaActor->stateFlags |= DYNAPOLY_STATE_RIDING_MOVING;
}
-void DynaPolyActor_SetRidingMovingStateByIndex(CollisionContext* colCtx, s32 index) {
- DynaPolyActor* dynaActor = BgCheck_GetActorOfMesh(colCtx, index);
+void DynaPolyActor_SetRidingMovingStateByIndex(CollisionContext* colCtx, s32 bgId) {
+ DynaPolyActor* dynaActor = DynaPoly_GetActor(colCtx, bgId);
if (dynaActor != NULL) {
DynaPolyActor_SetRidingMovingState(dynaActor);
@@ -46,8 +46,8 @@ void DynaPolyActor_SetRidingRotatingState(DynaPolyActor* dynaActor) {
dynaActor->stateFlags |= DYNAPOLY_STATE_RIDING_ROTATING;
}
-void DynaPolyActor_SetRidingRotatingStateByIndex(CollisionContext* colCtx, s32 index) {
- DynaPolyActor* dynaActor = BgCheck_GetActorOfMesh(colCtx, index);
+void DynaPolyActor_SetRidingRotatingStateByIndex(CollisionContext* colCtx, s32 bgId) {
+ DynaPolyActor* dynaActor = DynaPoly_GetActor(colCtx, bgId);
if (dynaActor != NULL) {
DynaPolyActor_SetRidingRotatingState(dynaActor);
@@ -125,16 +125,16 @@ s32 DynaPolyActor_ValidateMove(GlobalContext* globalCtx, DynaPolyActor* dynaActo
endPos.y = startPos.y;
endPos.z = sign * adjustedEndRadius * cos + startPos.z;
- if (func_800C56E0(&globalCtx->colCtx, &startPos, &endPos, &intersectionPos, &poly, true, false, false, true, &bgId,
- &dynaActor->actor, 0.0f)) {
+ if (BgCheck_EntityLineTest3(&globalCtx->colCtx, &startPos, &endPos, &intersectionPos, &poly, true, false, false,
+ true, &bgId, &dynaActor->actor, 0.0f)) {
return false;
}
startPos.x = (dynaActor->actor.world.pos.x * 2.0f) - startPos.x;
startPos.z = (dynaActor->actor.world.pos.z * 2.0f) - startPos.z;
endPos.x = sign * adjustedEndRadius * sin + startPos.x;
endPos.z = sign * adjustedEndRadius * cos + startPos.z;
- if (func_800C56E0(&globalCtx->colCtx, &startPos, &endPos, &intersectionPos, &poly, true, false, false, true, &bgId,
- &dynaActor->actor, 0.0f)) {
+ if (BgCheck_EntityLineTest3(&globalCtx->colCtx, &startPos, &endPos, &intersectionPos, &poly, true, false, false,
+ true, &bgId, &dynaActor->actor, 0.0f)) {
return false;
}
return true;
diff --git a/src/code/z_bgcheck.c b/src/code/z_bgcheck.c
index e607b978a..e5cb1ddb1 100644
--- a/src/code/z_bgcheck.c
+++ b/src/code/z_bgcheck.c
@@ -1,432 +1,4721 @@
#include "global.h"
-
-void BgCheck_PolygonLinkedListNodeInit(SSNode* node, s16* polyIndex, u16 next) {
+#include "vt.h"
+
+#define DYNA_RAYCAST_FLOORS 1
+#define DYNA_RAYCAST_WALLS 2
+#define DYNA_RAYCAST_CEILINGS 4
+
+static u32 sWallFlags[32] = {
+ 0, 1, 3, 5, 8, 16, 32, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+static u16 sSurfaceTypeSfx[] = {
+ /* 0x00 */ NA_SE_PL_WALK_GROUND - SFX_FLAG,
+ /* 0x01 */ NA_SE_PL_WALK_SAND - SFX_FLAG,
+ /* 0x02 */ NA_SE_PL_WALK_CONCRETE - SFX_FLAG,
+ /* 0x03 */ NA_SE_PL_WALK_DIRT - SFX_FLAG,
+ /* 0x04 */ NA_SE_PL_WALK_WATER0 - SFX_FLAG,
+ /* 0x05 */ NA_SE_PL_WALK_WATER1 - SFX_FLAG,
+ /* 0x06 */ NA_SE_PL_WALK_WATER2 - SFX_FLAG,
+ /* 0x07 */ NA_SE_PL_WALK_MAGMA - SFX_FLAG,
+ /* 0x08 */ NA_SE_PL_WALK_GRASS - SFX_FLAG,
+ /* 0x09 */ NA_SE_PL_WALK_GLASS - SFX_FLAG,
+ /* 0x0A */ NA_SE_PL_WALK_LADDER - SFX_FLAG,
+ /* 0x0B */ NA_SE_PL_WALK_GROUND - SFX_FLAG,
+ /* 0x0C */ NA_SE_PL_WALK_ICE - SFX_FLAG,
+ /* 0x0D */ NA_SE_PL_WALK_IRON - SFX_FLAG,
+ /* 0x0E */ NA_SE_PL_WALK_SNOW - SFX_FLAG
+};
+
+static u8 D_801B46C0[] = {
+ /* 0x00 */ 1,
+ /* 0x01 */ 1,
+ /* 0x02 */ 0,
+ /* 0x03 */ 1,
+ /* 0x04 */ 0,
+ /* 0x05 */ 0,
+ /* 0x06 */ 0,
+ /* 0x07 */ 0,
+ /* 0x08 */ 0,
+ /* 0x09 */ 0,
+ /* 0x0A */ 0,
+ /* 0x0B */ 0,
+ /* 0x0C */ 0,
+ /* 0x0D */ 0,
+ /* 0x0E */ 1
+};
+
+static s16 sSmallMemScenes[] = {
+ SCENE_F01,
+};
+
+typedef struct {
+ s16 sceneId;
+ u32 memSize;
+} BgCheckSceneMemEntry;
+
+static BgCheckSceneMemEntry sSceneMemList[] = {
+ { SCENE_00KEIKOKU, 0xC800 },
+};
+
+BgCheckSceneSubdivisionEntry sSceneSubdivisionList[] = {
+ { SCENE_00KEIKOKU, { 36, 1, 36 }, -1 },
+ { SCENE_30GYOSON, { 40, 1, 40 }, -1 },
+ { SCENE_31MISAKI, { 40, 1, 40 }, -1 },
+};
+
+BgSpecialSceneMaxObjects sCustomDynapolyMem[] = {
+ { SCENE_21MITURINMAE, 1000, 600, 512 },
+};
+
+char D_801ED950[80];
+char D_801ED9A0[80];
+Vec3f D_801ED9F0[3]; // polyVerts
+Vec3f D_801EDA18[3]; // polyVerts //not ok, needs to be inlined to match
+MtxF D_801EDA40;
+Vec3f D_801EDA80[3]; // polyVerts
+char D_801EDAA8[80];
+char D_801EDAF8[80];
+Vec3f D_801EDB48[3]; // polyVerts
+Vec3f D_801EDB70[3];
+Plane D_801EDB98;
+Sphere16 D_801EDBA8;
+TriNorm D_801EDBB0;
+
+void BgCheck_GetStaticLookupIndicesFromPos(CollisionContext* colCtx, Vec3f* pos, Vec3i* sector);
+f32 BgCheck_RaycastFloorDyna(DynaRaycast* dynaRaycast);
+s32 BgCheck_SphVsDynaWall(CollisionContext* colCtx, u16 xpFlags, f32* outX, f32* outZ, Vec3f* pos, f32 radius,
+ CollisionPoly** outPoly, s32* outBgId, Actor* actor);
+s32 BgCheck_CheckLineImpl(CollisionContext* colCtx, u16 xpFlags1, u16 xpFlags2, Vec3f* posA, Vec3f* posB,
+ Vec3f* posResult, CollisionPoly** outPoly, s32* outBgId, Actor* actor, f32 checkDist,
+ u32 bccFlags);
+s32 BgCheck_CheckDynaCeiling(CollisionContext* colCtx, u16 xpFlags, f32* outY, Vec3f* pos, f32 checkDist,
+ CollisionPoly** outPoly, s32* outBgId, Actor* actor);
+s32 BgCheck_CheckLineAgainstDyna(CollisionContext* colCtx, u16 xpFlags, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, f32* distSq, s32* outBgId, Actor* actor, f32 checkDist,
+ s32 bccFlags);
+s32 BgCheck_SphVsFirstDynaPoly(CollisionContext* colCtx, u16 xpFlags, CollisionPoly** outPoly, s32* outBgId,
+ Vec3f* center, f32 radius, Actor* actor, u16 bciFlags);
+void BgCheck_ResetPolyCheckTbl(SSNodeList* nodeList, s32 numPolys);
+s32 BgCheck_PosInStaticBoundingBox(CollisionContext* colCtx, Vec3f* pos);
+
+void SSNode_SetValue(SSNode* node, s16* polyIndex, u16 next) {
node->polyId = *polyIndex;
node->next = next;
}
-void BgCheck_PolygonLinkedListResetHead(u16* head) {
- *head = 0xFFFF;
+void SSList_SetNull(SSList* ssList) {
+ ssList->head = SS_NULL;
}
-void BgCheck_ScenePolygonListsNodeInsert(SSNodeList* list, u16* head, s16* polyIndex) {
+void SSNodeList_SetSSListHead(SSNodeList* list, SSList* ssList, s16* polyIndex) {
u16 index;
- index = BgCheck_ScenePolygonListsReserveNode(list);
- BgCheck_PolygonLinkedListNodeInit(&list->tbl[index], polyIndex, *head);
- *head = index;
+ index = SSNodeList_GetNextNodeIdx(list);
+ SSNode_SetValue(&list->tbl[index], polyIndex, ssList->head);
+ ssList->head = index;
}
-void BgCheck_PolygonLinkedListNodeInsert(DynaSSNodeList* list, u16* head, s16* polyIndex) {
+void DynaSSNodeList_SetSSListHead(DynaSSNodeList* list, SSList* ssList, s16* polyIndex) {
u16 index;
- index = BgCheck_AllocPolygonLinkedListNode(list);
- BgCheck_PolygonLinkedListNodeInit(&list->tbl[index], polyIndex, *head);
- *head = index;
+ index = DynaSSNodeList_GetNextNodeIdx(list);
+ SSNode_SetValue(&list->tbl[index], polyIndex, ssList->head);
+ ssList->head = index;
}
-void BgCheck_PolygonLinkedListInit(GlobalContext* globalCtx, DynaSSNodeList* list) {
+void DynaSSNodeList_Init(GlobalContext* globalCtx, DynaSSNodeList* list) {
list->tbl = NULL;
list->count = 0;
}
-void BgCheck_PolygonLinkedListAlloc(GlobalContext* globalCtx, DynaSSNodeList* list, u32 numNodes) {
- list->tbl = (SSNode*)THA_AllocEndAlign(&globalCtx->state.heap, numNodes << 2, 0xfffffffe);
- list->max = numNodes;
+void DynaSSNodeList_Alloc(GlobalContext* globalCtx, DynaSSNodeList* list, u32 numNodes) {
+ list->tbl = (SSNode*)THA_AllocEndAlign(&globalCtx->state.heap, numNodes * sizeof(SSNode), -2);
+ list->maxNodes = numNodes;
list->count = 0;
}
-void BgCheck_PolygonLinkedListReset(DynaSSNodeList* list) {
+void DynaSSNodeList_ResetCount(DynaSSNodeList* list) {
list->count = 0;
}
-u16 BgCheck_AllocPolygonLinkedListNode(DynaSSNodeList* list) {
- u16 index;
+u16 DynaSSNodeList_GetNextNodeIdx(DynaSSNodeList* list) {
+ u16 index = list->count++;
- index = list->count++;
- if (list->max <= index) {
- return 0xffff;
+ if (list->maxNodes <= index) {
+ return SS_NULL;
}
return index;
}
-void BgCheck_CreateVec3fFromVertex(Vec3s* vertex, Vec3f* vector) {
- vector->x = vertex->x;
- vector->y = vertex->y;
- vector->z = vertex->z;
+void BgCheck_Vec3sToVec3f(Vec3s* src, Vec3f* dest) {
+ dest->x = src->x;
+ dest->y = src->y;
+ dest->z = src->z;
+}
+
+void BgCheck_Vec3fToVec3s(Vec3s* dest, Vec3f* src) {
+ dest->x = src->x;
+ dest->y = src->y;
+ dest->z = src->z;
+}
+
+f32 func_800BFD84(CollisionPoly* poly, f32 arg1, f32 arg2) {
+ return (COLPOLY_GET_NORMAL(poly->normal.x * arg1 + poly->normal.z * arg2) + poly->dist) /
+ COLPOLY_GET_NORMAL(-poly->normal.y);
+}
+
+/**
+ * Unused
+ */
+s32 func_800BFDEC(CollisionPoly* polyA, CollisionPoly* polyB, u32* outVtxId0, u32* outVtxId1) {
+ s32 vtxIdA[3];
+ s32 vtxIdB[3];
+ s32 i;
+ s32 j;
+ s32 count;
+
+ *outVtxId0 = *outVtxId1 = 0;
+ for (i = 0; i < ARRAY_COUNT(vtxIdA); i++) {
+ vtxIdA[i] = COLPOLY_VTX_INDEX(polyA->vtxData[i]);
+ vtxIdB[i] = COLPOLY_VTX_INDEX(polyB->vtxData[i]);
+ }
+
+ count = 0;
+ for (i = 0; i < 2; i++) {
+ for (j = i + 1; j < 3; j++) {
+ if (vtxIdA[i] == vtxIdB[j]) {
+ if (count == 0) {
+ *outVtxId0 = vtxIdA[i];
+ } else if (count == 1) {
+ *outVtxId1 = vtxIdA[i];
+ }
+ count++;
+ }
+ }
+ }
+ return count;
+}
+
+s16 CollisionPoly_GetMinY(CollisionPoly* poly, Vec3s* vertices) {
+ s16 minY;
+ s32 a = COLPOLY_VTX_INDEX(poly->flags_vIA);
+ s32 b = COLPOLY_VTX_INDEX(poly->flags_vIB);
+ s32 c = poly->vIC;
+
+ minY = vertices[a].y;
+ if (vertices[b].y < minY) {
+ minY = vertices[b].y;
+ }
+ if (minY < vertices[c].y) {
+ return minY;
+ }
+ return vertices[c].y;
+}
+
+void CollisionPoly_GetNormalF(CollisionPoly* poly, f32* nx, f32* ny, f32* nz) {
+ *nx = COLPOLY_GET_NORMAL(poly->normal.x);
+ *ny = COLPOLY_GET_NORMAL(poly->normal.y);
+ *nz = COLPOLY_GET_NORMAL(poly->normal.z);
+}
+
+/**
+ * Compute transform matrix mapping +y (up) to the collision poly's normal
+ */
+void func_800C0094(CollisionPoly* poly, f32 tx, f32 ty, f32 tz, MtxF* dest) {
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ s32 pad;
+ f32 z_f14;
+ f32 phi_f14;
+ f32 phi_f12;
+ f32 inv_z_f14;
+
+ if (poly == NULL) {
+ return;
+ }
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
+
+ z_f14 = sqrtf(SQ(ny) + SQ(nz));
+ if (!IS_ZERO(z_f14)) {
+ inv_z_f14 = 1.0f / z_f14;
+ phi_f14 = ny * inv_z_f14;
+ phi_f12 = nz * inv_z_f14;
+ } else {
+ phi_f14 = 1.0f;
+ phi_f12 = 0.0f;
+ }
+ dest->xx = z_f14;
+ dest->xy = (-nx) * phi_f14;
+ dest->xz = (-nx) * phi_f12;
+ dest->yx = nx;
+ dest->yy = ny;
+ dest->yz = nz;
+ dest->zx = 0.0f;
+ dest->zy = -phi_f12;
+ dest->zz = phi_f14;
+ dest->wx = tx;
+ dest->wy = ty;
+ dest->wz = tz;
+ dest->xw = 0.0f;
+ dest->yw = 0.0f;
+ dest->zw = 0.0f;
+ dest->ww = 1.0f;
+}
+
+f32 CollisionPoly_GetPointDistanceFromPlane(CollisionPoly* poly, Vec3f* point) {
+ return COLPOLY_GET_NORMAL(poly->normal.x * point->x + poly->normal.y * point->y + poly->normal.z * point->z) +
+ poly->dist;
+}
+
+void CollisionPoly_GetVertices(CollisionPoly* poly, Vec3s* vtxList, Vec3f* dest) {
+ BgCheck_Vec3sToVec3f(&vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)], &dest[0]);
+ BgCheck_Vec3sToVec3f(&vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)], &dest[1]);
+ BgCheck_Vec3sToVec3f(&vtxList[poly->vIC], &dest[2]);
+}
+
+void CollisionPoly_GetVerticesByBgId(CollisionPoly* poly, s32 bgId, CollisionContext* colCtx, Vec3f* dest) {
+ Vec3s* vtxList;
+
+ if (poly == NULL || bgId > BG_ACTOR_MAX || dest == NULL) {
+ if (dest != NULL) {
+ // @bug: dest[2] x and y are not set to 0
+ dest[0].x = dest[0].y = dest[0].z = dest[1].x = dest[1].y = dest[1].z = dest[2].z = 0.0f;
+ }
+ } else {
+ if (bgId == BGCHECK_SCENE) {
+ vtxList = colCtx->colHeader->vtxList;
+ } else {
+ vtxList = colCtx->dyna.vtxList;
+ }
+ CollisionPoly_GetVertices(poly, vtxList, dest);
+ }
+}
+
+s32 CollisionPoly_CheckYIntersectApprox1(CollisionPoly* poly, Vec3s* vtxList, f32 x, f32 z, f32* yIntersect,
+ f32 checkDist) {
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ Vec3s* vA;
+ Vec3s* vB;
+ Vec3s* vC;
+
+ vA = &vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)];
+ Math_Vec3s_ToVec3f(&D_801ED9F0[0], vA);
+ vB = &vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)];
+ Math_Vec3s_ToVec3f(&D_801ED9F0[1], vB);
+ vC = &vtxList[poly->vIC];
+ Math_Vec3s_ToVec3f(&D_801ED9F0[2], vC);
+
+ nx = COLPOLY_GET_NORMAL(poly->normal.x);
+ ny = COLPOLY_GET_NORMAL(poly->normal.y);
+ nz = COLPOLY_GET_NORMAL(poly->normal.z);
+
+ return Math3D_TriChkPointParaYIntersectDist(&D_801ED9F0[0], &D_801ED9F0[1], &D_801ED9F0[2], nx, ny, nz, poly->dist,
+ z, x, yIntersect, checkDist);
+}
+
+/**
+ * Checks if point (`x`,`z`) is within `checkDist` of `poly`, computing `yIntersect` if true
+ * Determinant max 0.0f (checks if on or within poly)
+ */
+#ifdef NON_MATCHING
+s32 CollisionPoly_CheckYIntersect(CollisionPoly* poly, Vec3s* vtxList, f32 x, f32 z, f32* yIntersect, f32 checkDist) {
+ static Vec3f polyVerts[3]; // D_801EDA18
+ Vec3s* sVerts;
+ f32 nx;
+ f32 ny;
+ f32 nz;
+
+ sVerts = &vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)];
+ polyVerts[0].x = sVerts->x;
+ polyVerts[0].y = sVerts->y;
+ polyVerts[0].z = sVerts->z;
+ sVerts = &vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)];
+ polyVerts[1].x = sVerts->x;
+ polyVerts[1].y = sVerts->y;
+ polyVerts[1].z = sVerts->z;
+ sVerts = &vtxList[poly->vIC];
+ polyVerts[2].x = sVerts->x;
+ polyVerts[2].y = sVerts->y;
+ polyVerts[2].z = sVerts->z;
+
+ if (!func_8017A304(&polyVerts[0], &polyVerts[1], &polyVerts[2], z, x, checkDist)) {
+ return 0;
+ }
+ nx = COLPOLY_GET_NORMAL(poly->normal.x);
+ ny = COLPOLY_GET_NORMAL(poly->normal.y);
+ nz = COLPOLY_GET_NORMAL(poly->normal.z);
+ return Math3D_TriChkPointParaYIntersectInsideTri2(&polyVerts[0], &polyVerts[1], &polyVerts[2], nx, ny, nz,
+ poly->dist, z, x, yIntersect, checkDist);
+}
+#else
+s32 CollisionPoly_CheckYIntersect(CollisionPoly* poly, Vec3s* vtxList, f32 x, f32 z, f32* yIntersect, f32 checkDist);
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/CollisionPoly_CheckYIntersect.s")
+#endif
+
+s32 CollisionPoly_CheckYIntersectApprox2(CollisionPoly* poly, Vec3s* vtxList, f32 x, f32 z, f32* yIntersect) {
+ return CollisionPoly_CheckYIntersectApprox1(poly, vtxList, x, z, yIntersect, 1.0f);
+}
+
+s32 CollisionPoly_CheckXIntersectApprox(CollisionPoly* poly, Vec3s* vtxList, f32 y, f32 z, f32* xIntersect) {
+ f32 nx;
+ f32 ny;
+ f32 nz;
+
+ CollisionPoly_GetVertices(poly, vtxList, D_801EDA80);
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
+ return Math3D_TriChkPointParaXIntersect(&D_801EDA80[0], &D_801EDA80[1], &D_801EDA80[2], nx, ny, nz, poly->dist, y,
+ z, xIntersect);
+}
+
+s32 CollisionPoly_CheckZIntersectApprox(CollisionPoly* poly, Vec3s* vtxList, f32 x, f32 y, f32* zIntersect) {
+ f32 nx;
+ f32 ny;
+ f32 nz;
+
+ CollisionPoly_GetVertices(poly, vtxList, D_801EDB48);
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
+ return Math3D_TriChkPointParaZIntersect(&D_801EDB48[0], &D_801EDB48[1], &D_801EDB48[2], nx, ny, nz, poly->dist, x,
+ y, zIntersect);
+}
+
+#ifdef NON_MATCHING
+s32 CollisionPoly_LineVsPoly(BgLineVsPolyTest* a0) {
+ static Vec3f polyVerts[3]; // D_801EDB70
+ static Plane plane; // D_801EDB98
+ f32 planeDistA;
+ f32 planeDistB;
+ f32 planeDistDelta;
+
+ plane.originDist = a0->poly->dist;
+ planeDistA = COLPOLY_GET_NORMAL(a0->poly->normal.x * a0->posA->x + a0->poly->normal.y * a0->posA->y +
+ a0->poly->normal.z * a0->posA->z) +
+ plane.originDist;
+ planeDistB = COLPOLY_GET_NORMAL(a0->poly->normal.x * a0->posB->x + a0->poly->normal.y * a0->posB->y +
+ a0->poly->normal.z * a0->posB->z) +
+ plane.originDist;
+
+ planeDistDelta = planeDistA - planeDistB;
+ if ((planeDistA >= 0.0f && planeDistB >= 0.0f) || (planeDistA < 0.0f && planeDistB < 0.0f) ||
+ ((a0->checkOneFace != 0) && (planeDistA < 0.0f && planeDistB > 0.0f)) || IS_ZERO(planeDistDelta)) {
+ return false;
+ }
+
+ CollisionPoly_GetNormalF(a0->poly, &plane.normal.x, &plane.normal.y, &plane.normal.z);
+ CollisionPoly_GetVertices(a0->poly, a0->vtxList, polyVerts);
+ Math3D_Lerp(a0->posA, a0->posB, planeDistA / planeDistDelta, a0->planeIntersect);
+
+ if ((fabsf(plane.normal.x) > 0.5f &&
+ Math3D_TriChkPointParaXDist(&polyVerts[0], &polyVerts[1], &polyVerts[2], a0->planeIntersect->y,
+ a0->planeIntersect->z, 0.0f, a0->checkDist, plane.normal.x)) ||
+ (fabsf(plane.normal.y) > 0.5f &&
+ Math3D_TriChkPointParaYDist(&polyVerts[0], &polyVerts[1], &polyVerts[2], a0->planeIntersect->z,
+ a0->planeIntersect->x, 0.0f, a0->checkDist, plane.normal.y)) ||
+ (fabsf(plane.normal.z) > 0.5f &&
+ Math3D_TriChkLineSegParaZDist(&polyVerts[0], &polyVerts[1], &polyVerts[2], a0->planeIntersect->x,
+ a0->planeIntersect->y, 0.0f, a0->checkDist, plane.normal.z))) {
+ return true;
+ }
+ return false;
+}
+#else
+s32 CollisionPoly_LineVsPoly(BgLineVsPolyTest* a0);
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/CollisionPoly_LineVsPoly.s")
+#endif
+
+#ifdef NON_MATCHING
+// OK but .bss order issues
+s32 CollisionPoly_SphVsPoly(CollisionPoly* poly, Vec3s* vtxList, Vec3f* center, f32 radius) {
+ static Sphere16 sphere; // D_801EDBA8
+ static TriNorm tri; // D_801EDBB0
+ Vec3f intersect;
+
+ CollisionPoly_GetVertices(poly, vtxList, tri.vtx);
+ CollisionPoly_GetNormalF(poly, &tri.plane.normal.x, &tri.plane.normal.y, &tri.plane.normal.z);
+ tri.plane.originDist = poly->dist;
+ sphere.center.x = center->x;
+ sphere.center.y = center->y;
+ sphere.center.z = center->z;
+ sphere.radius = radius;
+ return Math3D_ColSphereTri(&sphere, &tri, &intersect);
+}
+#else
+s32 CollisionPoly_SphVsPoly(CollisionPoly* poly, Vec3s* vtxList, Vec3f* center, f32 radius);
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/CollisionPoly_SphVsPoly.s")
+#endif
+
+#ifdef NON_MATCHING
+/**
+ * Add poly to StaticLookup table
+ * Table is sorted by poly's smallest y vertex component
+ * `ssList` is the list to append a new poly to
+ * `polyList` is the CollisionPoly lookup list
+ * `vtxList` is the vertex lookup list
+ * `polyId` is the index of the poly in polyList to insert into the lookup table
+ */
+void StaticLookup_AddPolyToSSList(CollisionContext* colCtx, SSList* ssList, CollisionPoly* polyList, Vec3s* vtxList,
+ s16 polyId) {
+ SSNode* curNode;
+ SSNode* nextNode;
+ s32 polyYMin;
+ u16 newNodeId;
+ s16 curPolyId;
+
+ // if list is null
+ if (ssList->head == SS_NULL) {
+ SSNodeList_SetSSListHead(&colCtx->polyNodes, ssList, &polyId);
+ return;
+ }
+
+ polyYMin = CollisionPoly_GetMinY(&polyList[polyId], vtxList);
+
+ curNode = &colCtx->polyNodes.tbl[ssList->head];
+ curPolyId = curNode->polyId;
+
+ // if the poly being inserted has a lower y than the first poly
+ if (polyYMin < vtxList[COLPOLY_VTX_INDEX(polyList[curPolyId].flags_vIA)].y &&
+ polyYMin < vtxList[COLPOLY_VTX_INDEX(polyList[curPolyId].flags_vIB)].y &&
+ polyYMin < vtxList[polyList[curPolyId].vIC].y) {
+ SSNodeList_SetSSListHead(&colCtx->polyNodes, ssList, &polyId);
+ return;
+ }
+ while (true) {
+ // if at the end of the list
+ if (curNode->next == SS_NULL) {
+ newNodeId = SSNodeList_GetNextNodeIdx(&colCtx->polyNodes);
+ SSNode_SetValue(&colCtx->polyNodes.tbl[newNodeId], &polyId, SS_NULL);
+ curNode->next = newNodeId;
+ break;
+ }
+
+ nextNode = &colCtx->polyNodes.tbl[curNode->next];
+ curPolyId = nextNode->polyId;
+
+ // if the poly being inserted is lower than the next poly
+ if (polyYMin < vtxList[COLPOLY_VTX_INDEX(polyList[curPolyId].flags_vIA)].y &&
+ polyYMin < vtxList[COLPOLY_VTX_INDEX(polyList[curPolyId].flags_vIB)].y &&
+ polyYMin < vtxList[polyList[curPolyId].vIC].y) {
+ newNodeId = SSNodeList_GetNextNodeIdx(&colCtx->polyNodes);
+ SSNode_SetValue(&colCtx->polyNodes.tbl[newNodeId], &polyId, curNode->next);
+ curNode->next = newNodeId;
+ break;
+ }
+ curNode = nextNode;
+ }
+}
+#else
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/StaticLookup_AddPolyToSSList.s")
+#endif
+
+/**
+ * Add CollisionPoly to StaticLookup list
+ */
+void StaticLookup_AddPoly(StaticLookup* lookup, CollisionContext* colCtx, CollisionPoly* polyList, Vec3s* vtxList,
+ s16 index) {
+ if (polyList[index].normal.y > COLPOLY_SNORMAL(0.5f)) {
+ StaticLookup_AddPolyToSSList(colCtx, &lookup->floor, polyList, vtxList, index);
+ } else if (polyList[index].normal.y < COLPOLY_SNORMAL(-0.8f)) {
+ StaticLookup_AddPolyToSSList(colCtx, &lookup->ceiling, polyList, vtxList, index);
+ } else {
+ StaticLookup_AddPolyToSSList(colCtx, &lookup->wall, polyList, vtxList, index);
+ }
+}
+
+/**
+ * Locates the closest static poly directly underneath `pos`, starting at list `ssList`
+ * returns yIntersect of the closest poly, or `yIntersectMin`
+ * stores the pointer of the closest poly to `outPoly`
+ * if (flags & 1), ignore polys with a normal.y < 0 (from vertical walls to ceilings)
+ */
+f32 BgCheck_RaycastFloorStaticList(CollisionContext* colCtx, u16 xpFlags, SSList* ssList, CollisionPoly** outPoly,
+ Vec3f* pos, f32 yIntersectMin, f32 checkDist, s32 flags, Actor* actor, s32 arg9) {
+ SSNode* curNode;
+ s32 polyId;
+ f32 result;
+ f32 yIntersect;
+ CollisionPoly* colPoly;
+ s32 pad;
+
+ result = yIntersectMin;
+ if (ssList->head == SS_NULL) {
+ return result;
+ }
+
+ curNode = &colCtx->polyNodes.tbl[ssList->head];
+
+ while (true) {
+ polyId = curNode->polyId;
+ colPoly = &colCtx->colHeader->polyList[polyId];
+
+ if (((flags & 1) && (colPoly->normal.y < 0)) ||
+ ((arg9 & 0x20) && ((colCtx->colHeader->surfaceTypeList[colPoly->type].data[0] >> 0x1E) & 1)) ||
+ COLPOLY_VIA_FLAG_TEST(colPoly->flags_vIA, xpFlags) ||
+ (COLPOLY_VIA_FLAG_TEST(colPoly->flags_vIB, 4) && ((actor != NULL && actor->category != ACTORCAT_PLAYER) ||
+ (actor == NULL && xpFlags != COLPOLY_IGNORE_CAMERA)))) {
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+
+ if (pos->y < colCtx->colHeader->vtxList[COLPOLY_VTX_INDEX(colPoly->flags_vIA)].y &&
+ pos->y < colCtx->colHeader->vtxList[COLPOLY_VTX_INDEX(colPoly->flags_vIB)].y &&
+ pos->y < colCtx->colHeader->vtxList[colPoly->vIC].y) {
+ break;
+ }
+
+ if (CollisionPoly_CheckYIntersect(colPoly, colCtx->colHeader->vtxList, pos->x, pos->z, &yIntersect,
+ checkDist)) {
+ // if poly is closer to pos without going over
+ if (yIntersect < pos->y && result < yIntersect) {
+ result = yIntersect;
+ *outPoly = colPoly;
+ }
+ }
+
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ }
+ return result;
+}
+
+/**
+ * Locates the closest static poly directly underneath `pos` within `lookup`.
+ * returns yIntersect of the closest poly, or `yIntersectMin`
+ * stores the pointer of the closest poly to `outPoly`
+ */
+f32 BgCheck_RaycastFloorStatic(StaticLookup* lookup, CollisionContext* colCtx, u16 xpFlags, CollisionPoly** poly,
+ Vec3f* pos, u32 arg5, f32 checkDist, f32 yIntersectMin, Actor* actor) {
+ s32 flag; // skip polys with normal.y < 0
+ f32 yIntersect = yIntersectMin;
+
+ if (arg5 & 4) {
+ yIntersect = BgCheck_RaycastFloorStaticList(colCtx, xpFlags, &lookup->floor, poly, pos, yIntersect, checkDist,
+ 0, actor, arg5);
+ }
+
+ if ((arg5 & 2) || (arg5 & 8)) {
+ flag = 0;
+ if (arg5 & 0x10) {
+ flag = 1;
+ }
+ yIntersect = BgCheck_RaycastFloorStaticList(colCtx, xpFlags, &lookup->wall, poly, pos, yIntersect, checkDist,
+ flag, actor, arg5);
+ }
+
+ if (arg5 & 1) {
+ flag = 0;
+ if (arg5 & 0x10) {
+ flag = 1;
+ }
+ yIntersect = BgCheck_RaycastFloorStaticList(colCtx, xpFlags, &lookup->ceiling, poly, pos, yIntersect, checkDist,
+ flag, actor, arg5);
+ }
+
+ return yIntersect;
+}
+
+/**
+ * Compute wall displacement on `posX` and `posZ`
+ * sets `wallPolyPtr` to `poly` if `wallPolyPtr` is NULL
+ * returns true if `wallPolyPtr` was changed
+ * `invXZlength` is 1 / sqrt( sq(poly.normal.x) + sq(poly.normal.z) )
+ */
+s32 BgCheck_ComputeWallDisplacement(CollisionContext* colCtx, CollisionPoly* poly, f32* posX, f32* posZ, f32 nx, f32 ny,
+ f32 nz, f32 invXZlength, f32 planeDist, f32 radius, CollisionPoly** wallPolyPtr) {
+ f32 displacement = (radius - planeDist) * invXZlength;
+
+ *posX += displacement * nx;
+ *posZ += displacement * nz;
+
+ if (*wallPolyPtr == NULL) {
+ *wallPolyPtr = poly;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Performs collision detection on static poly walls within `lookup` on sphere `pos`, `radius`
+ * returns true if a collision was detected
+ * `outX` `outZ` return the displaced x,z coordinates,
+ * `outPoly` returns the pointer to the nearest poly collided with, or NULL
+ */
+s32 BgCheck_SphVsStaticWall(StaticLookup* lookup, CollisionContext* colCtx, u16 xpFlags, f32* outX, f32* outZ,
+ Vec3f* pos, f32 radius, CollisionPoly** outPoly, Actor* actor) {
+ Vec3f resultPos;
+ f32 zTemp;
+ f32 xTemp;
+ f32 planeDist;
+ f32 intersect;
+ s32 result;
+ CollisionPoly* curPoly;
+ CollisionPoly* polyList;
+ SSNode* curNode;
+ f32 invNormalXZ;
+ Vec3s* vtxA;
+ Vec3s* vtxB;
+ Vec3s* vtxC;
+ s32 polyId;
+ f32 normalXZ;
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ Vec3s* vtxList;
+ u16 pad;
+ f32 temp_f16;
+ f32 zMin;
+ f32 zMax;
+ f32 xMin;
+ f32 xMax;
+
+ result = false;
+ if (lookup->wall.head == SS_NULL) {
+ return result;
+ }
+ resultPos = *pos;
+
+ polyList = colCtx->colHeader->polyList;
+ vtxList = colCtx->colHeader->vtxList;
+ curNode = &colCtx->polyNodes.tbl[lookup->wall.head];
+
+ while (true) {
+ polyId = curNode->polyId;
+ curPoly = &polyList[polyId];
+ vtxA = &vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIA)];
+ vtxB = &vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIB)];
+ vtxC = &vtxList[curPoly->vIC];
+
+ if (pos->y < vtxA->y && pos->y < vtxB->y && pos->y < vtxC->y) {
+ break;
+ }
+
+ nx = COLPOLY_GET_NORMAL(curPoly->normal.x);
+ ny = COLPOLY_GET_NORMAL(curPoly->normal.y);
+ nz = COLPOLY_GET_NORMAL(curPoly->normal.z);
+ normalXZ = sqrtf(SQ(nx) + SQ(nz));
+ planeDist = Math3D_DistPlaneToPos(nx, ny, nz, curPoly->dist, &resultPos);
+ if (radius < fabsf(planeDist) || COLPOLY_VIA_FLAG_TEST(curPoly->flags_vIA, xpFlags) ||
+ (COLPOLY_VIA_FLAG_TEST(curPoly->flags_vIB, 4) && ((actor != NULL && actor->category != ACTORCAT_PLAYER) ||
+ (actor == NULL && xpFlags != COLPOLY_IGNORE_CAMERA)))) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+
+ invNormalXZ = 1.0f / normalXZ;
+ temp_f16 = fabsf(nz) * invNormalXZ;
+ if (temp_f16 < 0.4f) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+
+ // compute curPoly zMin/zMax
+ zTemp = vtxA->z;
+ zMax = zMin = zTemp;
+ zTemp = vtxB->z;
+
+ if (zTemp < zMin) {
+ zMin = zTemp;
+ } else if (zMax < zTemp) {
+ zMax = zTemp;
+ }
+ zTemp = vtxC->z;
+ if (zTemp < zMin) {
+ zMin = zTemp;
+ } else if (zTemp > zMax) {
+ zMax = zTemp;
+ }
+
+ zMin -= radius;
+ zMax += radius;
+
+ if (resultPos.z < zMin || resultPos.z > zMax) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ if (CollisionPoly_CheckZIntersectApprox(curPoly, vtxList, resultPos.x, pos->y, &intersect)) {
+ f32 test = intersect - resultPos.z;
+
+ if (fabsf(test) <= radius / temp_f16) {
+ if (test * nz <= 4.0f) {
+ if (BgCheck_ComputeWallDisplacement(colCtx, curPoly, &resultPos.x, &resultPos.z, nx, ny, nz,
+ invNormalXZ, planeDist, radius, outPoly)) {
+ result = true;
+ }
+ }
+ }
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ }
+ }
+
+ curNode = &colCtx->polyNodes.tbl[lookup->wall.head];
+
+ while (true) {
+ polyId = curNode->polyId;
+ curPoly = &polyList[polyId];
+ vtxA = &vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIA)];
+ vtxB = &vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIB)];
+ vtxC = &vtxList[curPoly->vIC];
+
+ if (pos->y < vtxA->y && pos->y < vtxB->y && pos->y < vtxC->y) {
+ break;
+ }
+
+ nx = COLPOLY_GET_NORMAL(curPoly->normal.x);
+ ny = COLPOLY_GET_NORMAL(curPoly->normal.y);
+ nz = COLPOLY_GET_NORMAL(curPoly->normal.z);
+ normalXZ = sqrtf(SQ(nx) + SQ(nz));
+ planeDist = Math3D_DistPlaneToPos(nx, ny, nz, curPoly->dist, &resultPos);
+ if (radius < fabsf(planeDist) || COLPOLY_VIA_FLAG_TEST(curPoly->flags_vIA, xpFlags) ||
+ (COLPOLY_VIA_FLAG_TEST(curPoly->flags_vIB, 4) && ((actor != NULL && actor->category != ACTORCAT_PLAYER) ||
+ (actor == NULL && xpFlags != COLPOLY_IGNORE_CAMERA)))) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+
+ invNormalXZ = 1.0f / normalXZ;
+ temp_f16 = fabsf(nx) * invNormalXZ;
+ if (temp_f16 < 0.4f) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+
+ // compute curPoly xMin/xMax
+ xTemp = vtxA->x;
+ xMax = xMin = xTemp;
+ xTemp = vtxB->x;
+
+ if (xTemp < xMin) {
+ xMin = xTemp;
+ } else if (xMax < xTemp) {
+ xMax = xTemp;
+ }
+ xTemp = vtxC->x;
+ if (xTemp < xMin) {
+ xMin = xTemp;
+ } else if (xMax < xTemp) {
+ xMax = xTemp;
+ }
+
+ xMin -= radius;
+ xMax += radius;
+
+ if (resultPos.x < xMin || xMax < resultPos.x) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ if (CollisionPoly_CheckXIntersectApprox(curPoly, vtxList, pos->y, resultPos.z, &intersect)) {
+ f32 test = intersect - resultPos.x;
+
+ if (fabsf(test) <= radius / temp_f16) {
+ if (test * nx <= 4.0f) {
+ if (BgCheck_ComputeWallDisplacement(colCtx, curPoly, &resultPos.x, &resultPos.z, nx, ny, nz,
+ invNormalXZ, planeDist, radius, outPoly)) {
+ result = true;
+ }
+ }
+ }
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+
+ *outX = resultPos.x;
+ *outZ = resultPos.z;
+ return result;
+}
+
+/**
+ * Tests for collision with a static poly ceiling
+ * returns true if a collision occurs, else false
+ * `outPoly` returns the poly collided with
+ * `outY` returns the y coordinate needed to not collide with `outPoly`
+ */
+#ifdef NON_MATCHING
+s32 BgCheck_CheckStaticCeiling(StaticLookup* lookup, u16 xpFlags, CollisionContext* colCtx, f32* outY, Vec3f* pos,
+ f32 checkHeight, CollisionPoly** outPoly, Actor* actor) {
+ s32 result = false;
+ // u16 nextId;
+ CollisionPoly* curPoly;
+ CollisionPoly* polyList;
+ f32 ceilingY;
+ Vec3s* vtxList;
+ SSNode* curNode;
+ s32 curPolyId;
+
+ if (lookup->ceiling.head == SS_NULL) {
+ return result;
+ }
+ curNode = &colCtx->polyNodes.tbl[lookup->ceiling.head];
+ polyList = colCtx->colHeader->polyList;
+ vtxList = colCtx->colHeader->vtxList;
+
+ *outY = pos->y;
+
+ while (true) {
+ curPolyId = curNode->polyId;
+ curPoly = &polyList[curPolyId];
+ if (COLPOLY_VIA_FLAG_TEST(colCtx->colHeader->polyList[curPolyId].flags_vIA, xpFlags) ||
+ (COLPOLY_VIA_FLAG_TEST(colCtx->colHeader->polyList[curPolyId].flags_vIB, 4) &&
+ ((actor != NULL && actor->category != ACTORCAT_PLAYER) ||
+ (actor == NULL && xpFlags != COLPOLY_IGNORE_CAMERA)))) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+
+ if (CollisionPoly_CheckYIntersectApprox2(curPoly, vtxList, pos->x, pos->z, &ceilingY)) {
+ f32 intersectDist = ceilingY - *outY;
+ f32 ny = COLPOLY_GET_NORMAL(curPoly->normal.y);
+
+ if (intersectDist > 0 && intersectDist < checkHeight && intersectDist * ny <= 0) {
+ *outY = ceilingY - checkHeight;
+ *outPoly = curPoly;
+ result = true;
+ }
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ return result;
+}
+#else
+s32 BgCheck_CheckStaticCeiling(StaticLookup* lookup, u16 xpFlags, CollisionContext* colCtx, f32* outY, Vec3f* pos,
+ f32 checkHeight, CollisionPoly** outPoly, Actor* actor);
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_CheckStaticCeiling.s")
+#endif
+
+/**
+ * Tests if line `posA` to `posB` intersects with a static poly in list `ssList`. Uses polyCheckTbl
+ * returns true if such a poly exists, else false
+ * `outPoly` returns the pointer of the poly intersected
+ * `posB` and `outPos` returns the point of intersection with `outPoly`
+ * `outDistSq` returns the squared distance from `posA` to the point of intersect
+ */
+#ifdef NON_MATCHING
+s32 BgCheck_CheckLineAgainstSSList(StaticLineTest* arg0) {
+ CollisionContext* colCtx;
+ s32 result;
+ Vec3f polyIntersect; // sp7C
+ SSNode* curNode;
+ u8* checkedPoly;
+ f32 minY;
+ f32 distSq;
+ BgLineVsPolyTest test; // sp50
+ s16 polyId;
+ CollisionPoly* polyList;
+
+ result = false;
+ if (arg0->ssList->head == SS_NULL) {
+ return result;
+ }
+ colCtx = arg0->colCtx;
+ curNode = &colCtx->polyNodes.tbl[arg0->ssList->head];
+ polyList = colCtx->colHeader->polyList;
+ test.vtxList = colCtx->colHeader->vtxList;
+ test.posA = arg0->posA;
+ test.posB = arg0->posB;
+ test.planeIntersect = &polyIntersect; // reorder maybe
+ test.checkOneFace = (arg0->bccFlags & BGCHECK_CHECK_ONE_FACE) != 0;
+ test.checkDist = arg0->checkDist;
+
+ while (true) {
+ polyId = curNode->polyId;
+ test.poly = &polyList[polyId];
+ checkedPoly = &arg0->colCtx->polyNodes.polyCheckTbl[polyId];
+
+ if (*checkedPoly == true ||
+ (arg0->xpFlags2 != 0 && !COLPOLY_VIA_FLAG_TEST(test.poly->flags_vIA, arg0->xpFlags2)) ||
+ COLPOLY_VIA_FLAG_TEST(test.poly->flags_vIA, arg0->xpFlags1) ||
+ (COLPOLY_VIA_FLAG_TEST(test.poly->flags_vIB, 4) &&
+ ((arg0->actor != NULL && arg0->actor->category != ACTORCAT_PLAYER) ||
+ (arg0->actor == NULL && arg0->xpFlags1 != COLPOLY_IGNORE_CAMERA)))) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ *checkedPoly = true;
+ minY = CollisionPoly_GetMinY(test.poly, test.vtxList);
+ if (test.posA->y < minY && test.posB->y < minY) {
+ break;
+ }
+ if (CollisionPoly_LineVsPoly(&test)) {
+ distSq = Math3D_Vec3fDistSq(test.posA, test.planeIntersect);
+ if (distSq < arg0->outDistSq) {
+ arg0->outDistSq = distSq;
+ *arg0->outPos = *test.planeIntersect;
+ *arg0->posB = *test.planeIntersect;
+ *arg0->outPoly = test.poly;
+ result = true;
+ }
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &arg0->colCtx->polyNodes.tbl[curNode->next];
+ }
+ return result;
+}
+#else
+s32 BgCheck_CheckLineAgainstSSList(StaticLineTest* arg0);
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_CheckLineAgainstSSList.s")
+#endif
+
+/**
+ * Tests if line `posA` to `posB` intersects with a static poly in `lookup`. Uses polyCheckTbl
+ * returns true if such a poly exists, else false
+ * `outPoly` returns the pointer of the poly intersected
+ * `posB` and `outPos` returns the point of intersection with `outPoly`
+ * `outDistSq` returns the squared distance from `posA` to the point of intersect
+ */
+s32 BgCheck_CheckLineInSubdivision(StaticLineTest* arg0) {
+ s32 result = false;
+
+ if ((arg0->bccFlags & BGCHECK_CHECK_FLOOR) && arg0->lookup->floor.head != SS_NULL) {
+ arg0->ssList = &arg0->lookup->floor;
+ if (BgCheck_CheckLineAgainstSSList(arg0)) {
+ result = true;
+ }
+ }
+
+ if ((arg0->bccFlags & BGCHECK_CHECK_WALL) && arg0->lookup->wall.head != SS_NULL) {
+ arg0->ssList = &arg0->lookup->wall;
+ if (BgCheck_CheckLineAgainstSSList(arg0)) {
+ result = true;
+ }
+ }
+
+ if ((arg0->bccFlags & BGCHECK_CHECK_CEILING) && arg0->lookup->ceiling.head != SS_NULL) {
+ arg0->ssList = &arg0->lookup->ceiling;
+ if (BgCheck_CheckLineAgainstSSList(arg0)) {
+ result = true;
+ }
+ }
+ return result;
+}
+
+/**
+ * Get first static poly intersecting sphere `center` `radius` from list `node`
+ * returns true if any poly intersects the sphere, else returns false
+ * `outPoly` returns the pointer of the first poly found that intersects
+ */
+#ifdef NON_MATCHING
+s32 BgCheck_SphVsFirstStaticPolyList(SSNode* node, u16 xpFlags, CollisionContext* colCtx, Vec3f* center, f32 radius,
+ CollisionPoly** outPoly, Actor* actor) {
+ Vec3s* vtxList;
+ CollisionPoly* polyList;
+ CollisionPoly* curPoly;
+ u16 nextId;
+ s16 curPolyId;
+ s32 pad;
+
+ polyList = colCtx->colHeader->polyList;
+ vtxList = colCtx->colHeader->vtxList;
+
+ while (true) {
+ curPolyId = node->polyId;
+ curPoly = &polyList[curPolyId];
+ if (COLPOLY_VIA_FLAG_TEST(colCtx->colHeader->polyList[curPolyId].flags_vIA, xpFlags) ||
+ (COLPOLY_VIA_FLAG_TEST(colCtx->colHeader->polyList[curPolyId].flags_vIB, 4) &&
+ ((actor != NULL && actor->category != ACTORCAT_PLAYER) ||
+ (actor == NULL && xpFlags != COLPOLY_IGNORE_CAMERA)))) {
+ if (node->next != SS_NULL) {
+ node = &colCtx->polyNodes.tbl[node->next];
+ continue;
+ }
+ break;
+ }
+
+ if (center->y + radius < vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIA)].y &&
+ center->y + radius < vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIB)].y &&
+ center->y + radius < vtxList[curPoly->vIC].y) {
+ break;
+ }
+
+ if (CollisionPoly_SphVsPoly(curPoly, vtxList, center, radius)) {
+ *outPoly = curPoly;
+ return true;
+ }
+ if (node->next != SS_NULL) {
+ node = &colCtx->polyNodes.tbl[node->next];
+ continue;
+ }
+ break;
+ }
+ return false;
+}
+#else
+s32 BgCheck_SphVsFirstStaticPolyList(SSNode* node, u16 xpFlags, CollisionContext* colCtx, Vec3f* center, f32 radius,
+ CollisionPoly** outPoly, Actor* actor);
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_SphVsFirstStaticPolyList.s")
+#endif
+
+/**
+ * Get first static poly intersecting sphere `center` `radius` within `lookup`
+ * returns true if any poly intersects the sphere, else false
+ * `outPoly` returns the first poly found that intersects
+ */
+s32 BgCheck_SphVsFirstStaticPoly(StaticLookup* lookup, u16 xpFlags, CollisionContext* colCtx, Vec3f* center, f32 radius,
+ CollisionPoly** outPoly, u16 bciFlags, Actor* actor) {
+ if (lookup->floor.head != SS_NULL && !(bciFlags & BGCHECK_IGNORE_FLOOR) &&
+ BgCheck_SphVsFirstStaticPolyList(&colCtx->polyNodes.tbl[lookup->floor.head], xpFlags, colCtx, center, radius,
+ outPoly, actor)) {
+ return true;
+ }
+
+ if (lookup->wall.head != SS_NULL && !(bciFlags & BGCHECK_IGNORE_WALL) &&
+ BgCheck_SphVsFirstStaticPolyList(&colCtx->polyNodes.tbl[lookup->wall.head], xpFlags, colCtx, center, radius,
+ outPoly, actor)) {
+ return true;
+ }
+
+ if (lookup->ceiling.head != SS_NULL && !(bciFlags & BGCHECK_IGNORE_CEILING) &&
+ BgCheck_SphVsFirstStaticPolyList(&colCtx->polyNodes.tbl[lookup->ceiling.head], xpFlags, colCtx, center, radius,
+ outPoly, actor)) {
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Get StaticLookup from `pos`
+ * Does not return NULL
+ */
+StaticLookup* BgCheck_GetNearestStaticLookup(CollisionContext* colCtx, StaticLookup* lookupTbl, Vec3f* pos) {
+ Vec3i sector;
+ s32 subdivAmountX;
+
+ BgCheck_GetStaticLookupIndicesFromPos(colCtx, pos, &sector);
+ subdivAmountX = colCtx->subdivAmount.x;
+ return (sector.z * subdivAmountX) * colCtx->subdivAmount.y + lookupTbl + sector.x + sector.y * subdivAmountX;
+}
+
+/**
+ * Get StaticLookup from `pos`
+ * Returns NULL if just outside the mesh bounding box
+ */
+StaticLookup* BgCheck_GetStaticLookup(CollisionContext* colCtx, StaticLookup* lookupTbl, Vec3f* pos) {
+ Vec3i sector;
+ s32 subdivAmountX;
+
+ if (!BgCheck_PosInStaticBoundingBox(colCtx, pos)) {
+ return NULL;
+ }
+ BgCheck_GetStaticLookupIndicesFromPos(colCtx, pos, &sector);
+ subdivAmountX = colCtx->subdivAmount.x;
+ return (sector.z * subdivAmountX) * colCtx->subdivAmount.y + lookupTbl + sector.x + sector.y * subdivAmountX;
+}
+
+/**
+ * Get StaticLookup subdivision indices from `pos`
+ * `sector` returns the subdivision x,y,z indices containing or is nearest to `pos`
+ */
+void BgCheck_GetStaticLookupIndicesFromPos(CollisionContext* colCtx, Vec3f* pos, Vec3i* sector) {
+ sector->x = (pos->x - colCtx->minBounds.x) * colCtx->subdivLengthInv.x;
+ sector->y = (pos->y - colCtx->minBounds.y) * colCtx->subdivLengthInv.y;
+ sector->z = (pos->z - colCtx->minBounds.z) * colCtx->subdivLengthInv.z;
+
+ if (sector->x < 0) {
+ sector->x = 0;
+ } else if (sector->x >= colCtx->subdivAmount.x) {
+ sector->x = colCtx->subdivAmount.x - 1;
+ }
+
+ if (sector->y < 0) {
+ sector->y = 0;
+ } else if (sector->y >= colCtx->subdivAmount.y) {
+ sector->y = colCtx->subdivAmount.y - 1;
+ }
+
+ if (sector->z < 0) {
+ sector->z = 0;
+ } else if (sector->z >= colCtx->subdivAmount.z) {
+ sector->z = colCtx->subdivAmount.z - 1;
+ }
+}
+
+/**
+ * Get negative bias subdivision indices
+ * decrements indices if `pos` is within BGCHECK_SUBDIV_OVERLAP units of the negative subdivision boundary
+ * `sx`, `sy`, `sz` returns the subdivision x, y, z indices
+ */
+void BgCheck_GetSubdivisionMinBounds(CollisionContext* colCtx, Vec3f* pos, s32* sx, s32* sy, s32* sz) {
+ f32 dx = pos->x - colCtx->minBounds.x;
+ f32 dy = pos->y - colCtx->minBounds.y;
+ f32 dz = pos->z - colCtx->minBounds.z;
+
+ *sx = dx * colCtx->subdivLengthInv.x;
+ *sy = dy * colCtx->subdivLengthInv.y;
+ *sz = dz * colCtx->subdivLengthInv.z;
+
+ if (((s32)dx % (s32)colCtx->subdivLength.x < BGCHECK_SUBDIV_OVERLAP) && (*sx > 0)) {
+ *sx -= 1;
+ }
+
+ if (((s32)dy % (s32)colCtx->subdivLength.y < BGCHECK_SUBDIV_OVERLAP) && (*sy > 0)) {
+ *sy -= 1;
+ }
+
+ if (((s32)dz % (s32)colCtx->subdivLength.z < BGCHECK_SUBDIV_OVERLAP) && (*sz > 0)) {
+ *sz -= 1;
+ }
}
-void BgCheck_CreateVertexFromVec3f(Vec3s* vertex, Vec3f* vector) {
- vertex->x = vector->x;
- vertex->y = vector->y;
- vertex->z = vector->z;
+/**
+ * Get positive bias subdivision indices
+ * increments indicies if `pos` is within BGCHECK_SUBDIV_OVERLAP units of the postive subdivision boundary
+ * `sx`, `sy`, `sz` returns the subdivision x, y, z indices
+ */
+void BgCheck_GetSubdivisionMaxBounds(CollisionContext* colCtx, Vec3f* pos, s32* sx, s32* sy, s32* sz) {
+ f32 dx = pos->x - colCtx->minBounds.x;
+ f32 dy = pos->y - colCtx->minBounds.y;
+ f32 dz = pos->z - colCtx->minBounds.z;
+
+ *sx = dx * colCtx->subdivLengthInv.x;
+ *sy = dy * colCtx->subdivLengthInv.y;
+ *sz = dz * colCtx->subdivLengthInv.z;
+
+ if (((s32)colCtx->subdivLength.x - BGCHECK_SUBDIV_OVERLAP < (s32)dx % (s32)colCtx->subdivLength.x) &&
+ (*sx < colCtx->subdivAmount.x - 1)) {
+ *sx += 1;
+ }
+
+ if (((s32)colCtx->subdivLength.y - BGCHECK_SUBDIV_OVERLAP < (s32)dy % (s32)colCtx->subdivLength.y) &&
+ (*sy < colCtx->subdivAmount.y - 1)) {
+ *sy += 1;
+ }
+
+ if (((s32)colCtx->subdivLength.z - BGCHECK_SUBDIV_OVERLAP < (s32)dz % (s32)colCtx->subdivLength.z) &&
+ (*sz < colCtx->subdivAmount.z - 1)) {
+ *sz += 1;
+ }
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800BFD84.s")
+/**
+ * Calculate the subdivision index bounding box for CollisionPoly `polyId`
+ * `subdivMinX`, `subdivMinY`, `subdivMinZ` returns the minimum subdivision x, y, z indices
+ * `subdivMaxX`, `subdivMaxY`, `subdivMaxZ` returns the maximum subdivision x, y, z indices
+ */
+void BgCheck_GetPolySubdivisionBounds(CollisionContext* colCtx, Vec3s* vtxList, CollisionPoly* polyList,
+ s32* subdivMinX, s32* subdivMinY, s32* subdivMinZ, s32* subdivMaxX,
+ s32* subdivMaxY, s32* subdivMaxZ, s16 polyId) {
+ u16* vtxDataTemp;
+ Vec3f minVtx;
+ Vec3f maxVtx;
+
+ f32 x;
+ f32 y;
+ f32 z;
+
+ Vec3s* vtx;
+ s16 vtxId = COLPOLY_VTX_INDEX(polyList[polyId].vtxData[0]);
+
+ Math_Vec3s_ToVec3f(&maxVtx, &vtxList[vtxId]);
+ Math_Vec3f_Copy(&minVtx, &maxVtx);
+
+ for (vtxDataTemp = polyList[polyId].vtxData + 1; vtxDataTemp < polyList[polyId].vtxData + 3; vtxDataTemp++) {
+ vtxId = COLPOLY_VTX_INDEX(*vtxDataTemp);
+ vtx = &vtxList[vtxId];
+ x = vtx->x;
+ y = vtx->y;
+ z = vtx->z;
+
+ if (minVtx.x > x) {
+ minVtx.x = x;
+ } else if (maxVtx.x < x) {
+ maxVtx.x = x;
+ }
+
+ if (minVtx.y > y) {
+ minVtx.y = y;
+ } else if (maxVtx.y < y) {
+ maxVtx.y = y;
+ }
+
+ if (minVtx.z > z) {
+ minVtx.z = z;
+ } else if (maxVtx.z < z) {
+ maxVtx.z = z;
+ }
+ }
+ BgCheck_GetSubdivisionMinBounds(colCtx, &minVtx, subdivMinX, subdivMinY, subdivMinZ);
+ BgCheck_GetSubdivisionMaxBounds(colCtx, &maxVtx, subdivMaxX, subdivMaxY, subdivMaxZ);
+}
+
+/**
+ * Test if poly `polyList`[`polyId`] intersects cube `min` `max`
+ * returns true if the poly intersects the cube, else false
+ */
+s32 BgCheck_PolyIntersectsSubdivision(Vec3f* min, Vec3f* max, CollisionPoly* polyList, Vec3s* vtxList, s16 polyId) {
+ f32 intersect;
+ Vec3f va2;
+ Vec3f vb2;
+ Vec3f vc2;
+ CollisionPoly* poly;
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ f32 dist;
+ Vec3f va;
+ Vec3f vb;
+ Vec3f vc;
+ s32 flags[3];
+
+ flags[0] = flags[1] = 0;
+ poly = &polyList[polyId];
+
+ BgCheck_Vec3sToVec3f(&vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)], &va);
+ flags[0] = Math3D_PointRelativeToCubeFaces(&va, min, max);
+ if (flags[0] == 0) {
+ return true;
+ }
+
+ BgCheck_Vec3sToVec3f(&vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)], &vb);
+ flags[1] = Math3D_PointRelativeToCubeFaces(&vb, min, max);
+ if (flags[1] == 0) {
+ return true;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800BFDEC.s")
+ BgCheck_Vec3sToVec3f(&vtxList[poly->vIC], &vc);
+ flags[2] = Math3D_PointRelativeToCubeFaces(&vc, min, max);
+ if (flags[2] == 0) {
+ return true;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_PolygonGetMinY.s")
+ if (flags[0] & flags[1] & flags[2]) {
+ return false;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_PolygonGetNormal.s")
+ flags[0] |= Math3D_PointRelativeToCubeEdges(&va, min, max) << 8;
+ flags[1] |= Math3D_PointRelativeToCubeEdges(&vb, min, max) << 8;
+ flags[2] |= Math3D_PointRelativeToCubeEdges(&vc, min, max) << 8;
+ if (flags[0] & flags[1] & flags[2]) {
+ return false;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C0094.s")
+ flags[0] |= Math3D_PointRelativeToCubeVertices(&va, min, max) << 0x18;
+ flags[1] |= Math3D_PointRelativeToCubeVertices(&vb, min, max) << 0x18;
+ flags[2] |= Math3D_PointRelativeToCubeVertices(&vc, min, max) << 0x18;
+ if (flags[0] & flags[1] & flags[2]) {
+ return false;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C01B8.s")
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
+ dist = poly->dist;
+
+ if (Math3D_TriChkLineSegParaYIntersect(&va, &vb, &vc, nx, ny, nz, dist, min->z, min->x, &intersect, min->y,
+ max->y) ||
+ Math3D_TriChkLineSegParaYIntersect(&va, &vb, &vc, nx, ny, nz, dist, max->z, min->x, &intersect, min->y,
+ max->y) ||
+ Math3D_TriChkLineSegParaYIntersect(&va, &vb, &vc, nx, ny, nz, dist, min->z, max->x, &intersect, min->y,
+ max->y) ||
+ Math3D_TriChkLineSegParaYIntersect(&va, &vb, &vc, nx, ny, nz, dist, max->z, max->x, &intersect, min->y,
+ max->y)) {
+ return true;
+ }
+ if (Math3D_TriChkLineSegParaZIntersect(&va, &vb, &vc, nx, ny, nz, dist, min->x, min->y, &intersect, min->z,
+ max->z) ||
+ Math3D_TriChkLineSegParaZIntersect(&va, &vb, &vc, nx, ny, nz, dist, min->x, max->y, &intersect, min->z,
+ max->z) ||
+ Math3D_TriChkLineSegParaZIntersect(&va, &vb, &vc, nx, ny, nz, dist, max->x, min->y, &intersect, min->z,
+ max->z) ||
+ Math3D_TriChkLineSegParaZIntersect(&va, &vb, &vc, nx, ny, nz, dist, max->x, max->y, &intersect, min->z,
+ max->z)) {
+ return true;
+ }
+ if (Math3D_TriChkLineSegParaXIntersect(&va, &vb, &vc, nx, ny, nz, dist, min->y, min->z, &intersect, min->x,
+ max->x) ||
+ Math3D_TriChkLineSegParaXIntersect(&va, &vb, &vc, nx, ny, nz, dist, min->y, max->z, &intersect, min->x,
+ max->x) ||
+ Math3D_TriChkLineSegParaXIntersect(&va, &vb, &vc, nx, ny, nz, dist, max->y, min->z, &intersect, min->x,
+ max->x) ||
+ Math3D_TriChkLineSegParaXIntersect(&va, &vb, &vc, nx, ny, nz, dist, max->y, max->z, &intersect, min->x,
+ max->x)) {
+ return true;
+ }
+
+ BgCheck_Vec3sToVec3f(&vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)], &va2);
+ BgCheck_Vec3sToVec3f(&vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)], &vb2);
+ BgCheck_Vec3sToVec3f(&vtxList[poly->vIC], &vc2);
+ if (Math3D_LineVsCube(min, max, &va2, &vb2) || Math3D_LineVsCube(min, max, &vb2, &vc2) ||
+ Math3D_LineVsCube(min, max, &vc2, &va2)) {
+ return true;
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_CreateTriNormFromPolygon.s")
+/**
+ * Initialize StaticLookup Table
+ * returns size of table, in bytes
+ */
+u32 BgCheck_InitStaticLookup(CollisionContext* colCtx, GlobalContext* globalCtx, StaticLookup* lookupTbl) {
+ Vec3s* vtxList;
+ CollisionPoly* polyList;
+ s32 polyMax;
+ s32 polyIdx;
+ s32 sx;
+ s32 sy;
+ s32 sz;
+ // subdivMin indices
+ s32 sxMin;
+ s32 syMin;
+ s32 szMin;
+ // subdivMax indices
+ s32 sxMax;
+ s32 syMax;
+ s32 szMax;
+ // subdiv min/max bounds for adding a poly
+ Vec3f curSubdivMin;
+ Vec3f curSubdivMax;
+ CollisionHeader* colHeader = colCtx->colHeader;
+ s32 pad[2];
+ StaticLookup* iLookup;
+ StaticLookup* jLookup;
+ StaticLookup* lookup;
+ s32 sp98;
+ f32 subdivLengthX;
+ f32 subdivLengthY;
+ f32 subdivLengthZ;
+
+ for (iLookup = lookupTbl;
+ iLookup < (colCtx->subdivAmount.x * colCtx->subdivAmount.y * colCtx->subdivAmount.z + lookupTbl); iLookup++) {
+ iLookup->floor.head = SS_NULL;
+ iLookup->wall.head = SS_NULL;
+ iLookup->ceiling.head = SS_NULL;
+ }
+
+ polyMax = colHeader->numPolygons;
+ vtxList = colHeader->vtxList;
+ polyList = colHeader->polyList;
+ sp98 = colCtx->subdivAmount.x * colCtx->subdivAmount.y;
+ subdivLengthX = colCtx->subdivLength.x + (2 * BGCHECK_SUBDIV_OVERLAP);
+ subdivLengthY = colCtx->subdivLength.y + (2 * BGCHECK_SUBDIV_OVERLAP);
+ subdivLengthZ = colCtx->subdivLength.z + (2 * BGCHECK_SUBDIV_OVERLAP);
+
+ for (polyIdx = 0; polyIdx < polyMax; polyIdx++) {
+ BgCheck_GetPolySubdivisionBounds(colCtx, vtxList, polyList, &sxMin, &syMin, &szMin, &sxMax, &syMax, &szMax,
+ polyIdx);
+ iLookup = szMin * sp98 + lookupTbl;
+ curSubdivMin.z = (colCtx->subdivLength.z * szMin + colCtx->minBounds.z) - BGCHECK_SUBDIV_OVERLAP;
+ curSubdivMax.z = curSubdivMin.z + subdivLengthZ;
+
+ for (sz = szMin; sz < szMax + 1; sz++) {
+ jLookup = (colCtx->subdivAmount.x * syMin) + iLookup;
+ curSubdivMin.y = (colCtx->subdivLength.y * syMin + colCtx->minBounds.y) - BGCHECK_SUBDIV_OVERLAP;
+ curSubdivMax.y = curSubdivMin.y + subdivLengthY;
+
+ for (sy = syMin; sy < syMax + 1; sy++) {
+ lookup = sxMin + jLookup;
+ curSubdivMin.x = (colCtx->subdivLength.x * sxMin + colCtx->minBounds.x) - BGCHECK_SUBDIV_OVERLAP;
+ curSubdivMax.x = curSubdivMin.x + subdivLengthX;
+
+ for (sx = sxMin; sx < sxMax + 1; sx++) {
+ if (BgCheck_PolyIntersectsSubdivision(&curSubdivMin, &curSubdivMax, polyList, vtxList, polyIdx)) {
+ StaticLookup_AddPoly(lookup, colCtx, polyList, vtxList, polyIdx);
+ }
+ curSubdivMin.x += colCtx->subdivLength.x;
+ curSubdivMax.x += colCtx->subdivLength.x;
+ lookup++;
+ }
+ curSubdivMin.y += colCtx->subdivLength.y;
+ curSubdivMax.y += colCtx->subdivLength.y;
+ jLookup += colCtx->subdivAmount.x;
+ }
+ curSubdivMin.z += colCtx->subdivLength.z;
+ curSubdivMax.z += colCtx->subdivLength.z;
+ iLookup += sp98;
+ }
+ }
+ return colCtx->polyNodes.count * sizeof(SSNode);
+}
+
+/**
+ * Returns whether the current scene should reserve less memory for it's collision lookup
+ */
+s32 BgCheck_IsSmallMemScene(GlobalContext* globalCtx) {
+ s16* i;
+
+ for (i = sSmallMemScenes; i < sSmallMemScenes + ARRAY_COUNT(sSmallMemScenes); i++) {
+ if (globalCtx->sceneNum == *i) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Get custom scene memSize
+ */
+s32 BgCheck_TryGetCustomMemsize(s32 sceneId, u32* memSize) {
+ s32 i;
+
+ for (i = 0; i < ARRAY_COUNT(sSceneMemList); i++) {
+ if (sceneId == sSceneMemList[i].sceneId) {
+ *memSize = sSceneMemList[i].memSize;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Compute subdivLength for scene mesh lookup, for a single dimension
+ */
+void BgCheck_SetSubdivisionDimension(f32 min, s32 subdivAmount, f32* max, f32* subdivLength, f32* subdivLengthInv) {
+ f32 length = (*max - min);
+
+ *subdivLength = (s32)(length / subdivAmount) + 1;
+ *subdivLength = CLAMP_MIN(*subdivLength, BGCHECK_SUBDIV_MIN);
+ *subdivLengthInv = 1.0f / *subdivLength;
+
+ *max = *subdivLength * subdivAmount + min;
+}
+
+s32 BgCheck_GetSpecialSceneMaxObjects(GlobalContext* globalCtx, s32* maxNodes, s32* maxPolygons, s32* maxVertices) {
+ s32 i;
+
+ for (i = 0; i < ARRAY_COUNT(sCustomDynapolyMem); i++) {
+ if (globalCtx->sceneNum == sCustomDynapolyMem[i].sceneId) {
+ *maxNodes = sCustomDynapolyMem[i].maxNodes;
+ *maxPolygons = sCustomDynapolyMem[i].maxPolygons;
+ *maxVertices = sCustomDynapolyMem[i].maxVertices;
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Allocate CollisionContext
+ */
+#ifdef NON_MATCHING
+void BgCheck_Allocate(CollisionContext* colCtx, GlobalContext* globalCtx, CollisionHeader* colHeader) {
+ u32 tblMax;
+ u32 memSize;
+ u32 lookupTblMemSize;
+ SSNodeList* nodeList;
+ s32 useCustomSubdivisions;
+ u32 customMemSize;
+ s32 customNodeListMax;
+ s32 i;
+
+ customNodeListMax = -1;
+ colCtx->colHeader = colHeader;
+ colCtx->flags = 0;
+
+ if (BgCheck_IsSmallMemScene(globalCtx)) {
+ colCtx->memSize = 0xF000;
+ colCtx->dyna.polyNodesMax = 1000;
+ colCtx->dyna.polyListMax = 512;
+ colCtx->dyna.vtxListMax = 512;
+ colCtx->subdivAmount.x = 16;
+ colCtx->subdivAmount.y = 4;
+ colCtx->subdivAmount.z = 16;
+ } else {
+ if (BgCheck_TryGetCustomMemsize(globalCtx->sceneNum, &customMemSize)) {
+ colCtx->memSize = customMemSize;
+ } else {
+ colCtx->memSize = 0x23000;
+ }
+ colCtx->dyna.polyNodesMax = 1000;
+ colCtx->dyna.polyListMax = 544;
+ colCtx->dyna.vtxListMax = 512;
+ BgCheck_GetSpecialSceneMaxObjects(globalCtx, &colCtx->dyna.polyNodesMax, &colCtx->dyna.polyListMax,
+ &colCtx->dyna.vtxListMax);
+ useCustomSubdivisions = false;
+
+ for (i = 0; i < ARRAY_COUNT(sSceneSubdivisionList); i++) {
+ if (globalCtx->sceneNum == sSceneSubdivisionList[i].sceneId) {
+ colCtx->subdivAmount.x = sSceneSubdivisionList[i].subdivAmount.x;
+ colCtx->subdivAmount.y = sSceneSubdivisionList[i].subdivAmount.y;
+ colCtx->subdivAmount.z = sSceneSubdivisionList[i].subdivAmount.z;
+ useCustomSubdivisions = true;
+ customNodeListMax = sSceneSubdivisionList[i].nodeListMax;
+ }
+ }
+ if (useCustomSubdivisions == false) {
+ colCtx->subdivAmount.x = 16;
+ colCtx->subdivAmount.y = 4;
+ colCtx->subdivAmount.z = 16;
+ }
+ }
+ colCtx->lookupTbl = THA_AllocEndAlign(
+ &globalCtx->state.heap,
+ colCtx->subdivAmount.x * sizeof(StaticLookup) * colCtx->subdivAmount.y * colCtx->subdivAmount.z, ~1);
+ if (colCtx->lookupTbl == NULL) {
+ Fault_AddHungupAndCrash("../z_bgcheck.c", 3955);
+ }
+ colCtx->minBounds.x = colCtx->colHeader->minBounds.x;
+ colCtx->minBounds.y = colCtx->colHeader->minBounds.y;
+ colCtx->minBounds.z = colCtx->colHeader->minBounds.z;
+ colCtx->maxBounds.x = colCtx->colHeader->maxBounds.x;
+ colCtx->maxBounds.y = colCtx->colHeader->maxBounds.y;
+ colCtx->maxBounds.z = colCtx->colHeader->maxBounds.z;
+ BgCheck_SetSubdivisionDimension(colCtx->minBounds.x, colCtx->subdivAmount.x, &colCtx->maxBounds.x,
+ &colCtx->subdivLength.x, &colCtx->subdivLengthInv.x);
+ BgCheck_SetSubdivisionDimension(colCtx->minBounds.y, colCtx->subdivAmount.y, &colCtx->maxBounds.y,
+ &colCtx->subdivLength.y, &colCtx->subdivLengthInv.y);
+ BgCheck_SetSubdivisionDimension(colCtx->minBounds.z, colCtx->subdivAmount.z, &colCtx->maxBounds.z,
+ &colCtx->subdivLength.z, &colCtx->subdivLengthInv.z);
+ memSize = colCtx->subdivAmount.x * sizeof(StaticLookup) * colCtx->subdivAmount.y * colCtx->subdivAmount.z +
+ colCtx->colHeader->numPolygons * sizeof(u8) + colCtx->dyna.polyNodesMax * sizeof(SSNode) +
+ colCtx->dyna.polyListMax * sizeof(CollisionPoly) + colCtx->dyna.vtxListMax * sizeof(Vec3s) +
+ sizeof(CollisionContext);
+ if (customNodeListMax > 0) {
+ // tblMax is set without checking if customNodeListMax will result in a memory overflow
+ // this is a non-issue as long as sSceneSubdivisionList.nodeListMax is -1
+ tblMax = customNodeListMax;
+ } else {
+ if (colCtx->memSize < memSize) {
+ Fault_AddHungupAndCrash("../z_bgcheck.c", 4011);
+ }
+ tblMax = (colCtx->memSize - memSize) / sizeof(SSNode);
+ }
+
+ SSNodeList_Init(&colCtx->polyNodes);
+ SSNodeList_Alloc(globalCtx, &colCtx->polyNodes, tblMax, colCtx->colHeader->numPolygons);
+
+ lookupTblMemSize = BgCheck_InitStaticLookup(colCtx, globalCtx, colCtx->lookupTbl);
+
+ DynaPoly_Init(globalCtx, &colCtx->dyna);
+ DynaPoly_Alloc(globalCtx, &colCtx->dyna);
+}
+#else
+void BgCheck_Allocate(CollisionContext* colCtx, GlobalContext* globalCtx, CollisionHeader* colHeader);
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_Allocate.s")
+#endif
+
+/**
+ * Enables CollisionContext wide flags
+ * Only used to reverse water flow in Great Bay Temple
+ */
+void BgCheck_SetContextFlags(CollisionContext* colCtx, u32 flags) {
+ colCtx->flags |= flags;
+}
+
+/**
+ * Disables CollisionContext wide flags
+ * Only used to revert the reverse water flow in Great Bay Temple
+ */
+void BgCheck_UnsetContextFlags(CollisionContext* colCtx, u32 flags) {
+ colCtx->flags &= ~flags;
+}
+
+/**
+ * original name: T_BGCheck_getBGDataInfo
+ */
+CollisionHeader* BgCheck_GetCollisionHeader(CollisionContext* colCtx, s32 bgId) {
+ if (bgId == BGCHECK_SCENE) {
+ return colCtx->colHeader;
+ }
+ if (bgId < 0 || bgId > BG_ACTOR_MAX) {
+ return NULL;
+ }
+ if (!(colCtx->dyna.bgActorFlags[bgId] & 1)) {
+ return NULL;
+ }
+ return colCtx->dyna.bgActors[bgId].colHeader;
+}
+
+/**
+ * Test if pos is near collision boundaries
+ */
+s32 BgCheck_PosInStaticBoundingBox(CollisionContext* colCtx, Vec3f* pos) {
+ if (pos->x < (colCtx->minBounds.x - BGCHECK_SUBDIV_OVERLAP) ||
+ (colCtx->maxBounds.x + BGCHECK_SUBDIV_OVERLAP) < pos->x ||
+ pos->y < (colCtx->minBounds.y - BGCHECK_SUBDIV_OVERLAP) ||
+ (colCtx->maxBounds.y + BGCHECK_SUBDIV_OVERLAP) < pos->y ||
+ pos->z < (colCtx->minBounds.z - BGCHECK_SUBDIV_OVERLAP) ||
+ (colCtx->maxBounds.z + BGCHECK_SUBDIV_OVERLAP) < pos->z) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Raycast Toward Floor
+ * returns the yIntersect of the nearest poly found directly below `pos`, or BGCHECK_Y_MIN if no floor detected
+ * returns the poly found in `outPoly`, and the bgId of the entity in `outBgId`
+ */
+f32 BgCheck_RaycastFloorImpl(GlobalContext* globalCtx, CollisionContext* colCtx, u16 xpFlags, CollisionPoly** outPoly,
+ s32* outBgId, Vec3f* pos, Actor* actor, u32 arg7, f32 checkDist, s32 arg9) {
+ f32 yIntersectDyna;
+ f32 yIntersect;
+ StaticLookup* lookupTbl;
+ Vec3f checkPos;
+ StaticLookup* lookup;
+ DynaRaycast dynaRaycast;
+
+ *outBgId = BGCHECK_SCENE;
+ *outPoly = NULL;
+ lookupTbl = colCtx->lookupTbl;
+ yIntersect = BGCHECK_Y_MIN;
+ checkPos = *pos;
+
+ while (true) {
+ if (checkPos.y < colCtx->minBounds.y) {
+ break;
+ }
+ lookup = BgCheck_GetStaticLookup(colCtx, lookupTbl, &checkPos);
+ if (lookup == NULL) {
+ checkPos.y -= colCtx->subdivLength.y;
+ continue;
+ }
+ yIntersect =
+ BgCheck_RaycastFloorStatic(lookup, colCtx, xpFlags, outPoly, pos, arg7, checkDist, BGCHECK_Y_MIN, actor);
+ if (yIntersect > BGCHECK_Y_MIN) {
+ break;
+ }
+ checkPos.y -= colCtx->subdivLength.y;
+ }
+ if (!(arg9 & 1)) {
+ dynaRaycast.globalCtx = globalCtx;
+ dynaRaycast.colCtx = colCtx;
+ dynaRaycast.xpFlags = xpFlags;
+ dynaRaycast.resultPoly = outPoly;
+ dynaRaycast.yIntersect = yIntersect;
+ dynaRaycast.pos = pos;
+ dynaRaycast.bgId = outBgId;
+ dynaRaycast.unk1C = 50;
+ dynaRaycast.actor = actor;
+ dynaRaycast.unk_24 = arg7;
+ dynaRaycast.checkDist = checkDist;
+
+ yIntersectDyna = BgCheck_RaycastFloorDyna(&dynaRaycast);
+ if (yIntersect < yIntersectDyna) {
+ yIntersect = yIntersectDyna;
+ }
+ }
+
+ if (yIntersect != BGCHECK_Y_MIN && func_800C9B68(colCtx, *outPoly, *outBgId)) {
+ yIntersect -= 1.0f;
+ }
+ return yIntersect;
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_CameraRaycastFloor1(CollisionContext* colCtx, CollisionPoly** outPoly, Vec3f* pos) {
+ s32 bgId;
+
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_CAMERA, outPoly, &bgId, pos, NULL, 0x1C, 1.0f, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor1(CollisionContext* colCtx, CollisionPoly** outPoly, Vec3f* pos) {
+ s32 bgId;
+
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, &bgId, pos, NULL, 0x1C, 1.0f, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor2(GlobalContext* globalCtx, CollisionContext* colCtx, CollisionPoly** outPoly,
+ Vec3f* pos) {
+ s32 bgId;
+
+ return BgCheck_RaycastFloorImpl(globalCtx, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, &bgId, pos, NULL, 0x1C, 1.0f, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor2_1(GlobalContext* globalCtx, CollisionContext* colCtx, CollisionPoly** outPoly,
+ Vec3f* pos) {
+ s32 bgId;
+
+ return BgCheck_RaycastFloorImpl(globalCtx, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, &bgId, pos, NULL, 0x1C, 1.0f, 1);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor3(CollisionContext* colCtx, CollisionPoly** outPoly, s32* bgId, Vec3f* pos) {
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, bgId, pos, NULL, 0x1C, 1.0f, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor5(CollisionContext* colCtx, CollisionPoly** outPoly, s32* outBgId, Actor* actor,
+ Vec3f* pos) {
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, outBgId, pos, actor, 0x1C, 1.0f, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor5_2(GlobalContext* globalCtx, CollisionContext* colCtx, CollisionPoly** outPoly,
+ s32* bgId, Actor* actor, Vec3f* pos) {
+ return BgCheck_RaycastFloorImpl(globalCtx, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, bgId, pos, actor, 0x1C, 1.0f, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor5_3(GlobalContext* globalCtx, CollisionContext* colCtx, CollisionPoly** outPoly,
+ s32* bgId, Actor* actor, Vec3f* pos) {
+ return BgCheck_RaycastFloorImpl(globalCtx, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, bgId, pos, actor, 0x3C, 1.0f, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor6(CollisionContext* colCtx, CollisionPoly** outPoly, s32* bgId, Actor* actor, Vec3f* pos,
+ f32 checkDist) {
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, bgId, pos, actor, 0x1C, checkDist, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor7(CollisionContext* colCtx, CollisionPoly** outPoly, s32* bgId, Actor* actor,
+ Vec3f* pos) {
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, bgId, pos, actor, 0x06, 1.0f, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_AnyRaycastFloor1(CollisionContext* colCtx, CollisionPoly* outPoly, Vec3f* pos) {
+ CollisionPoly* tempPoly;
+ f32 result;
+ s32 bgId;
+
+ result = BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_NONE, &tempPoly, &bgId, pos, NULL, 0x1C, 1.0f, 0);
+
+ if (tempPoly != NULL) {
+ *outPoly = *tempPoly;
+ }
+ return result;
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_AnyRaycastFloor2(CollisionContext* colCtx, CollisionPoly* outPoly, s32* bgId, Vec3f* pos) {
+ CollisionPoly* tempPoly;
+ f32 result = BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_NONE, &tempPoly, bgId, pos, NULL, 0x1C, 1.0f, 0);
+
+ if (tempPoly != NULL) {
+ *outPoly = *tempPoly;
+ }
+ return result;
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_CameraRaycastFloor2(CollisionContext* colCtx, CollisionPoly** outPoly, s32* bgId, Vec3f* pos) {
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_CAMERA, outPoly, bgId, pos, NULL, 0x06, 1.0f, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor8(CollisionContext* colCtx, CollisionPoly** outPoly, s32* bgId, Actor* actor,
+ Vec3f* pos) {
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, bgId, pos, actor, 0x02, 1.0f, 0);
+}
+
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor9(CollisionContext* colCtx, CollisionPoly** outPoly, s32* bgId, Vec3f* pos) {
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, bgId, pos, NULL, 0x06, 1.0f, 0);
+}
+
+#ifdef NON_MATCHING
+/**
+ * Tests if moving from `posPrev` to `posNext` will collide with a "wall"
+ * `radius` is used to form a sphere for collision detection purposes
+ * `checkHeight` is the positive height above posNext to perform certain checks
+ * returns true if a collision is detected, else false
+ * `outPoly` returns the closest poly detected, while `outBgId` returns the poly owner
+ */
+s32 BgCheck_CheckWallImpl(CollisionContext* colCtx, u16 xpFlags, Vec3f* posResult, Vec3f* posNext, Vec3f* posPrev,
+ f32 radius, CollisionPoly** outPoly, s32* outBgId, Actor* actor, f32 checkHeight, u8 argA) {
+ StaticLookup* lookupTbl;
+ f32 temp_f0;
+ s32 result;
+ CollisionPoly* poly;
+ // change between posPrev to posNext
+ f32 dx;
+ f32 dy;
+ f32 dz;
+ Vec3f sphCenter;
+ s32 dynaPolyCollision;
+ Vec3f posIntersect;
+ s32 bgId;
+ f32 temp_f0_2;
+ f32 f32temp;
+ f32 nx2, nz2;
+ Vec3f checkLineNext;
+ Vec3f checkLinePrev;
+ f32 n2XZDist;
+ f32 n3XZDist;
+ f32 nx3, nz3;
+ s32 bccFlags;
+ Vec3f posIntersect2;
+ s32 bgId2;
+ // unit normal of polygon
+ f32 nx;
+ f32 ny;
+ f32 nz;
+
+ result = false;
+ *outBgId = BGCHECK_SCENE;
+ *outPoly = NULL;
+ lookupTbl = colCtx->lookupTbl;
+ *posResult = *posNext;
+ dx = posNext->x - posPrev->x;
+ dy = posNext->y - posPrev->y;
+ dz = posNext->z - posPrev->z;
+
+ // if there's movement on the xz plane, and argA flag is 0,
+ if ((dx != 0.0f || dz != 0.0f) && (argA & 1) == 0) {
+ if ((checkHeight + dy) < 5.0f) {
+ //! @bug checkHeight is not applied to posPrev/posNext
+ result = BgCheck_CheckLineImpl(colCtx, xpFlags, COLPOLY_IGNORE_NONE, posPrev, posNext, &posIntersect, &poly,
+ &bgId, actor, 1.0f, BGCHECK_CHECK_ALL & ~BGCHECK_CHECK_CEILING);
+ if (result) {
+ ny = COLPOLY_GET_NORMAL(poly->normal.y);
+ // if poly is floor, push result underneath the floor
+ if (ny > 0.5f) {
+ posResult->x = posIntersect.x;
+ if (checkHeight > 1.0f) {
+ posResult->y = posIntersect.y - 1.0f;
+ } else {
+ posResult->y = posIntersect.y - checkHeight;
+ }
+ posResult->z = posIntersect.z;
+ if (actor != NULL) {
+ actor->bgCheckFlags |= 0x1000;
+ }
+ }
+ // poly is wall
+ else {
+ nx = COLPOLY_GET_NORMAL(poly->normal.x);
+ nz = COLPOLY_GET_NORMAL(poly->normal.z);
+ posResult->x = radius * nx + posIntersect.x;
+ posResult->y = radius * ny + posIntersect.y;
+ posResult->z = radius * nz + posIntersect.z;
+ }
+ *outPoly = poly;
+ *outBgId = bgId;
+ }
+ } else {
+ // if the radius is less than the distance travelled on the xz plane, also test for floor collisions
+ bccFlags = SQ(radius) < (SQ(dx) + SQ(dz))
+ ? (BGCHECK_CHECK_ALL & ~BGCHECK_CHECK_CEILING)
+ : (BGCHECK_CHECK_ALL & ~BGCHECK_CHECK_FLOOR & ~BGCHECK_CHECK_CEILING);
+
+ // perform a straight line test to see if a line at posNext.y + checkHeight from posPrev.xz to posNext.xz
+ // passes through any wall and possibly floor polys
+ checkLineNext = *posNext;
+ checkLineNext.y += checkHeight;
+ checkLinePrev = *posPrev;
+ checkLinePrev.y = checkLineNext.y;
+ result = BgCheck_CheckLineImpl(colCtx, xpFlags, COLPOLY_IGNORE_NONE, &checkLinePrev, &checkLineNext,
+ &posIntersect, &poly, &bgId, actor, 1.0f, bccFlags);
+
+ if (result) {
+ nx2 = COLPOLY_GET_NORMAL(poly->normal.x);
+ nz2 = COLPOLY_GET_NORMAL(poly->normal.z);
+ n2XZDist = sqrtf(SQ(nx2) + SQ(nz2));
+
+ // if poly is not a "flat" floor or "flat" ceiling
+ if (!IS_ZERO(n2XZDist)) {
+ // normalize nx,nz and multiply each by the radius to go back to the other side of the wall
+ f32temp = 1.0f / n2XZDist;
+ temp_f0 = radius * f32temp;
+ posResult->x = temp_f0 * nx2 + posIntersect.x;
+ posResult->z = temp_f0 * nz2 + posIntersect.z;
+ *outPoly = poly;
+ *outBgId = bgId;
+ result = true;
+ if (COLPOLY_GET_NORMAL(poly->normal.y) > 0.5f) {
+ if (actor != NULL) {
+ actor->bgCheckFlags |= 0x1000;
+ }
+ }
+ } else {
+ result = false;
+ }
+ }
+ }
+ }
+
+ sphCenter = *posResult;
+ dynaPolyCollision = false;
+ sphCenter.y += checkHeight;
+ // test if sphere (sphCenter, radius) collides with a dynamic wall, displacing the x/z coordinates
+ if (BgCheck_SphVsDynaWall(colCtx, xpFlags, &posResult->x, &posResult->z, &sphCenter, radius, outPoly, outBgId,
+ actor)) {
+ result = true;
+ dynaPolyCollision = true;
+ sphCenter = *posResult;
+ sphCenter.y += checkHeight;
+ }
+ // test if sphere (sphCenter, radius) collides with a static wall, displacing the x/z coordinates
+ if (BgCheck_PosInStaticBoundingBox(colCtx, posNext) &&
+ // possible bug? if the sphere's radius is smaller than the distance to a subdivision boundary, some static
+ // polys will be missed
+ BgCheck_SphVsStaticWall(BgCheck_GetNearestStaticLookup(colCtx, lookupTbl, posResult), colCtx, xpFlags,
+ &posResult->x, &posResult->z, &sphCenter, radius, outPoly, actor)) {
+ *outBgId = BGCHECK_SCENE;
+ result = true;
+ }
+ // if a collision with a dyna poly was detected
+ if (dynaPolyCollision || *outBgId != BGCHECK_SCENE) {
+ if (BgCheck_CheckLineImpl(colCtx, xpFlags, COLPOLY_IGNORE_NONE, posPrev, posResult, &posIntersect2, &poly,
+ &bgId2, actor, 1.0f, BGCHECK_CHECK_ONE_FACE | BGCHECK_CHECK_WALL)) {
+ nx3 = COLPOLY_GET_NORMAL(poly->normal.x);
+ nz3 = COLPOLY_GET_NORMAL(poly->normal.z);
+ n3XZDist = sqrtf(SQ(nx3) + SQ(nz3));
+
+ // if poly is not a "flat" floor or "flat" ceiling
+ if (!IS_ZERO(n3XZDist)) {
+ // normalize nx,nz and multiply each by the radius to go back to the other side of the wall
+ f32temp = 1.0f / n3XZDist;
+ temp_f0_2 = radius * f32temp;
+ posResult->x = temp_f0_2 * nx3 + posIntersect2.x;
+ posResult->z = temp_f0_2 * nz3 + posIntersect2.z;
+ *outPoly = poly;
+ *outBgId = bgId2;
+ result = true;
+ }
+ }
+ }
+ return result;
+}
+#else
+s32 BgCheck_CheckWallImpl(CollisionContext* colCtx, u16 xpFlags, Vec3f* posResult, Vec3f* posNext, Vec3f* posPrev,
+ f32 radius, CollisionPoly** outPoly, s32* outBgId, Actor* actor, f32 checkHeight, u8 argA);
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_CheckWallImpl.s")
+#endif
+
+/**
+ * Public. Tests if moving from `posPrev` to `posNext` will collide with a "wall"
+ * `radius` is used to form a sphere for collision detection purposes
+ * `checkHeight` is the positive height above posNext to perform certain checks
+ * returns true if a collision is detected, else false
+ * `outPoly` returns the closest poly detected
+ */
+s32 BgCheck_EntitySphVsWall1(CollisionContext* colCtx, Vec3f* posResult, Vec3f* posNext, Vec3f* posPrev, f32 radius,
+ CollisionPoly** outPoly, f32 checkHeight) {
+ s32 bgId;
+
+ return BgCheck_CheckWallImpl(colCtx, COLPOLY_IGNORE_ENTITY, posResult, posNext, posPrev, radius, outPoly, &bgId,
+ NULL, checkHeight, 0);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C02C0.s")
+/**
+ * Public. Tests if moving from `posPrev` to `posNext` will collide with a "wall"
+ * `radius` is used to form a sphere for collision detection purposes
+ * `checkHeight` is the positive height above posNext to perform certain checks
+ * returns true if a collision is detected, else false
+ * `outPoly` returns the closest poly detected, while `outBgId` returns the poly owner
+ */
+s32 BgCheck_EntitySphVsWall2(CollisionContext* colCtx, Vec3f* posResult, Vec3f* posNext, Vec3f* posPrev, f32 radius,
+ CollisionPoly** outPoly, s32* outBgId, f32 checkHeight) {
+ return BgCheck_CheckWallImpl(colCtx, COLPOLY_IGNORE_ENTITY, posResult, posNext, posPrev, radius, outPoly, outBgId,
+ NULL, checkHeight, 0);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C0340.s")
+/**
+ * Public. Tests if *moving from `posPrev` to `posNext` will collide with a "wall"
+ * `radius` is used to form a sphere for collision detection purposes
+ * `checkHeight` is the positive height above posNext to perform certain checks
+ * `actor` is the actor performing the check, allowing it to be skipped
+ * returns true if a collision is detected, else false
+ * `outPoly` returns the closest poly detected, while `outBgId` returns the poly owner
+ */
+s32 BgCheck_EntitySphVsWall3(CollisionContext* colCtx, Vec3f* posResult, Vec3f* posNext, Vec3f* posPrev, f32 radius,
+ CollisionPoly** outPoly, s32* outBgId, Actor* actor, f32 checkHeight) {
+ return BgCheck_CheckWallImpl(colCtx, COLPOLY_IGNORE_ENTITY, posResult, posNext, posPrev, radius, outPoly, outBgId,
+ actor, checkHeight, 0);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C0474.s")
+/**
+ * Public. Tests if moving from `posPrev` to `posNext` will collide with a "wall"
+ * Skips a check that occurs only when moving on the xz plane
+ * `radius` is used to form a sphere for collision detection purposes
+ * `checkHeight` is the positive height above posNext to perform certain checks
+ * `actor` is the actor performing the check, allowing it to be skipped
+ * returns true if a collision is detected, else false
+ * `outPoly` returns the closest poly detected, while `outBgId` returns the poly owner
+ */
+s32 BgCheck_EntitySphVsWall4(CollisionContext* colCtx, Vec3f* posResult, Vec3f* posNext, Vec3f* posPrev, f32 radius,
+ CollisionPoly** outPoly, s32* outBgId, Actor* actor, f32 checkHeight) {
+ return BgCheck_CheckWallImpl(colCtx, COLPOLY_IGNORE_ENTITY, posResult, posNext, posPrev, radius, outPoly, outBgId,
+ actor, checkHeight, 1);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C0668.s")
+/**
+ * Tests for collision with a ceiling poly
+ * `checkHeight` should be a positive value
+ * returns true if a collision occurs, else false
+ * `outPoly` returns the poly collided with, while `outBgId` returns the owner of the poly
+ * `outY` returns the y coordinate of pos needed to not collide with `outPoly`
+ */
+s32 BgCheck_CheckCeilingImpl(CollisionContext* colCtx, u16 xpFlags, f32* outY, Vec3f* pos, f32 checkHeight,
+ CollisionPoly** outPoly, s32* outBgId, Actor* actor) {
+ StaticLookup* lookupTbl;
+ StaticLookup* lookup;
+ s32 result;
+ Vec3f posTemp;
+ f32 tempY;
+
+ *outBgId = BGCHECK_SCENE;
+ *outY = pos->y;
+ lookupTbl = colCtx->lookupTbl;
+ if (!BgCheck_PosInStaticBoundingBox(colCtx, pos)) {
+ return false;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C06A8.s")
+ lookup = BgCheck_GetNearestStaticLookup(colCtx, lookupTbl, pos);
+ result = BgCheck_CheckStaticCeiling(lookup, xpFlags, colCtx, outY, pos, checkHeight, outPoly, actor);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C074C.s")
+ posTemp = *pos;
+ posTemp.y = *outY;
+ tempY = *outY;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C07F0.s")
+ if (BgCheck_CheckDynaCeiling(colCtx, xpFlags, &tempY, &posTemp, checkHeight, outPoly, outBgId, actor)) {
+ *outY = tempY;
+ result = true;
+ }
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_PolygonCollidesWithSphere.s")
+/**
+ * Tests for collision with any ceiling poly
+ * `checkHeight` must be a positive value
+ * returns true if a collision occurs, else false
+ * `outY` returns the displaced y coordinate needed to not collide with the poly
+ */
+s32 BgCheck_AnyCheckCeiling(CollisionContext* colCtx, f32* outY, Vec3f* pos, f32 checkHeight) {
+ CollisionPoly* poly;
+ s32 bgId;
+
+ return BgCheck_CheckCeilingImpl(colCtx, COLPOLY_IGNORE_NONE, outY, pos, checkHeight, &poly, &bgId, NULL);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ScenePolygonListsInsertSorted.s")
+/**
+ * Tests for collision with any entity solid ceiling poly
+ * `checkHeight` must be a positive value
+ * returns true if a collision occurs, else false
+ * `outY` returns the displaced y coordinate needed to not collide with the poly
+ */
+s32 BgCheck_EntityCheckCeiling(CollisionContext* colCtx, f32* outY, Vec3f* pos, f32 checkHeight,
+ CollisionPoly** outPoly, s32* outBgId, Actor* actor) {
+ return BgCheck_CheckCeilingImpl(colCtx, COLPOLY_IGNORE_ENTITY, outY, pos, checkHeight, outPoly, outBgId, actor);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ScenePolygonListsInsert.s")
+#ifdef NON_MATCHING
+/**
+ * Tests if a line from `posA` to `posB` intersects with a poly
+ * returns true if it does, else false
+ * `posB`? `posResult` returns the point of intersection
+ * `outPoly` returns the pointer to the intersected poly, while `outBgId` returns the entity the poly belongs to
+ */
+s32 BgCheck_CheckLineImpl(CollisionContext* colCtx, u16 xpFlags1, u16 xpFlags2, Vec3f* posA, Vec3f* posB,
+ Vec3f* posResult, CollisionPoly** outPoly, s32* outBgId, Actor* actor, f32 checkDist,
+ u32 bccFlags) {
+ StaticLookup* lookupTbl;
+ StaticLookup* iLookup;
+ s32 subdivMin[3];
+ s32 subdivMax[3];
+ s32 i;
+ s32 result;
+ Vec3f posBTemp;
+ StaticLineTest checkLine;
+ Vec3f sectorMin;
+ Vec3f sectorMax;
+ s32 k;
+ StaticLookup* lookup;
+ s32 j;
+ StaticLookup* jLookup;
+ s32 temp_lo;
+ s32 pad[2];
+
+ lookupTbl = colCtx->lookupTbl;
+ posBTemp = *posB;
+
+ *outBgId = BGCHECK_SCENE;
+
+ BgCheck_ResetPolyCheckTbl(&colCtx->polyNodes, colCtx->colHeader->numPolygons);
+ BgCheck_GetStaticLookupIndicesFromPos(colCtx, posA, (Vec3i*)&subdivMin);
+ BgCheck_GetStaticLookupIndicesFromPos(colCtx, &posBTemp, (Vec3i*)&subdivMax);
+ *posResult = *posB;
+ checkLine.outDistSq = 1.0e38f;
+ *outPoly = NULL;
+
+ checkLine.colCtx = colCtx;
+ checkLine.xpFlags2 = xpFlags2;
+ checkLine.posA = posA;
+ checkLine.posB = &posBTemp;
+ checkLine.outPoly = outPoly;
+ checkLine.xpFlags1 = xpFlags1;
+ checkLine.outPos = posResult;
+ checkLine.checkDist = checkDist;
+ checkLine.bccFlags = bccFlags;
+ checkLine.actor = actor;
+ result = false;
+
+ if (subdivMin[0] != subdivMax[0] || subdivMin[1] != subdivMax[1] || subdivMin[2] != subdivMax[2]) {
+ for (i = 0; i < 3; i++) {
+ if (subdivMax[i] < subdivMin[i]) {
+ j = subdivMax[i];
+ subdivMax[i] = subdivMin[i];
+ subdivMin[i] = j;
+ }
+ }
+ temp_lo = colCtx->subdivAmount.x * colCtx->subdivAmount.y;
+ iLookup = lookupTbl + subdivMin[2] * temp_lo;
+ sectorMin.z = subdivMin[2] * colCtx->subdivLength.z + colCtx->minBounds.z;
+ sectorMax.z = colCtx->subdivLength.z + sectorMin.z;
+
+ for (i = subdivMin[2]; i < subdivMax[2] + 1; i++) {
+ jLookup = iLookup + subdivMin[1] * colCtx->subdivAmount.x;
+ sectorMin.y = subdivMin[1] * colCtx->subdivLength.y + colCtx->minBounds.y;
+ sectorMax.y = colCtx->subdivLength.y + sectorMin.y;
+
+ for (j = subdivMin[1]; j < subdivMax[1] + 1; j++) {
+ lookup = jLookup + subdivMin[0];
+ sectorMin.x = subdivMin[0] * colCtx->subdivLength.x + colCtx->minBounds.x;
+ sectorMax.x = colCtx->subdivLength.x + sectorMin.x;
+
+ for (k = subdivMin[0]; k < subdivMax[0] + 1; k++) {
+ if (Math3D_LineVsCube(&sectorMin, &sectorMax, posA, &posBTemp)) {
+ checkLine.lookup = lookup;
+
+ if (BgCheck_CheckLineInSubdivision(&checkLine)) {
+ result = true;
+ }
+ }
+ lookup++;
+ sectorMin.x += colCtx->subdivLength.x;
+ sectorMax.x += colCtx->subdivLength.x;
+ }
+ jLookup += colCtx->subdivAmount.x;
+ sectorMin.y += colCtx->subdivLength.y;
+ sectorMax.y += colCtx->subdivLength.y;
+ }
+ iLookup += temp_lo;
+ sectorMin.z += colCtx->subdivLength.z;
+ sectorMax.z += colCtx->subdivLength.z;
+ }
+ } else if (BgCheck_PosInStaticBoundingBox(colCtx, posA) == false) {
+ return false;
+ } else {
+ checkLine.lookup = BgCheck_GetNearestStaticLookup(colCtx, lookupTbl, posA);
+ result = BgCheck_CheckLineInSubdivision(&checkLine);
+ if (result) {
+ checkLine.outDistSq = Math3D_Vec3fDistSq(posResult, posA);
+ }
+ }
+ if ((bccFlags & BGCHECK_CHECK_DYNA) &&
+ BgCheck_CheckLineAgainstDyna(colCtx, xpFlags1, posA, &posBTemp, posResult, outPoly, &checkLine.outDistSq,
+ outBgId, actor, checkDist, bccFlags)) {
+ result = true;
+ }
+ return result;
+}
+#else
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_CheckLineImpl.s")
+#endif
+
+/**
+ * Get bccFlags
+ */
+u32 BgCheck_GetBccFlags(s32 checkWall, s32 checkFloor, s32 checkCeil, s32 checkOneFace, s32 checkDyna) {
+ u32 result = 0;
+
+ if (checkWall) {
+ result = BGCHECK_CHECK_WALL;
+ }
+ if (checkFloor) {
+ result |= BGCHECK_CHECK_FLOOR;
+ }
+ if (checkCeil) {
+ result |= BGCHECK_CHECK_CEILING;
+ }
+ if (checkOneFace) {
+ result |= BGCHECK_CHECK_ONE_FACE;
+ }
+ if (checkDyna) {
+ result |= BGCHECK_CHECK_DYNA;
+ }
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C0E74.s")
+/**
+ * Public. Tests if a line from `posA` to `posB` intersects with a poly
+ * returns true if it does, else false
+ */
+s32 BgCheck_CameraLineTest1(CollisionContext* colCtx, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, s32 checkWall, s32 checkFloor, s32 checkCeil, s32 checkOneFace,
+ s32* bgId) {
+ return BgCheck_CheckLineImpl(colCtx, COLPOLY_IGNORE_CAMERA, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly,
+ bgId, NULL, 1.0f,
+ BgCheck_GetBccFlags(checkWall, checkFloor, checkCeil, checkOneFace, true));
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C10FC.s")
+/**
+ * Public. Tests if a line from `posA` to `posB` intersects with a poly
+ * returns true if it does, else false
+ */
+s32 BgCheck_CameraLineTest2(CollisionContext* colCtx, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, s32 checkWall, s32 checkFloor, s32 checkCeil, s32 checkOneFace,
+ s32* bgId) {
+ return BgCheck_CheckLineImpl(colCtx, COLPOLY_IGNORE_NONE, COLPOLY_IGNORE_CAMERA, posA, posB, posResult, outPoly,
+ bgId, NULL, 1.0f,
+ BgCheck_GetBccFlags(checkWall, checkFloor, checkCeil, checkOneFace, true));
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C1238.s")
+/**
+ * Public. Tests if a line from `posA` to `posB` intersects with a poly
+ * returns true if it does, else false
+ */
+s32 BgCheck_EntityLineTest1(CollisionContext* colCtx, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, s32 checkWall, s32 checkFloor, s32 checkCeil, s32 checkOneFace,
+ s32* bgId) {
+ return BgCheck_CheckLineImpl(colCtx, COLPOLY_IGNORE_ENTITY, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly,
+ bgId, NULL, 1.0f,
+ BgCheck_GetBccFlags(checkWall, checkFloor, checkCeil, checkOneFace, true));
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C12A4.s")
+/**
+ * Public. Tests if a line from `posA` to `posB` intersects with a poly
+ * returns true if it does, else false
+ */
+s32 BgCheck_EntityLineTest2(CollisionContext* colCtx, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, s32 checkWall, s32 checkFloor, s32 checkCeil, s32 checkOneFace,
+ s32* bgId, Actor* actor) {
+ return BgCheck_CheckLineImpl(colCtx, COLPOLY_IGNORE_ENTITY, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly,
+ bgId, actor, 1.0f,
+ BgCheck_GetBccFlags(checkWall, checkFloor, checkCeil, checkOneFace, true));
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C1B68.s")
+/**
+ * Public. Tests if a line from `posA` to `posB` intersects with a poly
+ * returns true if it does, else false
+ */
+s32 BgCheck_EntityLineTest3(CollisionContext* colCtx, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, s32 checkWall, s32 checkFloor, s32 checkCeil, s32 checkOneFace,
+ s32* bgId, Actor* actor, f32 checkDist) {
+ return BgCheck_CheckLineImpl(colCtx, COLPOLY_IGNORE_ENTITY, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly,
+ bgId, actor, checkDist,
+ BgCheck_GetBccFlags(checkWall, checkFloor, checkCeil, checkOneFace, true));
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C1D7C.s")
+/**
+ * Public. Tests if a line from `posA` to `posB` intersects with a poly
+ * returns true if it does, else false
+ */
+s32 BgCheck_ProjectileLineTest(CollisionContext* colCtx, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, s32 checkWall, s32 checkFloor, s32 checkCeil, s32 checkOneFace,
+ s32* bgId) {
+ return BgCheck_CheckLineImpl(colCtx, COLPOLY_IGNORE_PROJECTILES, COLPOLY_IGNORE_NONE, posA, posB, posResult,
+ outPoly, bgId, NULL, 1.0f,
+ BgCheck_GetBccFlags(checkWall, checkFloor, checkCeil, checkOneFace, true));
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C2008.s")
+/**
+ * Public. Tests if a line from `posA` to `posB` intersects with a poly
+ * returns true if it does, else false
+ */
+s32 BgCheck_AnyLineTest1(CollisionContext* colCtx, Vec3f* posA, Vec3f* posB, Vec3f* posResult, CollisionPoly** outPoly,
+ s32 checkOneFace) {
+ return BgCheck_AnyLineTest2(colCtx, posA, posB, posResult, outPoly, true, true, true, checkOneFace);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C20F4.s")
+/**
+ * Public. Tests if a line from `posA` to `posB` intersects with a poly
+ * returns true if it does, else false
+ */
+s32 BgCheck_AnyLineTest2(CollisionContext* colCtx, Vec3f* posA, Vec3f* posB, Vec3f* posResult, CollisionPoly** outPoly,
+ s32 checkWall, s32 checkFloor, s32 checkCeil, s32 checkOneFace) {
+ s32 bgId;
+
+ return BgCheck_CheckLineImpl(colCtx, COLPOLY_IGNORE_NONE, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly,
+ &bgId, NULL, 1.0f,
+ BgCheck_GetBccFlags(checkWall, checkFloor, checkCeil, checkOneFace, true));
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C2310.s")
+/**
+ * Public. Tests if a line from `posA` to `posB` intersects with a poly
+ * returns true if it does, else false
+ */
+s32 BgCheck_AnyLineTest3(CollisionContext* colCtx, Vec3f* posA, Vec3f* posB, Vec3f* posResult, CollisionPoly** outPoly,
+ s32 checkWall, s32 checkFloor, s32 checkCeil, s32 checkOneFace, s32* bgId) {
+ return BgCheck_CheckLineImpl(colCtx, COLPOLY_IGNORE_NONE, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly, bgId,
+ NULL, 1.0f, BgCheck_GetBccFlags(checkWall, checkFloor, checkCeil, checkOneFace, true));
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C2460.s")
+/**
+ * Get first poly intersecting sphere `center` `radius`
+ * ignores `actor` dyna poly
+ * returns true if any poly intersects the sphere, else false
+ * `outPoly` returns the pointer of the first poly found that intersects
+ * `outBgId` returns the bgId of the entity that owns `outPoly`
+ */
+s32 BgCheck_SphVsFirstPolyImpl(CollisionContext* colCtx, u16 xpFlags, CollisionPoly** outPoly, s32* outBgId,
+ Vec3f* center, f32 radius, Actor* actor, u16 bciFlags) {
+ StaticLookup* lookup;
+
+ *outBgId = BGCHECK_SCENE;
+ lookup = BgCheck_GetStaticLookup(colCtx, colCtx->lookupTbl, center);
+ if (lookup == NULL) {
+ return false;
+ } else if (BgCheck_SphVsFirstStaticPoly(lookup, xpFlags, colCtx, center, radius, outPoly, bciFlags, actor) ||
+ BgCheck_SphVsFirstDynaPoly(colCtx, xpFlags, outPoly, outBgId, center, radius, actor, bciFlags)) {
+ return true;
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C2514.s")
+/**
+ * Public get first poly intersecting sphere `center` `radius`
+ */
+s32 BgCheck_SphVsFirstPoly(CollisionContext* colCtx, Vec3f* center, f32 radius) {
+ CollisionPoly* poly;
+ s32 bgId;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C25E0.s")
+ return BgCheck_SphVsFirstPolyImpl(colCtx, COLPOLY_IGNORE_NONE, &poly, &bgId, center, radius, NULL,
+ BGCHECK_IGNORE_NONE);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_GetPolyMinSubdivisions.s")
+/**
+ * Public get first wall poly intersecting sphere `center` `radius`
+ */
+s32 BgCheck_SphVsFirstWall(CollisionContext* colCtx, Vec3f* center, f32 radius) {
+ CollisionPoly* poly;
+ s32 bgId;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_GetPolyMaxSubdivisions.s")
+ return BgCheck_SphVsFirstPolyImpl(colCtx, COLPOLY_IGNORE_NONE, &poly, &bgId, center, radius, NULL,
+ BGCHECK_IGNORE_FLOOR | BGCHECK_IGNORE_CEILING);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_GetPolyMinMaxSubdivisions.s")
+/**
+ * Init SSNodeList
+ */
+void SSNodeList_Init(SSNodeList* this) {
+ this->max = 0;
+ this->count = 0;
+ this->tbl = NULL;
+ this->polyCheckTbl = NULL;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C2BE0.s")
+/**
+ * Allocate SSNodeList
+ * tblMax is the number of SSNode records to allocate
+ * numPolys is the number of polygons defined within the CollisionHeader
+ */
+void SSNodeList_Alloc(GlobalContext* globalCtx, SSNodeList* this, s32 tblMax, s32 numPolys) {
+ this->max = tblMax;
+ this->count = 0;
+ this->tbl = THA_AllocEndAlign(&globalCtx->state.heap, tblMax * sizeof(SSNode), -2);
+ this->polyCheckTbl = THA_AllocEndAlign16(&globalCtx->state.heap, numPolys * sizeof(u8));
+
+ if (this->polyCheckTbl == NULL) {
+ sprintf(D_801ED950, "this->polygon_check == NULL(game_alloc() MemoryAllocationError.)\n");
+ sprintf(D_801ED9A0, "short_slist_node_size = %d/polygon_num = %d\n", tblMax, numPolys);
+ Fault_AddHungupAndCrashImpl(D_801ED950, D_801ED9A0);
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_SplitScenePolygonsIntoSubdivisions.s")
+/**
+ * Get next SSNodeList SSNode
+ */
+SSNode* SSNodeList_GetNextNode(SSNodeList* this) {
+ SSNode* result = &this->tbl[this->count];
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_GetIsDefaultSpecialScene.s")
+ this->count++;
+ if (!(this->count < this->max)) {
+ return NULL;
+ }
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_GetSpecialSceneMaxMemory.s")
+/**
+ * Get next SSNodeList SSNode index
+ */
+u16 SSNodeList_GetNextNodeIdx(SSNodeList* this) {
+ u16 new_index = this->count++;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_CalcSubdivisionSize.s")
+ return new_index;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_GetSpecialSceneMaxObjects.s")
+/**
+ * Initialize ScaleRotPos
+ */
+void ScaleRotPos_Init(ScaleRotPos* srp) {
+ srp->scale.x = srp->scale.y = srp->scale.z = 1;
+ srp->rot.x = 0;
+ srp->rot.y = 0;
+ srp->rot.z = 0;
+ srp->pos.x = srp->pos.y = srp->pos.z = 0;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_Init.s")
+/**
+ * Set ScaleRotPos
+ */
+void ScaleRotPos_SetValue(ScaleRotPos* srp, Vec3f* scale, Vec3s* rot, Vec3f* pos) {
+ srp->scale = *scale;
+ srp->rot = *rot;
+ srp->pos = *pos;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C3C00.s")
+/**
+ * ScaleRotPos equality test
+ */
+s32 ScaleRotPos_IsEqual(ScaleRotPos* a, ScaleRotPos* b) {
+ if (a->scale.x != b->scale.x || a->scale.y != b->scale.y || a->scale.z != b->scale.z || a->rot.x != b->rot.x ||
+ a->rot.y != b->rot.y || a->rot.z != b->rot.z || a->pos.x != b->pos.x || a->pos.y != b->pos.y ||
+ a->pos.z != b->pos.z) {
+ return false;
+ }
+ return true;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C3C14.s")
+/**
+ * Reset DynaLookup lists
+ */
+void DynaLookup_ResetLists(DynaLookup* dynaLookup) {
+ SSList_SetNull(&dynaLookup->ceiling);
+ SSList_SetNull(&dynaLookup->wall);
+ SSList_SetNull(&dynaLookup->floor);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_GetActorMeshHeader.s")
+/**
+ * Reset DynaLookup
+ */
+void DynaLookup_Reset(DynaLookup* dynaLookup) {
+ dynaLookup->polyStartIndex = 0;
+ DynaLookup_ResetLists(dynaLookup);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C3C94.s")
+/**
+ * Reset vtxStartIndex
+ */
+void DynaLookup_ResetVtxStartIndex(u16* vtxStartIndex) {
+ *vtxStartIndex = 0;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C3D50.s")
+/**
+ * Reset waterBoxStartIndex
+ */
+void DynaLookup_ResetWaterBoxStartIndex(u16* waterBoxStartIndex) {
+ *waterBoxStartIndex = 0;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C3F40.s")
+/**
+ * Initialize BgActor
+ */
+void BgActor_Init(GlobalContext* globalCtx, BgActor* bgActor) {
+ bgActor->actor = NULL;
+ bgActor->colHeader = NULL;
+ ScaleRotPos_Init(&bgActor->prevTransform);
+ ScaleRotPos_Init(&bgActor->curTransform);
+ DynaLookup_Reset(&bgActor->dynaLookup);
+ DynaLookup_ResetVtxStartIndex(&bgActor->vtxStartIndex);
+ DynaLookup_ResetWaterBoxStartIndex(&bgActor->waterboxesStartIndex);
+ bgActor->boundingSphere.center.x = bgActor->boundingSphere.center.y = bgActor->boundingSphere.center.z = 0;
+ bgActor->boundingSphere.radius = 0;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C3FA0.s")
+/**
+ * setActor internal
+ */
+void BgActor_SetActor(BgActor* bgActor, Actor* actor, CollisionHeader* colHeader) {
+ bgActor->actor = actor;
+ bgActor->colHeader = colHeader;
+ bgActor->prevTransform.scale = actor->scale;
+ bgActor->prevTransform.rot = actor->shape.rot;
+ bgActor->prevTransform.rot.x--;
+ bgActor->prevTransform.pos = actor->world.pos;
+ bgActor->curTransform.scale = actor->scale;
+ bgActor->curTransform.rot = actor->shape.rot;
+ bgActor->curTransform.pos = actor->world.pos;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4000.s")
+/**
+ * Test if the BgActor transform is the same
+ */
+s32 BgActor_IsTransformUnchanged(BgActor* bgActor) {
+ return ScaleRotPos_IsEqual(&bgActor->prevTransform, &bgActor->curTransform);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4058.s")
+/**
+ * NULL polyList
+ */
+void DynaPoly_NullPolyList(CollisionPoly** polyList) {
+ *polyList = NULL;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C40B4.s")
+/**
+ * Allocate dyna.polyList
+ */
+void DynaPoly_AllocPolyList(GlobalContext* globalCtx, CollisionPoly** polyList, s32 numPolys) {
+ *polyList = THA_AllocEndAlign(&globalCtx->state.heap, numPolys * sizeof(CollisionPoly), -2);
+}
-f32 func_800C411C(CollisionContext* colCtx, CollisionPoly** arg1, s32* arg2, Actor* actor, Vec3f* pos) {
- return func_800C3D50(0, colCtx, 2, arg1, arg2, pos, actor, 28, 1.0f, 0);
+/**
+ * NULL vtxList
+ */
+void DynaPoly_NullVtxList(Vec3s** vtxList) {
+ *vtxList = NULL;
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4188.s")
+/**
+ * Allocate dyna.vtxList
+ */
+void DynaPoly_AllocVtxList(GlobalContext* globalCtx, Vec3s** vtxList, s32 numVtx) {
+ *vtxList = THA_AllocEndAlign(&globalCtx->state.heap, numVtx * sizeof(Vec3s), -2);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C41E4.s")
+/**
+ * Init dyna.waterBoxList
+ */
+void DynaPoly_InitWaterBoxList(DynaWaterBoxList* waterBoxList) {
+ waterBoxList->unk0 = 0;
+ waterBoxList->boxes = NULL;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4240.s")
+/**
+ * Allocate dyna.waterBoxList
+ */
+void DynaPoly_AllocWaterBoxList(GlobalContext* globalCtx, DynaWaterBoxList* waterBoxList, s32 numWaterBoxes) {
+ waterBoxList->boxes = THA_AllocEndAlign(&globalCtx->state.heap, numWaterBoxes * sizeof(WaterBox), -2);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C42A8.s")
+/**
+ * Update BgActor's prevTransform
+ */
+void DynaPoly_SetBgActorPrevTransform(GlobalContext* globalCtx, BgActor* bgActor) {
+ bgActor->prevTransform = bgActor->curTransform;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4314.s")
+/**
+ * Is BgActor Id
+ */
+s32 DynaPoly_IsBgIdBgActor(s32 bgId) {
+ if (bgId < 0 || bgId >= BG_ACTOR_MAX) {
+ return false;
+ }
+ return true;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C43CC.s")
+/**
+ * Init DynaCollisionContext
+ */
+void DynaPoly_Init(GlobalContext* globalCtx, DynaCollisionContext* dyna) {
+ dyna->bitFlag = DYNAPOLY_INVALIDATE_LOOKUP;
+ DynaPoly_NullPolyList(&dyna->polyList);
+ DynaPoly_NullVtxList(&dyna->vtxList);
+ DynaPoly_InitWaterBoxList(&dyna->waterBoxList);
+ DynaSSNodeList_Init(globalCtx, &dyna->polyNodes);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4488.s")
+/**
+ * Set DynaCollisionContext
+ */
+void DynaPoly_Alloc(GlobalContext* globalCtx, DynaCollisionContext* dyna) {
+ s32 i;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C44F0.s")
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ BgActor_Init(globalCtx, &dyna->bgActors[i]);
+ dyna->bgActorFlags[i] = 0;
+ }
+ DynaPoly_NullPolyList(&dyna->polyList);
+ DynaPoly_AllocPolyList(globalCtx, &dyna->polyList, dyna->polyListMax);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C455C.s")
+ DynaPoly_NullVtxList(&dyna->vtxList);
+ DynaPoly_AllocVtxList(globalCtx, &dyna->vtxList, dyna->vtxListMax);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C45C4.s")
+ DynaPoly_InitWaterBoxList(&dyna->waterBoxList);
+ DynaPoly_AllocWaterBoxList(globalCtx, &dyna->waterBoxList, DYNA_WATERBOX_MAX);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4C74.s")
+ DynaSSNodeList_Init(globalCtx, &dyna->polyNodes);
+ DynaSSNodeList_Alloc(globalCtx, &dyna->polyNodes, dyna->polyNodesMax);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4CD8.s")
+/**
+ * Set BgActor
+ * original name: DynaPolyInfo_setActor
+ */
+s32 DynaPoly_SetBgActor(GlobalContext* globalCtx, DynaCollisionContext* dyna, Actor* actor,
+ CollisionHeader* colHeader) {
+ s32 bgId;
+ s32 foundSlot = false;
+
+ for (bgId = 0; bgId < BG_ACTOR_MAX; bgId++) {
+ if (!(dyna->bgActorFlags[bgId] & 1)) {
+ dyna->bgActorFlags[bgId] |= 1;
+ foundSlot = true;
+ break;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4D3C.s")
+ if (foundSlot == false) {
+ return BG_ACTOR_MAX;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4DA4.s")
+ BgActor_SetActor(&dyna->bgActors[bgId], actor, colHeader);
+ dyna->bitFlag |= DYNAPOLY_INVALIDATE_LOOKUP;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4E10.s")
+ dyna->bgActorFlags[bgId] &= ~2;
+ return bgId;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4F38.s")
+/**
+ * Gets the actor assigned to `bgId`
+ */
+DynaPolyActor* DynaPoly_GetActor(CollisionContext* colCtx, s32 bgId) {
+ if (!DynaPoly_IsBgIdBgActor(bgId) || !(colCtx->dyna.bgActorFlags[bgId] & 1) ||
+ colCtx->dyna.bgActorFlags[bgId] & 2) {
+ return NULL;
+ }
+ return (DynaPolyActor*)colCtx->dyna.bgActors[bgId].actor;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4F84.s")
+void func_800C62BC(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ dyna->bgActorFlags[bgId] |= 4;
+ dyna->bitFlag |= DYNAPOLY_INVALIDATE_LOOKUP;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C4FD4.s")
+void func_800C6314(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ dyna->bgActorFlags[bgId] &= ~4;
+ dyna->bitFlag |= DYNAPOLY_INVALIDATE_LOOKUP;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C5464.s")
+void func_800C636C(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ dyna->bgActorFlags[bgId] |= 8;
+ dyna->bitFlag |= DYNAPOLY_INVALIDATE_LOOKUP;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C54AC.s")
+void func_800C63C4(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ dyna->bgActorFlags[bgId] &= ~8;
+ dyna->bitFlag |= DYNAPOLY_INVALIDATE_LOOKUP;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C5538.s")
+void func_800C641C(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ dyna->bgActorFlags[bgId] |= 0x20;
+ dyna->bitFlag |= DYNAPOLY_INVALIDATE_LOOKUP;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C55C4.s")
+void func_800C6474(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ dyna->bgActorFlags[bgId] &= ~0x20;
+ dyna->bitFlag |= DYNAPOLY_INVALIDATE_LOOKUP;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C5650.s")
+/**
+ * original name: DynaPolyInfo_delReserve
+ */
+void DynaPoly_DeleteBgActor(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ DynaPolyActor* actor;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C56E0.s")
+ if (DynaPoly_IsBgIdBgActor(bgId) == false) {
+ return;
+ }
+ actor = DynaPoly_GetActor(&globalCtx->colCtx, bgId);
+ if (actor != NULL) {
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C576C.s")
+ actor->bgId = BGACTOR_NEG_ONE;
+ dyna->bgActors[bgId].actor = NULL;
+ dyna->bgActorFlags[bgId] |= 2;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C57F8.s")
+void func_800C6554(GlobalContext* globalCtx, DynaCollisionContext* dyna) {
+ dyna->bitFlag |= DYNAPOLY_INVALIDATE_LOOKUP;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C583C.s")
+void BgCheck_CalcWaterboxDimensions(Vec3f* minPos, Vec3f* maxXPos, Vec3f* maxZPos, Vec3s* minPosOut, s16* xLength,
+ s16* zLength) {
+ f32 temp;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C58C8.s")
+ minPosOut->x = minPos->x;
+ minPosOut->y = minPos->y;
+ minPosOut->z = minPos->z;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C5954.s")
+ if (maxXPos->x < minPosOut->x) {
+ minPosOut->x = maxXPos->x;
+ }
+ if (maxXPos->y < minPosOut->y) {
+ minPosOut->y = maxXPos->y;
+ }
+ if (maxXPos->z < minPosOut->z) {
+ minPosOut->z = maxXPos->z;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C5A20.s")
+ if (maxZPos->x < minPosOut->x) {
+ minPosOut->x = maxZPos->x;
+ }
+ if (maxZPos->y < minPosOut->y) {
+ minPosOut->y = maxZPos->y;
+ }
+ if (maxZPos->z < minPosOut->z) {
+ minPosOut->z = maxZPos->z;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C5A64.s")
+ *xLength = minPos->x - minPosOut->x;
+ temp = maxXPos->x - minPosOut->x;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ScenePolygonListsInit.s")
+ if (*xLength < temp) {
+ *xLength = temp;
+ }
+ temp = maxZPos->x - minPosOut->x;
+ if (*xLength < temp) {
+ *xLength = temp;
+ }
+ *zLength = minPos->z - minPosOut->z;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ScenePolygonListsAlloc.s")
+ temp = maxXPos->z - minPosOut->z;
+ if (*zLength < temp) {
+ *zLength = temp;
+ }
+ temp = maxZPos->z - minPosOut->z;
+ if (*zLength < temp) {
+ *zLength = temp;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C5B80.s")
+#ifdef NON_MATCHING
+/**
+ * original name: DynaPolyInfo_expandSRT
+ */
+void DynaPoly_ExpandSRT(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId, s32* vtxStartIndex,
+ s32* polyStartIndex, s32* waterBoxStartIndex) {
+ Actor* actor;
+ s32 pad;
+ s32 pad2;
+ f32 numVtxInverse;
+ s32 i;
+ Vec3f pos; // sp170
+ Sphere16* sphere;
+ Vec3s* dVtxList;
+ Vec3s* point;
+ Vec3f newCenterPoint; // sp158
+
+ f32 newRadiusSq;
+ CollisionHeader* pbgdata;
+ Vec3f newVtx; // sp144
+ Vec3f vtxA; // sp138
+ Vec3f vtxB; // sp12C
+ Vec3f vtxC; // sp120
+ Vec3f newNormal;
+ s32 wi;
+ Vec3f spB8; // waterbox ?
+ Vec3f spAC;
+ Vec3f spA0; // waterbox ?
+ Vec3f sp94;
+ Vec3f sp88; // waterbox ?
+ Vec3f sp7C;
+ WaterBox* waterBox;
+
+ pbgdata = dyna->bgActors[bgId].colHeader;
+ sphere = &dyna->bgActors[bgId].boundingSphere;
+ actor = dyna->bgActors[bgId].actor;
+ dyna->bgActors[bgId].dynaLookup.polyStartIndex = *polyStartIndex;
+ dyna->bgActors[bgId].vtxStartIndex = *vtxStartIndex;
+ dyna->bgActors[bgId].waterboxesStartIndex = *waterBoxStartIndex;
+ pos = actor->world.pos;
+ pos.y += actor->shape.yOffset * actor->scale.y;
+
+ ScaleRotPos_SetValue(&dyna->bgActors[bgId].curTransform, &actor->scale, &actor->shape.rot, &pos);
+
+ if (dyna->bgActorFlags[bgId] & 4) {
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ScenePolygonListsReserveNode.s")
+ if (!(DYNA_WATERBOX_MAX >= *waterBoxStartIndex + pbgdata->numWaterBoxes)) {
+ sprintf(D_801EDAA8, "water_poly Error:[MoveBG OSUGI!!!]");
+ sprintf(D_801EDAF8, "num = %d > %d\n", *waterBoxStartIndex + pbgdata->numWaterBoxes, DYNA_WATERBOX_MAX);
+ Fault_AddHungupAndCrashImpl(D_801EDAA8, D_801EDAF8);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ActorMeshParamsInit.s")
+ if (!(dyna->polyListMax >= *polyStartIndex + pbgdata->numPolygons)) {
+ sprintf(D_801EDAA8, "bg_poly Error:[MoveBG OSUGI!!!]");
+ sprintf(D_801EDAF8, "num = %d > %d\n", *polyStartIndex + pbgdata->numPolygons, dyna->polyListMax);
+ Fault_AddHungupAndCrashImpl(D_801EDAA8, D_801EDAF8);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_SetActorMeshParams.s")
+ if (!(dyna->vtxListMax >= *vtxStartIndex + pbgdata->numVertices)) {
+ sprintf(D_801EDAA8, "bg_vert Error:[MoveBG OSUGI!!!]");
+ sprintf(D_801EDAF8, "num = %d > %d\n", *vtxStartIndex + pbgdata->numVertices, dyna->vtxListMax);
+ Fault_AddHungupAndCrashImpl(D_801EDAA8, D_801EDAF8);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_AreActorMeshParamsEqual.s")
+ if (!(dyna->bitFlag & DYNAPOLY_INVALIDATE_LOOKUP) && BgActor_IsTransformUnchanged(&dyna->bgActors[bgId])) {
+ s32 pi;
+
+ for (pi = *polyStartIndex; pi < *polyStartIndex + pbgdata->numPolygons; pi++) {
+ CollisionPoly* poly = &dyna->polyList[pi];
+ s16 normalY = poly->normal.y;
+
+ if (normalY > COLPOLY_SNORMAL(0.5f)) {
+ if (!(dyna->bgActorFlags[bgId] & 0x20)) {
+ s16 polyIndex = pi;
+
+ DynaSSNodeList_SetSSListHead(&dyna->polyNodes, &dyna->bgActors[bgId].dynaLookup.floor, &polyIndex);
+ }
+ } else if (normalY < COLPOLY_SNORMAL(-0.8f)) {
+ if (!(dyna->bgActorFlags[bgId] & 8)) {
+ s16 polyIndex = pi;
+
+ DynaSSNodeList_SetSSListHead(&dyna->polyNodes, &dyna->bgActors[bgId].dynaLookup.ceiling,
+ &polyIndex);
+ }
+ } else {
+ s16 polyIndex = pi;
+
+ DynaSSNodeList_SetSSListHead(&dyna->polyNodes, &dyna->bgActors[bgId].dynaLookup.wall, &polyIndex);
+ }
+ }
+
+ *polyStartIndex += pbgdata->numPolygons;
+ *vtxStartIndex += pbgdata->numVertices;
+ *waterBoxStartIndex += pbgdata->numWaterBoxes;
+ } else {
+ SkinMatrix_SetScaleRotateYRPTranslate(
+ &D_801EDA40, dyna->bgActors[bgId].curTransform.scale.x, dyna->bgActors[bgId].curTransform.scale.y,
+ dyna->bgActors[bgId].curTransform.scale.z, dyna->bgActors[bgId].curTransform.rot.x,
+ dyna->bgActors[bgId].curTransform.rot.y, dyna->bgActors[bgId].curTransform.rot.z,
+ dyna->bgActors[bgId].curTransform.pos.x, dyna->bgActors[bgId].curTransform.pos.y,
+ dyna->bgActors[bgId].curTransform.pos.z);
+
+ if (pbgdata->numVertices != 0 && pbgdata->numPolygons != 0) {
+ numVtxInverse = 1.0f / pbgdata->numVertices;
+ newCenterPoint.x = newCenterPoint.y = newCenterPoint.z = 0.0f;
+ for (i = 0; i < pbgdata->numVertices; i++) {
+ Vec3f vtx; // spF4
+ Vec3f vtxT; // spE8 Vtx after mtx transform
+
+ Math_Vec3s_ToVec3f(&vtx, &pbgdata->vtxList[i]);
+ SkinMatrix_Vec3fMtxFMultXYZ(&D_801EDA40, &vtx, &vtxT);
+ BgCheck_Vec3fToVec3s(&dyna->vtxList[*vtxStartIndex + i], &vtxT);
+
+ if (i == 0) {
+ dyna->bgActors[bgId].minY = dyna->bgActors[bgId].maxY = vtxT.y;
+ } else if (vtxT.y < dyna->bgActors[bgId].minY) {
+ dyna->bgActors[bgId].minY = vtxT.y;
+ } else if (dyna->bgActors[bgId].maxY < vtxT.y) {
+ dyna->bgActors[bgId].maxY = vtxT.y;
+ }
+ newCenterPoint.x += vtxT.x;
+ newCenterPoint.y += vtxT.y;
+ newCenterPoint.z += vtxT.z;
+ }
+
+ newCenterPoint.x *= numVtxInverse;
+ newCenterPoint.y *= numVtxInverse;
+ newCenterPoint.z *= numVtxInverse;
+ sphere->center.x = newCenterPoint.x;
+ sphere->center.y = newCenterPoint.y;
+ sphere->center.z = newCenterPoint.z;
+ newRadiusSq = -100.0f;
+
+ for (i = 0; i < pbgdata->numVertices; i++) {
+ f32 radiusSq;
+ s32 idx = *vtxStartIndex + i;
+
+ newVtx.x = dyna->vtxList[idx].x;
+ newVtx.y = dyna->vtxList[idx].y;
+ newVtx.z = dyna->vtxList[idx].z;
+ radiusSq = Math3D_Vec3fDistSq(&newVtx, &newCenterPoint);
+ if (newRadiusSq < radiusSq) {
+ newRadiusSq = radiusSq;
+ }
+ }
+
+ sphere->radius = sqrtf(newRadiusSq) * 1.1f;
+
+ for (i = 0; i < pbgdata->numPolygons; i++) {
+ CollisionPoly* newPoly = &dyna->polyList[*polyStartIndex + i];
+ f32 newNormMagnitude;
+ u32 vIA;
+ u32 vIB;
+ u32 vIC;
+
+ *newPoly = pbgdata->polyList[i];
+
+ vIA = (COLPOLY_VTX_INDEX(newPoly->flags_vIA) + *vtxStartIndex);
+ vIB = (COLPOLY_VTX_INDEX(newPoly->flags_vIB) + *vtxStartIndex);
+ vIC = newPoly->vIC + *vtxStartIndex;
+
+ newPoly->flags_vIA = vIA | ((*newPoly).flags_vIA & 0xE000);
+ newPoly->flags_vIB = vIB | ((*newPoly).flags_vIB & 0xE000);
+ newPoly->vIC = vIC;
+ dVtxList = dyna->vtxList;
+ vtxA.x = dVtxList[vIA].x;
+ vtxA.y = dVtxList[vIA].y;
+ vtxA.z = dVtxList[vIA].z;
+ vtxB.x = dVtxList[vIB].x;
+ vtxB.y = dVtxList[vIB].y;
+ vtxB.z = dVtxList[vIB].z;
+ vtxC.x = dVtxList[vIC].x;
+ vtxC.y = dVtxList[vIC].y;
+ vtxC.z = dVtxList[vIC].z;
+ Math3D_SurfaceNorm(&vtxA, &vtxB, &vtxC, &newNormal);
+ newNormMagnitude = Math3D_Vec3fMagnitude(&newNormal);
+
+ if (!IS_ZERO(newNormMagnitude)) {
+ newNormal.x *= (1.0f / newNormMagnitude);
+ newNormal.y *= (1.0f / newNormMagnitude);
+ newNormal.z *= (1.0f / newNormMagnitude);
+ newPoly->normal.x = COLPOLY_SNORMAL(newNormal.x);
+ newPoly->normal.y = COLPOLY_SNORMAL(newNormal.y);
+ newPoly->normal.z = COLPOLY_SNORMAL(newNormal.z);
+ }
+
+ newPoly->dist = -DOTXYZ(newNormal, dVtxList[vIA]);
+ if (newNormal.y > 0.5f) {
+ s16 polyId = *polyStartIndex + i;
+
+ DynaSSNodeList_SetSSListHead(&dyna->polyNodes, &dyna->bgActors[bgId].dynaLookup.floor, &polyId);
+ } else if (newNormal.y < -0.8f) {
+ s16 polyId = *polyStartIndex + i;
+
+ DynaSSNodeList_SetSSListHead(&dyna->polyNodes, &dyna->bgActors[bgId].dynaLookup.ceiling, &polyId);
+ } else {
+ s16 polyId = *polyStartIndex + i;
+
+ DynaSSNodeList_SetSSListHead(&dyna->polyNodes, &dyna->bgActors[bgId].dynaLookup.wall, &polyId);
+ }
+ }
+ }
+
+ for (wi = 0; wi < pbgdata->numWaterBoxes; wi++) {
+ Math_Vec3s_ToVec3f(&spB8, &pbgdata->waterBoxes[wi].minPos);
+ Math_Vec3f_Copy(&spA0, &spB8);
+ spA0.x += pbgdata->waterBoxes[wi].xLength;
+ Math_Vec3f_Copy(&sp88, &spB8);
+ sp88.z += pbgdata->waterBoxes[wi].zLength;
+ SkinMatrix_Vec3fMtxFMultXYZ(&D_801EDA40, &spB8, &spAC);
+ SkinMatrix_Vec3fMtxFMultXYZ(&D_801EDA40, &spA0, &sp94);
+ SkinMatrix_Vec3fMtxFMultXYZ(&D_801EDA40, &sp88, &sp7C);
+ waterBox = &dyna->waterBoxList.boxes[*waterBoxStartIndex + wi];
+ BgCheck_CalcWaterboxDimensions(&spAC, &sp94, &sp7C, &waterBox->minPos, &waterBox->xLength,
+ &waterBox->zLength);
+ waterBox->properties = pbgdata->waterBoxes[wi].properties;
+ }
+
+ *polyStartIndex += pbgdata->numPolygons;
+ *vtxStartIndex += pbgdata->numVertices;
+ *waterBoxStartIndex += pbgdata->numWaterBoxes;
+ }
+}
+#else
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/DynaPoly_ExpandSRT.s")
+#endif
+
+void BgCheck_ResetFlagsIfLoadedActor(GlobalContext* globalCtx, DynaCollisionContext* dyna, Actor* actor) {
+ DynaPolyActor* dynaActor;
+ s32 i;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if ((dyna->bgActorFlags[i] & 1)) {
+ dynaActor = DynaPoly_GetActor(&globalCtx->colCtx, i);
+ if (dynaActor != NULL && &dynaActor->actor == actor) {
+ DynaPolyActor_ResetState((DynaPolyActor*)actor);
+ return;
+ }
+ }
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ActorMeshPolyListsHeadsInit.s")
+/**
+ * original name: DynaPolyInfo_setup
+ */
+void DynaPoly_Setup(GlobalContext* globalCtx, DynaCollisionContext* dyna) {
+ DynaPolyActor* actor;
+ s32 vtxStartIndex;
+ s32 polyStartIndex;
+ s32 waterBoxStartIndex;
+ s32 i;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ActorMeshPolyListsInit.s")
+ DynaSSNodeList_ResetCount(&dyna->polyNodes);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ActorMeshVerticesIndexInit.s")
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ DynaLookup_ResetLists(&dyna->bgActors[i].dynaLookup);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ActorMeshWaterboxesIndexInit.s")
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (dyna->bgActorFlags[i] & 2) {
+ // Initialize BgActor
+ dyna->bgActorFlags[i] = 0;
+ BgActor_Init(globalCtx, &dyna->bgActors[i]);
+ dyna->bitFlag |= DYNAPOLY_INVALIDATE_LOOKUP;
+ }
+ if (dyna->bgActors[i].actor != NULL && dyna->bgActors[i].actor->update == NULL) {
+ // Delete BgActor
+ actor = DynaPoly_GetActor(&globalCtx->colCtx, i);
+ if (actor == NULL) {
+ return;
+ }
+ actor->bgId = BGACTOR_NEG_ONE;
+ dyna->bgActorFlags[i] = 0;
+
+ BgActor_Init(globalCtx, &dyna->bgActors[i]);
+ dyna->bitFlag |= DYNAPOLY_INVALIDATE_LOOKUP;
+ }
+ }
+ vtxStartIndex = 0;
+ polyStartIndex = 0;
+ waterBoxStartIndex = 0;
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if ((dyna->bgActorFlags[i] & 1) && !(dyna->bgActorFlags[i] & 2)) {
+ DynaPoly_ExpandSRT(globalCtx, dyna, i, &vtxStartIndex, &polyStartIndex, &waterBoxStartIndex);
+ }
+ }
+ dyna->bitFlag &= ~DYNAPOLY_INVALIDATE_LOOKUP;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ActorMeshInit.s")
+/**
+ * Compute the number of dynamic resources in use?
+ */
+void func_800C756C(DynaCollisionContext* dyna, s32* numPolygons, s32* numVertices, s32* numWaterBoxes) {
+ s32 i;
+ CollisionHeader* colHeader;
+
+ *numPolygons = 0;
+ *numVertices = 0;
+ *numWaterBoxes = 0;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if ((dyna->bgActorFlags[i] & 1) && !(dyna->bgActorFlags[i] & 2) && !(dyna->bgActorFlags[i] & 4)) {
+ colHeader = dyna->bgActors[i].colHeader;
+ *numPolygons += colHeader->numPolygons;
+ *numVertices += colHeader->numVertices;
+ *numWaterBoxes += colHeader->numWaterBoxes;
+ }
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ActorMeshInitFromActor.s")
+/**
+ * Update all BgActor's previous ScaleRotPos
+ */
+void DynaPoly_UpdateBgActorTransforms(GlobalContext* globalCtx, DynaCollisionContext* dyna) {
+ s32 i;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_HasActorMeshChanged.s")
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (dyna->bgActorFlags[i] & 1) {
+ DynaPoly_SetBgActorPrevTransform(globalCtx, &dyna->bgActors[i]);
+ }
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_PolygonsInit.s")
+/**
+ * Perform dyna poly raycast toward floor on a list of floor, wall, or ceiling polys
+ * `listType` specifies the poly list type (e.g. DYNA_RAYCAST_FLOORS)
+ */
+f32 BgCheck_RaycastFloorDynaList(DynaRaycast* dynaRaycast, u32 listType) {
+ CollisionPoly* polyList;
+ SSNode* curNode;
+ f32 result;
+ f32 yIntersect;
+ s16 id;
+
+ result = dynaRaycast->yIntersect;
+ if (dynaRaycast->ssList->head == SS_NULL) {
+ return result;
+ }
+ polyList = dynaRaycast->dyna->polyList;
+ curNode = &dynaRaycast->dyna->polyNodes.tbl[dynaRaycast->ssList->head];
+
+ while (true) {
+ id = curNode->polyId;
+ if (COLPOLY_VIA_FLAG_TEST(polyList[id].flags_vIA, dynaRaycast->xpFlags) ||
+ (COLPOLY_VIA_FLAG_TEST(polyList[id].flags_vIB, 4) &&
+ ((dynaRaycast->actor != NULL && dynaRaycast->actor->category != ACTORCAT_PLAYER) ||
+ (dynaRaycast->actor == NULL && dynaRaycast->xpFlags != COLPOLY_IGNORE_CAMERA))) ||
+ ((dynaRaycast->unk_24 & 0x20) && func_800C9B68(dynaRaycast->colCtx, &polyList[id], dynaRaycast->unk1C))) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dynaRaycast->dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ if ((listType & (DYNA_RAYCAST_WALLS | DYNA_RAYCAST_CEILINGS)) && (dynaRaycast->unk_24 & 0x10) &&
+ COLPOLY_GET_NORMAL(polyList[id].normal.y) < 0.0f) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dynaRaycast->dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ if (CollisionPoly_CheckYIntersectApprox1(&polyList[id], dynaRaycast->dyna->vtxList, dynaRaycast->pos->x,
+ dynaRaycast->pos->z, &yIntersect, dynaRaycast->checkDist) &&
+ yIntersect < dynaRaycast->pos->y && result < yIntersect) {
+ result = yIntersect;
+ *dynaRaycast->resultPoly = &dynaRaycast->dyna->polyList[id];
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dynaRaycast->dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_PolygonsAlloc.s")
+#ifdef NON_MATCHING
+/**
+ * Perform dyna poly raycast toward floor
+ * returns the yIntersect of the poly found, or BGCHECK_Y_MIN if no poly is found
+ */
+f32 BgCheck_RaycastFloorDyna(DynaRaycast* dynaRaycast) {
+ s32 i;
+ f32 result;
+ f32 intersect2;
+ s32 i2;
+ s32 pauseState;
+ DynaPolyActor* dynaActor;
+ s32 pad;
+ Vec3f polyVtx[3];
+ Vec3f polyNorm;
+ u32 polyIndex;
+ CollisionPoly* polyMin;
+ MtxF srpMtx;
+ f32 magnitude;
+ Vec3s* vtxList;
+ f32 polyDist;
+ Vec3f vtx;
+ f32 intersect;
+ ScaleRotPos* curTransform;
+ CollisionPoly* poly;
+
+ result = BGCHECK_Y_MIN;
+ *dynaRaycast->bgId = BGCHECK_SCENE;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (!(dynaRaycast->colCtx->dyna.bgActorFlags[i] & 1) || (dynaRaycast->colCtx->dyna.bgActorFlags[i] & 2)) {
+ continue;
+ }
+
+ if (dynaRaycast->actor == dynaRaycast->colCtx->dyna.bgActors[i].actor ||
+ dynaRaycast->pos->y < dynaRaycast->colCtx->dyna.bgActors[i].minY ||
+ !Math3D_XZInSphere(&dynaRaycast->colCtx->dyna.bgActors[i].boundingSphere, dynaRaycast->pos->x,
+ dynaRaycast->pos->z)) {
+ continue;
+ }
+
+ dynaRaycast->unk1C = i;
+ dynaRaycast->dyna = &dynaRaycast->colCtx->dyna;
+ if (dynaRaycast->unk_24 & BGCHECK_IGNORE_FLOOR) {
+ dynaRaycast->ssList = &dynaRaycast->colCtx->dyna.bgActors[i].dynaLookup.floor;
+ intersect2 = BgCheck_RaycastFloorDynaList(dynaRaycast, DYNA_RAYCAST_FLOORS);
+
+ if (dynaRaycast->yIntersect < intersect2) {
+ dynaRaycast->yIntersect = intersect2;
+ *dynaRaycast->bgId = i;
+ result = intersect2;
+ }
+ }
+ if ((dynaRaycast->unk_24 & BGCHECK_IGNORE_WALL) ||
+ (*dynaRaycast->resultPoly == NULL && (dynaRaycast->unk_24 & 8))) {
+ dynaRaycast->ssList = &dynaRaycast->colCtx->dyna.bgActors[i].dynaLookup.wall;
+ intersect2 = BgCheck_RaycastFloorDynaList(dynaRaycast, DYNA_RAYCAST_WALLS);
+ if (dynaRaycast->yIntersect < intersect2) {
+
+ dynaRaycast->yIntersect = intersect2;
+ *dynaRaycast->bgId = i;
+ result = intersect2;
+ }
+ }
+
+ if (dynaRaycast->unk_24 & BGCHECK_IGNORE_CEILING) {
+ dynaRaycast->ssList = &dynaRaycast->colCtx->dyna.bgActors[i].dynaLookup.ceiling;
+ intersect2 = BgCheck_RaycastFloorDynaList(dynaRaycast, DYNA_RAYCAST_CEILINGS);
+ if (dynaRaycast->yIntersect < intersect2) {
+
+ dynaRaycast->yIntersect = intersect2;
+ *dynaRaycast->bgId = i;
+ result = intersect2;
+ }
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_VerticesInit.s")
+ dynaActor = DynaPoly_GetActor(dynaRaycast->colCtx, *dynaRaycast->bgId);
+ if ((result != BGCHECK_Y_MIN) && (dynaActor != NULL) && (dynaRaycast->globalCtx != NULL)) {
+ pauseState = dynaRaycast->globalCtx->pauseCtx.state != 0;
+ if (!pauseState) {
+ pauseState = dynaRaycast->globalCtx->pauseCtx.debugState != 0;
+ }
+ if (!pauseState && (dynaRaycast->colCtx->dyna.bgActorFlags[*dynaRaycast->bgId] & 2)) {
+ curTransform = &dynaRaycast->dyna->bgActors[*dynaRaycast->bgId].curTransform;
+ polyMin = &dynaRaycast->dyna
+ ->polyList[(u16)dynaRaycast->dyna->bgActors[*dynaRaycast->bgId].dynaLookup.polyStartIndex];
+ polyIndex = *dynaRaycast->resultPoly - polyMin;
+ poly = &dynaRaycast->dyna->bgActors[*dynaRaycast->bgId].colHeader->polyList[polyIndex];
+
+ SkinMatrix_SetScaleRotateYRPTranslate(&srpMtx, curTransform->scale.x, curTransform->scale.y,
+ curTransform->scale.z, curTransform->rot.x, curTransform->rot.y,
+ curTransform->rot.z, curTransform->pos.x, curTransform->pos.y,
+ curTransform->pos.z);
+
+ vtxList = dynaRaycast->dyna->bgActors[*dynaRaycast->bgId].colHeader->vtxList;
+
+ for (i2 = 0; i2 < 3; i2++) {
+ Math_Vec3s_ToVec3f(&vtx, &vtxList[COLPOLY_VTX_INDEX(poly->vtxData[i2])]);
+ SkinMatrix_Vec3fMtxFMultXYZ(&srpMtx, &vtx, &polyVtx[i2]);
+ }
+ Math3D_SurfaceNorm(&polyVtx[0], &polyVtx[1], &polyVtx[2], &polyNorm);
+ magnitude = Math3D_Vec3fMagnitude(&polyNorm);
+
+ if (!IS_ZERO(magnitude)) {
+ polyNorm.x *= 1.0f / magnitude;
+ polyNorm.y *= 1.0f / magnitude;
+ polyNorm.z *= 1.0f / magnitude;
+ polyDist = -DOTXYZ(polyNorm, polyVtx[0]);
+ if (Math3D_TriChkPointParaYIntersectInsideTri(
+ &polyVtx[0], &polyVtx[1], &polyVtx[2], polyNorm.x, polyNorm.y, polyNorm.z, polyDist,
+ dynaRaycast->pos->z, dynaRaycast->pos->x, &intersect, dynaRaycast->checkDist)) {
+ if (fabsf(intersect - result) < 1.0f) {
+
+ result = intersect;
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+#else
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_RaycastFloorDyna.s")
+#endif
+
+#ifdef NON_MATCHING
+// regalloc, minor instruction ordering
+/**
+ * Performs collision detection on a BgActor's wall polys on sphere `pos`, `radius`
+ * returns true if a collision was detected
+ * `outX` `outZ` return the displaced x,z coordinates
+ * `outPoly` returns the pointer to the nearest poly collided with, or NULL
+ * `outBgId` returns `bgId` if the poly SurfaceType's wall damage flag is not set, else ?
+ */
+s32 BgCheck_SphVsDynaWallInBgActor(CollisionContext* colCtx, u16 xpFlags, DynaCollisionContext* dyna, SSList* ssList,
+ f32* outX, f32* outZ, CollisionPoly** outPoly, s32* outBgId, Vec3f* pos, f32 radius,
+ s32 bgId, Actor* actor) {
+ f32 temp;
+ f32 intersect;
+ s32 result = false;
+ CollisionPoly* poly;
+ SSNode* curNode;
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ Vec3f resultPos;
+ s16 polyId;
+ f32 zTemp;
+ f32 xTemp;
+ f32 normalXZ;
+ f32 invNormalXZ;
+ f32 planeDist;
+ f32 temp_f18;
+ f32 zIntersectDist;
+ f32 xIntersectDist;
+ f32 zMin;
+ f32 zMax;
+ f32 xMin;
+ f32 xMax;
+
+ if (ssList->head == SS_NULL) {
+ return result;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_VerticesListAlloc.s")
+ resultPos = *pos;
+ curNode = &dyna->polyNodes.tbl[ssList->head];
+
+ while (true) {
+ polyId = curNode->polyId;
+ poly = &dyna->polyList[polyId];
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
+ normalXZ = sqrtf(SQ(nx) + SQ(nz));
+
+ planeDist = Math3D_DistPlaneToPos(nx, ny, nz, poly->dist, &resultPos);
+ if (radius < fabsf(planeDist) || COLPOLY_VIA_FLAG_TEST(poly->flags_vIA, xpFlags) ||
+ ((COLPOLY_VIA_FLAG_TEST(poly->flags_vIB, 4)) && ((actor != NULL && actor->category != ACTORCAT_PLAYER) ||
+ (actor == NULL && xpFlags != COLPOLY_IGNORE_CAMERA)))) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ invNormalXZ = 1.0f / normalXZ;
+ temp_f18 = fabsf(nz) * invNormalXZ;
+ if (temp_f18 < 0.4f) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+
+ // compute poly zMin/zMax
+ zTemp = dyna->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)].z;
+ zMax = zMin = zTemp;
+
+ zTemp = dyna->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)].z;
+ if (zTemp < zMin) {
+ zMin = zTemp;
+ } else if (zTemp > zMax) {
+ zMax = zTemp;
+ }
+
+ zTemp = dyna->vtxList[poly->vIC].z;
+ if (zTemp < zMin) {
+ zMin = zTemp;
+ } else if (zMax < zTemp) {
+ zMax = zTemp;
+ }
+
+ zMin -= radius;
+ zMax += radius;
+ if (resultPos.z < zMin || zMax < resultPos.z) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ if (CollisionPoly_CheckZIntersectApprox(poly, dyna->vtxList, resultPos.x, pos->y, &intersect)) {
+ if (fabsf(intersect - resultPos.z) <= radius / temp_f18) {
+ if ((intersect - resultPos.z) * nz <= 4.0f) {
+ if (BgCheck_ComputeWallDisplacement(colCtx, poly, &resultPos.x, &resultPos.z, nx, ny, nz,
+ invNormalXZ, planeDist, radius, outPoly)) {
+ *outBgId = bgId;
+ }
+ result = true;
+ }
+ }
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_WaterboxListInit.s")
+ curNode = &dyna->polyNodes.tbl[ssList->head];
+ while (true) {
+ polyId = curNode->polyId;
+ poly = &dyna->polyList[polyId];
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
+ normalXZ = sqrtf(SQ(nx) + SQ(nz));
+
+ planeDist = Math3D_DistPlaneToPos(nx, ny, nz, poly->dist, &resultPos);
+ if (radius < fabsf(planeDist) || COLPOLY_VIA_FLAG_TEST(poly->flags_vIA, xpFlags) ||
+ (COLPOLY_VIA_FLAG_TEST(poly->flags_vIB, 4) && ((actor != NULL && actor->category != ACTORCAT_PLAYER) ||
+ (actor == NULL && xpFlags != COLPOLY_IGNORE_CAMERA)))) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+
+ invNormalXZ = 1.0f / normalXZ;
+ temp_f18 = fabsf(nx) * invNormalXZ;
+ if (temp_f18 < 0.4f) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+
+ // compute poly xMin/xMax
+ xTemp = dyna->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)].x;
+ xMax = xMin = xTemp;
+ xTemp = dyna->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)].x;
+
+ if (xTemp < xMin) {
+ xMin = xTemp;
+ } else if (xMax < xTemp) {
+ xMax = xTemp;
+ }
+ xTemp = dyna->vtxList[poly->vIC].x;
+ if (xTemp < xMin) {
+ xMin = xTemp;
+ } else if (xMax < xTemp) {
+ xMax = xTemp;
+ }
+
+ xMin -= radius;
+ xMax += radius;
+ if (resultPos.x < xMin || xMax < resultPos.x) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+
+ if (CollisionPoly_CheckXIntersectApprox(poly, dyna->vtxList, pos->y, resultPos.z, &intersect)) {
+ xIntersectDist = intersect - resultPos.x;
+ if (fabsf(xIntersectDist) <= radius / temp_f18) {
+ if (xIntersectDist * nx <= 4.0f) {
+ if (BgCheck_ComputeWallDisplacement(colCtx, poly, &resultPos.x, &resultPos.z, nx, ny, nz,
+ invNormalXZ, planeDist, radius, outPoly)) {
+ *outBgId = bgId;
+ }
+ result = true;
+ }
+ }
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ }
+ *outX = resultPos.x;
+ *outZ = resultPos.z;
+ return result;
+}
+#else
+s32 BgCheck_SphVsDynaWallInBgActor(CollisionContext* colCtx, u16 xpFlags, DynaCollisionContext* dyna, SSList* ssList,
+ f32* outX, f32* outZ, CollisionPoly** outPoly, s32* outBgId, Vec3f* pos, f32 radius,
+ s32 bgId, Actor* actor);
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_SphVsDynaWallInBgActor.s")
+#endif
+
+/**
+ * Performs collision detection on all dyna poly walls using sphere `pos`, `radius`
+ * returns true if a collision was detected
+ * `outX` `outZ` return the displaced x,z coordinates
+ * `outPoly` returns the pointer to the nearest poly collided with, or NULL
+ * `outBgId` returns the index of the BgActor that owns `outPoly`
+ * If `actor` is not NULL, an BgActor bound to that actor will be ignored
+ */
+s32 BgCheck_SphVsDynaWall(CollisionContext* colCtx, u16 xpFlags, f32* outX, f32* outZ, Vec3f* pos, f32 radius,
+ CollisionPoly** outPoly, s32* outBgId, Actor* actor) {
+ Vec3f resultPos;
+ s32 result;
+ f32 r;
+ f32 dz;
+ f32 dx;
+ BgActor* bgActor;
+ s32 i;
+
+ result = false;
+ resultPos = *pos;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (!(colCtx->dyna.bgActorFlags[i] & 1) || (colCtx->dyna.bgActorFlags[i] & 2)) {
+ continue;
+ }
+ if ((colCtx->dyna.bgActors + i)->actor == actor) {
+ continue;
+ }
+ bgActor = &colCtx->dyna.bgActors[i];
+
+ if (bgActor->minY > resultPos.y || bgActor->maxY < resultPos.y) {
+ continue;
+ }
+
+ bgActor->boundingSphere.radius += (s16)radius;
+
+ r = bgActor->boundingSphere.radius;
+ dx = bgActor->boundingSphere.center.x - resultPos.x;
+ dz = bgActor->boundingSphere.center.z - resultPos.z;
+ if (SQ(r) < (SQ(dx) + SQ(dz)) || (!Math3D_XYInSphere(&bgActor->boundingSphere, resultPos.x, resultPos.y) &&
+ !Math3D_YZInSphere(&bgActor->boundingSphere, resultPos.y, resultPos.z))) {
+ bgActor->boundingSphere.radius -= (s16)radius;
+ continue;
+ }
+ bgActor->boundingSphere.radius -= (s16)radius;
+ if (BgCheck_SphVsDynaWallInBgActor(colCtx, xpFlags, &colCtx->dyna,
+ &(colCtx->dyna.bgActors + i)->dynaLookup.wall, outX, outZ, outPoly, outBgId,
+ &resultPos, radius, i, actor)) {
+ resultPos.x = *outX;
+ resultPos.z = *outZ;
+ result = true;
+ }
+ }
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_WaterboxListAlloc.s")
+/**
+ * Tests for collision with a dyna poly ceiling, starting at `ssList`
+ * returns true if a collision occurs, else false
+ * `outPoly` returns the poly collided with
+ * `outY` returns the y coordinate needed to not collide with `outPoly`
+ */
+s32 BgCheck_CheckDynaCeilingList(CollisionContext* colCtx, u16 xpFlags, DynaCollisionContext* dyna, SSList* ssList,
+ f32* outY, Vec3f* pos, f32 checkHeight, CollisionPoly** outPoly, Actor* actor,
+ s32 bgId) {
+ s16 polyId;
+ SSNode* curNode;
+ CollisionPoly* poly;
+ Vec3f testPos;
+ f32 ceilingY;
+ f32 sign;
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ s32 result = false;
+ f32 intersectDist;
+ u16 padding;
+
+ if (ssList->head == SS_NULL) {
+ return false;
+ }
+ curNode = &dyna->polyNodes.tbl[ssList->head];
+ testPos = *pos;
+
+ while (true) {
+ polyId = curNode->polyId;
+ poly = &dyna->polyList[polyId];
+ if (COLPOLY_VIA_FLAG_TEST(poly->flags_vIA, xpFlags) ||
+ (COLPOLY_VIA_FLAG_TEST(poly->flags_vIB, 4) && ((actor != NULL && actor->category != ACTORCAT_PLAYER) ||
+ (actor == NULL && xpFlags != COLPOLY_IGNORE_CAMERA)))) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
+ if (checkHeight < Math3D_UDistPlaneToPos(nx, ny, nz, poly->dist, &testPos)) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ if (CollisionPoly_CheckYIntersectApprox2(poly, dyna->vtxList, testPos.x, testPos.z, &ceilingY)) {
+ intersectDist = ceilingY - testPos.y;
+ if (testPos.y < ceilingY && intersectDist < checkHeight && intersectDist * ny <= 0.0f) {
+ sign = (0.0f <= ny) ? 1.0f : -1.0f;
+ testPos.y = (sign * checkHeight) + ceilingY;
+ result = true;
+ *outPoly = poly;
+ }
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ *outY = testPos.y;
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ActorMeshUpdateParams.s")
+/**
+ * Tests collision with a dyna poly ceiling
+ * returns true if a collision occurs, else false
+ * `outPoly` returns the poly collided with, while `outBgId` returns the id of the BgActor that owns the poly
+ * `outY` returns the y coordinate needed to not collide with `outPoly`, or `pos`.y + `checkDist` if no collision occurs
+ */
+s32 BgCheck_CheckDynaCeiling(CollisionContext* colCtx, u16 xpFlags, f32* outY, Vec3f* pos, f32 checkDist,
+ CollisionPoly** outPoly, s32* outBgId, Actor* actor) {
+ s32 i;
+ s32 result = false;
+ f32 resultY;
+ f32 tempY = checkDist + pos->y;
+ BgActor* bgActor;
+ CollisionPoly* poly;
+
+ resultY = tempY;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (!(colCtx->dyna.bgActorFlags[i] & 1) || (colCtx->dyna.bgActorFlags[i] & 2)) {
+ continue;
+ }
+ if (actor == colCtx->dyna.bgActors[i].actor) {
+ continue;
+ }
+ if (!Math3D_XZInSphere(&colCtx->dyna.bgActors[i].boundingSphere, pos->x, pos->z)) {
+ continue;
+ }
+ if (BgCheck_CheckDynaCeilingList(colCtx, xpFlags, &colCtx->dyna, &colCtx->dyna.bgActors[i].dynaLookup.ceiling,
+ &tempY, pos, checkDist, &poly, actor, i) &&
+ tempY < resultY) {
+
+ resultY = tempY;
+ *outPoly = poly;
+ *outBgId = i;
+ result = true;
+ }
+ }
+ *outY = resultY;
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_IsActorMeshIndexValid.s")
+/**
+ * Tests if DynaLineTest intersects with a poly
+ * returns true if a poly was intersected, else false
+ */
+s32 BgCheck_CheckLineAgainstBgActorSSList(DynaLineTest* dynaLineTest) {
+ f32 distSq;
+ s32 result;
+ SSNode* curNode;
+ Vec3f polyIntersect;
+ s16 polyId;
+ BgLineVsPolyTest test;
+
+ result = false;
+ if (dynaLineTest->ssList->head == SS_NULL) {
+ return result;
+ }
+ curNode = &dynaLineTest->dyna->polyNodes.tbl[dynaLineTest->ssList->head];
+
+ test.vtxList = dynaLineTest->dyna->vtxList;
+ test.posA = dynaLineTest->posA;
+ test.posB = dynaLineTest->posB;
+ test.planeIntersect = &polyIntersect;
+ test.checkOneFace = dynaLineTest->checkOneFace;
+ test.checkDist = dynaLineTest->checkDist;
+
+ while (true) {
+ polyId = curNode->polyId;
+ test.poly = &dynaLineTest->dyna->polyList[polyId];
+ if (COLPOLY_VIA_FLAG_TEST(test.poly->flags_vIA, dynaLineTest->xpFlags) ||
+ (COLPOLY_VIA_FLAG_TEST(test.poly->flags_vIB, 4) &&
+ ((dynaLineTest->actor != NULL && dynaLineTest->actor->category != ACTORCAT_PLAYER) ||
+ (dynaLineTest->actor == NULL && dynaLineTest->xpFlags != COLPOLY_IGNORE_CAMERA)))) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dynaLineTest->dyna->polyNodes.tbl[curNode->next];
+ }
+ } else {
+ if (CollisionPoly_LineVsPoly(&test)) {
+ distSq = Math3D_Vec3fDistSq(dynaLineTest->posA, test.planeIntersect);
+ if (distSq < *dynaLineTest->distSq) {
+ *dynaLineTest->distSq = distSq;
+ *dynaLineTest->posResult = *test.planeIntersect;
+ *dynaLineTest->posB = *test.planeIntersect;
+ *dynaLineTest->resultPoly = test.poly;
+ result = true;
+ }
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dynaLineTest->dyna->polyNodes.tbl[curNode->next];
+ }
+ }
+ }
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_DynaInit.s")
+/**
+ * Tests if line `posA` `posB` intersects with a dyna poly within BgActor `bgId`
+ * `distSq` is the maximum squared distance to check for a collision
+ * returns true if an intersection occurred, else false
+ * `posB`? and `posResult` return the point of intersection
+ * `outPoly` returns the poly intersected
+ * `distSq` returns the squared distance of the intersection
+ */
+s32 BgCheck_CheckLineAgainstBgActor(CollisionContext* colCtx, u16 xpFlags, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, f32* distSq, s32 bgId, f32 checkDist, s32 bccFlags,
+ Actor* actor) {
+ s32 result = false;
+ DynaLineTest dynaLineTest;
+
+ dynaLineTest.colCtx = colCtx;
+ dynaLineTest.xpFlags = xpFlags;
+ dynaLineTest.dyna = &colCtx->dyna;
+ dynaLineTest.posA = posA;
+ dynaLineTest.posB = posB;
+ dynaLineTest.posResult = posResult;
+ dynaLineTest.resultPoly = outPoly;
+ dynaLineTest.checkOneFace = (bccFlags & BGCHECK_CHECK_ONE_FACE) != 0;
+ dynaLineTest.distSq = distSq;
+ dynaLineTest.checkDist = checkDist;
+ dynaLineTest.actor = actor;
+ dynaLineTest.bgId = bgId;
+
+ dynaLineTest.ssList = &colCtx->dyna.bgActors[bgId].dynaLookup.wall;
+ if (bccFlags & BGCHECK_CHECK_WALL) {
+ if (BgCheck_CheckLineAgainstBgActorSSList(&dynaLineTest)) {
+ result = true;
+ }
+ }
+ dynaLineTest.ssList = &colCtx->dyna.bgActors[bgId].dynaLookup.floor;
+ if (bccFlags & BGCHECK_CHECK_FLOOR) {
+ if (BgCheck_CheckLineAgainstBgActorSSList(&dynaLineTest)) {
+ result = true;
+ }
+ }
+ dynaLineTest.ssList = &colCtx->dyna.bgActors[bgId].dynaLookup.ceiling;
+ if (bccFlags & BGCHECK_CHECK_CEILING) {
+ if (BgCheck_CheckLineAgainstBgActorSSList(&dynaLineTest)) {
+ result = true;
+ }
+ }
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_DynaAlloc.s")
+/**
+ * Tests if line from `posA` to `posB` passes through a dyna poly.
+ * returns true if so, otherwise false
+ * `outPoly` returns the pointer of the poly intersected.
+ * `outBgId` returns the BgActor index of the poly
+ */
+s32 BgCheck_CheckLineAgainstDyna(CollisionContext* colCtx, u16 xpFlags, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, f32* distSq, s32* outBgId, Actor* actor, f32 checkDist,
+ s32 bccFlags) {
+ s32 pad;
+ s32 i;
+ s32 result = false;
+ LineSegment line;
+ f32 ay;
+ f32 by;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if ((colCtx->dyna.bgActorFlags[i] & 1) && !(colCtx->dyna.bgActorFlags[i] & 2)) {
+ if (actor != colCtx->dyna.bgActors[i].actor) {
+ ay = posA->y;
+ by = posB->y;
+ if (!(ay < colCtx->dyna.bgActors[i].minY) || !(by < colCtx->dyna.bgActors[i].minY)) {
+ if (!(colCtx->dyna.bgActors[i].maxY < ay) || !(colCtx->dyna.bgActors[i].maxY < by)) {
+ line.a = *posA;
+ line.b = *posB;
+ if (Math3D_LineVsSph(&colCtx->dyna.bgActors[i].boundingSphere, &line) != 0) {
+ if (BgCheck_CheckLineAgainstBgActor(colCtx, xpFlags, posA, posB, posResult, outPoly, distSq,
+ i, checkDist, bccFlags, actor)) {
+ *outBgId = i;
+ result = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_AddActorMesh.s")
+/**
+ * Get first dyna poly intersecting sphere `center` `radius` from list `ssList`
+ * returns true if any poly intersects the sphere, else returns false
+ * `outPoly` returns the pointer of the first poly found that intersects
+ */
+s32 BgCheck_SphVsFirstDynaPolyList(CollisionContext* colCtx, u16 xpFlags, CollisionPoly** outPoly, Vec3f* center,
+ f32 radius, SSList* ssList, Actor* actor, s32 bgId) {
+ CollisionPoly* curPoly;
+ DynaCollisionContext* dyna;
+ SSNode* curNode;
+ s32 curPolyId;
+
+ if (ssList->head == SS_NULL) {
+ return false;
+ }
+ dyna = &colCtx->dyna;
+ curNode = &dyna->polyNodes.tbl[ssList->head];
+ while (true) {
+ curPolyId = curNode->polyId;
+ curPoly = &dyna->polyList[curPolyId];
+ if (COLPOLY_VIA_FLAG_TEST(curPoly->flags_vIA, xpFlags) ||
+ (COLPOLY_VIA_FLAG_TEST(curPoly->flags_vIB, 4) && ((actor != NULL && actor->category != ACTORCAT_PLAYER) ||
+ (actor == NULL && xpFlags != COLPOLY_IGNORE_CAMERA))))
+
+ {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ if (CollisionPoly_SphVsPoly(curPoly, dyna->vtxList, center, radius)) {
+ *outPoly = curPoly;
+ return true;
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_GetActorOfMesh.s")
+/**
+ * Get first dyna poly intersecting sphere `center` `radius` from BgActor `bgId`
+ * returns true if any poly intersects the sphere, else false
+ * `outPoly` returns the pointer of the first poly found that intersects
+ */
+s32 BgCheck_SphVsFirstDynaPolyInBgActor(CollisionContext* colCtx, u16 xpFlags, CollisionPoly** outPoly, Vec3f* center,
+ f32 radius, s32 bgId, u16 bciFlags, Actor* actor) {
+ if (!(bciFlags & BGCHECK_IGNORE_CEILING)) {
+ if (BgCheck_SphVsFirstDynaPolyList(colCtx, xpFlags, outPoly, center, radius,
+ &colCtx->dyna.bgActors[bgId].dynaLookup.ceiling, actor, bgId)) {
+ return true;
+ }
+ }
+ if (!(bciFlags & BGCHECK_IGNORE_WALL)) {
+ if (BgCheck_SphVsFirstDynaPolyList(colCtx, xpFlags, outPoly, center, radius,
+ &colCtx->dyna.bgActors[bgId].dynaLookup.wall, actor, bgId)) {
+ return true;
+ }
+ }
+ if (!(bciFlags & BGCHECK_IGNORE_FLOOR)) {
+ if (BgCheck_SphVsFirstDynaPolyList(colCtx, xpFlags, outPoly, center, radius,
+ &colCtx->dyna.bgActors[bgId].dynaLookup.floor, actor, bgId)) {
+ return true;
+ }
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C62BC.s")
+/**
+ * Gets first dyna poly intersecting sphere `center` `radius`
+ * returns true if poly detected, else false
+ * `outPoly` returns the first intersecting poly, while `outBgId` returns the BgActor index of that poly
+ */
+s32 BgCheck_SphVsFirstDynaPoly(CollisionContext* colCtx, u16 xpFlags, CollisionPoly** outPoly, s32* outBgId,
+ Vec3f* center, f32 radius, Actor* actor, u16 bciFlags) {
+ s32 i = 0;
+ Sphere16 testSphere;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (!(colCtx->dyna.bgActorFlags[i] & 1) || (colCtx->dyna.bgActorFlags[i] & 2)) {
+ continue;
+ }
+ if (colCtx->dyna.bgActors[i].actor == actor) {
+ continue;
+ }
+ testSphere.center.x = center->x;
+ testSphere.center.y = center->y;
+ testSphere.center.z = center->z;
+ testSphere.radius = radius;
+ if (!Math3D_SphVsSph(&testSphere, &colCtx->dyna.bgActors[i].boundingSphere)) {
+ continue;
+ }
+ if (BgCheck_SphVsFirstDynaPolyInBgActor(colCtx, xpFlags, outPoly, center, radius, i, bciFlags, actor)) {
+ return true;
+ }
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C6314.s")
+/**
+ * SEGMENTED_TO_VIRTUAL CollisionHeader members
+ */
+void CollisionHeader_SegmentedToVirtual(CollisionHeader* colHeader) {
+ colHeader->vtxList = Lib_SegmentedToVirtual(colHeader->vtxList);
+ colHeader->polyList = Lib_SegmentedToVirtual(colHeader->polyList);
+ if (colHeader->surfaceTypeList) {
+ colHeader->surfaceTypeList = Lib_SegmentedToVirtual(colHeader->surfaceTypeList);
+ }
+ if (colHeader->cameraDataList) {
+ colHeader->cameraDataList = Lib_SegmentedToVirtual(colHeader->cameraDataList);
+ }
+ if (colHeader->waterBoxes) {
+ colHeader->waterBoxes = Lib_SegmentedToVirtual(colHeader->waterBoxes);
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C636C.s")
+/**
+ * Convert CollisionHeader Segmented to Virtual addressing
+ */
+void CollisionHeader_GetVirtual(CollisionHeader* colHeader, CollisionHeader** dest) {
+ *dest = Lib_SegmentedToVirtual(colHeader);
+ CollisionHeader_SegmentedToVirtual(*dest);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C63C4.s")
+/**
+ * SEGMENT_TO_VIRTUAL all active BgActor CollisionHeaders
+ */
+void BgCheck_InitCollisionHeaders(CollisionContext* colCtx, GlobalContext* globalCtx) {
+ DynaCollisionContext* dyna = &colCtx->dyna;
+ s32 i;
+ u16 flag;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ flag = dyna->bgActorFlags[i];
+ if ((flag & 1) && !(flag & 2)) {
+ Actor_SetObjectSegment(globalCtx, dyna->bgActors[i].actor);
+ CollisionHeader_SegmentedToVirtual(dyna->bgActors[i].colHeader);
+ }
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C641C.s")
+/**
+ * Reset SSNodeList polyCheckTbl
+ */
+void BgCheck_ResetPolyCheckTbl(SSNodeList* nodeList, s32 numPolys) {
+ u8* end = nodeList->polyCheckTbl + numPolys;
+ u8* t;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C6474.s")
+ for (t = nodeList->polyCheckTbl; t < end; t++) {
+ *t = 0;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_RemoveActorMesh.s")
+/**
+ * Get SurfaceType property set
+ */
+u32 SurfaceType_GetData(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId, s32 dataIdx) {
+ CollisionHeader* colHeader;
+ SurfaceType* surfaceTypes;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C6554.s")
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if (colHeader == NULL || poly == NULL) {
+ return 0;
+ }
+ surfaceTypes = colHeader->surfaceTypeList;
+ if (surfaceTypes == NULL) {
+ return 0;
+ }
+ return surfaceTypes[poly->type].data[dataIdx];
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_CalcWaterboxDimensions.s")
+/**
+ * SurfaceType return CamData Index
+ */
+u32 SurfaceType_GetCamDataIndex(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) & 0xFF;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_AddActorMeshToLists.s")
+/**
+ * CamData return camera setting
+ */
+u16 func_800C9728(CollisionContext* colCtx, u32 camId, s32 bgId) {
+ u16 result;
+ CollisionHeader* colHeader;
+ CamData* camData;
+
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if (colHeader == NULL) {
+ return 0;
+ }
+ camData = colHeader->cameraDataList;
+ result = camData[camId].cameraSType;
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_ResetFlagsIfLoadedActor.s")
+/**
+ * SurfaceType return camera setting
+ */
+u16 SurfaceType_GetCameraSetting(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ CollisionHeader* colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ CamData* camData;
+ SurfaceType* surfaceTypes;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_Update.s")
+ if (colHeader == NULL) {
+ return 0;
+ }
+ camData = colHeader->cameraDataList;
+ if (camData == NULL) {
+ return 0;
+ }
+ surfaceTypes = colHeader->surfaceTypeList;
+ if (surfaceTypes == NULL) {
+ return 0;
+ }
+ return func_800C9728(colCtx, SurfaceType_GetCamDataIndex(colCtx, poly, bgId), bgId);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C756C.s")
+/**
+ * CamData get number of camera data blocks
+ */
+u16 func_800C97F8(CollisionContext* colCtx, u32 camId, s32 bgId) {
+ CollisionHeader* colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ CamData* camData;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_UpdateAllActorMeshes.s")
+ if (colHeader == NULL) {
+ return 0;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C76EC.s")
+ camData = colHeader->cameraDataList;
+ if (camData == NULL) {
+ return 0;
+ }
+ return camData[camId].unk_02;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C7974.s")
+/**
+ * SurfaceType get number of camera data blocks
+ */
+u16 func_800C9844(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ CollisionHeader* colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ CamData* camData;
+ SurfaceType* surfaceTypes;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C7E40.s")
+ if (colHeader == NULL) {
+ return 0;
+ }
+ camData = colHeader->cameraDataList;
+ if (camData == NULL) {
+ return 0;
+ }
+ surfaceTypes = colHeader->surfaceTypeList;
+ if (surfaceTypes == NULL) {
+ return 0;
+ }
+ return func_800C97F8(colCtx, SurfaceType_GetCamDataIndex(colCtx, poly, bgId), bgId);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C8580.s")
+/**
+ * CamData get camPosData
+ */
+Vec3s* func_800C98CC(CollisionContext* colCtx, s32 camId, s32 bgId) {
+ CollisionHeader* colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ CamData* cameraDataList;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C87D0.s")
+ if (colHeader == NULL) {
+ return NULL;
+ }
+ cameraDataList = colHeader->cameraDataList;
+ if (cameraDataList == NULL) {
+ return NULL;
+ }
+ return Lib_SegmentedToVirtual(cameraDataList[camId].camPosData);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C8A60.s")
+/**
+ * SurfaceType Get camPosData
+ */
+Vec3s* SurfaceType_GetCamPosData(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ CollisionHeader* colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ CamData* camData;
+ SurfaceType* surfaceTypes;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C8BD0.s")
+ if (colHeader == NULL) {
+ return NULL;
+ }
+ camData = colHeader->cameraDataList;
+ if (camData == NULL) {
+ return NULL;
+ }
+ surfaceTypes = colHeader->surfaceTypeList;
+ if (surfaceTypes == NULL) {
+ return NULL;
+ }
+ return func_800C98CC(colCtx, SurfaceType_GetCamDataIndex(colCtx, poly, bgId), bgId);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C8DC0.s")
+/**
+ * SurfaceType Get Scene Exit Index
+ */
+u32 SurfaceType_GetSceneExitIndex(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 8 & 0x1F;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C8EEC.s")
+/**
+ * SurfaceType Get ? Property (& 0x0003_E000)
+ */
+u32 func_800C99D4(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 13 & 0x1F;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C90AC.s")
+/**
+ * SurfaceType Get ? Property (& 0x001C_0000)
+ */
+u32 func_800C99FC(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 18 & 7;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C921C.s")
+/**
+ * SurfaceType Get Wall Property (Internal)
+ */
+u32 func_800C9A24(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 21 & 0x1F;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9380.s")
+/**
+ * SurfaceType Get Wall Flags
+ */
+s32 func_800C9A4C(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return sWallFlags[func_800C9A24(colCtx, poly, bgId)];
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_RelocateMeshHeaderPointers.s")
+/**
+ * SurfaceType Is Wall Flag (1 << 0) Set
+ */
+s32 func_800C9A7C(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return (func_800C9A4C(colCtx, poly, bgId) & 1) ? true : false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_RelocateMeshHeader.s")
+/**
+ * SurfaceType Is Wall Flag (1 << 1) Set
+ */
+s32 func_800C9AB0(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return (func_800C9A4C(colCtx, poly, bgId) & 2) ? true : false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_RelocateAllMeshHeaders.s")
+/**
+ * SurfaceType Is Wall Flag (1 << 2) Set
+ */
+s32 func_800C9AE4(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return (func_800C9A4C(colCtx, poly, bgId) & 4) ? true : false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9640.s")
+/**
+ * unused
+ */
+u32 func_800C9B18(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 26 & 0xF;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_GetPolygonAttributes.s")
+/**
+ * SurfaceType Get Floor Property
+ */
+u32 func_800C9B40(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 26 & 0xF;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9704.s")
+/**
+ * SurfaceType Is Floor Minus 1
+ */
+u32 func_800C9B68(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 30 & 1;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9728.s")
+/**
+ * SurfaceType Is Horse Blocked
+ */
+u32 SurfaceType_IsHorseBlocked(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 31 & 1;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9770.s")
+u32 func_800C9BB8(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) & 0xF;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C97F8.s")
+/**
+ * SurfaceType Get Poly Sfx
+ */
+u16 SurfaceType_GetSfx(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ s32 id = func_800C9BB8(colCtx, poly, bgId);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9844.s")
+ if (id < 0 || id > 14) {
+ return NA_SE_PL_WALK_GROUND - SFX_FLAG;
+ }
+ return sSurfaceTypeSfx[id];
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C98CC.s")
+/**
+ * SurfaceType Get ? (same indexer as Get Poly Sfx)
+ */
+s32 func_800C9C24(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId, s32 arg3) {
+ s32 id = func_800C9BB8(colCtx, poly, bgId);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9924.s")
+ if (id < 0 || id > 14) {
+ return 0;
+ }
+ return D_801B46C0[id] & arg3;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C99AC.s")
+/**
+ * SurfaceType get terrain slope surface
+ */
+u32 SurfaceType_GetSlope(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 4 & 3;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C99D4.s")
+/**
+ * SurfaceType get surface lighting setting
+ */
+u32 SurfaceType_GetLightSettingIndex(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 6 & 0x1F;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C99FC.s")
+/**
+ * SurfaceType get echo
+ */
+u32 SurfaceType_GetEcho(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 11 & 0x3F;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9A24.s")
+/**
+ * SurfaceType Is Hookshot Surface
+ */
+u32 SurfaceType_IsHookshotSurface(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 17 & 1;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9A4C.s")
+/**
+ * CollisionPoly is ignored by entities
+ * Returns true if poly is ignored by entities, else false
+ */
+s32 SurfaceType_IsIgnoredByEntities(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ u32 flags;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9A7C.s")
+ if (BgCheck_GetCollisionHeader(colCtx, bgId) == NULL) {
+ return true;
+ }
+ flags = poly->flags_vIA & 0x4000;
+ return !!flags;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9AB0.s")
+/**
+ * CollisionPoly is ignored by projectiles
+ * Returns true if poly is ignored by projectiles, else false
+ */
+s32 SurfaceType_IsIgnoredByProjectiles(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ u32 flags;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9AE4.s")
+ if (BgCheck_GetCollisionHeader(colCtx, bgId) == NULL) {
+ return true;
+ }
+ flags = poly->flags_vIA & 0x8000;
+ return !!flags;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9B18.s")
+/**
+ * CollisionPoly is conveyor enabled
+ * Returns true if `poly` is a conveyor surface, else false
+ */
+s32 SurfaceType_IsConveyor(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ u32 flags;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9B40.s")
+ if (BgCheck_GetCollisionHeader(colCtx, bgId) == NULL) {
+ return true;
+ }
+ if (poly == NULL) {
+ return false;
+ }
+ flags = poly->flags_vIB & 0x2000;
+ return !!flags;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9B68.s")
+s32 func_800C9DDC(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ u32 flags;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9B90.s")
+ if (BgCheck_GetCollisionHeader(colCtx, bgId) == NULL) {
+ return true;
+ }
+ flags = poly->flags_vIB & 0x4000;
+ return !!flags;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9BB8.s")
+/**
+ * SurfaceType Get Conveyor Surface Speed
+ */
+u32 SurfaceType_GetConveyorSpeed(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 18 & 7;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9BDC.s")
+/**
+ * SurfaceType Get Conveyor Direction
+ * returns a value between 0-63, representing 360 / 64 degrees of rotation
+ */
+u32 SurfaceType_GetConveyorDirection(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ u32 data;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9C24.s")
+ data = SurfaceType_GetData(colCtx, poly, bgId, 1) >> 21;
+ if (colCtx->flags & 1) {
+ data += 0x20;
+ }
+ return data & 0x3F;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9C74.s")
+/**
+ * SurfaceType is Wall Damage
+ */
+u32 SurfaceType_IsWallDamage(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return (SurfaceType_GetData(colCtx, poly, bgId, 1) & 0x8000000) ? true : false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9C9C.s")
+/**
+ * Internal. Get the water surface at point (`x`, `ySurface`, `z`). `ySurface` doubles as position y input
+ * returns true if point is within the xz boundaries of an active water box, else false
+ * `ySurface` returns the water box's surface, while `outWaterBox` returns a pointer to the WaterBox
+ */
+s32 WaterBox_GetSurfaceImpl(GlobalContext* globalCtx, CollisionContext* colCtx, f32 x, f32 z, f32* ySurface,
+ WaterBox** outWaterBox, s32* bgId) {
+ CollisionHeader* colHeader;
+ u32 room;
+ WaterBox* curWaterBox;
+ s32 i;
+
+ *bgId = BGCHECK_SCENE;
+ colHeader = colCtx->colHeader;
+
+ if (colHeader->numWaterBoxes != 0 && colHeader->waterBoxes != NULL) {
+ for (curWaterBox = colHeader->waterBoxes; curWaterBox < colHeader->waterBoxes + colHeader->numWaterBoxes;
+ curWaterBox++) {
+ room = 0x3F & (curWaterBox->properties >> 13);
+ if (room == (u32)globalCtx->roomCtx.currRoom.num || room == 0x3F) {
+ if (curWaterBox->properties & 0x80000) {
+ continue;
+ }
+ if (curWaterBox->minPos.x < x && x < curWaterBox->minPos.x + curWaterBox->xLength) {
+ if (curWaterBox->minPos.z < z && z < curWaterBox->minPos.z + curWaterBox->zLength) {
+ *outWaterBox = curWaterBox;
+ *ySurface = curWaterBox->minPos.y;
+ return true;
+ }
+ }
+ }
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9CC4.s")
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (colCtx->dyna.bgActorFlags[i] & 1) {
+ BgActor* bgActor;
+ if (colCtx->dyna.bgActorFlags[i] & 4) {
+ continue;
+ }
+ bgActor = &colCtx->dyna.bgActors[i];
+ if (bgActor->colHeader->numWaterBoxes != 0 && bgActor->colHeader->waterBoxes != NULL) {
+ for (curWaterBox = colCtx->dyna.waterBoxList.boxes + bgActor->waterboxesStartIndex;
+ curWaterBox < colCtx->dyna.waterBoxList.boxes + bgActor->waterboxesStartIndex +
+ bgActor->colHeader->numWaterBoxes;
+ curWaterBox++) {
+ if (curWaterBox->properties & 0x80000) {
+ continue;
+ }
+ if (curWaterBox->minPos.x < x && x < curWaterBox->minPos.x + curWaterBox->xLength) {
+ if (curWaterBox->minPos.z < z && z < curWaterBox->minPos.z + curWaterBox->zLength) {
+ *outWaterBox = curWaterBox;
+ *ySurface = curWaterBox->minPos.y;
+ *bgId = i;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9CEC.s")
+s32 WaterBox_GetSurface1(GlobalContext* globalCtx, CollisionContext* colCtx, f32 x, f32 z, f32* ySurface,
+ WaterBox** outWaterBox) {
+ WaterBox_GetSurface1_2(globalCtx, colCtx, x, z, ySurface, outWaterBox);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9D14.s")
+s32 WaterBox_GetSurface1_2(GlobalContext* globalCtx, CollisionContext* colCtx, f32 x, f32 z, f32* ySurface,
+ WaterBox** outWaterBox) {
+ s32 bgId;
+ return WaterBox_GetSurfaceImpl(globalCtx, colCtx, x, z, ySurface, outWaterBox, &bgId);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9D50.s")
+#ifdef NON_MATCHING
+/**
+ * Gets the first active WaterBox at `pos` where WaterBox.properties & 0x80000 == 0
+ * `surfaceCheckDist` is the absolute y distance from the water surface to check
+ * returns the index of the waterbox found, or -1 if no waterbox is found
+ * `outWaterBox` returns the pointer to the waterbox found, or NULL if none is found
+ */
+s32 WaterBox_GetSurface2(GlobalContext* globalCtx, CollisionContext* colCtx, Vec3f* pos, f32 surfaceCheckDist,
+ WaterBox** outWaterBox, s32* bgId) {
+ CollisionHeader* colHeader;
+ s32 room;
+ s32 i;
+ WaterBox* waterBox;
+
+ *bgId = BGCHECK_SCENE;
+ colHeader = colCtx->colHeader;
+
+ //! @bug: check skips testing BgActor waterboxes
+ if (colHeader->numWaterBoxes == 0 || colHeader->waterBoxes == NULL) {
+ *outWaterBox = NULL;
+ return -1;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9D8C.s")
+ for (i = 0; i < colHeader->numWaterBoxes; i++) {
+ waterBox = &colHeader->waterBoxes[i];
+
+ room = WATERBOX_ROOM(waterBox->properties);
+ if (!(room == globalCtx->roomCtx.currRoom.num || room == 0x3F)) {
+ continue;
+ }
+ if ((waterBox->properties & 0x80000)) {
+ continue;
+ }
+ if ((waterBox->minPos.x < pos->x && pos->x < waterBox->minPos.x + waterBox->xLength)) {
+ if ((waterBox->minPos.z < pos->z && pos->z < waterBox->minPos.z + waterBox->zLength)) {
+ if (pos->y - surfaceCheckDist < waterBox->minPos.y && waterBox->minPos.y < pos->y + surfaceCheckDist) {
+ *outWaterBox = waterBox;
+ return i;
+ }
+ }
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9DDC.s")
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ WaterBox* iterator;
+ WaterBox* start;
+ BgActor* bgActor;
+ if (!(colCtx->dyna.bgActorFlags[i] & 1) || (colCtx->dyna.bgActorFlags[i] & 4) ||
+ (colCtx->dyna.bgActorFlags[i] & 2)) {
+ continue;
+ }
+ bgActor = &colCtx->dyna.bgActors[i];
+ for (iterator = colCtx->dyna.waterBoxList.boxes + bgActor->waterboxesStartIndex;
+ iterator <
+ colCtx->dyna.waterBoxList.boxes + bgActor->waterboxesStartIndex + bgActor->colHeader->numWaterBoxes;
+ iterator++) {
+ if (iterator->properties & 0x80000) {
+ continue;
+ }
+ if ((iterator->minPos.x < pos->x) && pos->x < iterator->minPos.x + iterator->xLength) {
+ if ((iterator->minPos.z < pos->z) && pos->z < iterator->minPos.z + iterator->zLength) {
+ if (pos->y - surfaceCheckDist < iterator->minPos.y &&
+ iterator->minPos.y < pos->y + surfaceCheckDist) {
+ *bgId = i;
+ *outWaterBox = iterator;
+ return i;
+ }
+ }
+ }
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9E18.s")
+ *outWaterBox = NULL;
+ return -1;
+}
+#else
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/WaterBox_GetSurface2.s")
+#endif
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9E40.s")
+f32 func_800CA568(CollisionContext* colCtx, s32 waterBoxId, s32 bgId) {
+ CollisionHeader* colHeader;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9E88.s")
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if ((colHeader == NULL) || (waterBoxId < 0) || (waterBoxId >= (s32)colHeader->numWaterBoxes)) {
+ return 0.0f;
+ }
+ if (bgId == BGCHECK_SCENE) {
+ return colCtx->colHeader->waterBoxes[waterBoxId].minPos.y;
+ }
+ return (&colCtx->dyna.waterBoxList.boxes[colCtx->dyna.bgActors[bgId].waterboxesStartIndex])[waterBoxId].minPos.y;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800C9EBC.s")
+/**
+ * WaterBox get CamData index
+ */
+u32 WaterBox_GetCamDataIndex(CollisionContext* colCtx, WaterBox* waterBox) {
+ u32 prop = waterBox->properties >> 0;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CA1AC.s")
+ return prop & 0xFF;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CA1E8.s")
+/**
+ * WaterBox get CamData camera setting
+ */
+u16 WaterBox_GetCameraSetting(CollisionContext* colCtx, WaterBox* waterBox, s32 bgId) {
+ s32 pad[2];
+ u16 result = 0;
+ CollisionHeader* colHeader;
+ CamData* camData;
+ s32 camId;
+
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if (colHeader == NULL) {
+ return result;
+ }
+ camId = WaterBox_GetCamDataIndex(colCtx, waterBox);
+ camData = colHeader->cameraDataList;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CA22C.s")
+ if (camData == NULL) {
+ return result;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CA568.s")
+ result = camData[camId].cameraSType;
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CA634.s")
+void func_800CA6B8(CollisionContext* colCtx, WaterBox* waterBox) {
+ WaterBox_GetCameraSetting(colCtx, waterBox, BGCHECK_SCENE);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CA648.s")
+/**
+ * WaterBox get lighting settings
+ */
+u32 WaterBox_GetLightSettingIndex(CollisionContext* colCtx, WaterBox* waterBox) {
+ u32 prop = waterBox->properties >> 8;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CA6B8.s")
+ return prop & 0x1F;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CA6D8.s")
+#ifdef NON_MATCHING
+/**
+ * Get the water surface at point (`x`, `ySurface`, `z`). `ySurface` doubles as position y input
+ * same as WaterBox_GetSurfaceImpl, but tests if WaterBox properties & 0x80000 != 0
+ * returns true if point is within the xz boundaries of an active water box, else false
+ * `ySurface` returns the water box's surface, while `outWaterBox` returns a pointer to the WaterBox
+ */
+s32 func_800CA6F0(GlobalContext* globalCtx, CollisionContext* colCtx, f32 x, f32 z, f32* ySurface,
+ WaterBox** outWaterBox, s32* bgId) {
+ CollisionHeader* colHeader;
+ u32 room;
+ WaterBox* curWaterBox;
+ s32 i;
+ BgActor* bgActor;
+
+ colHeader = colCtx->colHeader;
+ *outWaterBox = NULL;
+ *bgId = BGCHECK_SCENE;
+
+ if (colHeader->numWaterBoxes == 0 || colHeader->waterBoxes == NULL) {
+ return false;
+ }
+ for (curWaterBox = colHeader->waterBoxes; curWaterBox < colHeader->waterBoxes + colHeader->numWaterBoxes;
+ curWaterBox++) {
+ room = WATERBOX_ROOM(curWaterBox->properties);
+ if (room == (u32)globalCtx->roomCtx.currRoom.num || room == 0x3F) {
+ if ((curWaterBox->properties & 0x80000) != 0) {
+ if (curWaterBox->minPos.x < x && x < curWaterBox->minPos.x + curWaterBox->xLength) {
+ if (curWaterBox->minPos.z < z && z < curWaterBox->minPos.z + curWaterBox->zLength) {
+ *outWaterBox = curWaterBox;
+ *ySurface = curWaterBox->minPos.y;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if ((colCtx->dyna.bgActorFlags[i] & 1) && !(colCtx->dyna.bgActorFlags[i] & 2)) {
+ WaterBox* boxes;
+ boxes = colCtx->dyna.waterBoxList.boxes;
+ bgActor = &colCtx->dyna.bgActors[i];
+ if (bgActor->colHeader->numWaterBoxes != 0 && bgActor->colHeader->waterBoxes != NULL) {
+ for (curWaterBox = boxes + bgActor->waterboxesStartIndex;
+ curWaterBox < boxes + bgActor->waterboxesStartIndex + bgActor->colHeader->numWaterBoxes;
+ curWaterBox++) {
+ if ((curWaterBox->properties & 0x80000) != 0) {
+ if (curWaterBox->minPos.x < x && x < curWaterBox->minPos.x + curWaterBox->xLength) {
+ if (curWaterBox->minPos.z < z && z < curWaterBox->minPos.z + curWaterBox->zLength) {
+ *outWaterBox = curWaterBox;
+ *ySurface = curWaterBox->minPos.y;
+ *bgId = i;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+#else
#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CA6F0.s")
+#endif
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CA9D0.s")
+s32 func_800CA9D0(GlobalContext* globalCtx, CollisionContext* colCtx, f32 x, f32 z, f32* ySurface,
+ WaterBox** outWaterBox) {
+ s32 bgId;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800CAA14.s")
+ return func_800CA6F0(globalCtx, colCtx, x, z, ySurface, outWaterBox, &bgId);
+}
+
+/**
+ * Get the `closestPoint` to line (`pointA`, `pointB`) formed from the intersection of planes `polyA` and `polyB`
+ * returns true if the `closestPoint` exists, else returns false
+ */
+s32 func_800CAA14(CollisionPoly* polyA, CollisionPoly* polyB, Vec3f* pointA, Vec3f* pointB, Vec3f* closestPoint) {
+ f32 n1X;
+ f32 n1Y;
+ f32 n1Z;
+ f32 n2X;
+ f32 n2Y;
+ f32 n2Z;
+ s32 result;
+
+ CollisionPoly_GetNormalF(polyA, &n1X, &n1Y, &n1Z);
+ CollisionPoly_GetNormalF(polyB, &n2X, &n2Y, &n2Z);
+ result = Math3D_PlaneVsLineSegClosestPoint(n1X, n1Y, n1Z, polyA->dist, n2X, n2Y, n2Z, polyB->dist, pointA, pointB,
+ closestPoint);
+ return result;
+}
diff --git a/src/code/z_collision_check.c b/src/code/z_collision_check.c
index 059fbce09..e11e6cbd7 100644
--- a/src/code/z_collision_check.c
+++ b/src/code/z_collision_check.c
@@ -941,7 +941,7 @@ s32 Collider_QuadSetNearestAC(GlobalContext* globalCtx, ColliderQuad* quad, Vec3
return 1;
}
Math_Vec3s_ToVec3f(&dcMid, &quad->dim.dcMid);
- acDist = Math3D_DistanceSquared(&dcMid, hitPos);
+ acDist = Math3D_Vec3fDistSq(&dcMid, hitPos);
if (acDist < quad->dim.acDist) {
quad->dim.acDist = acDist;
@@ -3510,7 +3510,7 @@ s32 CollisionCheck_LineOC_JntSph(GlobalContext* globalCtx, CollisionCheckContext
D_801EDEB0.a = *a;
D_801EDEB0.b = *b;
- if (Math3D_ColSphereLineSeg(&element->dim.worldSphere, &D_801EDEB0) != 0) {
+ if (Math3D_LineVsSph(&element->dim.worldSphere, &D_801EDEB0) != 0) {
return 1;
}
}
@@ -3548,7 +3548,7 @@ s32 CollisionCheck_LineOC_Sphere(GlobalContext* globalCtx, CollisionCheckContext
D_801EDFC8.a = *a;
D_801EDFC8.b = *b;
- if (Math3D_ColSphereLineSeg(&sphere->dim.worldSphere, &D_801EDFC8) != 0) {
+ if (Math3D_LineVsSph(&sphere->dim.worldSphere, &D_801EDFC8) != 0) {
return 1;
}
diff --git a/src/code/z_fireobj.c b/src/code/z_fireobj.c
index 816fec2be..6e543d115 100644
--- a/src/code/z_fireobj.c
+++ b/src/code/z_fireobj.c
@@ -94,7 +94,7 @@ void FireObj_StepSize(FireObj* fire) {
void FireObj_UpdateStateTransitions(GlobalContext* globalCtx, FireObj* fire) {
Player* player = GET_PLAYER(globalCtx);
WaterBox* waterBox;
- f32 sp44;
+ f32 waterY;
s32 sp40 = 0;
u8 nextState;
Vec3f dist;
@@ -113,8 +113,8 @@ void FireObj_UpdateStateTransitions(GlobalContext* globalCtx, FireObj* fire) {
FireObj_SetState(fire, fire->dynamicSizeStep, nextState);
}
if ((fire->flags & 1) && (fire->state != FIRE_STATE_3) &&
- (func_800CA1E8(globalCtx, &globalCtx->colCtx, fire->position.x, fire->position.z, &sp44, &waterBox) != 0) &&
- ((fire->yScale * ((void)0, 6500.0f)) < (sp44 - fire->position.y))) { // Fake but IDK what else
+ WaterBox_GetSurface1_2(globalCtx, &globalCtx->colCtx, fire->position.x, fire->position.z, &waterY, &waterBox) &&
+ ((fire->yScale * ((void)0, 6500.0f)) < (waterY - fire->position.y))) { // Fake but IDK what else
FireObj_SetState(fire, fire->dynamicSizeStep, FIRE_STATE_3);
}
if ((fire->flags & 2) && (player->itemActionParam == PLAYER_AP_STICK)) {
diff --git a/src/code/z_quake.c b/src/code/z_quake.c
index d08ff5993..9c5288139 100644
--- a/src/code/z_quake.c
+++ b/src/code/z_quake.c
@@ -416,8 +416,9 @@ void Quake2_ClearType(s32 type) {
}
s32 Quake2_GetFloorQuake(Player* player) {
- if (func_800C9D8C(&sQuake2Context.globalCtx->colCtx, player->actor.floorPoly, player->actor.floorBgId) == 0) {
- return func_800C9E18(&sQuake2Context.globalCtx->colCtx, player->actor.floorPoly, player->actor.floorBgId);
+ if (!SurfaceType_IsConveyor(&sQuake2Context.globalCtx->colCtx, player->actor.floorPoly, player->actor.floorBgId)) {
+ return SurfaceType_GetConveyorSpeed(&sQuake2Context.globalCtx->colCtx, player->actor.floorPoly,
+ player->actor.floorBgId);
}
return 0;
}
diff --git a/src/code/z_scene.c b/src/code/z_scene.c
index 293a9762d..6bebcf938 100644
--- a/src/code/z_scene.c
+++ b/src/code/z_scene.c
@@ -204,7 +204,7 @@ void Scene_HeaderCmdColHeader(GlobalContext* globalCtx, SceneCmd* cmd) {
colHeader->waterBoxes = (WaterBox*)Lib_SegmentedToVirtual(colHeader->waterBoxes);
}
- BgCheck_Init(&globalCtx->colCtx, globalCtx, colHeader);
+ BgCheck_Allocate(&globalCtx->colCtx, globalCtx, colHeader);
}
// SceneTableEntry Header Command 0x04: Room List
diff --git a/src/code/z_scene_proc.c b/src/code/z_scene_proc.c
index bdd3ea1ad..57e2930a2 100644
--- a/src/code/z_scene_proc.c
+++ b/src/code/z_scene_proc.c
@@ -722,9 +722,9 @@ void Scene_DrawConfigGreatBayTemple(GlobalContext* globalCtx) {
if (Flags_GetSwitch(globalCtx, 0x33) && Flags_GetSwitch(globalCtx, 0x34) && Flags_GetSwitch(globalCtx, 0x35) &&
Flags_GetSwitch(globalCtx, 0x36)) {
- func_800C3C00(&globalCtx->colCtx, 1);
+ BgCheck_SetContextFlags(&globalCtx->colCtx, BGCHECK_FLAG_REVERSE_CONVEYOR_FLOW);
} else {
- func_800C3C14(&globalCtx->colCtx, 1);
+ BgCheck_UnsetContextFlags(&globalCtx->colCtx, BGCHECK_FLAG_REVERSE_CONVEYOR_FLOW);
}
dList = (Gfx*)GRAPH_ALLOC(globalCtx->state.gfxCtx, sizeof(Gfx) * 18);
diff --git a/src/code/z_snap.c b/src/code/z_snap.c
index 120861ff5..1c0ab3a27 100644
--- a/src/code/z_snap.c
+++ b/src/code/z_snap.c
@@ -113,11 +113,11 @@ s32 func_8013A530(GlobalContext* globalCtx, Actor* actor, s32 flag, Vec3f* pos,
s16 x;
s16 y;
f32 distance;
- CollisionPoly* unk1;
+ CollisionPoly* poly;
Camera* camera;
Actor* actors[2];
s32 ret = 0;
- u32 unk2;
+ s32 bgId;
camera = GET_ACTIVE_CAM(globalCtx);
@@ -142,7 +142,8 @@ s32 func_8013A530(GlobalContext* globalCtx, Actor* actor, s32 flag, Vec3f* pos,
ret |= 0x3d;
}
- if (func_800C576C(&globalCtx->colCtx, pos, &camera->eye, &screenSpace, &unk1, 1, 1, 1, 1, &unk2) != 0) {
+ if (BgCheck_ProjectileLineTest(&globalCtx->colCtx, pos, &camera->eye, &screenSpace, &poly, true, true, true, true,
+ &bgId)) {
func_8013A41C(0x3c);
ret |= 0x3c;
}