summaryrefslogtreecommitdiff
path: root/src/code
diff options
context:
space:
mode:
authormzxrules <mzxrules@gmail.com>2021-01-08 06:12:58 -0500
committerGitHub <noreply@github.com>2021-01-08 06:12:58 -0500
commit3cef03f5ff9c0341544afec9636bd0581f87d0cc (patch)
tree91ff5c72cadc5c647b52c285f9432f9f40e327dd /src/code
parent209f0d21b87fa01c033a943fd8c862cb46b31315 (diff)
z_bgcheck.c, 800430A0.c, 80043480.c (#256)
* beginning of migrating changes * got matching * changed order a bit * clean up bgcheck * fix conflict * fix conflict again * first stab at identifying types, some oks * Clean up most bad structs/pointer math, move relevant structs to z64bgcheck.h, get some OKs * more OKs, z_bgcheck.bss migration, update some sys_math3d.c args * couple more OKs * pushing some OKs * fix compilation issues * code_800430A0.c OK, more files decomp'd * 8003A3E0 big OK :) * Decomp most of func_8003C614, decomp helper funcs * Decomp SurfaceType, CamData, and WaterBox property related functions * more OKs, big OK in 8003C078 * more OKs, more progress, move a function definition in z_collision_check to functions.h * more clean-ups, more OKs, dyn_vtx is now defined as u8* * 8003A5B8, 8003A7D8, 8003C614, 8003DD6C OK, document function args better * data migrated, more OKs * 80041240 OK, func_8003B3C8 and func_8003BB18 disassembled * func_80040284, 800409A8 non_matching, add IS_ZERO macro * All asm files have C representations, some big OKs, lots of minor tweaks * More OKs, non-matching code cleanup * 8003FBF4 and 80040BE4 OK, improve codegen for most functions * format z_bgcheck.c * fix warnings, compile errors on NON_MATCHING * func_8003EE80 is now NON_MATCHING * begin documenting some functions * formatting * more documentation, func_8003A95C OK * fix PHYSICAL_TO_VIRTUAL changes * fix var rename * More documentation, functions 80040E40, 80041648 OK, change types to not be compatible with ZAP * func_8004239C ok, more NON_MATCHING improvements, more documentation * Implement most suggested changes * Convert comments to slower comments * /** * Implement ZAP2 changes * my anti-virus ate my format.sh results * Rename a couple hundred functions, fix minor stuff * rename var so that clang formats correctly * run format.sh * implement Petrie's matches/suggestions * format * matches * and the asm * slight error * Add SSList * two more matches * stuff * implement code changes * clean up Petrie's matchings Co-authored-by: Arthur <arthurtilly413@gmail.com> Co-authored-by: fig02 <fig02srl@gmail.com> Co-authored-by: petrie911 <pmontag@DESKTOP-LG8A167.localdomain>
Diffstat (limited to 'src/code')
-rw-r--r--src/code/code_800430A0.c93
-rw-r--r--src/code/code_80043480.c68
-rw-r--r--src/code/z_actor.c75
-rw-r--r--src/code/z_bgcheck.c4592
-rw-r--r--src/code/z_camera.c97
-rw-r--r--src/code/z_collision_check.c34
-rw-r--r--src/code/z_en_a_keep.c37
-rw-r--r--src/code/z_en_item00.c6
-rw-r--r--src/code/z_onepointdemo.c4
-rw-r--r--src/code/z_play.c62
-rw-r--r--src/code/z_player_lib.c6
-rw-r--r--src/code/z_room.c2
-rw-r--r--src/code/z_scene.c10
13 files changed, 4630 insertions, 456 deletions
diff --git a/src/code/code_800430A0.c b/src/code/code_800430A0.c
index 29eaae1e1..9673fc86a 100644
--- a/src/code/code_800430A0.c
+++ b/src/code/code_800430A0.c
@@ -1,23 +1,64 @@
#include "global.h"
+#include "vt.h"
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_800430A0/func_800430A0.s")
+void func_800430A0(CollisionContext* colCtx, s32 bgId, Actor* actor) {
+ MtxF prevTransform;
+ MtxF prevTransformInv;
+ MtxF curTransform;
+ Vec3f pos;
+ Vec3f tempPos;
-void func_800432A0(CollisionContext* colCtx, u32 floorPolySource, Actor* actor) {
- if (func_8003E934(floorPolySource) != 0) {
- s16 v1 = colCtx->dyna.actorMeshArr[floorPolySource].rot2.y - colCtx->dyna.actorMeshArr[floorPolySource].rot1.y;
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ SkinMatrix_SetScaleRotateYRPTranslate(
+ &prevTransform, 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(&prevTransform, &prevTransformInv) != 2) {
+ SkinMatrix_SetScaleRotateYRPTranslate(
+ &curTransform, 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(&prevTransformInv, &actor->posRot.pos, &tempPos);
+ SkinMatrix_Vec3fMtxFMultXYZ(&curTransform, &tempPos, &pos);
+ actor->posRot.pos = pos;
+ if (BGCHECK_XYZ_ABSMAX <= pos.x || pos.x <= -BGCHECK_XYZ_ABSMAX || BGCHECK_XYZ_ABSMAX <= pos.y ||
+ pos.y <= -BGCHECK_XYZ_ABSMAX || BGCHECK_XYZ_ABSMAX <= pos.z || pos.z <= -BGCHECK_XYZ_ABSMAX) {
- if (actor->id == 0) {
- ((Player*)actor)->currentYaw += v1;
+ osSyncPrintf(VT_FGCOL(RED));
+ // @bug file and line are not passed to osSyncPrintf
+ // Position is not valid
+ osSyncPrintf(
+ "BGCheckCollection_typicalActorPos():位置が妥当ではありません。\npos (%f,%f,%f) file:%s line:%d\n",
+ pos.x, pos.y, pos.z);
+ osSyncPrintf(VT_RST);
+ }
+ }
+ }
+}
+
+/**
+ * Rotate actor
+ */
+void func_800432A0(CollisionContext* colCtx, s32 bgId, Actor* actor) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ s16 rot = colCtx->dyna.bgActors[bgId].curTransform.rot.y - colCtx->dyna.bgActors[bgId].prevTransform.rot.y;
+
+ if (actor->id == ACTOR_PLAYER) {
+ ((Player*)actor)->currentYaw += rot;
}
- actor->shape.rot.y += v1;
- actor->posRot.rot.y += v1;
+ actor->shape.rot.y += rot;
+ actor->posRot.rot.y += rot;
}
}
-void func_80043334(CollisionContext* colCtx, Actor* actor, u32 floorPolySource) {
- if (func_8003E934(floorPolySource) != 0) {
- DynaPolyActor* dynaActor = DynaPolyInfo_GetActor(colCtx, floorPolySource);
+void func_80043334(CollisionContext* colCtx, Actor* actor, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ DynaPolyActor* dynaActor = DynaPoly_GetActor(colCtx, bgId);
if (dynaActor != NULL) {
func_800434A8(dynaActor);
@@ -28,33 +69,37 @@ void func_80043334(CollisionContext* colCtx, Actor* actor, u32 floorPolySource)
}
}
-s32 func_800433A4(CollisionContext* colCtx, u32 floorPolySource, Actor* actor) {
- s32 sp24 = 0;
+/**
+ * Transform actor's position
+ * `actor` is the actor to update
+ */
+s32 func_800433A4(CollisionContext* colCtx, s32 bgId, Actor* actor) {
+ s32 result = false;
DynaPolyActor* dynaActor;
- if (func_8003E934(floorPolySource) == 0) {
- return 0;
+ if (DynaPoly_IsBgIdBgActor(bgId) == false) {
+ return false;
}
- if ((colCtx->dyna.flags[floorPolySource] & 2) || !(colCtx->dyna.flags[floorPolySource] & 1)) {
- return 0;
+ if ((colCtx->dyna.bgActorFlags[bgId] & 2) || !(colCtx->dyna.bgActorFlags[bgId] & 1)) {
+ return false;
}
- dynaActor = DynaPolyInfo_GetActor(colCtx, floorPolySource);
+ dynaActor = (DynaPolyActor*)DynaPoly_GetActor(colCtx, bgId);
if (dynaActor == NULL) {
- return 0;
+ return false;
}
if (dynaActor->unk_15C & 1) {
- func_800430A0(colCtx, floorPolySource, actor);
- sp24 = 1;
+ func_800430A0(colCtx, bgId, actor);
+ result = true;
}
if (dynaActor->unk_15C & 2) {
- func_800432A0(colCtx, floorPolySource, actor);
- sp24 = 1;
+ func_800432A0(colCtx, bgId, actor);
+ result = true;
}
- return sp24;
+ return result;
}
diff --git a/src/code/code_80043480.c b/src/code/code_80043480.c
index 54f422a6f..900dd9683 100644
--- a/src/code/code_80043480.c
+++ b/src/code/code_80043480.c
@@ -1,7 +1,7 @@
#include "global.h"
-void DynaPolyInfo_SetActorMove(DynaPolyActor* dynaActor, DynaPolyMoveFlag flags) {
- dynaActor->dynaPolyId = -1;
+void DynaPolyActor_Init(DynaPolyActor* dynaActor, DynaPolyMoveFlag flags) {
+ dynaActor->bgId = -1;
dynaActor->unk_15C = flags;
dynaActor->unk_160 = 0;
dynaActor->unk_150 = 0.0f;
@@ -20,8 +20,8 @@ void func_800434B8(DynaPolyActor* dynaActor) {
dynaActor->unk_160 |= 2;
}
-void func_800434C8(CollisionContext* colCtx, u32 floorPolySource) {
- DynaPolyActor* dynaActor = DynaPolyInfo_GetActor(colCtx, floorPolySource);
+void func_800434C8(CollisionContext* colCtx, s32 floorPolySource) {
+ DynaPolyActor* dynaActor = (DynaPolyActor*)DynaPoly_GetActor(colCtx, floorPolySource);
if (dynaActor != NULL) {
func_800434B8(dynaActor);
@@ -32,8 +32,8 @@ void func_800434F8(DynaPolyActor* dynaActor) {
dynaActor->unk_160 |= 4;
}
-void func_80043508(CollisionContext* colCtx, u32 floorPolySource) {
- DynaPolyActor* dynaActor = DynaPolyInfo_GetActor(colCtx, floorPolySource);
+void func_80043508(CollisionContext* colCtx, s32 floorPolySource) {
+ DynaPolyActor* dynaActor = (DynaPolyActor*)DynaPoly_GetActor(colCtx, floorPolySource);
if (dynaActor != NULL) {
func_800434F8(dynaActor);
@@ -46,34 +46,72 @@ void func_80043538(DynaPolyActor* dynaActor) {
s32 func_80043548(DynaPolyActor* dynaActor) {
if (dynaActor->unk_160 & 1) {
- return 1;
+ return true;
} else {
- return 0;
+ return false;
}
}
s32 func_8004356C(DynaPolyActor* dynaActor) {
if (dynaActor->unk_160 & 2) {
- return 1;
+ return true;
} else {
- return 0;
+ return false;
}
}
s32 func_80043590(DynaPolyActor* dynaActor) {
if (dynaActor->unk_160 & 4) {
- return 1;
+ return true;
} else {
- return 0;
+ return false;
}
}
s32 func_800435B4(DynaPolyActor* dynaActor) {
if (dynaActor->unk_160 & 8) {
- return 1;
+ return true;
} else {
- return 0;
+ return false;
}
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/code_80043480/func_800435D8.s")
+s32 func_800435D8(GlobalContext* globalCtx, DynaPolyActor* actor, s16 arg2, s16 arg3, s16 arg4) {
+ Vec3f posA;
+ Vec3f posB;
+ Vec3f posResult;
+ f32 sin;
+ f32 cos;
+ s32 bgId;
+ CollisionPoly* poly;
+ f32 a2;
+ f32 a3;
+ f32 sign;
+
+ sin = Math_SinS(actor->unk_158);
+ cos = Math_CosS(actor->unk_158);
+ sign = (0.0f <= actor->unk_150) ? 1.0f : -1.0f;
+
+ a2 = (f32)arg2 - 0.1f;
+ posA.x = actor->actor.posRot.pos.x + (a2 * cos);
+ posA.y = actor->actor.posRot.pos.y + arg4;
+ posA.z = actor->actor.posRot.pos.z - (a2 * sin);
+
+ a3 = (f32)arg3 - 0.1f;
+ posB.x = sign * a3 * sin + posA.x;
+ posB.y = posA.y;
+ posB.z = sign * a3 * cos + posA.z;
+ if (BgCheck_EntityLineTest3(&globalCtx->colCtx, &posA, &posB, &posResult, &poly, true, false, false, true, &bgId,
+ actor, 0.0f)) {
+ return false;
+ }
+ posA.x = (actor->actor.posRot.pos.x * 2) - posA.x;
+ posA.z = (actor->actor.posRot.pos.z * 2) - posA.z;
+ posB.x = sign * a3 * sin + posA.x;
+ posB.z = sign * a3 * cos + posA.z;
+ if (BgCheck_EntityLineTest3(&globalCtx->colCtx, &posA, &posB, &posResult, &poly, true, false, false, true, &bgId,
+ actor, 0.0f)) {
+ return false;
+ }
+ return true;
+}
diff --git a/src/code/z_actor.c b/src/code/z_actor.c
index 973f903c2..c5d2f3d4a 100644
--- a/src/code/z_actor.c
+++ b/src/code/z_actor.c
@@ -821,7 +821,7 @@ void Actor_Init(Actor* actor, GlobalContext* globalCtx) {
actor->uncullZoneScale = 350.0f;
actor->uncullZoneDownward = 700.0f;
func_80061E48(&actor->colChkInfo);
- actor->floorPolySource = 0x32;
+ actor->floorPolySource = BGCHECK_SCENE;
ActorShape_Init(&actor->shape, 0.0f, NULL, 0.0f);
if (Object_IsLoaded(&globalCtx->objectCtx, actor->objBankIndex)) {
Actor_SetObjectDependency(globalCtx, actor);
@@ -1142,30 +1142,30 @@ s32 func_8002E234(Actor* actor, f32 arg1, s32 arg2) {
return 1;
}
-UNK_TYPE D_8015BBA0;
-u32 D_8015BBA4;
+CollisionPoly* D_8015BBA0;
+s32 D_8015BBA4;
s32 func_8002E2AC(GlobalContext* globalCtx, Actor* actor, Vec3f* arg2, s32 arg3) {
f32 sp34;
- s32 sp30;
+ s32 bgId;
arg2->y += 50.0f;
- actor->groundY = func_8003CA0C(globalCtx, &globalCtx->colCtx, &actor->floorPoly, &sp30, actor, arg2);
+ actor->groundY = BgCheck_EntityRaycastFloor5(globalCtx, &globalCtx->colCtx, &actor->floorPoly, &bgId, actor, arg2);
actor->bgCheckFlags &= ~0x0086;
- if (actor->groundY <= -32000.0f) {
- return func_8002E234(actor, -32000.0f, arg3);
+ if (actor->groundY <= BGCHECK_Y_MIN) {
+ return func_8002E234(actor, BGCHECK_Y_MIN, arg3);
}
sp34 = actor->groundY - actor->posRot.pos.y;
- actor->floorPolySource = sp30;
+ actor->floorPolySource = bgId;
if (sp34 >= 0.0f) {
actor->bgCheckFlags |= 0x80;
if (actor->bgCheckFlags & 0x10) {
- if (sp30 != D_8015BBA4) {
+ if (bgId != D_8015BBA4) {
if (sp34 > 15.0f) {
actor->bgCheckFlags |= 0x100;
}
@@ -1204,29 +1204,29 @@ void func_8002E4B4(GlobalContext* globalCtx, Actor* actor, f32 arg2, f32 arg3, f
f32 sp74;
s32 pad;
Vec3f sp64;
- u32 sp60;
+ s32 bgId;
CollisionPoly* sp5C;
f32 sp58;
- WaterBox* sp54;
+ WaterBox* waterBox;
f32 sp50;
Vec3f ripplePos;
sp74 = actor->posRot.pos.y - actor->pos4.y;
- if ((actor->floorPolySource != 0x32) && (actor->bgCheckFlags & 1)) {
+ if ((actor->floorPolySource != BGCHECK_SCENE) && (actor->bgCheckFlags & 1)) {
func_800433A4(&globalCtx->colCtx, actor->floorPolySource, actor);
}
if (arg5 & 1) {
- if ((!(arg5 & 0x80) && func_8003D52C(&globalCtx->colCtx, &sp64, &actor->posRot.pos, &actor->pos4, arg3,
- &actor->wallPoly, &sp60, actor, arg2)) ||
- ((arg5 & 0x80) && func_8003D594(&globalCtx->colCtx, &sp64, &actor->posRot.pos, &actor->pos4, arg3,
- &actor->wallPoly, &sp60, actor, arg2))) {
+ if ((!(arg5 & 0x80) && BgCheck_EntitySphVsWall3(&globalCtx->colCtx, &sp64, &actor->posRot.pos, &actor->pos4,
+ arg3, &actor->wallPoly, &bgId, actor, arg2)) ||
+ ((arg5 & 0x80) && BgCheck_EntitySphVsWall4(&globalCtx->colCtx, &sp64, &actor->posRot.pos, &actor->pos4,
+ arg3, &actor->wallPoly, &bgId, actor, arg2))) {
sp5C = actor->wallPoly;
Math_Vec3f_Copy(&actor->posRot.pos, &sp64);
- actor->wallPolyRot = Math_Atan2S(sp5C->norm.z, sp5C->norm.x);
+ actor->wallPolyRot = Math_Atan2S(sp5C->normal.z, sp5C->normal.x);
actor->bgCheckFlags |= 8;
- actor->wallPolySource = sp60;
+ actor->wallPolySource = bgId;
} else {
actor->bgCheckFlags &= ~8;
}
@@ -1237,7 +1237,8 @@ void func_8002E4B4(GlobalContext* globalCtx, Actor* actor, f32 arg2, f32 arg3, f
if (arg5 & 2) {
sp64.y = actor->pos4.y + 10.0f;
- if (func_8003D7A0(&globalCtx->colCtx, &sp58, &sp64, (arg4 + sp74) - 10.0f, &D_8015BBA0, &D_8015BBA4, actor)) {
+ if (BgCheck_EntityCheckCeiling(&globalCtx->colCtx, &sp58, &sp64, (arg4 + sp74) - 10.0f, &D_8015BBA0,
+ &D_8015BBA4, actor)) {
actor->bgCheckFlags |= 0x10;
actor->posRot.pos.y = (sp58 + sp74) - 10.0f;
} else {
@@ -1249,7 +1250,8 @@ void func_8002E4B4(GlobalContext* globalCtx, Actor* actor, f32 arg2, f32 arg3, f
sp64.y = actor->pos4.y;
func_8002E2AC(globalCtx, actor, &sp64, arg5);
sp50 = actor->posRot.pos.y;
- if (func_8004213C(globalCtx, &globalCtx->colCtx, actor->posRot.pos.x, actor->posRot.pos.z, &sp50, &sp54)) {
+ if (WaterBox_GetSurface1(globalCtx, &globalCtx->colCtx, actor->posRot.pos.x, actor->posRot.pos.z, &sp50,
+ &waterBox)) {
actor->yDistToWater = sp50 - actor->posRot.pos.y;
if (actor->yDistToWater < 0.0f) {
actor->bgCheckFlags &= ~0x60;
@@ -1269,7 +1271,7 @@ void func_8002E4B4(GlobalContext* globalCtx, Actor* actor, f32 arg2, f32 arg3, f
}
} else {
actor->bgCheckFlags &= ~0x60;
- actor->yDistToWater = -32000.0f;
+ actor->yDistToWater = BGCHECK_Y_MIN;
}
}
}
@@ -1674,7 +1676,7 @@ void func_8002F850(GlobalContext* globalCtx, Actor* actor) {
sfxId = NA_SE_PL_WALK_WATER1 - SFX_FLAG;
}
} else {
- sfxId = func_80041F34(&globalCtx->colCtx, actor->floorPoly, actor->floorPolySource);
+ sfxId = SurfaceType_GetSfx(&globalCtx->colCtx, actor->floorPoly, actor->floorPolySource);
}
func_80078914(&actor->projectedPos, NA_SE_EV_BOMB_BOUND);
@@ -1716,15 +1718,16 @@ void func_8002F994(Actor* actor, s32 arg1) {
}
}
-s32 func_8002F9EC(GlobalContext* globalCtx, Actor* actor, CollisionPoly* arg2, u32 arg3, Vec3f* arg4) {
- if (func_80041D4C(&globalCtx->colCtx, arg2, arg3) == 8) {
+// Tests if something hit Jabu Jabu surface, displaying hit splash and playing sfx if true
+s32 func_8002F9EC(GlobalContext* globalCtx, Actor* actor, CollisionPoly* poly, s32 bgId, Vec3f* pos) {
+ if (func_80041D4C(&globalCtx->colCtx, poly, bgId) == 8) {
globalCtx->unk_11D30[0] = 1;
- func_8005DFAC(globalCtx, 0, arg4);
+ func_8005DFAC(globalCtx, NULL, pos);
Audio_PlayActorSound2(actor, NA_SE_IT_WALL_HIT_BUYO);
- return 1;
+ return true;
}
- return 0;
+ return false;
}
// Local data used for Farore's Wind light (stored in BSS, possibly a struct?)
@@ -2104,7 +2107,7 @@ void Actor_UpdateAll(GlobalContext* globalCtx, ActorContext* actorCtx) {
}
if (i == ACTORTYPE_BG) {
- func_8003F984(globalCtx, &globalCtx->colCtx.dyna);
+ DynaPoly_Setup(globalCtx, &globalCtx->colCtx.dyna);
}
}
@@ -2125,7 +2128,7 @@ void Actor_UpdateAll(GlobalContext* globalCtx, ActorContext* actorCtx) {
func_8002C7BC(&actorCtx->targetCtx, player, actor, globalCtx);
TitleCard_Update(globalCtx, &actorCtx->titleCtx);
- func_8003FB64(globalCtx, &globalCtx->colCtx.dyna);
+ DynaPoly_UpdateBgActorTransforms(globalCtx, &globalCtx->colCtx.dyna);
}
void Actor_FaultPrint(Actor* actor, char* command) {
@@ -2927,9 +2930,9 @@ void func_800328D4(GlobalContext* globalCtx, ActorContext* actorCtx, Player* pla
if (actor != sp84) {
var = func_8002EFC0(actor, player, D_8015BBFC);
if ((var < D_8015BBF0) && func_8002F090(actor, var) && func_80032880(globalCtx, actor) &&
- (!func_8003DD6C(&globalCtx->colCtx, &player->actor.posRot2.pos, &actor->posRot2.pos, &sp70, &sp80,
- 1, 1, 1, 1, &sp7C) ||
- func_80042048(&globalCtx->colCtx, sp80, sp7C))) {
+ (!BgCheck_CameraLineTest1(&globalCtx->colCtx, &player->actor.posRot2.pos, &actor->posRot2.pos,
+ &sp70, &sp80, 1, 1, 1, 1, &sp7C) ||
+ SurfaceType_IsIgnoredByProjectiles(&globalCtx->colCtx, sp80, sp7C))) {
if (actor->unk_10D != 0) {
if (actor->unk_10D < D_8015BBF8) {
D_8015BBEC = actor;
@@ -3433,7 +3436,7 @@ void func_80033C30(Vec3f* arg0, Vec3f* arg1, u8 alpha, GlobalContext* globalCtx)
sp50.y = arg0->y + 1.0f;
sp50.z = arg0->z;
- var = func_8003C8EC(globalCtx, &globalCtx->colCtx, &sp4C, &sp50);
+ var = BgCheck_EntityRaycastFloor2(globalCtx, &globalCtx->colCtx, &sp4C, &sp50);
if (sp4C != NULL) {
func_80038A28(sp4C, arg0->x, var, arg0->z, &sp60);
@@ -4113,9 +4116,9 @@ void func_800359B8(Actor* actor, s16 arg1, Vec3s* arg2) {
if (actor->floorPoly != NULL) {
floorPoly = actor->floorPoly;
- sp44 = floorPoly->norm.x * (1.0f / 32767);
- sp40 = floorPoly->norm.y * (1.0f / 32767);
- sp3C = floorPoly->norm.z * (1.0f / 32767);
+ sp44 = COLPOLY_GET_NORMAL(floorPoly->normal.x);
+ sp40 = COLPOLY_GET_NORMAL(floorPoly->normal.y);
+ sp3C = COLPOLY_GET_NORMAL(floorPoly->normal.z);
sp38 = Math_SinS(arg1);
sp34 = Math_CosS(arg1);
diff --git a/src/code/z_bgcheck.c b/src/code/z_bgcheck.c
index 546e62684..1880878eb 100644
--- a/src/code/z_bgcheck.c
+++ b/src/code/z_bgcheck.c
@@ -1,460 +1,4538 @@
#include "global.h"
+#include "vt.h"
+
+#define SS_NULL 0xFFFF
+
+// bccFlags
+#define BGCHECK_CHECK_WALL (1 << 0)
+#define BGCHECK_CHECK_FLOOR (1 << 1)
+#define BGCHECK_CHECK_CEILING (1 << 2)
+#define BGCHECK_CHECK_ONE_FACE (1 << 3)
+#define BGCHECK_CHECK_DYNA (1 << 4)
+#define BGCHECK_CHECK_ALL \
+ (BGCHECK_CHECK_WALL | BGCHECK_CHECK_FLOOR | BGCHECK_CHECK_CEILING | BGCHECK_CHECK_ONE_FACE | BGCHECK_CHECK_DYNA)
+
+// bciFlags
+#define BGCHECK_IGNORE_NONE 0
+#define BGCHECK_IGNORE_CEILING (1 << 0)
+#define BGCHECK_IGNORE_WALL (1 << 1)
+#define BGCHECK_IGNORE_FLOOR (1 << 2)
+
+// xpFlags
+#define COLPOLY_IGNORE_NONE 0
+#define COLPOLY_IGNORE_CAMERA (1 << 0)
+#define COLPOLY_IGNORE_ENTITY (1 << 1)
+#define COLPOLY_IGNORE_PROJECTILES (1 << 2)
+
+// func_80041DB8, SurfaceType wall properties
+s32 D_80119D90[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,
+};
+
+// SurfaceType_GetSfx
+u16 D_80119E10[14] = {
+ NA_SE_PL_WALK_GROUND - SFX_FLAG, NA_SE_PL_WALK_SAND - SFX_FLAG, NA_SE_PL_WALK_CONCRETE - SFX_FLAG,
+ NA_SE_PL_WALK_DIRT - SFX_FLAG, NA_SE_PL_WALK_WATER0 - SFX_FLAG, NA_SE_PL_WALK_WATER1 - SFX_FLAG,
+ NA_SE_PL_WALK_WATER2 - SFX_FLAG, NA_SE_PL_WALK_MAGMA - SFX_FLAG, NA_SE_PL_WALK_GRASS - SFX_FLAG,
+ NA_SE_PL_WALK_GLASS - SFX_FLAG, NA_SE_PL_WALK_LADDER - SFX_FLAG, NA_SE_PL_WALK_GROUND - SFX_FLAG,
+ NA_SE_PL_WALK_ICE - SFX_FLAG, NA_SE_PL_WALK_IRON - SFX_FLAG,
+};
+
+/**
+ * original name: T_BGCheck_PosErrorCheck
+ */
+s32 BgCheck_PosErrorCheck(Vec3f* pos, char* file, s32 line) {
+ if (pos->x >= BGCHECK_XYZ_ABSMAX || pos->x <= -BGCHECK_XYZ_ABSMAX || pos->y >= BGCHECK_XYZ_ABSMAX ||
+ pos->y <= -BGCHECK_XYZ_ABSMAX || pos->z >= BGCHECK_XYZ_ABSMAX || pos->z <= -BGCHECK_XYZ_ABSMAX) {
+ osSyncPrintf(VT_FGCOL(RED));
+ // "Translates to: Position is invalid."
+ osSyncPrintf("T_BGCheck_PosErrorCheck():位置が妥当ではありません。pos (%f,%f,%f) file:%s line:%d\n", pos->x,
+ pos->y, pos->z, file, line);
+ osSyncPrintf(VT_RST);
+ return true;
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038600.s")
+/**
+ * Set SSNode
+ */
+void SSNode_SetValue(SSNode* node, s16* polyId, u16 next) {
+ node->polyId = *polyId;
+ node->next = next;
+}
-void func_80038708(s16* puParm1, s16* puParm2, u16 uParm3) {
- *puParm1 = *puParm2;
- puParm1[1] = uParm3;
+/**
+ * Set SSList to SS_NULL
+ */
+void SSList_SetNull(SSList* ssList) {
+ ssList->head = SS_NULL;
}
-void func_8003871C(u16* puParm1) {
- *puParm1 = 0xFFFF;
+/**
+ * Insert `polyId` at the start of the static `ssList` list
+ */
+void SSNodeList_SetSSListHead(SSNodeList* nodeList, SSList* ssList, s16* polyId) {
+ u16 newNodeId = SSNodeList_GetNextNodeIdx(nodeList);
+
+ SSNode_SetValue(&nodeList->tbl[newNodeId], polyId, ssList->head);
+ ssList->head = newNodeId;
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038728.s")
+/**
+ * Insert `polyId` at the start of the dyna `ssList` list
+ */
+void DynaSSNodeList_SetSSListHead(DynaSSNodeList* nodeList, SSList* ssList, s16* polyId) {
+ u16 newNodeId = DynaSSNodeList_GetNextNodeIdx(nodeList);
+
+ (newNodeId != SS_NULL) ? (void)0 : __assert("new_node != SS_NULL", "../z_bgcheck.c", 1776);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038780.s")
+ SSNode_SetValue(&nodeList->tbl[newNodeId], polyId, ssList->head);
+ ssList->head = newNodeId;
+}
-void func_800387FC(u32 uParm1, u32* puParm2) {
- *puParm2 = 0;
- puParm2[1] = 0;
+/**
+ * Initialize DynaSSNodeList
+ */
+void DynaSSNodeList_Initialize(GlobalContext* globalCtx, DynaSSNodeList* nodeList) {
+ nodeList->tbl = NULL;
+ nodeList->count = 0;
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003880C.s")
+/**
+ * Initialize DynaSSNodeList tbl
+ */
+void DynaSSNodeList_Alloc(GlobalContext* globalCtx, DynaSSNodeList* nodeList, s32 max) {
+ nodeList->tbl = THA_AllocEndAlign(&globalCtx->state.tha, max * sizeof(SSNode), -2);
-void func_80038870(s32 iParm1) {
- *(u32*)(iParm1 + 4) = 0;
+ (nodeList->tbl != NULL) ? (void)0 : __assert("psst->tbl != NULL", "../z_bgcheck.c", 1811);
+
+ nodeList->max = max;
+ nodeList->count = 0;
}
-u32 func_80038878(s32 iParm1) {
- u32 uVar1;
+/**
+ * Reset DynaSSNodeList count
+ */
+void DynaSSNodeList_ResetCount(DynaSSNodeList* nodeList) {
+ nodeList->count = 0;
+}
- uVar1 = *(u32*)(iParm1 + 4) & 0xffff;
- *(s32*)(iParm1 + 4) = *(u32*)(iParm1 + 4) + 1;
+/**
+ * Get next available node index in DynaSSNodeList
+ * returns SS_NULL if list is full
+ */
+u16 DynaSSNodeList_GetNextNodeIdx(DynaSSNodeList* nodeList) {
+ u16 idx = nodeList->count++;
- if (*(s32*)(iParm1 + 8) <= (s32)uVar1) {
- return 0xffff;
+ if (nodeList->max <= idx) {
+ return SS_NULL;
}
- return uVar1;
+ return idx;
+}
+
+/**
+ * original name: T_BGCheck_Vec3sToVec3f
+ */
+void BgCheck_Vec3sToVec3f(Vec3s* src, Vec3f* dst) {
+ dst->x = src->x;
+ dst->y = src->y;
+ dst->z = src->z;
+}
+
+/**
+ * original name: T_BGCheck_Vec3fToVec3s
+ */
+void BgCheck_Vec3fToVec3s(Vec3s* dst, Vec3f* src) {
+ dst->x = src->x;
+ dst->y = src->y;
+ dst->z = src->z;
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800388A8.s")
+/**
+ * Get CollisionPoly's lowest y point
+ */
+s16 CollisionPoly_GetMinY(CollisionPoly* poly, Vec3s* vtxList) {
+ s32 a, b, c;
+ s16 min;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800388E8.s")
+ if (poly->normal.y == COLPOLY_SNORMAL(1.0f) || poly->normal.y == COLPOLY_SNORMAL(-1.0f)) {
+ return vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)].y;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038924.s")
+ a = COLPOLY_VTX_INDEX(poly->flags_vIA);
+ b = COLPOLY_VTX_INDEX(poly->flags_vIB);
+ c = poly->vIC;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800389D4.s")
+ min = vtxList[a].y;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038A28.s")
+ if (min > vtxList[b].y) {
+ min = vtxList[b].y;
+ }
+ if (min < vtxList[c].y) {
+ return min;
+ }
+ return vtxList[c].y;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038B7C.s")
+/**
+ * CollisionPoly get unit normal
+ */
+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);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038BE0.s")
+/**
+ * Compute transform matrix mapping +y (up) to the collision poly's normal
+ */
+void func_80038A28(CollisionPoly* poly, f32 tx, f32 ty, f32 tz, MtxF* dest) {
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ s32 pad;
+ f32 phi_f2;
+ f32 phi_f14;
+ f32 phi_f12;
+ f32 inv_phi_f2;
+ f32 inv_phi_f14;
+
+ if (poly == NULL) {
+ return;
+ }
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038C78.s")
+ phi_f2 = sqrtf(1.0f - SQ(nx));
+ if (!IS_ZERO(phi_f2)) {
+ inv_phi_f2 = 1.0f / phi_f2;
+ phi_f14 = ny * inv_phi_f2;
+ phi_f12 = -(nz * inv_phi_f2);
+ } else {
+ phi_f14 = sqrtf(1.0f - SQ(ny));
+ if (1) {}
+ if (!IS_ZERO(phi_f14)) {
+ inv_phi_f14 = (1.0f / phi_f14);
+ phi_f12 = nx * inv_phi_f14;
+ phi_f2 = -(nz * inv_phi_f14);
+ } else {
+ phi_f12 = 0.0f;
+ phi_f2 = 0.0f;
+ }
+ }
+ dest->xx = phi_f2;
+ dest->xy = (-nx) * phi_f14;
+ dest->xz = nx * phi_f12;
+ dest->yx = nx;
+ dest->yy = ny;
+ dest->yz = nz;
+ dest->zy = phi_f12;
+ dest->zz = phi_f14;
+ dest->xw = 0.0f;
+ dest->yw = 0.0f;
+ dest->zx = 0.0f;
+ dest->zw = 0.0f;
+ dest->wx = tx;
+ dest->wy = ty;
+ dest->wz = tz;
+ dest->ww = 1.0f;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038D48.s")
+/**
+ * Calculate point distance from plane along normal
+ */
+f32 CollisionPoly_GetPointDistanceFromPlane(CollisionPoly* poly, Vec3f* point) {
+ return (poly->normal.x * point->x + poly->normal.y * point->y + poly->normal.z * point->z) * COLPOLY_NORMAL_FRAC +
+ poly->dist;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038E78.s")
+/**
+ * Get Poly Vertices
+ */
+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]);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038F20.s")
+/**
+ * Get vertices by bgId
+ * original name: T_Polygon_GetVertex_bg_ai
+ */
+void CollisionPoly_GetVerticesByBgId(CollisionPoly* poly, s32 bgId, CollisionContext* colCtx, Vec3f* dest) {
+ Vec3s* vtxList;
+
+ if (poly == NULL || bgId > BG_ACTOR_MAX || dest == NULL) {
+ osSyncPrintf(VT_COL(RED, WHITE));
+ // translates to: "Argument not appropriate. Processing terminated."
+ osSyncPrintf("T_Polygon_GetVertex_bg_ai(): Error %d %d %d 引数が適切ではありません。処理を終了します。\n",
+ poly == NULL, bgId > BG_ACTOR_MAX, dest == NULL);
+ osSyncPrintf(VT_RST);
+
+ 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;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80038F60.s")
+ CollisionPoly_GetVertices(poly, vtxList, dest);
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80039000.s")
+/**
+ * Checks if point (`x`,`z`) is within `chkDist` of `poly`, computing `yIntersect` if true
+ * Determinant max 300.0f
+ */
+s32 CollisionPoly_CheckYIntersectApprox1(CollisionPoly* poly, Vec3s* vtxList, f32 x, f32 z, f32* yIntersect,
+ f32 chkDist) {
+ static Vec3f polyVerts[3];
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ Vec3s* vA;
+ Vec3s* vB;
+ Vec3s* vC;
+
+ vA = &vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)];
+ Math_Vec3s_ToVec3f(&polyVerts[0], vA);
+ vB = &vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)];
+ Math_Vec3s_ToVec3f(&polyVerts[1], vB);
+ vC = &vtxList[poly->vIC];
+ Math_Vec3s_ToVec3f(&polyVerts[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(&polyVerts[0], &polyVerts[1], &polyVerts[2], nx, ny, nz, poly->dist, z,
+ x, yIntersect, chkDist);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800390A0.s")
+/**
+ * Checks if point (`x`,`z`) is within `chkDist` of `poly`, computing `yIntersect` if true
+ * Determinant max 0.0f (checks if on or within poly)
+ */
+s32 CollisionPoly_CheckYIntersect(CollisionPoly* poly, Vec3s* vtxList, f32 x, f32 z, f32* yIntersect, f32 chkDist) {
+ static Vec3f polyVerts[3];
+ f32 nx;
+ f32 ny;
+ f32 nz;
+
+ CollisionPoly_GetVertices(poly, vtxList, polyVerts);
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
+ return Math3D_TriChkPointParaYIntersectInsideTri(&polyVerts[0], &polyVerts[1], &polyVerts[2], nx, ny, nz,
+ poly->dist, z, x, yIntersect, chkDist);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003937C.s")
+/**
+ * Checks if point (`x`,`z`) is within 1.0f of `poly`, computing `yIntersect` if true
+ * Determinant max 300.0f
+ */
+s32 CollisionPoly_CheckYIntersectApprox2(CollisionPoly* poly, Vec3s* vtxList, f32 x, f32 z, f32* yIntersect) {
+ return CollisionPoly_CheckYIntersectApprox1(poly, vtxList, x, z, yIntersect, 1.0f);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80039448.s")
+/**
+ * Checks if point (`y`,`z`) is within 1.0f of `poly`, computing `xIntersect` if true
+ * Determinant max 300.0f
+ */
+s32 CollisionPoly_CheckXIntersectApprox(CollisionPoly* poly, Vec3s* vtxList, f32 y, f32 z, f32* xIntersect) {
+ static Vec3f polyVerts[3];
+ f32 nx;
+ f32 ny;
+ f32 nz;
+
+ CollisionPoly_GetVertices(poly, vtxList, polyVerts);
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
+ return Math3D_TriChkPointParaXIntersect(&polyVerts[0], &polyVerts[1], &polyVerts[2], nx, ny, nz, poly->dist, y, z,
+ xIntersect);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003965C.s")
+/**
+ * Checks if point (`x`,`y`) is within 1.0f of `poly`, computing `zIntersect` if true
+ * Determinant max 300.0f
+ */
+s32 CollisionPoly_CheckZIntersectApprox(CollisionPoly* poly, Vec3s* vtxList, f32 x, f32 y, f32* zIntersect) {
+ static Vec3f polyVerts[3];
+ f32 nx;
+ f32 ny;
+ f32 nz;
+
+ CollisionPoly_GetVertices(poly, vtxList, polyVerts);
+ CollisionPoly_GetNormalF(poly, &nx, &ny, &nz);
+ return Math3D_TriChkPointParaZIntersect(&polyVerts[0], &polyVerts[1], &polyVerts[2], nx, ny, nz, poly->dist, x, y,
+ zIntersect);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800396F0.s")
+/**
+ * Test if travelling from `posA` to `posB` intersects `poly`
+ * returns true if an intersection occurs, else false
+ * returns `planeIntersect`, which is the point at which the line from `posA` to `posB` crosses `poly`'s plane
+ * if `chkOneFace` is true, return false (no intersection) when going through the poly from A to B is done in the
+ * normal's direction
+ */
+s32 CollisionPoly_LineVsPoly(CollisionPoly* poly, Vec3s* vtxList, Vec3f* posA, Vec3f* posB, Vec3f* planeIntersect,
+ s32 chkOneFace, f32 chkDist) {
+ static Vec3f polyVerts[3];
+ static Plane plane;
+ f32 planeDistA;
+ f32 planeDistB;
+ f32 planeDistDelta;
+
+ plane.originDist = poly->dist;
+ planeDistA =
+ (poly->normal.x * posA->x + poly->normal.y * posA->y + poly->normal.z * posA->z) * COLPOLY_NORMAL_FRAC +
+ plane.originDist;
+ planeDistB =
+ (poly->normal.x * posB->x + poly->normal.y * posB->y + poly->normal.z * posB->z) * COLPOLY_NORMAL_FRAC +
+ plane.originDist;
+
+ planeDistDelta = planeDistA - planeDistB;
+ if ((planeDistA >= 0.0f && planeDistB >= 0.0f) || (planeDistA < 0.0f && planeDistB < 0.0f) ||
+ (chkOneFace && planeDistA < 0.0f && planeDistB > 0.0f) || IS_ZERO(planeDistDelta)) {
+ return false;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003992C.s")
+ CollisionPoly_GetNormalF(poly, &plane.normal.x, &plane.normal.y, &plane.normal.z);
+ CollisionPoly_GetVertices(poly, vtxList, polyVerts);
+ Math3D_LineSplitRatio(posA, posB, planeDistA / planeDistDelta, planeIntersect);
+ if ((fabsf(plane.normal.x) > 0.5f &&
+ Math3D_TriChkPointParaXDist(&polyVerts[0], &polyVerts[1], &polyVerts[2], &plane, planeIntersect->y,
+ planeIntersect->z, chkDist)) ||
+ (fabsf(plane.normal.y) > 0.5f &&
+ Math3D_TriChkPointParaYDist(&polyVerts[0], &polyVerts[1], &polyVerts[2], &plane, planeIntersect->z,
+ planeIntersect->x, chkDist)) ||
+ (fabsf(plane.normal.z) > 0.5f &&
+ Math3D_TriChkLineSegParaZDist(&polyVerts[0], &polyVerts[1], &polyVerts[2], &plane, planeIntersect->x,
+ planeIntersect->y, chkDist))) {
+ return true;
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80039A3C.s")
+/**
+ * Tests if sphere `center` `radius` intersects `poly`
+ */
+s32 CollisionPoly_SphVsPoly(CollisionPoly* poly, Vec3s* vtxList, Vec3f* center, f32 radius) {
+ static Sphere16 sphere;
+ static TriNorm tri;
+ 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_TriVsSphIntersect(&sphere, &tri, &intersect);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80039AEC.s")
+/**
+ * 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;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003A3E0.s")
+ polyYMin = CollisionPoly_GetMinY(&polyList[polyId], vtxList);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003A5B8.s")
+ // Swapped operands on this pointer addition
+ curNode = &colCtx->polyNodes.tbl[ssList->head];
+ curPolyId = curNode->polyId;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003A7D8.s")
+ // 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;
+ return;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003A95C.s")
+ 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;
+ return;
+ }
+ curNode = nextNode;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003AB28.s")
+/**
+ * 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);
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003AC54.s")
+/**
+ * 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 chkDist, s32 flags) {
+ SSNode* curNode;
+ s32 polyId;
+ f32 result;
+ f32 yIntersect;
+
+ result = yIntersectMin;
+ if (ssList->head == SS_NULL) {
+ return result;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003AD00.s")
+ curNode = &colCtx->polyNodes.tbl[ssList->head];
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003ADC8.s")
+ while (true) {
+ polyId = curNode->polyId;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003AEA8.s")
+ if (COLPOLY_VIA_FLAG_TEST(colCtx->colHeader->polyList[polyId].flags_vIA, xpFlags) ||
+ ((flags & 1) && colCtx->colHeader->polyList[polyId].normal.y < 0)) {
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003B04C.s")
+ if (pos->y < colCtx->colHeader->vtxList[COLPOLY_VTX_INDEX(colCtx->colHeader->polyList[polyId].flags_vIA)].y &&
+ pos->y < colCtx->colHeader->vtxList[COLPOLY_VTX_INDEX(colCtx->colHeader->polyList[polyId].flags_vIB)].y &&
+ pos->y < colCtx->colHeader->vtxList[colCtx->colHeader->polyList[polyId].vIC].y) {
+ break;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003B218.s")
+ if (CollisionPoly_CheckYIntersect(&colCtx->colHeader->polyList[polyId], colCtx->colHeader->vtxList, pos->x,
+ pos->z, &yIntersect, chkDist) == true) {
+ // if poly is closer to pos without going over
+ if (yIntersect < pos->y && result < yIntersect) {
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003B3C8.s")
+ result = yIntersect;
+ *outPoly = &colCtx->colHeader->polyList[polyId];
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003BB18.s")
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ }
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003BF18.s")
+/**
+ * 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 chkDist, f32 yIntersectMin) {
+ s32 flag; // skip polys with normal.y < 0
+ f32 yIntersect = yIntersectMin;
+
+ if (arg5 & 4) {
+ yIntersect = BgCheck_RaycastFloorStaticList(colCtx, xpFlags, &lookup->floor, poly, pos, yIntersect, chkDist, 0);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003BF5C.s")
+ if ((arg5 & 2) || (arg5 & 8)) {
+ flag = 0;
+ if (arg5 & 0x10) {
+ flag = 1;
+ }
+ yIntersect =
+ BgCheck_RaycastFloorStaticList(colCtx, xpFlags, &lookup->wall, poly, pos, yIntersect, chkDist, flag);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003BFF4.s")
+ if (arg5 & 1) {
+ flag = 0;
+ if (arg5 & 0x10) {
+ flag = 1;
+ }
+ yIntersect =
+ BgCheck_RaycastFloorStaticList(colCtx, xpFlags, &lookup->ceiling, poly, pos, yIntersect, chkDist, flag);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003C078.s")
+ return yIntersect;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/T_BGCheck_getBGDataInfo.s")
+/**
+ * Compute wall displacement on `posX` and `posZ`
+ * sets `wallPolyPtr` to `poly` if `wallPolyPtr` is NULL or not a damage wall
+ * 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) {
+ CollisionPoly* wallPoly;
+ u32 surfaceData;
+ u32 wallDamage;
+ f32 displacement = (radius - planeDist) * invXZlength;
+
+ *posX += displacement * nx;
+ *posZ += displacement * nz;
+
+ wallPoly = *wallPolyPtr;
+ if (wallPoly == NULL) {
+ *wallPolyPtr = poly;
+ return true;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003C55C.s")
+ surfaceData = colCtx->colHeader->surfaceTypeList[wallPoly->type].data[1];
+ wallDamage = surfaceData & 0x08000000 ? 1 : 0;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003C614.s")
+ if (!wallDamage) {
+ *wallPolyPtr = poly;
+ return true;
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003C890.s")
+/**
+ * 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);
+#ifdef NON_MATCHING
+// regalloc issues
+s32 BgCheck_SphVsStaticWall(StaticLookup* lookup, CollisionContext* colCtx, u16 xpFlags, f32* outX, f32* outZ,
+ Vec3f* pos, f32 radius, CollisionPoly** outPoly) {
+ // f32 sp104;
+ Vec3f resultPos; // spFC
+ f32 temp_f2;
+ f32 temp_f2_2;
+ f32 planeDist; // f30
+ f32 intersect; // spEC
+ s32 result; // spE8
+ CollisionPoly* curPoly; // s0
+ CollisionPoly* polyList; // spE0
+ SSNode* curNode; // s1
+ // f32 temp_f0; // pad
+ f32 invNormalXZ; // sp9C //f14
+ f32 temp_f0_3; // f0
+ f32 xTemp; // f0
+ s32 polyId;
+ f32 normalXZ; // f20
+ f32 nx; // f22
+ f32 ny; // f26
+ f32 nz; // f24
+ f32 temp_f16; // spB8
+ Vec3s* vtxList; // s2
+ u16 pad; // temp_v0;
+
+ f32 zMin; // f2
+ f32 zMax; // f12
+ f32 xMin; // f2
+ f32 xMax; // f12
+
+ 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];
+ if (pos->y < vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIA)].y &&
+ pos->y < vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIB)].y && pos->y < vtxList[curPoly->vIC].y) {
+ break;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003C8EC.s")
+ 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)) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003C940.s")
+ (!IS_ZERO(normalXZ)) ? (void)0 : __assert("!IS_ZERO(ac_size)", "../z_bgcheck.c", 2854);
+ 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;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003C9A4.s")
+ // compute curPoly zMin/zMax
+ zMin = zMax = vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIA)].z;
+ temp_f0_3 = vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIB)].z;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003CA0C.s")
+ if (temp_f0_3 < zMin) {
+ zMin = temp_f0_3;
+ } else if (zMax < temp_f0_3) {
+ zMax = temp_f0_3;
+ }
+ temp_f0_3 = vtxList[curPoly->vIC].z;
+ if (temp_f0_3 < zMin) {
+ zMin = temp_f0_3;
+ } else if (temp_f0_3 > zMax) {
+ zMax = temp_f0_3;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003CA64.s")
+ zMin -= radius;
+ zMax += radius;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003CB30.s")
+ 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)) {
+ temp_f2 = intersect - resultPos.z;
+ if (fabsf(temp_f2) <= radius / temp_f16) {
+ if (temp_f2 * nz <= 4.0f) {
+ 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];
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003CCA4.s")
+ curNode = &colCtx->polyNodes.tbl[lookup->wall.head];
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003CDD4.s")
+ while (true) {
+ polyId = curNode->polyId;
+ curPoly = &polyList[polyId];
+ if (pos->y < vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIA)].y &&
+ pos->y < vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIB)].y && pos->y < vtxList[curPoly->vIC].y) {
+ break;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003D464.s")
+ 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)) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003D52C.s")
+ (!IS_ZERO(normalXZ)) ? (void)0 : __assert("!IS_ZERO(ac_size)", "../z_bgcheck.c", 2964);
+ 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;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003D594.s")
+ // compute curPoly xMin/xMax
+ xMin = xMax = vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIA)].x;
+ temp_f0_3 = vtxList[COLPOLY_VTX_INDEX(curPoly->flags_vIB)].x;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003D600.s")
+ if (temp_f0_3 < xMin) {
+ xMin = temp_f0_3;
+ } else if (xMax < temp_f0_3) {
+ xMax = temp_f0_3;
+ }
+ temp_f0_3 = vtxList[curPoly->vIC].x;
+ if (temp_f0_3 < xMin) {
+ xMin = temp_f0_3;
+ } else if (xMax < temp_f0_3) {
+ xMax = temp_f0_3;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003D7A0.s")
+ xMin -= radius;
+ xMax += radius;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003D7F0.s")
+ 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)) {
+ temp_f2 = intersect - resultPos.x;
+ if (fabsf(temp_f2) <= radius / temp_f16) {
+ if (temp_f2 * nx <= 4.0f) {
+ 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;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003DD28.s")
+ *outX = resultPos.x;
+ *outZ = resultPos.z;
+ return result;
+}
+#else
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_SphVsStaticWall.s")
+#endif
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003DD6C.s")
+/**
+ * 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`
+ */
+s32 BgCheck_CheckStaticCeiling(StaticLookup* lookup, u16 xpFlags, CollisionContext* colCtx, f32* outY, Vec3f* pos,
+ f32 checkHeight, CollisionPoly** outPoly) {
+ s32 result = false;
+ u16 nextId;
+ CollisionPoly* curPoly;
+ CollisionPoly* polyList;
+ f32 ceilingY;
+ Vec3s* vtxList;
+ SSNode* curNode;
+ s32 curPolyId;
+
+ if (lookup->ceiling.head == SS_NULL) {
+ return false;
+ }
+ curNode = &colCtx->polyNodes.tbl[lookup->ceiling.head];
+ polyList = colCtx->colHeader->polyList;
+ vtxList = colCtx->colHeader->vtxList;
+
+ *outY = pos->y;
+
+ while (true) {
+ curPolyId = curNode->polyId;
+ if (COLPOLY_VIA_FLAG_TEST(colCtx->colHeader->polyList[curPolyId].flags_vIA, xpFlags)) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ curPoly = &polyList[curPolyId];
+ 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.0f && 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;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003DFA0.s")
+/**
+ * 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
+ */
+s32 func_8003A5B8(SSList* ssList, CollisionContext* colCtx, u16 xpFlags1, u16 xpFlags2, Vec3f* posA, Vec3f* posB,
+ Vec3f* outPos, CollisionPoly** outPoly, f32* outDistSq, f32 chkDist, s32 bccFlags) {
+ SSNode* curNode;
+ u8* checkedPoly;
+ Vec3f polyIntersect;
+ CollisionPoly* polyList;
+ CollisionPoly* curPoly;
+ s32 result;
+ f32 minY;
+ f32 distSq;
+ s16 polyId;
+
+ result = false;
+ polyList = colCtx->colHeader->polyList;
+ if (ssList->head == SS_NULL) {
+ return result;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E02C.s")
+ curNode = &colCtx->polyNodes.tbl[ssList->head];
+ while (true) {
+ polyId = curNode->polyId;
+ checkedPoly = &colCtx->polyNodes.polyCheckTbl[polyId];
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E0B8.s")
+ if (*checkedPoly == true || COLPOLY_VIA_FLAG_TEST(polyList[polyId].flags_vIA, xpFlags1) ||
+ !(xpFlags2 == 0 || COLPOLY_VIA_FLAG_TEST(polyList[polyId].flags_vIA, xpFlags2))) {
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E0FC.s")
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ continue;
+ }
+ }
+ *checkedPoly = true;
+ curPoly = &polyList[polyId];
+ minY = CollisionPoly_GetMinY(curPoly, colCtx->colHeader->vtxList);
+ if (posA->y < minY && posB->y < minY) {
+ break;
+ }
+ if (CollisionPoly_LineVsPoly(curPoly, colCtx->colHeader->vtxList, posA, posB, &polyIntersect,
+ (bccFlags & BGCHECK_CHECK_ONE_FACE) != 0, chkDist)) {
+ distSq = Math3D_Vec3fDistSq(posA, &polyIntersect);
+ if (distSq < *outDistSq) {
+
+ *outDistSq = distSq;
+ *outPos = polyIntersect;
+ *posB = polyIntersect;
+ *outPoly = curPoly;
+ result = true;
+ }
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ }
+ return result;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E188.s")
+/**
+ * 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 func_8003A7D8(StaticLookup* lookup, CollisionContext* colCtx, u16 xpFlags1, u16 xpFlags2, Vec3f* posA, Vec3f* posB,
+ Vec3f* outPos, CollisionPoly** outPoly, f32 chkDist, f32* outDistSq, u32 bccFlags) {
+ s32 result = false;
+ if ((bccFlags & BGCHECK_CHECK_FLOOR) && lookup->floor.head != SS_NULL) {
+ if (func_8003A5B8(&lookup->floor, colCtx, xpFlags1, xpFlags2, posA, posB, outPos, outPoly, outDistSq, chkDist,
+ bccFlags)) {
+ result = true;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E214.s")
+ if ((bccFlags & BGCHECK_CHECK_WALL) && lookup->wall.head != SS_NULL) {
+ if (func_8003A5B8(&lookup->wall, colCtx, xpFlags1, xpFlags2, posA, posB, outPos, outPoly, outDistSq, chkDist,
+ bccFlags)) {
+ result = true;
+ }
+ }
-void func_8003E398(u16* puParm1) {
- *puParm1 = 0;
- puParm1[1] = 0;
- *(u32*)(puParm1 + 2) = 0;
- *(u32*)(puParm1 + 4) = 0;
+ if ((bccFlags & BGCHECK_CHECK_CEILING) && lookup->ceiling.head != SS_NULL) {
+ if (func_8003A5B8(&lookup->ceiling, colCtx, xpFlags1, xpFlags2, posA, posB, outPos, outPoly, outDistSq, chkDist,
+ bccFlags)) {
+ result = true;
+ }
+ }
+ return result;
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E3AC.s")
+/**
+ * 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
+ */
+s32 BgCheck_SphVsFirstStaticPolyList(SSNode* node, u16 xpFlags, CollisionContext* colCtx, Vec3f* center, f32 radius,
+ CollisionPoly** outPoly) {
+ CollisionPoly* polyList;
+ Vec3s* vtxList;
+ CollisionPoly* curPoly;
+ u16 nextId;
+ s16 curPolyId;
+
+ 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)) {
+ if (node->next == SS_NULL) {
+ break;
+ } else {
+ node = &colCtx->polyNodes.tbl[node->next];
+ continue;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E4DC.s")
+ 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) {
+ break;
+ }
+ node = &colCtx->polyNodes.tbl[node->next];
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E530.s")
+/**
+ * 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) {
+ if (lookup->floor.head != SS_NULL && !(bciFlags & BGCHECK_IGNORE_FLOOR) &&
+ BgCheck_SphVsFirstStaticPolyList(&colCtx->polyNodes.tbl[lookup->floor.head], xpFlags, colCtx, center, radius,
+ outPoly)) {
+ return true;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E568.s")
+ if (lookup->wall.head != SS_NULL && !(bciFlags & BGCHECK_IGNORE_WALL) &&
+ BgCheck_SphVsFirstStaticPolyList(&colCtx->polyNodes.tbl[lookup->wall.head], xpFlags, colCtx, center, radius,
+ outPoly)) {
+ return true;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E5B4.s")
+ if (lookup->ceiling.head != SS_NULL && !(bciFlags & BGCHECK_IGNORE_CEILING) &&
+ BgCheck_SphVsFirstStaticPolyList(&colCtx->polyNodes.tbl[lookup->ceiling.head], xpFlags, colCtx, center, radius,
+ outPoly)) {
+ return true;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E688.s")
+ return false;
+}
-void func_8003E6C4(u16* puParm1) {
- *puParm1 = 0;
- func_8003E688();
+/**
+ * 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; // fix regalloc
+ return (sector.z * subdivAmountX) * colCtx->subdivAmount.y + lookupTbl + sector.x + sector.y * subdivAmountX;
}
-void func_8003E6E4(u16* a0) {
- *a0 = 0;
+/**
+ * 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; // fix regalloc
+ return (sector.z * subdivAmountX) * colCtx->subdivAmount.y + lookupTbl + sector.x + sector.y * subdivAmountX;
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E6EC.s")
+/**
+ * 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;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E750.s")
+ if (sector->y < 0) {
+ sector->y = 0;
+ } else if (sector->y >= colCtx->subdivAmount.y) {
+ sector->y = colCtx->subdivAmount.y - 1;
+ }
-void func_8003E804(s32 iParm1) {
- func_8003E5B4(iParm1 + 0x14, iParm1 + 0x34);
+ if (sector->z < 0) {
+ sector->z = 0;
+ } else if (sector->z >= colCtx->subdivAmount.z) {
+ sector->z = colCtx->subdivAmount.z - 1;
+ }
}
-void func_8003E82C(u32* a0) {
- *a0 = 0;
+/**
+ * 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 func_8003AEA8(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;
+ }
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E834.s")
+/**
+ * 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 func_8003B04C(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;
+ }
-void func_8003E888(u32* a0) {
- *a0 = 0;
+ 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_8003E890.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 func_8003B218(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;
+
+ 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;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E8EC.s")
+ if (minVtx.z > z) {
+ minVtx.z = z;
+ } else if (maxVtx.z < z) {
+ maxVtx.z = z;
+ }
+ }
+ func_8003AEA8(colCtx, &minVtx, subdivMinX, subdivMinY, subdivMinZ);
+ func_8003B04C(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 func_8003B3C8(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;
+ }
+ BgCheck_Vec3sToVec3f(&vtxList[poly->vIC], &vc);
+ flags[2] = Math3D_PointRelativeToCubeFaces(&vc, min, max);
+ if (flags[2] == 0) {
+ return true;
+ }
+ if (flags[0] & flags[1] & flags[2]) {
+ return false;
+ }
-/*
-NON-MATCHING
-void func_8003E8EC(u32 uParm1, u32* iParm2) {
- iParm2[0x06] = iParm2[0x0E];
- iParm2[0x05] = iParm2[0x0D];
- iParm2[0x07] = iParm2[0x0F];
- iParm2[0x08] = iParm2[0x10];
- iParm2[0x0A] = iParm2[0x12];
- iParm2[0x09] = iParm2[0x11];
- iParm2[0x0B] = iParm2[0x13];
- iParm2[0x0C] = iParm2[0x14];
+ 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;
+ }
+ 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;
+ }
- //s32 i;
- //for (i = 0; i < 4; i++) {
- //iParm2[0x06 + (i * 2)] = iParm2[0x0E + (i * 2)];
- //iParm2[0x07 + (i * 2)] = iParm2[0x0D + (i * 2)];
- //}
+ 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;
}
-*/
-u32 func_8003E934(s32 iParm1) {
- if (!((-1 < iParm1) && (iParm1 < 0x32))) {
- return 0;
+/**
+ * Initialize StaticLookup Table
+ * returns size of table, in bytes
+ */
+u32 func_8003BB18(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;
+ StaticLookup* spA4;
+ StaticLookup* phi_fp;
+ StaticLookup* phi_s0;
+ s32 sp98;
+ f32 subdivLengthX;
+ f32 subdivLengthY;
+ f32 subdivLengthZ;
+
+ colHeader = colCtx->colHeader;
+
+ for (spA4 = lookupTbl;
+ spA4 < (colCtx->subdivAmount.x * colCtx->subdivAmount.y * colCtx->subdivAmount.z + lookupTbl); spA4++) {
+ spA4->floor.head = SS_NULL;
+ spA4->wall.head = SS_NULL;
+ spA4->ceiling.head = SS_NULL;
+ }
+ polyMax = colHeader->nbPolygons;
+ 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++) {
+ func_8003B218(colCtx, vtxList, polyList, &sxMin, &syMin, &szMin, &sxMax, &syMax, &szMax, polyIdx);
+
+ spA4 = 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++) {
+ phi_fp = (colCtx->subdivAmount.x * syMin) + spA4;
+ curSubdivMin.y = (colCtx->subdivLength.y * syMin + colCtx->minBounds.y) - BGCHECK_SUBDIV_OVERLAP;
+ curSubdivMax.y = curSubdivMin.y + subdivLengthY;
+
+ for (sy = syMin; sy < syMax + 1; sy++) {
+ phi_s0 = sxMin + phi_fp;
+ 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 (func_8003B3C8(&curSubdivMin, &curSubdivMax, polyList, vtxList, polyIdx)) {
+ StaticLookup_AddPoly(phi_s0, colCtx, polyList, vtxList, polyIdx);
+ }
+ curSubdivMin.x += colCtx->subdivLength.x;
+ curSubdivMax.x += colCtx->subdivLength.x;
+ phi_s0++;
+ }
+ curSubdivMin.y += colCtx->subdivLength.y;
+ curSubdivMax.y += colCtx->subdivLength.y;
+ phi_fp += colCtx->subdivAmount.x;
+ }
+ curSubdivMin.z += colCtx->subdivLength.z;
+ curSubdivMax.z += colCtx->subdivLength.z;
+ spA4 += sp98;
+ }
}
+ return colCtx->polyNodes.count * sizeof(SSNode);
+}
- return 1;
+/**
+ * Is current scene a SPOT scene
+ */
+s32 BgCheck_IsSpotScene(GlobalContext* globalCtx) {
+ static s16 spotScenes[] = {
+ SCENE_SPOT00, SCENE_SPOT01, SCENE_SPOT02, SCENE_SPOT03, SCENE_SPOT04, SCENE_SPOT05, SCENE_SPOT06,
+ SCENE_SPOT07, SCENE_SPOT08, SCENE_SPOT09, SCENE_SPOT10, SCENE_SPOT11, SCENE_SPOT12, SCENE_SPOT13,
+ SCENE_SPOT15, SCENE_SPOT16, SCENE_SPOT17, SCENE_SPOT18, SCENE_SPOT20,
+ };
+ s16* i;
+
+ for (i = spotScenes; i < spotScenes + ARRAY_COUNT(spotScenes); i++) {
+ if (globalCtx->sceneNum == *i) {
+ return true;
+ }
+ }
+ return false;
}
-void func_8003E954(u32 uParm1, u8* puParm2) {
- *puParm2 = 1;
- func_8003E82C(puParm2 + 0x13f0);
- func_8003E888(puParm2 + 0x13f4);
- func_800387FC(uParm1, puParm2 + 0x13f8);
+typedef struct {
+ s16 sceneId;
+ u32 memSize;
+} BgCheckSceneMemEntry;
+
+/**
+ * Get custom scene memSize
+ */
+s32 BgCheck_TryGetCustomMemsize(s32 sceneId, u32* memSize) {
+ static BgCheckSceneMemEntry sceneMemList[] = {
+ { SCENE_SPOT00, 0xB798 }, { SCENE_GANON_FINAL, 0x78C8 }, { SCENE_GANON_DEMO, 0x70C8 },
+ { SCENE_JYASINBOSS, 0xACC8 }, { SCENE_KENJYANOMA, 0x70C8 }, { SCENE_JYASINZOU, 0x16CC8 },
+ { SCENE_HIDAN, 0x198C8 }, { SCENE_GANON_BOSS, 0x84C8 },
+ };
+ s32 i;
+ for (i = 0; i < ARRAY_COUNT(sceneMemList); i++) {
+ if (sceneId == sceneMemList[i].sceneId) {
+ *memSize = sceneMemList[i].memSize;
+ return true;
+ }
+ }
+ return false;
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003E9A0.s")
+/**
+ * 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);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003EA74.s")
+ *subdivLength = (s32)(length / subdivAmount) + 1;
+ *subdivLength = CLAMP_MIN(*subdivLength, BGCHECK_SUBDIV_MIN);
+ *subdivLengthInv = 1.0f / *subdivLength;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003EB84.s")
+ *max = *subdivLength * subdivAmount + min;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003ECA8.s")
+typedef struct {
+ s16 sceneId;
+ Vec3s subdivAmount;
+ s32 nodeListMax; // if -1, dynamically compute max nodes
+} BgCheckSceneSubdivisionEntry;
+
+/**
+ * Allocate CollisionContext
+ */
+void BgCheck_Allocate(CollisionContext* colCtx, GlobalContext* globalCtx, CollisionHeader* colHeader) {
+ static BgCheckSceneSubdivisionEntry sceneSubdivisionList[] = {
+ { SCENE_HAKADAN, { 23, 7, 14 }, -1 },
+ { SCENE_BMORI1, { 38, 1, 38 }, -1 },
+ };
+ u32 tblMax;
+ u32 memSize;
+ u32 lookupTblMemSize;
+ SSNodeList* nodeList;
+ s32 useCustomSubdivisions;
+ u32 customMemSize;
+ s32 customNodeListMax;
+ s32 i;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003ED58.s")
+ colCtx->colHeader = colHeader;
+ customNodeListMax = -1;
+ osSyncPrintf("/*---------------- BGCheck バッファーメモリサイズ -------------*/\n");
+ // /*---------------- BGCheck Buffer Memory Size -------------*/\n
+
+ if (YREG(15) == 0x10 || YREG(15) == 0x20 || YREG(15) == 0x30 || YREG(15) == 0x40) {
+ if (globalCtx->sceneNum == SCENE_MALON_STABLE) {
+ osSyncPrintf("/* BGCheck LonLonサイズ %dbyte */\n", 0x3520);
+ // /* BGCheck LonLon Size %dbyte */\n
+ colCtx->memSize = 0x3520;
+ } else {
+ osSyncPrintf("/* BGCheck ミニサイズ %dbyte */\n", 0x4E20);
+ // /* BGCheck Mini Size %dbyte */\n
+ colCtx->memSize = 0x4E20;
+ }
+ colCtx->dyna.polyNodesMax = 500;
+ colCtx->dyna.polyListMax = 256;
+ colCtx->dyna.vtxListMax = 256;
+ colCtx->subdivAmount.x = 2;
+ colCtx->subdivAmount.y = 2;
+ colCtx->subdivAmount.z = 2;
+ } else if (BgCheck_IsSpotScene(globalCtx) == true) {
+ colCtx->memSize = 0xF000;
+ osSyncPrintf("/* BGCheck Spot用サイズ %dbyte */\n", 0xF000);
+ // /* BGCheck Spot Size %dbyte */\n
+ 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 = 0x1CC00;
+ }
+ osSyncPrintf("/* BGCheck ノーマルサイズ %dbyte */\n", colCtx->memSize);
+ // /* BGCheck Normal Size %dbyte */\n
+ colCtx->dyna.polyNodesMax = 1000;
+ colCtx->dyna.polyListMax = 512;
+ colCtx->dyna.vtxListMax = 512;
+ useCustomSubdivisions = false;
+
+ for (i = 0; i < ARRAY_COUNT(sceneSubdivisionList); i++) {
+ if (globalCtx->sceneNum == sceneSubdivisionList[i].sceneId) {
+ colCtx->subdivAmount.x = sceneSubdivisionList[i].subdivAmount.x;
+ colCtx->subdivAmount.y = sceneSubdivisionList[i].subdivAmount.y;
+ colCtx->subdivAmount.z = sceneSubdivisionList[i].subdivAmount.z;
+ useCustomSubdivisions = true;
+ customNodeListMax = sceneSubdivisionList[i].nodeListMax;
+ }
+ }
+ if (useCustomSubdivisions == false) {
+ colCtx->subdivAmount.x = 16;
+ colCtx->subdivAmount.y = 4;
+ colCtx->subdivAmount.z = 16;
+ }
+ }
+ colCtx->lookupTbl = THA_AllocEndAlign(
+ &globalCtx->state.tha,
+ colCtx->subdivAmount.x * sizeof(StaticLookup) * colCtx->subdivAmount.y * colCtx->subdivAmount.z, ~1);
+ if (colCtx->lookupTbl == NULL) {
+ LogUtils_HungupThread("../z_bgcheck.c", 4176);
+ }
+ 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->nbPolygons * 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 sceneSubdivisionList.nodeListMax is -1
+ tblMax = customNodeListMax;
+ } else {
+ if (colCtx->memSize < memSize) {
+ LogUtils_HungupThread("../z_bgcheck.c", 4230);
+ }
+ tblMax = (colCtx->memSize - memSize) / sizeof(SSNode);
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003EE6C.s")
+ SSNodeList_Initialize(&colCtx->polyNodes);
+ SSNodeList_Alloc(globalCtx, &colCtx->polyNodes, tblMax, colCtx->colHeader->nbPolygons);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003EE80.s")
+ lookupTblMemSize = func_8003BB18(colCtx, globalCtx, colCtx->lookupTbl);
+ osSyncPrintf(VT_FGCOL(GREEN));
+ osSyncPrintf("/*---結局 BG使用サイズ %dbyte---*/\n", memSize + lookupTblMemSize);
+ osSyncPrintf(VT_RST);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003F8EC.s")
+ DynaPoly_Init(globalCtx, &colCtx->dyna);
+ DynaPoly_Alloc(globalCtx, &colCtx->dyna);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003F984.s")
+/**
+ * Get CollisionHeader
+ * 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)) {
+ osSyncPrintf(VT_COL(YELLOW, BLACK));
+ osSyncPrintf("T_BGCheck_getBGDataInfo():そのbg_actor_indexは使われておりません。index=%d\n");
+ osSyncPrintf(VT_RST);
+ return NULL;
+ }
+ return colCtx->dyna.bgActors[bgId].colHeader;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003FB64.s")
+/**
+ * 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;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003FBF4.s")
+/**
+ * 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 chkDist) {
+
+ f32 yIntersectDyna;
+ s32* temp_a0;
+ StaticLookup* lookupTbl;
+ Vec3f checkPos;
+ StaticLookup* lookup;
+ DynaRaycast dynaRaycast;
+ f32 yIntersect;
+
+ *outBgId = BGCHECK_SCENE;
+ *outPoly = NULL;
+ lookupTbl = colCtx->lookupTbl;
+ yIntersect = BGCHECK_Y_MIN;
+ checkPos = *pos;
+
+ while (true) {
+ if (checkPos.y < colCtx->minBounds.y) {
+ break;
+ }
+ if (BgCheck_PosErrorCheck(&checkPos, "../z_bgcheck.c", 4410)) {
+ if (actor != NULL) {
+ osSyncPrintf("こいつ,pself_actor->name %d\n", actor->id);
+ }
+ }
+ lookup = BgCheck_GetStaticLookup(colCtx, lookupTbl, &checkPos);
+ if (lookup == NULL) {
+ checkPos.y -= colCtx->subdivLength.y;
+ continue;
+ }
+ yIntersect = BgCheck_RaycastFloorStatic(lookup, colCtx, xpFlags, outPoly, pos, arg7, chkDist, BGCHECK_Y_MIN);
+ if (yIntersect > BGCHECK_Y_MIN) {
+ break;
+ }
+ checkPos.y -= colCtx->subdivLength.y;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8003FDDC.s")
+ dynaRaycast.colCtx = colCtx;
+ dynaRaycast.xpFlags = xpFlags;
+ dynaRaycast.yIntersect = yIntersect;
+ dynaRaycast.pos = pos;
+ dynaRaycast.actor = actor;
+ dynaRaycast.unk_20 = arg7;
+ dynaRaycast.chkDist = chkDist;
+ dynaRaycast.globalCtx = globalCtx;
+ dynaRaycast.resultPoly = outPoly;
+ dynaRaycast.bgId = outBgId;
+
+ yIntersectDyna = BgCheck_RaycastFloorDyna(&dynaRaycast);
+
+ if (yIntersect < yIntersectDyna) {
+ yIntersect = yIntersectDyna;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80040284.s")
+ if (yIntersect != BGCHECK_Y_MIN && func_80041EC8(colCtx, *outPoly, *outBgId)) {
+ yIntersect -= 1.0f;
+ }
+ return yIntersect;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800409A8.s")
+/**
+ * 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;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80040BE4.s")
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_CAMERA, outPoly, &bgId, pos, NULL, 0x1C, 1.0f);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80040E40.s")
+/**
+ * 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;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80040FA4.s")
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, &bgId, pos, NULL, 0x1C, 1.0f);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041128.s")
+/**
+ * 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;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041240.s")
+ return BgCheck_RaycastFloorImpl(globalCtx, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, &bgId, pos, NULL, 0x1C, 1.0f);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800413F8.s")
+/**
+ * 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);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041510.s")
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor4(CollisionContext* colCtx, CollisionPoly** outPoly, s32* bgId, Actor* actor,
+ Vec3f* pos) {
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, bgId, pos, actor, 0x1C, 1.0f);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041648.s")
+/**
+ * Public raycast toward floor
+ * returns yIntersect of the poly found, or BGCHECK_Y_MIN if no poly detected
+ */
+f32 BgCheck_EntityRaycastFloor5(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);
+}
-typedef struct {
- /* 0x00 */ char unk_00[0x10];
- /* 0x10 */ void* unk_10;
- /* 0x14 */ char unk_[0x04];
- /* 0x18 */ void* unk_18;
- /* 0x1C */ void* unk_1C;
- /* 0x20 */ void* unk_20;
- /* 0x24 */ char unk_24[4];
- /* 0x28 */ void* unk_28;
-} Struct800417A0; // size = 0x32
-
-// called by func_800418D0 with actorMesh->unk_08
-void func_800417A0(Struct800417A0* arg0) {
- arg0->unk_10 = SEGMENTED_TO_VIRTUAL(arg0->unk_10);
- arg0->unk_18 = SEGMENTED_TO_VIRTUAL(arg0->unk_18);
- arg0->unk_1C = SEGMENTED_TO_VIRTUAL(arg0->unk_1C);
- arg0->unk_20 = SEGMENTED_TO_VIRTUAL(arg0->unk_20);
- arg0->unk_28 = SEGMENTED_TO_VIRTUAL(arg0->unk_28);
-}
-
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041880.s")
+/**
+ * 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 chkDist) {
+ return BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_ENTITY, outPoly, bgId, pos, actor, 0x1C, chkDist);
+}
-void func_800418D0(CollisionContext* colCtx, GlobalContext* globalCtx) {
- ActorMesh* actorMesh;
- DynaCollisionContext* dynaColCtx;
+/**
+ * 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);
+}
+
+/**
+ * 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);
+ 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;
+
+ result = BgCheck_RaycastFloorImpl(NULL, colCtx, COLPOLY_IGNORE_NONE, &tempPoly, bgId, pos, NULL, 0x1C, 1.0f);
+ 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);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * 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_SphVsWallImpl(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;
+ f32 dx, dy, dz; // change between posPrev to posNext
+ 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;
+ f32 nx, ny, nz; // unit normal of polygon
+
+ 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 (BgCheck_PosErrorCheck(posNext, "../z_bgcheck.c", 4831) == true ||
+ BgCheck_PosErrorCheck(posPrev, "../z_bgcheck.c", 4832) == true) {
+ if (actor != NULL) {
+ osSyncPrintf("こいつ,pself_actor->name %d\n", actor->id);
+ }
+ }
+ // 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) {
+ result = BgCheck_LineTestImpl(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;
+ }
+ // 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_LineTestImpl(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;
+ }
+ }
+ }
+ }
+ 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) == true &&
+ // 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)) {
+ *outBgId = BGCHECK_SCENE;
+ result = true;
+ }
+ // if a collision with a dyna poly was detected
+ if (dynaPolyCollision == true || *outBgId != BGCHECK_SCENE) {
+ if (BgCheck_LineTestImpl(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;
+}
+
+/**
+ * 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_SphVsWallImpl(colCtx, COLPOLY_IGNORE_ENTITY, posResult, posNext, posPrev, radius, outPoly, &bgId,
+ NULL, checkHeight, 0);
+}
+
+/**
+ * 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_SphVsWallImpl(colCtx, COLPOLY_IGNORE_ENTITY, posResult, posNext, posPrev, radius, outPoly, outBgId,
+ NULL, checkHeight, 0);
+}
+
+/**
+ * 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_SphVsWallImpl(colCtx, COLPOLY_IGNORE_ENTITY, posResult, posNext, posPrev, radius, outPoly, outBgId,
+ actor, checkHeight, 0);
+}
+
+/***
+ * 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_SphVsWallImpl(colCtx, COLPOLY_IGNORE_ENTITY, posResult, posNext, posPrev, radius, outPoly, outBgId,
+ actor, checkHeight, 1);
+}
+
+/***
+ * 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;
+ if (BgCheck_PosErrorCheck(pos, "../z_bgcheck.c", 5206) == true) {
+ if (actor != NULL) {
+ osSyncPrintf("こいつ,pself_actor->name %d\n", actor->id);
+ }
+ }
+ lookupTbl = colCtx->lookupTbl;
+ if (!BgCheck_PosInStaticBoundingBox(colCtx, pos)) {
+ return false;
+ }
+
+ lookup = BgCheck_GetNearestStaticLookup(colCtx, lookupTbl, pos);
+ result = BgCheck_CheckStaticCeiling(lookup, xpFlags, colCtx, outY, pos, checkHeight, outPoly);
+
+ posTemp = *pos;
+ posTemp.y = *outY;
+ tempY = *outY;
+
+ if (BgCheck_CheckDynaCeiling(colCtx, xpFlags, &tempY, &posTemp, checkHeight, outPoly, outBgId, actor)) {
+ *outY = tempY;
+ result = true;
+ }
+ return result;
+}
+
+/**
+ * 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);
+}
+
+/**
+ * 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);
+}
+
+/**
+ * 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_LineTestImpl(CollisionContext* colCtx, u16 xpFlags1, u16 xpFlags2, Vec3f* posA, Vec3f* posB,
+ Vec3f* posResult, CollisionPoly** outPoly, s32* outBgId, Actor* actor, f32 chkDist,
+ u32 bccFlags) {
+ StaticLookup* lookupTbl;
+ StaticLookup* iLookup;
+ s32 subdivMin[3];
+ s32 subdivMax[3];
s32 i;
- u16 flag;
+ s32 result;
+ f32 distSq;
+ Vec3f posBTemp;
+ Vec3f sectorMin;
+ Vec3f sectorMax;
+ s32 k;
+ StaticLookup* lookup;
+ s32 j;
+ StaticLookup* jLookup;
+ s32 temp_lo;
+
+ lookupTbl = colCtx->lookupTbl;
+ posBTemp = *posB;
+ *outBgId = BGCHECK_SCENE;
+ if (BgCheck_PosErrorCheck(posA, "../z_bgcheck.c", 5334) == true ||
+ BgCheck_PosErrorCheck(posB, "../z_bgcheck.c", 5335) == true) {
+ if (actor != NULL) {
+ osSyncPrintf("こいつ,pself_actor->name %d\n", actor->id);
+ } else {
+ osSyncPrintf("pself_actor == NULLで犯人不明\n");
+ }
+ }
- dynaColCtx = &colCtx->dyna;
- for (i = 0; i < 50; i++) {
- flag = dynaColCtx->flags[i];
- if ((flag & 1) && !(flag & 2)) {
- actorMesh = &dynaColCtx->actorMeshArr[i];
- Actor_SetObjectDependency(globalCtx, actorMesh->actor);
- func_800417A0(actorMesh->unk_08);
+ BgCheck_ResetPolyCheckTbl(&colCtx->polyNodes, colCtx->colHeader->nbPolygons);
+ BgCheck_GetStaticLookupIndicesFromPos(colCtx, posA, &subdivMin);
+ BgCheck_GetStaticLookupIndicesFromPos(colCtx, &posBTemp, &subdivMax);
+ *posResult = *posB;
+ result = false;
+ distSq = 1.0e38f;
+ *outPoly = NULL;
+
+ 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) == true &&
+ func_8003A7D8(lookup, colCtx, xpFlags1, xpFlags2, posA, &posBTemp, posResult, outPoly, chkDist,
+ &distSq, bccFlags)) {
+ 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 {
+ result = func_8003A7D8(BgCheck_GetNearestStaticLookup(colCtx, lookupTbl, posA), colCtx, xpFlags1, xpFlags2,
+ posA, &posBTemp, posResult, outPoly, chkDist, &distSq, bccFlags);
+ if (result == true) {
+ distSq = Math3D_Vec3fDistSq(posResult, posA);
}
}
+ if ((bccFlags & BGCHECK_CHECK_DYNA) && func_80041240(colCtx, xpFlags1, posA, &posBTemp, posResult, outPoly, &distSq,
+ outBgId, actor, chkDist, bccFlags)) {
+ result = true;
+ }
+ return result;
}
+/**
+ * Get bccFlags
+ */
+u32 BgCheck_GetBccFlags(s32 chkWall, s32 chkFloor, s32 chkCeil, s32 chkOneFace, s32 chkDyna) {
+ u32 result;
+
+ result = 0;
+ if (chkWall) {
+ result = BGCHECK_CHECK_WALL;
+ }
+ if (chkFloor) {
+ result |= BGCHECK_CHECK_FLOOR;
+ }
+ if (chkCeil) {
+ result |= BGCHECK_CHECK_CEILING;
+ }
+ if (chkOneFace) {
+ result |= BGCHECK_CHECK_ONE_FACE;
+ }
+ if (chkDyna) {
+ result |= BGCHECK_CHECK_DYNA;
+ }
+ return result;
+}
+
+/**
+ * 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 chkWall, s32 chkFloor, s32 chkCeil, s32 chkOneFace,
+ s32* bgId) {
+ return BgCheck_LineTestImpl(colCtx, COLPOLY_IGNORE_CAMERA, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly,
+ bgId, NULL, 1.0f, BgCheck_GetBccFlags(chkWall, chkFloor, chkCeil, chkOneFace, true));
+}
+
+/**
+ * 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 chkWall, s32 chkFloor, s32 chkCeil, s32 chkOneFace,
+ s32* bgId) {
+ return BgCheck_LineTestImpl(colCtx, COLPOLY_IGNORE_NONE, COLPOLY_IGNORE_CAMERA, posA, posB, posResult, outPoly,
+ bgId, NULL, 1.0f, BgCheck_GetBccFlags(chkWall, chkFloor, chkCeil, chkOneFace, true));
+}
+
+/**
+ * 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 chkWall, s32 chkFloor, s32 chkCeil, s32 chkOneFace,
+ s32* bgId) {
+ return BgCheck_LineTestImpl(colCtx, COLPOLY_IGNORE_ENTITY, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly,
+ bgId, NULL, 1.0f, BgCheck_GetBccFlags(chkWall, chkFloor, chkCeil, chkOneFace, true));
+}
+
+/**
+ * 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 chkWall, s32 chkFloor, s32 chkCeil, s32 chkOneFace, s32* bgId,
+ Actor* actor) {
+ return BgCheck_LineTestImpl(colCtx, COLPOLY_IGNORE_ENTITY, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly,
+ bgId, actor, 1.0f, BgCheck_GetBccFlags(chkWall, chkFloor, chkCeil, chkOneFace, true));
+}
+
+/**
+ * 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 chkWall, s32 chkFloor, s32 chkCeil, s32 chkOneFace, s32* bgId,
+ Actor* actor, f32 chkDist) {
+ return BgCheck_LineTestImpl(colCtx, COLPOLY_IGNORE_ENTITY, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly,
+ bgId, actor, chkDist,
+ BgCheck_GetBccFlags(chkWall, chkFloor, chkCeil, chkOneFace, true));
+}
+
+/**
+ * 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 chkWall, s32 chkFloor, s32 chkCeil, s32 chkOneFace,
+ s32* bgId) {
+ return BgCheck_LineTestImpl(colCtx, COLPOLY_IGNORE_PROJECTILES, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly,
+ bgId, NULL, 1.0f, BgCheck_GetBccFlags(chkWall, chkFloor, chkCeil, chkOneFace, true));
+}
+
+/**
+ * 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 chkOneFace) {
+ return BgCheck_AnyLineTest2(colCtx, posA, posB, posResult, outPoly, true, true, true, chkOneFace);
+}
+
+/**
+ * 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 chkWall, s32 chkFloor, s32 chkCeil, s32 chkOneFace) {
+ s32 bgId;
+
+ return BgCheck_LineTestImpl(colCtx, COLPOLY_IGNORE_NONE, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly, &bgId,
+ NULL, 1.0f, BgCheck_GetBccFlags(chkWall, chkFloor, chkCeil, chkOneFace, true));
+}
+
+/**
+ * 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 chkWall, s32 chkFloor, s32 chkCeil, s32 chkOneFace, s32* bgId) {
+ return BgCheck_LineTestImpl(colCtx, COLPOLY_IGNORE_NONE, COLPOLY_IGNORE_NONE, posA, posB, posResult, outPoly, bgId,
+ NULL, 1.0f, BgCheck_GetBccFlags(chkWall, chkFloor, chkCeil, chkOneFace, true));
+}
+
+/**
+ * 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;
+ if (BgCheck_PosErrorCheck(center, "../z_bgcheck.c", 5852) == true) {
+ if (actor != NULL) {
+ osSyncPrintf("こいつ,pself_actor->name %d\n", actor->id);
+ }
+ }
+ lookup = BgCheck_GetStaticLookup(colCtx, colCtx->lookupTbl, center);
+ if (lookup == NULL) {
+ return false;
+ } else {
+ if (BgCheck_SphVsFirstStaticPoly(lookup, xpFlags, colCtx, center, radius, outPoly, bciFlags) ||
+ BgCheck_SphVsFirstDynaPoly(colCtx, xpFlags, outPoly, outBgId, center, radius, actor, bciFlags)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Public get first poly intersecting sphere `center` `radius`
+ */
+s32 BgCheck_SphVsFirstPoly(CollisionContext* colCtx, Vec3f* center, f32 radius) {
+ CollisionPoly* poly;
+ s32 bgId;
+
+ return BgCheck_SphVsFirstPolyImpl(colCtx, COLPOLY_IGNORE_NONE, &poly, &bgId, center, radius, NULL,
+ BGCHECK_IGNORE_NONE);
+}
+
+/**
+ * Public get first wall poly intersecting sphere `center` `radius`
+ */
+s32 BgCheck_SphVsFirstWall(CollisionContext* colCtx, Vec3f* center, f32 radius) {
+ CollisionPoly* poly;
+ s32 bgId;
+
+ return BgCheck_SphVsFirstPolyImpl(colCtx, COLPOLY_IGNORE_NONE, &poly, &bgId, center, radius, NULL,
+ BGCHECK_IGNORE_FLOOR | BGCHECK_IGNORE_CEILING);
+}
+
+/**
+ * Init SSNodeList
+ */
+void SSNodeList_Initialize(SSNodeList* this) {
+ this->max = 0;
+ this->count = 0;
+ this->tbl = NULL;
+ this->polyCheckTbl = NULL;
+}
+
+/**
+ * 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.tha, tblMax * sizeof(SSNode), -2);
+
+ (this->tbl != NULL) ? (void)0 : __assert("this->short_slist_node_tbl != NULL", "../z_bgcheck.c", 5975);
+ this->polyCheckTbl = GameState_Alloc(&globalCtx->state, numPolys, "../z_bgcheck.c", 5979);
+ (this->polyCheckTbl != NULL) ? (void)0 : __assert("this->polygon_check != NULL", "../z_bgcheck.c", 5981);
+}
+
+/**
+ * Get next SSNodeList SSNode
+ */
+SSNode* SSNodeList_GetNextNode(SSNodeList* this) {
+ SSNode* result = &this->tbl[this->count];
+ this->count++;
+
+ (this->count < this->max)
+ ? (void)0
+ : __assert("this->short_slist_node_last_index < this->short_slist_node_size", "../z_bgcheck.c", 5998);
+ if (!(this->count < this->max)) {
+ return NULL;
+ }
+ return result;
+}
+
+/**
+ * Get next SSNodeList SSNode index
+ */
+u16 SSNodeList_GetNextNodeIdx(SSNodeList* this) {
+ u16 new_index = this->count++;
+
+ (new_index < this->max) ? (void)0 : __assert("new_index < this->short_slist_node_size", "../z_bgcheck.c", 6021);
+ return new_index;
+}
+
+/**
+ * Initialize ScaleRotPos
+ */
+void ScaleRotPos_Initialize(ScaleRotPos* srp) {
+ srp->scale.x = srp->scale.y = srp->scale.z = 1.0f;
+ srp->pos.x = srp->pos.y = srp->pos.z = 0.0f;
+ srp->rot.x = srp->rot.y = srp->rot.z = 0;
+}
+
+/**
+ * Set ScaleRotPos
+ */
+void ScaleRotPos_SetValue(ScaleRotPos* srp, Vec3f* scale, Vec3s* rot, Vec3f* pos) {
+ srp->scale = *scale;
+ srp->rot = *rot;
+ srp->pos = *pos;
+}
+
+/**
+ * ScaleRotPos equality test
+ */
+s32 ScaleRotPos_Equals(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;
+}
+
+/**
+ * Reset DynaLookup lists
+ */
+void DynaLookup_ResetLists(DynaLookup* dynaLookup) {
+ SSList_SetNull(&dynaLookup->ceiling);
+ SSList_SetNull(&dynaLookup->wall);
+ SSList_SetNull(&dynaLookup->floor);
+}
+
+/**
+ * Reset DynaLookup
+ */
+void DynaLookup_Reset(DynaLookup* dynaLookup) {
+ dynaLookup->polyStartIndex = 0;
+ DynaLookup_ResetLists(dynaLookup);
+}
+
+/**
+ * Reset vtxStartIndex
+ */
+void DynaLookup_ResetVtxStartIndex(u16* vtxStartIndex) {
+ *vtxStartIndex = 0;
+}
+
+/**
+ * Initialize BgActor
+ */
+void BgActor_Initialize(GlobalContext* globalCtx, BgActor* bgActor) {
+ bgActor->actor = NULL;
+ bgActor->colHeader = NULL;
+ ScaleRotPos_Initialize(&bgActor->prevTransform);
+ ScaleRotPos_Initialize(&bgActor->curTransform);
+ DynaLookup_Reset(&bgActor->dynaLookup);
+ DynaLookup_ResetVtxStartIndex(&bgActor->vtxStartIndex);
+ bgActor->boundingSphere.center.x = bgActor->boundingSphere.center.y = bgActor->boundingSphere.center.z = 0;
+ bgActor->boundingSphere.radius = 0;
+}
+
+/**
+ * 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->posRot.pos;
+ bgActor->curTransform.scale = actor->scale;
+ bgActor->curTransform.rot = actor->shape.rot;
+ bgActor->curTransform.pos = actor->posRot.pos;
+}
+
+/**
+ * Test if the BgActor transform changed
+ */
+s32 BgActor_HasTransformChanged(BgActor* bgActor) {
+ return ScaleRotPos_Equals(&bgActor->prevTransform, &bgActor->curTransform);
+}
+
+/**
+ * NULL polyList
+ */
+void DynaPoly_NullPolyList(CollisionPoly** polyList) {
+ *polyList = NULL;
+}
+
+/**
+ * Allocate dyna.polyList
+ */
+void DynaPoly_AllocPolyList(GlobalContext* globalCtx, CollisionPoly** polyList, s32 numPolys) {
+ *polyList = THA_AllocEndAlign(&globalCtx->state.tha, numPolys * sizeof(CollisionPoly), -2);
+ (*polyList != NULL) ? (void)0 : __assert("ptbl->pbuf != NULL", "../z_bgcheck.c", 6247);
+}
+
+/**
+ * NULL vtxList
+ */
+void DynaPoly_NullVtxList(Vec3s** vtxList) {
+ *vtxList = NULL;
+}
+
+/**
+ * Allocate dyna.vtxList
+ */
+void DynaPoly_AllocVtxList(GlobalContext* globalCtx, Vec3s** vtxList, s32 numVtx) {
+ *vtxList = THA_AllocEndAlign(&globalCtx->state.tha, numVtx * sizeof(Vec3s), -2);
+ (*vtxList != NULL) ? (void)0 : __assert("ptbl->pbuf != NULL", "../z_bgcheck.c", 6277);
+}
+
+/**
+ * Update BgActor's prevTransform
+ */
+void DynaPoly_SetBgActorPrevTransform(GlobalContext* globalCtx, BgActor* bgActor) {
+ bgActor->prevTransform = bgActor->curTransform;
+}
+
+/**
+ * Is BgActor Id
+ */
+s32 DynaPoly_IsBgIdBgActor(s32 bgId) {
+ if (bgId < 0 || bgId >= BG_ACTOR_MAX) {
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Init DynaCollisionContext
+ */
+void DynaPoly_Init(GlobalContext* globalCtx, DynaCollisionContext* dyna) {
+ dyna->bitFlag = 1;
+ DynaPoly_NullPolyList(&dyna->polyList);
+ DynaPoly_NullVtxList(&dyna->vtxList);
+ DynaSSNodeList_Initialize(globalCtx, &dyna->polyNodes);
+}
+
+/**
+ * Set DynaCollisionContext
+ */
+void DynaPoly_Alloc(GlobalContext* globalCtx, DynaCollisionContext* dyna) {
+ s32 i;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ BgActor_Initialize(globalCtx, &dyna->bgActors[i]);
+ dyna->bgActorFlags[i] = 0;
+ }
+ DynaPoly_NullPolyList(&dyna->polyList);
+ DynaPoly_AllocPolyList(globalCtx, &dyna->polyList, dyna->polyListMax);
+
+ DynaPoly_NullVtxList(&dyna->vtxList);
+ DynaPoly_AllocVtxList(globalCtx, &dyna->vtxList, dyna->vtxListMax);
+
+ DynaSSNodeList_Initialize(globalCtx, &dyna->polyNodes);
+ DynaSSNodeList_Alloc(globalCtx, &dyna->polyNodes, dyna->polyNodesMax);
+}
+
+/**
+ * Set BgActor
+ * original name: DynaPolyInfo_setActor
+ */
+s32 DynaPoly_SetBgActor(GlobalContext* globalCtx, DynaCollisionContext* dyna, Actor* actor,
+ CollisionHeader* colHeader) {
+ s32 bgId;
+ s32 foundSlot;
+
+ foundSlot = false;
+ for (bgId = 0; bgId < BG_ACTOR_MAX; bgId++) {
+ if (!(dyna->bgActorFlags[bgId] & 1)) {
+ dyna->bgActorFlags[bgId] |= 1;
+ foundSlot = true;
+ break;
+ }
+ }
+
+ if (foundSlot == false) {
+ osSyncPrintf(VT_FGCOL(RED));
+ osSyncPrintf("DynaPolyInfo_setActor():ダイナミックポリゴン 空きインデックスはありません\n");
+ osSyncPrintf(VT_RST);
+ return BG_ACTOR_MAX;
+ }
+
+ BgActor_SetActor(&dyna->bgActors[bgId], actor, colHeader);
+ dyna->bitFlag |= 1;
+
+ dyna->bgActorFlags[bgId] &= ~2;
+ osSyncPrintf(VT_FGCOL(GREEN));
+ osSyncPrintf("DynaPolyInfo_setActor():index %d\n", bgId);
+ osSyncPrintf(VT_RST);
+ return bgId;
+}
+
+/**
+ * Gets the actor assigned to `bgId`
+ * possible orginal name: DynaPolyInfo_getActor
+ */
+Actor* DynaPoly_GetActor(CollisionContext* colCtx, s32 bgId) {
+ if (!DynaPoly_IsBgIdBgActor(bgId) || !(colCtx->dyna.bgActorFlags[bgId] & 1) ||
+ colCtx->dyna.bgActorFlags[bgId] & 2) {
+ return NULL;
+ }
+ return colCtx->dyna.bgActors[bgId].actor;
+}
+
+void func_8003EBF8(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ dyna->bgActorFlags[bgId] |= 4;
+ dyna->bitFlag |= 1;
+ }
+}
+
+void func_8003EC50(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ dyna->bgActorFlags[bgId] &= ~4;
+ dyna->bitFlag |= 1;
+ }
+}
+
+void func_8003ECA8(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ dyna->bgActorFlags[bgId] |= 8;
+ dyna->bitFlag |= 1;
+ }
+}
+
+void func_8003ED00(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ if (DynaPoly_IsBgIdBgActor(bgId)) {
+ dyna->bgActorFlags[bgId] &= ~8;
+ dyna->bitFlag |= 1;
+ }
+}
+
+/**
+ * original name: DynaPolyInfo_delReserve
+ */
+void DynaPoly_DeleteBgActor(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId) {
+ DynaPolyActor* actor;
+
+ osSyncPrintf(VT_FGCOL(GREEN));
+ osSyncPrintf("DynaPolyInfo_delReserve():index %d\n", bgId);
+ osSyncPrintf(VT_RST);
+ if (DynaPoly_IsBgIdBgActor(bgId) == false) {
+
+ if (bgId == -1) {
+ osSyncPrintf(VT_FGCOL(GREEN));
+ osSyncPrintf(
+ "DynaPolyInfo_delReserve():削除されているはずの(?)\nインデックス(== -1)のため,処理を中止します。\n");
+ // The index that should have been deleted(? ) was(== -1), processing aborted.
+ osSyncPrintf(VT_RST);
+ return;
+ } else {
+ osSyncPrintf(VT_FGCOL(RED));
+ osSyncPrintf("DynaPolyInfo_delReserve():"
+ "確保していない/出来なかったインデックスの解放のため、処理を中止します。index == %d\n",
+ bgId);
+ // Unable to deallocate index / index unallocated, processing aborted.
+ osSyncPrintf(VT_RST);
+ return;
+ }
+ }
+ actor = (DynaPolyActor*)DynaPoly_GetActor(&globalCtx->colCtx, bgId);
+ if (actor != NULL) {
+
+ actor->bgId = BGACTOR_NEG_ONE;
+ dyna->bgActors[bgId].actor = NULL;
+ dyna->bgActorFlags[bgId] |= 2;
+ }
+}
+
+void func_8003EE6C(GlobalContext* globalCtx, DynaCollisionContext* dyna) {
+ dyna->bitFlag |= 1;
+}
+
+/**
+ * original name: DynaPolyInfo_expandSRT
+ */
+void DynaPoly_ExpandSRT(GlobalContext* globalCtx, DynaCollisionContext* dyna, s32 bgId, s32* vtxStartIndex,
+ s32* polyStartIndex) {
+ MtxF mtx;
+ Actor* actor;
+ s32 pad;
+ s32 pad2;
+ f32 numVtxInverse;
+ s32 i;
+ Vec3f pos;
+ Sphere16* sphere;
+ Vec3s* dVtxList;
+ Vec3s* point;
+ Vec3f newCenterPoint;
+ f32 newRadiusSq;
+ CollisionHeader* pbgdata;
+ Vec3f newVtx;
+ Vec3f vtxA;
+ Vec3f vtxB;
+ Vec3f vtxC;
+ Vec3f newNormal;
+
+ 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;
+ pos = actor->posRot.pos;
+ pos.y += actor->shape.unk_08 * actor->scale.y;
+
+ ScaleRotPos_SetValue(&dyna->bgActors[bgId].curTransform, &actor->scale, &actor->shape.rot, &pos);
+
+ if (dyna->bgActorFlags[bgId] & 4) {
+ return;
+ }
+
+ if (!(dyna->polyListMax >= *polyStartIndex + pbgdata->nbPolygons)) {
+ osSyncPrintf(VT_FGCOL(RED));
+ // do not use if %d[*polyStartIndex + pbgdata->nbPolygons] exceeds %d[dyna->polyListMax]
+ osSyncPrintf("DynaPolyInfo_expandSRT():polygon over %dが%dを越えるとダメ\n",
+ *polyStartIndex + pbgdata->nbPolygons, dyna->polyListMax);
+ }
+
+ if (!(dyna->vtxListMax >= *vtxStartIndex + pbgdata->nbVertices)) {
+ osSyncPrintf(VT_FGCOL(RED));
+ // do not use if %d[*vtxStartIndex + pbgdata->nbVertices] exceeds %d[dyna->vtxListMax]
+ osSyncPrintf("DynaPolyInfo_expandSRT():vertex over %dが%dを越えるとダメ\n",
+ *vtxStartIndex + pbgdata->nbVertices, dyna->vtxListMax);
+ }
+
+ (dyna->polyListMax >= *polyStartIndex + pbgdata->nbPolygons)
+ ? (void)0
+ : __assert("pdyna_poly_info->poly_num >= *pstart_poly_index + pbgdata->poly_num", "../z_bgcheck.c", 6687);
+ (dyna->vtxListMax >= *vtxStartIndex + pbgdata->nbVertices)
+ ? (void)0
+ : __assert("pdyna_poly_info->vert_num >= *pstart_vert_index + pbgdata->vtx_num", "../z_bgcheck.c", 6688);
+
+ if (!(dyna->bitFlag & 1) && (BgActor_HasTransformChanged(&dyna->bgActors[bgId]) == true)) {
+ s32 pi;
+ for (pi = *polyStartIndex; pi < *polyStartIndex + pbgdata->nbPolygons; pi++) {
+ CollisionPoly* poly = &dyna->polyList[pi];
+ s16 normalY = poly->normal.y;
+
+ if (normalY > COLPOLY_SNORMAL(0.5f)) {
+ 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->nbPolygons;
+ *vtxStartIndex += pbgdata->nbVertices;
+ } else {
+ SkinMatrix_SetScaleRotateYRPTranslate(
+ &mtx, 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);
+
+ numVtxInverse = 1.0f / pbgdata->nbVertices;
+ newCenterPoint.x = newCenterPoint.y = newCenterPoint.z = 0.0f;
+ for (i = 0; i < pbgdata->nbVertices; i++) {
+ Vec3f vtx;
+ Vec3f vtxT; // Vtx after mtx transform
+ Math_Vec3s_ToVec3f(&vtx, &pbgdata->vtxList[i]);
+ SkinMatrix_Vec3fMtxFMultXYZ(&mtx, &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->nbVertices; i++) {
+ f32 radiusSq;
+ newVtx.x = dyna->vtxList[*vtxStartIndex + i].x;
+ newVtx.y = dyna->vtxList[*vtxStartIndex + i].y;
+ newVtx.z = dyna->vtxList[*vtxStartIndex + i].z;
+ radiusSq = Math3D_Vec3fDistSq(&newVtx, &newCenterPoint);
+ if (newRadiusSq < radiusSq) {
+ newRadiusSq = radiusSq;
+ }
+ }
+
+ sphere->radius = sqrtf(newRadiusSq) * 1.1f;
+
+ for (i = 0; i < pbgdata->nbPolygons; i++) {
+ CollisionPoly* newPoly = &dyna->polyList[*polyStartIndex + i];
+ f32 newNormMagnitude;
+ *newPoly = pbgdata->polyList[i];
+
+ // Yeah, this is all kinds of fake, but my God, it matches.
+ newPoly->flags_vIA =
+ (COLPOLY_VTX_INDEX(newPoly->flags_vIA) + *vtxStartIndex) | ((*newPoly).flags_vIA & 0xE000);
+ newPoly->flags_vIB =
+ (COLPOLY_VTX_INDEX(newPoly->flags_vIB) + *vtxStartIndex) | ((*newPoly).flags_vIB & 0xE000);
+ newPoly->vIC = *vtxStartIndex + newPoly->vIC;
+ dVtxList = dyna->vtxList;
+ vtxA.x = dVtxList[(u32)COLPOLY_VTX_INDEX(newPoly->flags_vIA)].x;
+ vtxA.y = dVtxList[(u32)COLPOLY_VTX_INDEX(newPoly->flags_vIA)].y;
+ vtxA.z = dVtxList[(u32)COLPOLY_VTX_INDEX(newPoly->flags_vIA)].z;
+ vtxB.x = dVtxList[(u32)COLPOLY_VTX_INDEX(newPoly->flags_vIB)].x;
+ vtxB.y = dVtxList[(u32)COLPOLY_VTX_INDEX(newPoly->flags_vIB)].y;
+ vtxB.z = dVtxList[(u32)COLPOLY_VTX_INDEX(newPoly->flags_vIB)].z;
+ vtxC.x = dVtxList[newPoly->vIC].x;
+ vtxC.y = dVtxList[newPoly->vIC].y;
+ vtxC.z = dVtxList[newPoly->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[(u32)COLPOLY_VTX_INDEX(newPoly->flags_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);
+ }
+ }
+
+ *polyStartIndex += pbgdata->nbPolygons;
+ *vtxStartIndex += pbgdata->nbVertices;
+ }
+}
+
+void func_8003F8EC(GlobalContext* globalCtx, DynaCollisionContext* dyna, Actor* actor) {
+ Actor* 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) {
+ func_800434A0((DynaPolyActor*)actor);
+ return;
+ }
+ }
+ }
+}
+
+/**
+ * DynaPolyInfo_setup
+ */
+void DynaPoly_Setup(GlobalContext* globalCtx, DynaCollisionContext* dyna) {
+ DynaPolyActor* actor;
+ s32 vtxStartIndex;
+ s32 polyStartIndex;
+ s32 i;
+
+ DynaSSNodeList_ResetCount(&dyna->polyNodes);
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ DynaLookup_ResetLists(&dyna->bgActors[i].dynaLookup);
+ }
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (dyna->bgActorFlags[i] & 2) {
+ // Initialize BgActor
+ osSyncPrintf(VT_FGCOL(GREEN));
+ osSyncPrintf("DynaPolyInfo_setup():削除 index=%d\n", i);
+ osSyncPrintf(VT_RST);
+
+ dyna->bgActorFlags[i] = 0;
+ BgActor_Initialize(globalCtx, &dyna->bgActors[i]);
+ dyna->bitFlag |= 1;
+ }
+ if (dyna->bgActors[i].actor != NULL && dyna->bgActors[i].actor->update == NULL) {
+ // Delete BgActor
+ osSyncPrintf(VT_FGCOL(GREEN));
+ osSyncPrintf("DynaPolyInfo_setup():削除 index=%d\n", i);
+ osSyncPrintf(VT_RST);
+ actor = (DynaPolyActor*)DynaPoly_GetActor(&globalCtx->colCtx, i);
+ if (actor == NULL) {
+ return;
+ }
+ actor->bgId = BGACTOR_NEG_ONE;
+ dyna->bgActorFlags[i] = 0;
+
+ BgActor_Initialize(globalCtx, &dyna->bgActors[i]);
+ dyna->bitFlag |= 1;
+ }
+ }
+ vtxStartIndex = 0;
+ polyStartIndex = 0;
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (dyna->bgActorFlags[i] & 1) {
+ DynaPoly_ExpandSRT(globalCtx, dyna, i, &vtxStartIndex, &polyStartIndex);
+ }
+ }
+ dyna->bitFlag &= ~1;
+}
+
+/**
+ * Update all BgActor's previous ScaleRotPos
+ */
+void DynaPoly_UpdateBgActorTransforms(GlobalContext* globalCtx, DynaCollisionContext* dyna) {
+ s32 i;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (dyna->bgActorFlags[i] & 1) {
+ DynaPoly_SetBgActorPrevTransform(globalCtx, &dyna->bgActors[i]);
+ }
+ }
+}
+
+#define DYNA_RAYCAST_FLOORS 1
+#define DYNA_RAYCAST_WALLS 2
+#define DYNA_RAYCAST_CEILINGS 4
+
+/**
+ * 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)) {
+ 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_20 & 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->chkDist) == true &&
+ 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;
+}
+
+/**
+ * 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;
+ Actor* actor;
+ 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)) {
+ 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) == false) {
+ continue;
+ }
+
+ dynaRaycast->dyna = &dynaRaycast->colCtx->dyna;
+ if (dynaRaycast->unk_20 & 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_20 & BGCHECK_IGNORE_WALL) ||
+ (*dynaRaycast->resultPoly == NULL && (dynaRaycast->unk_20 & 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_20 & 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;
+ }
+ }
+ }
+
+ actor = DynaPoly_GetActor(dynaRaycast->colCtx, *dynaRaycast->bgId);
+ if ((result != BGCHECK_Y_MIN) && (actor != NULL) && (dynaRaycast->globalCtx != NULL)) {
+ pauseState = dynaRaycast->globalCtx->pauseCtx.state != 0;
+ if (pauseState == 0) {
+ pauseState = dynaRaycast->globalCtx->pauseCtx.flag != 0;
+ }
+ if (!pauseState && (dynaRaycast->colCtx->dyna.bgActorFlags[*dynaRaycast->bgId] & 2)) {
+ curTransform = &dynaRaycast->dyna->bgActors[*dynaRaycast->bgId].curTransform;
+ polyMin =
+ &dynaRaycast->dyna->polyList[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->chkDist)) {
+ if (fabsf(intersect - result) < 1.0f) {
+
+ result = intersect;
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/**
+ * 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);
#ifdef NON_MATCHING
-void func_80041978(s32 iParm1, s32 iParm2) {
- u8* puVar1;
+// regalloc
+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) {
+ f32 temp;
+ f32 intersect; // spD0
+ s32 result = false; // spCC
+ CollisionPoly* poly;
+ SSNode* curNode; // curNode s1
+ f32 nx; // spC0
+ f32 ny; // spBC
+ f32 nz; // spB8
+ Vec3f resultPos; // spAC;
+ s16 polyId;
+ f32 zTemp; // f0
+ f32 xTemp; // f0
+ f32 normalXZ; // f20
+ f32 invNormalXZ; // sp70 //f16
+ f32 planeDist; // f24
+ f32 temp_f18; // sp90
+ f32 zIntersectDist; // f2
+ f32 xIntersectDist; // f2
+ f32 zMin; // f2
+ f32 zMax; // f12
+ f32 xMin; // f2
+ f32 xMax; // f12
+
+ if (ssList->head == SS_NULL) {
+ return result;
+ }
+ 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));
+ (!IS_ZERO(normalXZ)) ? (void)0 : __assert("!IS_ZERO(ac_size)", "../z_bgcheck.c", 7382);
+
+ planeDist = Math3D_DistPlaneToPos(nx, ny, nz, poly->dist, &resultPos);
+ if (radius < fabsf(planeDist) || COLPOLY_VIA_FLAG_TEST(poly->flags_vIA, xpFlags)) {
+ 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;
+ }
+ }
+ // ab75e8
+
+ // compute poly zMin/zMax
+ zMin = zMax = dyna->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)].z; // 7610
+
+ zTemp = dyna->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)].z;
+ if (zTemp < zMin) { // 7630
+ zMin = zTemp;
+ } else if (zTemp > zMax) {
+ zMax = zTemp;
+ }
+
+ zTemp = dyna->vtxList[poly->vIC].z;
+ if (zTemp < zMin) {
+ zMin = zTemp;
+ } else if (zMax < zTemp) { // 76A0
+ 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)) {
+ // zIntersectDist = ;
+ if (fabsf(intersect - resultPos.z) <= radius / temp_f18) {
+ if ((intersect - resultPos.z) * nz <= 4.0f) {
+ // ab779c
+ if (BgCheck_ComputeWallDisplacement(colCtx, poly, &resultPos.x, &resultPos.z, nx, ny, nz,
+ invNormalXZ, planeDist, radius, outPoly)) {
+ *outBgId = bgId;
+ }
+ result = true;
+ }
+ }
+ }
+ // ab77b4
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ }
+
+ // ab77d0
+ 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));
+ (!IS_ZERO(normalXZ)) ? (void)0 : __assert("!IS_ZERO(ac_size)", "../z_bgcheck.c", 7489);
+
+ planeDist = Math3D_DistPlaneToPos(nx, ny, nz, poly->dist, &resultPos);
+ if (radius < fabsf(planeDist) || COLPOLY_VIA_FLAG_TEST(poly->flags_vIA, xpFlags)) {
+ 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
+ xMin = xMax = dyna->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIA)].x;
+ xTemp = dyna->vtxList[COLPOLY_VTX_INDEX(poly->flags_vIB)].x;
- puVar1 = *(u8**)(iParm1 + 8);
- if (puVar1 < puVar1 + iParm2) {
- *puVar1 = 0;
- while (puVar1++ < (u8*)(*(s32*)(iParm1 + 8) + iParm2)) {
- *puVar1 = 0;
+ 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;
+ }
+ }
+ // 7a2c
+ 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) {
+ // ab7ac8
+ 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
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041978.s")
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_SphVsDynaWallInBgActor.s")
#endif
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800419B0.s")
+/**
+ * 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);
+#ifdef NON_MATCHING
+// Codegen Issues
+s32 BgCheck_SphVsDynaWall(CollisionContext* colCtx, u16 xpFlags, f32* outX, f32* outZ, Vec3f* pos, f32 radius,
+ CollisionPoly** outPoly, s32* outBgId, Actor* actor) {
+ Vec3f resultPos; // sp9C
+ s32 result; // sp90;
+ f32 r; // f0
+ f32 dz; // f12
+ f32 dx; // f2
+ // s16 temp_s2;
+ BgActor* bgActor; // s0
+ // Sphere16* temp_s1;
+ s32 i; // s4
+ BgActor* list;
+
+ result = false;
+ resultPos = *pos;
+ list = colCtx->dyna.bgActors;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (!(colCtx->dyna.bgActorFlags[i] & 1)) {
+ continue;
+ }
+ if (list[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)) {
+ resultPos.x = *outX;
+ resultPos.z = *outZ;
+ result = true;
+ }
+ }
+ return result;
+}
+#else
+#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/BgCheck_SphVsDynaWall.s")
+#endif
+
+/**
+ * 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) {
+ s16 polyId;
+ SSNode* curNode;
+ CollisionPoly* poly;
+ Vec3f testPos;
+ f32 ceilingY;
+ f32 sign;
+ f32 nx;
+ f32 ny;
+ f32 nz;
+ s32 result;
+ f32 intersectDist;
+ u16 padding;
+
+ result = false;
+
+ 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)) {
+ 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;
+}
+
+/**
+ * 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 + `chkDist` if no collision occurs
+ */
+s32 BgCheck_CheckDynaCeiling(CollisionContext* colCtx, u16 xpFlags, f32* outY, Vec3f* pos, f32 chkDist,
+ CollisionPoly** outPoly, s32* outBgId, Actor* actor) {
+ s32 i = 0;
+ s32 result = false;
+ f32 resultY;
+ f32 tempY;
+ BgActor* bgActor;
+ CollisionPoly* poly;
+
+ tempY = chkDist + pos->y;
+ resultY = tempY;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (!(colCtx->dyna.bgActorFlags[i] & 1)) {
+ 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, chkDist, &poly) == true &&
+ tempY < resultY) {
+
+ resultY = tempY;
+ *outPoly = poly;
+ *outBgId = i;
+ result = true;
+ }
+ }
+ *outY = resultY;
+ return result;
+}
+
+/**
+ * Tests if DynaLineTest intersects with a poly
+ * returns true if a poly was intersected, else false
+ */
+s32 func_80040FA4(DynaLineTest* dynaLineTest) {
+ f32 distSq;
+ s32 result;
+ CollisionPoly* curPoly;
+ SSNode* curNode;
+ Vec3f polyIntersect;
+ s16 polyId;
+
+ if (dynaLineTest->ssList->head == SS_NULL) {
+ return false;
+ }
+
+ curNode = &dynaLineTest->dyna->polyNodes.tbl[dynaLineTest->ssList->head];
+ result = false;
+
+ while (true) {
+ polyId = curNode->polyId;
+ curPoly = &dynaLineTest->dyna->polyList[polyId];
+ if (COLPOLY_VIA_FLAG_TEST(curPoly->flags_vIA, dynaLineTest->xpFlags)) {
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dynaLineTest->dyna->polyNodes.tbl[curNode->next];
+ }
+ } else {
+ if (CollisionPoly_LineVsPoly(curPoly, dynaLineTest->dyna->vtxList, dynaLineTest->posA, dynaLineTest->posB,
+ &polyIntersect, dynaLineTest->chkOneFace, dynaLineTest->chkDist)) {
+ distSq = Math3D_Vec3fDistSq(dynaLineTest->posA, &polyIntersect);
+ if (distSq < *dynaLineTest->distSq) {
+ *dynaLineTest->distSq = distSq;
+ *dynaLineTest->posResult = polyIntersect;
+ *dynaLineTest->posB = polyIntersect;
+ *dynaLineTest->resultPoly = curPoly;
+ result = true;
+ }
+ }
+ if (curNode->next == SS_NULL) {
+ break;
+ } else {
+ curNode = &dynaLineTest->dyna->polyNodes.tbl[curNode->next];
+ }
+ }
+ }
+ return result;
+}
+
+/**
+ * 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 func_80041128(CollisionContext* colCtx, u16 xpFlags, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, f32* distSq, s32 bgId, f32 chkDist, s32 bccFlags) {
+ 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.chkOneFace = (bccFlags & BGCHECK_CHECK_ONE_FACE) != 0;
+ dynaLineTest.distSq = distSq;
+ dynaLineTest.chkDist = chkDist;
+
+ dynaLineTest.ssList = &colCtx->dyna.bgActors[bgId].dynaLookup.wall;
+ if (bccFlags & BGCHECK_CHECK_WALL) {
+ if (func_80040FA4(&dynaLineTest)) {
+ result = true;
+ }
+ }
+ dynaLineTest.ssList = &colCtx->dyna.bgActors[bgId].dynaLookup.floor;
+ if (bccFlags & BGCHECK_CHECK_FLOOR) {
+ if (func_80040FA4(&dynaLineTest)) {
+ result = true;
+ }
+ }
+ dynaLineTest.ssList = &colCtx->dyna.bgActors[bgId].dynaLookup.ceiling;
+ if (bccFlags & BGCHECK_CHECK_CEILING) {
+ if (func_80040FA4(&dynaLineTest)) {
+ result = true;
+ }
+ }
+ return result;
+}
+
+/**
+ * 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 func_80041240(CollisionContext* colCtx, u16 xpFlags, Vec3f* posA, Vec3f* posB, Vec3f* posResult,
+ CollisionPoly** outPoly, f32* distSq, s32* outBgId, Actor* actor, f32 chkDist, s32 bccFlags) {
+ s32 pad;
+ s32 i;
+ s32 result = false;
+ Linef line;
+ f32 ay, by;
+
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (colCtx->dyna.bgActorFlags[i] & 1) {
+ 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 (func_80041128(colCtx, xpFlags, posA, posB, posResult, outPoly, distSq, i, chkDist,
+ bccFlags) == true) {
+ *outBgId = i;
+ result = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/**
+ * 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) {
+ 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)) {
+ 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;
+}
+
+/**
+ * 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) {
+ if ((bciFlags & BGCHECK_IGNORE_CEILING) == 0) {
+ if (BgCheck_SphVsFirstDynaPolyList(colCtx, xpFlags, outPoly, center, radius,
+ &colCtx->dyna.bgActors[bgId].dynaLookup.ceiling)) {
+ return true;
+ }
+ }
+ if ((bciFlags & BGCHECK_IGNORE_WALL) == 0) {
+ if (BgCheck_SphVsFirstDynaPolyList(colCtx, xpFlags, outPoly, center, radius,
+ &colCtx->dyna.bgActors[bgId].dynaLookup.wall)) {
+ return true;
+ }
+ }
+ if ((bciFlags & BGCHECK_IGNORE_FLOOR) == 0) {
+ if (BgCheck_SphVsFirstDynaPolyList(colCtx, xpFlags, outPoly, center, radius,
+ &colCtx->dyna.bgActors[bgId].dynaLookup.floor)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * 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)) {
+ 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)) {
+ return true;
+ }
+ }
+ return false;
+}
-s32 func_80041A28(CollisionContext* a0, CollisionPoly* a1, u32 a2) {
- u32 uVar1;
+/**
+ * SEGMENTED_TO_VIRTUAL CollisionHeader members
+ */
+void CollisionHeader_SegmentedToVirtual(CollisionHeader* colHeader) {
+ colHeader->vtxList = SEGMENTED_TO_VIRTUAL(colHeader->vtxList);
+ colHeader->polyList = SEGMENTED_TO_VIRTUAL(colHeader->polyList);
+ colHeader->surfaceTypeList = SEGMENTED_TO_VIRTUAL(colHeader->surfaceTypeList);
+ colHeader->cameraDataList = SEGMENTED_TO_VIRTUAL(colHeader->cameraDataList);
+ colHeader->waterBoxes = SEGMENTED_TO_VIRTUAL(colHeader->waterBoxes);
+}
+
+/**
+ * Convert CollisionHeader Segmented to Virtual addressing
+ */
+void CollisionHeader_GetVirtual(void* colHeader, CollisionHeader** dest) {
+ *dest = SEGMENTED_TO_VIRTUAL(colHeader);
+ CollisionHeader_SegmentedToVirtual(*dest);
+}
+
+/**
+ * SEGMENT_TO_VIRTUAL all active BgActor CollisionHeaders
+ */
+void func_800418D0(CollisionContext* colCtx, GlobalContext* globalCtx) {
+ DynaCollisionContext* dyna;
+ s32 i;
+ u16 flag;
- uVar1 = func_800419B0(a0, a1, a2, 0);
- return uVar1 & 0xff;
+ dyna = &colCtx->dyna;
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ flag = dyna->bgActorFlags[i];
+ if ((flag & 1) && !(flag & 2)) {
+ Actor_SetObjectDependency(globalCtx, dyna->bgActors[i].actor);
+ CollisionHeader_SegmentedToVirtual(dyna->bgActors[i].colHeader);
+ }
+ }
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041A4C.s")
+/**
+ * Reset SSNodeList polyCheckTbl
+ */
+void BgCheck_ResetPolyCheckTbl(SSNodeList* nodeList, s32 numPolys) {
+ u8* t;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041B24.s")
+ for (t = nodeList->polyCheckTbl; t < nodeList->polyCheckTbl + numPolys; t++) {
+ *t = 0;
+ }
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041B80.s")
+/**
+ * Get SurfaceType property set
+ */
+u32 SurfaceType_GetData(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId, s32 dataIdx) {
+ CollisionHeader* colHeader;
+ SurfaceType* surfaceTypes;
+
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if (colHeader == NULL || poly == NULL) {
+ return 0;
+ }
+ surfaceTypes = colHeader->surfaceTypeList;
+ if (surfaceTypes == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return 0;
+ }
+ return surfaceTypes[poly->type].data[dataIdx];
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041C10.s")
+/**
+ * SurfaceType return CamData Index
+ */
+u32 SurfaceType_GetCamDataIndex(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041C98.s")
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) & 0xFF;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041D28.s")
+/**
+ * CamData return cameraSType
+ */
+u16 func_80041A4C(CollisionContext* colCtx, u32 camId, s32 bgId) {
+ u16 result;
+ CollisionHeader* colHeader;
+ CamData* camData;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041D4C.s")
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if (colHeader == NULL) {
+ return 0;
+ }
+ camData = colHeader->cameraDataList;
+ result = camData[camId].cameraSType;
+ return result;
+}
-u32 func_80041D94(u32 a0, u32 a1, u32 a2) {
- u32 uVar1;
+/**
+ * SurfaceType return cameraSType
+ */
+u16 SurfaceType_GetCameraSType(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ CollisionHeader* colHeader;
+ CamData* camData;
+ SurfaceType* surfaceTypes;
- uVar1 = func_800419B0(a0, a1, a2, 0);
- return uVar1 >> 0x15 & 0x1f;
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if (colHeader == NULL) {
+ return 0;
+ }
+ camData = colHeader->cameraDataList;
+ if (camData == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return 0;
+ }
+ surfaceTypes = colHeader->surfaceTypeList;
+ if (surfaceTypes == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return 0;
+ }
+ return func_80041A4C(colCtx, SurfaceType_GetCamDataIndex(colCtx, poly, bgId), bgId);
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041DB8.s")
+/**
+ * CamData Get number of cameras
+ */
+u16 func_80041B24(CollisionContext* colCtx, u32 camId, s32 bgId) {
+ CollisionHeader* colHeader;
+ CamData* camData;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041DE4.s")
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if (colHeader == NULL) {
+ return 0;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041E18.s")
+ camData = colHeader->cameraDataList;
+ if (camData == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return 0;
+ }
+ return camData[camId].numCameras;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041E4C.s")
+/**
+ * SurfaceType Get number of cameras
+ */
+u16 SurfaceType_GetNumCameras(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ CollisionHeader* colHeader;
+ CamData* camData;
+ SurfaceType* surfaceTypes;
+
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if (colHeader == NULL) {
+ return 0;
+ }
+ camData = colHeader->cameraDataList;
+ if (camData == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return 0;
+ }
+ surfaceTypes = colHeader->surfaceTypeList;
+ if (surfaceTypes == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return 0;
+ }
+ return func_80041B24(colCtx, SurfaceType_GetCamDataIndex(colCtx, poly, bgId), bgId);
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041EC8.s")
+/**
+ * CamData Get camPosData
+ */
+Vec3s* func_80041C10(CollisionContext* colCtx, s32 camId, s32 bgId) {
+ CollisionHeader* colHeader;
+ CamData* cameraDataList;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80041EEC.s")
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if (colHeader == NULL) {
+ return NULL;
+ }
+ cameraDataList = colHeader->cameraDataList;
+ if (cameraDataList == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return NULL;
+ }
+ return (Vec3s*)SEGMENTED_TO_VIRTUAL(cameraDataList[camId].camPosData);
+}
-u32 func_80041F10(u32 a0, u32 a1, u32 a2) {
- u32 uVar1;
+/**
+ * SurfaceType Get camPosData
+ */
+Vec3s* SurfaceType_GetCamPosData(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ CollisionHeader* colHeader;
+ CamData* camData;
+ SurfaceType* surfaceTypes;
+
+ colHeader = BgCheck_GetCollisionHeader(colCtx, bgId);
+ if (colHeader == NULL) {
+ return NULL;
+ }
+ camData = colHeader->cameraDataList;
+ if (camData == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return NULL;
+ }
+ surfaceTypes = colHeader->surfaceTypeList;
+ if (surfaceTypes == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return NULL;
+ }
+ return func_80041C10(colCtx, SurfaceType_GetCamDataIndex(colCtx, poly, bgId), bgId);
+}
- uVar1 = func_800419B0(a0, a1, a2, 1);
- return uVar1 & 0xf;
+/**
+ * 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_80041F34.s")
+/**
+ * SurfaceType Get ? Property (& 0x0003 E000)
+ */
+u32 func_80041D4C(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_80041F7C.s")
+/**
+ * SurfaceType Get ? Property (& 0x001C 0000)
+ */
+u32 func_80041D70(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_80041FA0.s")
+/**
+ * SurfaceType Get Wall Property (Internal)
+ */
+u32 func_80041D94(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_80041FC4.s")
+/**
+ * SurfaceType Get Wall Flags
+ */
+s32 func_80041DB8(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return D_80119D90[func_80041D94(colCtx, poly, bgId)];
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8004200C.s")
+/**
+ * SurfaceType Is Wall Flag (1 << 0) Set
+ */
+s32 func_80041DE4(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return (func_80041DB8(colCtx, poly, bgId) & 1) ? true : false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80042048.s")
+/**
+ * SurfaceType Is Wall Flag (1 << 1) Set
+ */
+s32 func_80041E18(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return (func_80041DB8(colCtx, poly, bgId) & 2) ? true : false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80042084.s")
+/**
+ * SurfaceType Is Wall Flag (1 << 2) Set
+ */
+s32 func_80041E4C(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return (func_80041DB8(colCtx, poly, bgId) & 4) ? true : false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800420E4.s")
+/**
+ * unused
+ */
+u32 func_80041E80(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 26 & 0xF;
+}
-s32 func_80042108(CollisionContext* a0, CollisionPoly* a1, u32 a2) {
- u32 result;
- s32 var1;
+/**
+ * SurfaceType Get Floor Property
+ */
+u32 func_80041EA4(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 26 & 0xF;
+}
- var1 = func_800419B0(a0, a1, a2, 1);
+/**
+ * SurfaceType Is Floor Minus 1
+ */
+u32 func_80041EC8(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 30 & 1;
+}
- if (var1 << 4 < 0) {
- result = 1;
- } else {
- result = 0;
+/**
+ * SurfaceType Is Horse Blocked
+ */
+u32 SurfaceType_IsHorseBlocked(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 0) >> 31 & 1;
+}
+
+u32 func_80041F10(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) & 0xF;
+}
+
+/**
+ * SurfaceType Get Poly Sfx
+ */
+u16 SurfaceType_GetSfx(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ s32 id;
+
+ id = func_80041F10(colCtx, poly, bgId);
+ if (id < 0 || id > 13) {
+ return NA_SE_PL_WALK_GROUND - SFX_FLAG;
}
+ return D_80119E10[id];
+}
- return result;
+/**
+ * SurfaceType get terrain slope surface
+ */
+u32 SurfaceType_GetSlope(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 4 & 3;
+}
+
+/**
+ * SurfaceType get surface lighting setting
+ */
+u32 SurfaceType_GetLightSettingIndex(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 6 & 0x1F;
+}
+
+/**
+ * SurfaceType get echo
+ */
+u32 SurfaceType_GetEcho(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 11 & 0x3F;
+}
+
+/**
+ * SurfaceType Is Hookshot Surface
+ */
+u32 SurfaceType_IsHookshotSurface(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 17 & 1;
+}
+
+/**
+ * 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;
+ if (BgCheck_GetCollisionHeader(colCtx, bgId) == NULL) {
+ return true;
+ }
+ flags = poly->flags_vIA & 0x4000;
+ return !!flags;
+}
+
+/**
+ * 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;
+ if (BgCheck_GetCollisionHeader(colCtx, bgId) == NULL) {
+ return true;
+ }
+ flags = poly->flags_vIA & 0x8000;
+ return !!flags;
+}
+
+/**
+ * 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;
+ if (BgCheck_GetCollisionHeader(colCtx, bgId) == NULL) {
+ return true;
+ }
+ flags = poly->flags_vIB & 0x2000;
+ return !!flags;
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8004213C.s")
+/**
+ * SurfaceType Get Conveyor Surface Speed
+ */
+u32 SurfaceType_GetConveyorSpeed(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 18 & 7;
+}
+
+/**
+ * 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) {
+ return SurfaceType_GetData(colCtx, poly, bgId, 1) >> 21 & 0x3F;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80042244.s")
+/**
+ * SurfaceType is Wall Damage
+ */
+u32 SurfaceType_IsWallDamage(CollisionContext* colCtx, CollisionPoly* poly, s32 bgId) {
+ return (SurfaceType_GetData(colCtx, poly, bgId, 1) & 0x8000000) ? 1 : 0;
+}
-u32 func_80042538(CollisionContext* colCtx, WaterBox* arg1) {
- u32 properties = arg1->properties;
- return properties & 0xFF;
+/**
+ * Zora's Domain WaterBox in King Zora's Room
+ */
+WaterBox zdWaterBox = { -348, 877, -1746, 553, 780, 0x2104 };
+
+/**
+ * WaterBox's effective bounding box
+ */
+f32 zdWaterBoxMinX = -348.0f;
+f32 zdWaterBoxMinY = 777.0f;
+f32 zdWaterBoxMinZ = -1746.0f;
+f32 zdWaterBoxMaxX = 205.0f;
+f32 zdWaterBoxMaxY = 977.0f;
+f32 zdWaterBoxMaxZ = -967.0f;
+
+/**
+ * Public. 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_GetSurface1(GlobalContext* globalCtx, CollisionContext* colCtx, f32 x, f32 z, f32* ySurface,
+ WaterBox** outWaterBox) {
+ if (globalCtx->sceneNum == SCENE_SPOT07) {
+ if (zdWaterBoxMinX < x && x < zdWaterBoxMaxX && zdWaterBoxMinY < *ySurface && *ySurface < zdWaterBoxMaxY &&
+ zdWaterBoxMinZ < z && z < zdWaterBoxMaxZ) {
+ *outWaterBox = &zdWaterBox;
+ *ySurface = zdWaterBox.ySurface;
+ return true;
+ }
+ }
+ return WaterBox_GetSurfaceImpl(globalCtx, colCtx, x, z, ySurface, outWaterBox);
}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80042548.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) {
+ CollisionHeader* colHeader;
+ u32 room;
+ WaterBox* curWaterBox;
+
+ colHeader = colCtx->colHeader;
+ if (colHeader->nbWaterBoxes == 0 || colHeader->waterBoxes == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return false;
+ }
+
+ for (curWaterBox = colHeader->waterBoxes; curWaterBox < colHeader->waterBoxes + colHeader->nbWaterBoxes;
+ curWaterBox++) {
+ room = (curWaterBox->properties >> 13) & 0x3F;
+ if (room == globalCtx->roomCtx.curRoom.num || room == 0x3F) {
+ if ((curWaterBox->properties & 0x80000) == 0) {
+ if (curWaterBox->xMin < x && x < curWaterBox->xMin + curWaterBox->xLength) {
+ if (curWaterBox->zMin < z && z < curWaterBox->zMin + curWaterBox->zLength) {
+ *outWaterBox = curWaterBox;
+ *ySurface = curWaterBox->ySurface;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_8004259C.s")
+/**
+ * Gets the first active WaterBox at `pos` where WaterBox.properties & 0x80000 == 0
+ * `surfaceChkDist` 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 surfaceChkDist,
+ WaterBox** outWaterBox) {
+ CollisionHeader* colHeader;
+ s32 room;
+ s32 i;
+ WaterBox* waterBox;
+ WaterBox* waterBoxList; // unused, needed for matching
+
+ colHeader = colCtx->colHeader;
+ waterBoxList = colHeader->waterBoxes;
+ if (colHeader->nbWaterBoxes == 0 || colHeader->waterBoxes == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ *outWaterBox = NULL;
+ return -1;
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_800427B4.s")
+ for (i = 0; i < colHeader->nbWaterBoxes; i++) {
+ waterBox = &colHeader->waterBoxes[i];
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80042868.s")
+ room = WATERBOX_ROOM(waterBox->properties);
+ if (!(room == globalCtx->roomCtx.curRoom.num || room == 0x3F)) {
+ continue;
+ }
+ if ((waterBox->properties & 0x80000)) {
+ continue;
+ }
+ if (!(waterBox->xMin < pos->x && pos->x < waterBox->xMin + waterBox->xLength)) {
+ continue;
+ }
+ if (!(waterBox->zMin < pos->z && pos->z < waterBox->zMin + waterBox->zLength)) {
+ continue;
+ }
+ if (pos->y - surfaceChkDist < waterBox->ySurface && waterBox->ySurface < pos->y + surfaceChkDist) {
+ *outWaterBox = waterBox;
+ return i;
+ }
+ }
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80042B2C.s")
+ *outWaterBox = NULL;
+ return -1;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80042C3C.s")
+/**
+ * WaterBox get CamData index
+ */
+u32 WaterBox_GetCamDataIndex(CollisionContext* colCtx, WaterBox* waterBox) {
+ u32 prop = waterBox->properties >> 0;
+ return prop & 0xFF;
+}
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80042CB8.s")
+/**
+ * WaterBox get CamData cameraSType
+ */
+u16 WaterBox_GetCameraSType(CollisionContext* colCtx, WaterBox* waterBox) {
+ s32 camId;
+ CamData* camData;
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80042EF8.s")
+ camId = WaterBox_GetCamDataIndex(colCtx, waterBox);
-#pragma GLOBAL_ASM("asm/non_matchings/code/z_bgcheck/func_80042FC4.s")
+ camData = colCtx->colHeader->cameraDataList;
+ if (camData == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return 0;
+ }
+
+ return colCtx->colHeader->cameraDataList[camId].cameraSType;
+}
+
+/**
+ * WaterBox get lighting settings
+ */
+u32 WaterBox_GetLightSettingIndex(CollisionContext* colCtx, WaterBox* waterBox) {
+ u32 prop = waterBox->properties >> 8;
+ return prop & 0x1F;
+}
+
+/**
+ * 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_800425B0(GlobalContext* globalCtx, CollisionContext* colCtx, f32 x, f32 z, f32* ySurface,
+ WaterBox** outWaterBox) {
+ CollisionHeader* colHeader;
+ u32 room;
+ WaterBox* curWaterBox;
+
+ colHeader = colCtx->colHeader;
+ if (colHeader->nbWaterBoxes == 0 || colHeader->waterBoxes == PHYSICAL_TO_VIRTUAL(gSegments[0])) {
+ return false;
+ }
+
+ for (curWaterBox = colHeader->waterBoxes; curWaterBox < colHeader->waterBoxes + colHeader->nbWaterBoxes;
+ curWaterBox++) {
+ room = (curWaterBox->properties >> 0xD) & 0x3F;
+ if ((room == globalCtx->roomCtx.curRoom.num) || (room == 0x3F)) {
+ if ((curWaterBox->properties & 0x80000) != 0) {
+ if (curWaterBox->xMin < x && x < (curWaterBox->xMin + curWaterBox->xLength)) {
+ if (curWaterBox->zMin < z && z < (curWaterBox->zMin + curWaterBox->zLength)) {
+ *outWaterBox = curWaterBox;
+ *ySurface = curWaterBox->ySurface;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Gets the `closestPoint` to `point` on the line formed from the intesection of planes `polyA` and `polyB`
+ * returns true if the `closestPoint` exists, else returns false
+ */
+s32 func_80042708(CollisionPoly* polyA, CollisionPoly* polyB, Vec3f* point, Vec3f* closestPoint) {
+ f32 n1X;
+ f32 n1Y;
+ f32 n1Z;
+ f32 n2X;
+ f32 n2Y;
+ f32 n2Z;
+
+ CollisionPoly_GetNormalF(polyA, &n1X, &n1Y, &n1Z);
+ CollisionPoly_GetNormalF(polyB, &n2X, &n2Y, &n2Z);
+ return Math3D_PlaneVsPlaneVsLineClosestPoint(n1X, n1Y, n1Z, polyA->dist, n2X, n2Y, n2Z, polyB->dist, point,
+ closestPoint);
+}
+
+/**
+ * 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_800427B4(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;
+}
+
+/**
+ * Draw a list of dyna polys, specified by `ssList`
+ */
+void BgCheck_DrawDynaPolyList(GlobalContext* globalCtx, CollisionContext* colCtx, DynaCollisionContext* dyna,
+ SSList* ssList, u8 r, u8 g, u8 b) {
+ s16 curPolyId;
+ CollisionPoly* poly;
+ SSNode* curNode;
+ Vec3f vA;
+ Vec3f vB;
+ Vec3f vC;
+ f32 nx;
+ f32 ny;
+ f32 nz;
+
+ if (ssList->head != SS_NULL) {
+ curNode = &dyna->polyNodes.tbl[ssList->head];
+ while (true) {
+ curPolyId = curNode->polyId;
+ poly = &dyna->polyList[curPolyId];
+ BgCheck_Vec3sToVec3f(COLPOLY_VTX_INDEX(poly->flags_vIA) + dyna->vtxList, &vA);
+ BgCheck_Vec3sToVec3f(COLPOLY_VTX_INDEX(poly->flags_vIB) + dyna->vtxList, &vB);
+ BgCheck_Vec3sToVec3f((s32)(poly->vIC) + dyna->vtxList, &vC);
+ if (AREG(26)) {
+ nx = COLPOLY_GET_NORMAL(poly->normal.x);
+ ny = COLPOLY_GET_NORMAL(poly->normal.y);
+ nz = COLPOLY_GET_NORMAL(poly->normal.z);
+ vA.x += AREG(26) * nx;
+ vA.y += AREG(26) * ny;
+ vA.z += AREG(26) * nz;
+ vB.x += AREG(26) * nx;
+ vB.y += AREG(26) * ny;
+ vB.z += AREG(26) * nz;
+ vC.x += AREG(26) * nx;
+ vC.y += AREG(26) * ny;
+ vC.z += AREG(26) * nz;
+ }
+ func_8005B2AC(globalCtx->state.gfxCtx, &vA, &vB, &vC, r, g, b);
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &dyna->polyNodes.tbl[curNode->next];
+ }
+ }
+}
+
+/**
+ * Draw a BgActor's dyna polys
+ * `bgId` is the BgActor index that should be drawn
+ */
+void BgCheck_DrawBgActor(GlobalContext* globalCtx, CollisionContext* colCtx, s32 bgId) {
+ if (AREG(21)) {
+ BgCheck_DrawDynaPolyList(globalCtx, colCtx, &colCtx->dyna, &colCtx->dyna.bgActors[bgId].dynaLookup.ceiling, 255,
+ 0, 0);
+ }
+ if (AREG(22)) {
+ BgCheck_DrawDynaPolyList(globalCtx, colCtx, &colCtx->dyna, &colCtx->dyna.bgActors[bgId].dynaLookup.wall, 0, 255,
+ 0);
+ }
+ if (AREG(23)) {
+ BgCheck_DrawDynaPolyList(globalCtx, colCtx, &colCtx->dyna, &colCtx->dyna.bgActors[bgId].dynaLookup.floor, 0, 0,
+ 255);
+ }
+}
+
+/**
+ * Draw all dyna polys
+ */
+void BgCheck_DrawDynaCollision(GlobalContext* globalCtx, CollisionContext* colCtx) {
+ s32 bgId;
+
+ for (bgId = 0; bgId < BG_ACTOR_MAX; bgId++) {
+
+ if (!(colCtx->dyna.bgActorFlags[bgId] & 1)) {
+ continue;
+ }
+ BgCheck_DrawBgActor(globalCtx, colCtx, bgId);
+ }
+}
+
+/**
+ * Draw a static poly
+ */
+void BgCheck_DrawStaticPoly(GlobalContext* globalCtx, CollisionContext* colCtx, CollisionPoly* poly, u8 r, u8 g, u8 b) {
+ Vec3f vA;
+ Vec3f vB;
+ Vec3f vC;
+ f32 nx;
+ f32 ny;
+ f32 nz;
+
+ BgCheck_Vec3sToVec3f(COLPOLY_VTX_INDEX(poly->flags_vIA) + colCtx->colHeader->vtxList, &vA);
+ BgCheck_Vec3sToVec3f(COLPOLY_VTX_INDEX(poly->flags_vIB) + colCtx->colHeader->vtxList, &vB);
+ BgCheck_Vec3sToVec3f(poly->vIC + colCtx->colHeader->vtxList, &vC);
+ if (AREG(26) != 0) {
+ nx = COLPOLY_GET_NORMAL(poly->normal.x);
+ ny = COLPOLY_GET_NORMAL(poly->normal.y);
+ nz = COLPOLY_GET_NORMAL(poly->normal.z);
+ vA.x += AREG(26) * nx;
+ vA.y += AREG(26) * ny;
+ vA.z += AREG(26) * nz;
+ vB.x += AREG(26) * nx;
+ vB.y += AREG(26) * ny;
+ vB.z += AREG(26) * nz;
+ vC.x += AREG(26) * nx;
+ vC.y += AREG(26) * ny;
+ vC.z += AREG(26) * nz;
+ }
+ func_8005B2AC(globalCtx->state.gfxCtx, &vA, &vB, &vC, r, g, b);
+}
+
+/**
+ * Draw a list of static polys, specified by `ssList`
+ */
+void BgCheck_DrawStaticPolyList(GlobalContext* globalCtx, CollisionContext* colCtx, SSList* ssList, u8 r, u8 g, u8 b) {
+ SSNode* curNode;
+ CollisionPoly* polyList;
+ s16 curPolyId;
+
+ polyList = colCtx->colHeader->polyList;
+ if (ssList->head != SS_NULL) {
+ curNode = &colCtx->polyNodes.tbl[ssList->head];
+ while (true) {
+ curPolyId = curNode->polyId;
+ BgCheck_DrawStaticPoly(globalCtx, colCtx, &polyList[curPolyId], r, g, b);
+ if (curNode->next == SS_NULL) {
+ break;
+ }
+ curNode = &colCtx->polyNodes.tbl[curNode->next];
+ }
+ }
+}
+
+/**
+ * Draw scene collision
+ */
+void BgCheck_DrawStaticCollision(GlobalContext* globalCtx, CollisionContext* colCtx) {
+ Player* player;
+ StaticLookup* lookup;
+
+ player = PLAYER;
+ lookup = BgCheck_GetNearestStaticLookup(colCtx, colCtx->lookupTbl, &player->actor.posRot.pos);
+ if (AREG(23) != 0) {
+ BgCheck_DrawStaticPolyList(globalCtx, colCtx, &lookup->floor, 0, 0, 255);
+ }
+ if (AREG(22) != 0) {
+ BgCheck_DrawStaticPolyList(globalCtx, colCtx, &lookup->wall, 0, 255, 0);
+ }
+ if (AREG(21) != 0) {
+ BgCheck_DrawStaticPolyList(globalCtx, colCtx, &lookup->ceiling, 255, 0, 0);
+ }
+}
diff --git a/src/code/z_camera.c b/src/code/z_camera.c
index 87c3cf85a..3b0a98d3c 100644
--- a/src/code/z_camera.c
+++ b/src/code/z_camera.c
@@ -215,7 +215,7 @@ s32 Camera_BGCheckInfo(Camera* camera, Vec3f* from, CamColChk* to) {
fromToOffset.r += 8.0f;
Camera_Vec3fVecSphGeoAdd(&toPoint, from, &fromToOffset);
- if (!func_8003DD6C(colCtx, from, &toPoint, &toNewPos, &to->poly, 1, 1, 1, -1, &to->bgId)) {
+ if (!BgCheck_CameraLineTest1(colCtx, from, &toPoint, &toNewPos, &to->poly, 1, 1, 1, -1, &to->bgId)) {
// no poly in path.
OLib_Vec3fDistNormalize(&fromToNorm, from, &to->pos);
@@ -225,7 +225,7 @@ s32 Camera_BGCheckInfo(Camera* camera, Vec3f* from, CamColChk* to) {
toNewPos = to->pos;
toNewPos.y += 5.0f;
- floorPolyY = func_8003CCA4(colCtx, &floorPoly, &floorBgId, &toNewPos);
+ floorPolyY = BgCheck_CameraRaycastFloor2(colCtx, &floorPoly, &floorBgId, &toNewPos);
if ((to->pos.y - floorPolyY) > 5.0f) {
// if the y distance from the check point to the floor is more than 5 units
@@ -241,9 +241,9 @@ s32 Camera_BGCheckInfo(Camera* camera, Vec3f* from, CamColChk* to) {
to->bgId = floorBgId;
}
- to->norm.x = to->poly->norm.x * COLPOLY_NORM_FRAC;
- to->norm.y = to->poly->norm.y * COLPOLY_NORM_FRAC;
- to->norm.z = to->poly->norm.z * COLPOLY_NORM_FRAC;
+ to->norm.x = COLPOLY_GET_NORMAL(to->poly->normal.x);
+ to->norm.y = COLPOLY_GET_NORMAL(to->poly->normal.y);
+ to->norm.z = COLPOLY_GET_NORMAL(to->poly->normal.z);
to->pos.x = to->norm.x + toNewPos.x;
to->pos.y = to->norm.y + toNewPos.y;
to->pos.z = to->norm.z + toNewPos.z;
@@ -278,14 +278,14 @@ s32 func_80043F94(Camera* camera, Vec3f* from, CamColChk* to) {
OLib_Vec3fDiffToVecSphGeo(&fromToGeo, from, &to->pos);
fromToGeo.r += 8.0f;
Camera_Vec3fVecSphGeoAdd(&toPos, from, &fromToGeo);
- if (!func_8003DD6C(colCtx, from, &toPos, &toNewPos, &to->poly, 1, 1, 1, -1, &to->bgId)) {
+ if (!BgCheck_CameraLineTest1(colCtx, from, &toPos, &toNewPos, &to->poly, 1, 1, 1, -1, &to->bgId)) {
OLib_Vec3fDistNormalize(&fromToNorm, from, &to->pos);
to->norm.x = -fromToNorm.x;
to->norm.y = -fromToNorm.y;
to->norm.z = -fromToNorm.z;
toNewPos = to->pos;
toNewPos.y += 5.0f;
- floorY = func_8003CCA4(colCtx, &floorPoly, &bgId, &toNewPos);
+ floorY = BgCheck_CameraRaycastFloor2(colCtx, &floorPoly, &bgId, &toNewPos);
if ((to->pos.y - floorY) > 5.0f) {
// to is not on the ground or below it.
to->pos.x += to->norm.x;
@@ -298,17 +298,17 @@ s32 func_80043F94(Camera* camera, Vec3f* from, CamColChk* to) {
toNewPos.y = floorY + 1.0f;
to->bgId = bgId;
}
- to->norm.x = to->poly->norm.x * COLPOLY_NORM_FRAC;
- to->norm.y = to->poly->norm.y * COLPOLY_NORM_FRAC;
- to->norm.z = to->poly->norm.z * COLPOLY_NORM_FRAC;
+ to->norm.x = COLPOLY_GET_NORMAL(to->poly->normal.x);
+ to->norm.y = COLPOLY_GET_NORMAL(to->poly->normal.y);
+ to->norm.z = COLPOLY_GET_NORMAL(to->poly->normal.z);
if ((to->norm.y > 0.5f) || (to->norm.y < -0.8f)) {
to->pos.x = to->norm.x + toNewPos.x;
to->pos.y = to->norm.y + toNewPos.y;
to->pos.z = to->norm.z + toNewPos.z;
} else if (playerFloorPoly != NULL) {
- playerFloorNormF.x = playerFloorPoly->norm.x * COLPOLY_NORM_FRAC;
- playerFloorNormF.y = playerFloorPoly->norm.y * COLPOLY_NORM_FRAC;
- playerFloorNormF.z = playerFloorPoly->norm.z * COLPOLY_NORM_FRAC;
+ playerFloorNormF.x = COLPOLY_GET_NORMAL(playerFloorPoly->normal.x);
+ playerFloorNormF.y = COLPOLY_GET_NORMAL(playerFloorPoly->normal.y);
+ playerFloorNormF.z = COLPOLY_GET_NORMAL(playerFloorPoly->normal.z);
if (Math3D_LineSegVsPlane(playerFloorNormF.x, playerFloorNormF.y, playerFloorNormF.z, playerFloorPoly->dist,
from, &toPos, &toNewPos, 1)) {
// line is from->to is touching the poly the player is on.
@@ -353,7 +353,8 @@ s32 Camera_CheckOOB(Camera* camera, Vec3f* from, Vec3f* to) {
CollisionContext* colCtx = &camera->globalCtx->colCtx;
poly = NULL;
- if (func_8003DD6C(colCtx, from, to, &intersect, &poly, 1, 1, 1, 0, &bgId) && (func_80038B7C(poly, from) < 0.0f)) {
+ if (BgCheck_CameraLineTest1(colCtx, from, to, &intersect, &poly, 1, 1, 1, 0, &bgId) &&
+ (CollisionPoly_GetPointDistanceFromPlane(poly, from) < 0.0f)) {
// if there is a poly between `from` and `to` and the `from` is behind the poly.
return true;
}
@@ -368,7 +369,7 @@ s32 Camera_CheckOOB(Camera* camera, Vec3f* from, Vec3f* to) {
f32 Camera_GetFloorYNorm(Camera* camera, Vec3f* floorNorm, Vec3f* chkPos, s32* bgId) {
s32 pad;
CollisionPoly* floorPoly;
- f32 floorY = func_8003C940(&camera->globalCtx->colCtx, &floorPoly, bgId, chkPos);
+ f32 floorY = BgCheck_EntityRaycastFloor3(&camera->globalCtx->colCtx, &floorPoly, bgId, chkPos);
if (floorY == BGCHECK_Y_MIN) {
// no floor
@@ -376,9 +377,9 @@ f32 Camera_GetFloorYNorm(Camera* camera, Vec3f* floorNorm, Vec3f* chkPos, s32* b
floorNorm->y = 1.0f;
floorNorm->z = 0.0f;
} else {
- floorNorm->x = floorPoly->norm.x * COLPOLY_NORM_FRAC;
- floorNorm->y = floorPoly->norm.y * COLPOLY_NORM_FRAC;
- floorNorm->z = floorPoly->norm.z * COLPOLY_NORM_FRAC;
+ floorNorm->x = COLPOLY_GET_NORMAL(floorPoly->normal.x);
+ floorNorm->y = COLPOLY_GET_NORMAL(floorPoly->normal.y);
+ floorNorm->z = COLPOLY_GET_NORMAL(floorPoly->normal.z);
}
return floorY;
@@ -409,9 +410,9 @@ f32 Camera_GetFloorYLayer(Camera* camera, Vec3f* norm, Vec3f* pos, u32* bgId) {
s32 i;
for (i = 3; i > 0; i--) {
- floorY = func_8003CCA4(colCtx, &floorPoly, bgId, pos);
+ floorY = BgCheck_CameraRaycastFloor2(colCtx, &floorPoly, bgId, pos);
if (floorY == BGCHECK_Y_MIN ||
- (camera->playerGroundY < floorY && !((floorPoly->norm.y * COLPOLY_NORM_FRAC) > 0.5f))) {
+ (camera->playerGroundY < floorY && !(COLPOLY_GET_NORMAL(floorPoly->normal.y) > 0.5f))) {
// no floor, or player is below the floor and floor is not considered steep
norm->x = 0.0f;
norm->y = 1.0f;
@@ -423,9 +424,9 @@ f32 Camera_GetFloorYLayer(Camera* camera, Vec3f* norm, Vec3f* pos, u32* bgId) {
pos->y = floorY - 10.0f;
continue;
} else {
- norm->x = floorPoly->norm.x * COLPOLY_NORM_FRAC;
- norm->y = floorPoly->norm.y * COLPOLY_NORM_FRAC;
- norm->z = floorPoly->norm.z * COLPOLY_NORM_FRAC;
+ norm->x = COLPOLY_GET_NORMAL(floorPoly->normal.x);
+ norm->y = COLPOLY_GET_NORMAL(floorPoly->normal.y);
+ norm->z = COLPOLY_GET_NORMAL(floorPoly->normal.z);
break;
}
}
@@ -439,14 +440,14 @@ f32 Camera_GetFloorYLayer(Camera* camera, Vec3f* norm, Vec3f* pos, u32* bgId) {
* Returns the CameraSettingType of the camera at index `camDataIdx`
*/
s16 Camera_GetCamDataSetting(Camera* camera, s32 camDataIdx) {
- return func_80041A4C(&camera->globalCtx->colCtx, camDataIdx, 50);
+ return func_80041A4C(&camera->globalCtx->colCtx, camDataIdx, BGCHECK_SCENE);
}
/**
* Returns the scene camera info for the current camera data index
*/
Vec3s* Camera_GetCamBGData(Camera* camera) {
- return func_80041C10(&camera->globalCtx->colCtx, camera->camDataIdx, 50);
+ return func_80041C10(&camera->globalCtx->colCtx, camera->camDataIdx, BGCHECK_SCENE);
}
/**
@@ -459,7 +460,7 @@ s32 Camera_GetDataIdxForPoly(Camera* camera, u32* bgId, CollisionPoly* poly) {
s32 ret;
func_8002EF44(&playerPosRot, &camera->player->actor); // unused.
- camDataIdx = func_80041A28(&camera->globalCtx->colCtx, poly, *bgId);
+ camDataIdx = SurfaceType_GetCamDataIndex(&camera->globalCtx->colCtx, poly, *bgId);
if (func_80041A4C(&camera->globalCtx->colCtx, camDataIdx, *bgId) == CAM_SET_NONE) {
ret = -1;
@@ -482,12 +483,13 @@ Vec3s* Camera_GetCamBgDataUnderPlayer(Camera* camera, u16* dataCnt) {
func_8002EF44(&playerPosShape, &camera->player->actor);
playerPosShape.pos.y += Player_GetHeight(camera->player);
- if (func_8003C940(&camera->globalCtx->colCtx, &floorPoly, &bgId, &playerPosShape.pos) == BGCHECK_Y_MIN) {
+ if (BgCheck_EntityRaycastFloor3(&camera->globalCtx->colCtx, &floorPoly, &bgId, &playerPosShape.pos) ==
+ BGCHECK_Y_MIN) {
// no floor
return NULL;
}
- *dataCnt = func_80041B80(&camera->globalCtx->colCtx, floorPoly, bgId);
- return func_80041C98(&camera->globalCtx->colCtx, floorPoly, bgId);
+ *dataCnt = SurfaceType_GetNumCameras(&camera->globalCtx->colCtx, floorPoly, bgId);
+ return SurfaceType_GetCamPosData(&camera->globalCtx->colCtx, floorPoly, bgId);
}
/**
@@ -504,8 +506,8 @@ s32 Camera_GetWaterBoxDataIdx(Camera* camera, f32* waterY) {
func_8002EF44(&playerPosShape, &camera->player->actor);
*waterY = playerPosShape.pos.y;
- if (!func_8004213C(camera->globalCtx, &camera->globalCtx->colCtx, playerPosShape.pos.x, playerPosShape.pos.z,
- waterY, &waterBox)) {
+ if (!WaterBox_GetSurface1(camera->globalCtx, &camera->globalCtx->colCtx, playerPosShape.pos.x, playerPosShape.pos.z,
+ waterY, &waterBox)) {
// player's position is not in a water box.
*waterY = BGCHECK_Y_MIN;
return -1;
@@ -517,8 +519,8 @@ s32 Camera_GetWaterBoxDataIdx(Camera* camera, f32* waterY) {
return -1;
}
- ret = func_80042538(&camera->globalCtx->colCtx, waterBox);
- if ((ret <= 0) || (func_80042548(&camera->globalCtx->colCtx, waterBox) <= 0)) {
+ ret = WaterBox_GetCamDataIndex(&camera->globalCtx->colCtx, waterBox);
+ if ((ret <= 0) || (WaterBox_GetCameraSType(&camera->globalCtx->colCtx, waterBox) <= 0)) {
// no camera data idx, or no CameraSettingType
return -2;
}
@@ -539,7 +541,8 @@ f32 Camera_GetWaterSurface(Camera* camera, Vec3f* chkPos, s32* envProp) {
func_8002EF44(&playerPosRot, &camera->player->actor);
waterY = playerPosRot.pos.y;
- if (!func_8004213C(camera->globalCtx, &camera->globalCtx->colCtx, chkPos->x, chkPos->z, &waterY, &waterBox)) {
+ if (!WaterBox_GetSurface1(camera->globalCtx, &camera->globalCtx->colCtx, chkPos->x, chkPos->z, &waterY,
+ &waterBox)) {
// chkPos is not within the x/z boundaries of a water box.
return BGCHECK_Y_MIN;
}
@@ -550,7 +553,7 @@ f32 Camera_GetWaterSurface(Camera* camera, Vec3f* chkPos, s32* envProp) {
return BGCHECK_Y_MIN;
}
- *envProp = func_8004259C(&camera->globalCtx->colCtx, waterBox);
+ *envProp = WaterBox_GetLightSettingIndex(&camera->globalCtx->colCtx, waterBox);
return waterY;
}
@@ -1284,7 +1287,7 @@ s16 Camera_CalcDefaultYaw(Camera* camera, s16 cur, s16 target, f32 arg3, f32 acc
if (camera->xzSpeed > 0.001f) {
angDelta = target - BINANG_ROT180(cur);
- speedT = BINANG_ROT180(angDelta) * COLPOLY_NORM_FRAC;
+ speedT = COLPOLY_GET_NORMAL(BINANG_ROT180(angDelta));
} else {
angDelta = target - BINANG_ROT180(cur);
speedT = PCT(OREG(48));
@@ -3603,7 +3606,7 @@ s32 Camera_KeepOn4(Camera* camera) {
OLib_Vec3fDiffToVecSphGeo(&spA8, at, eyeNext);
D_8015BD50 = playerPosRot->pos;
D_8015BD50.y += playerHeight;
- temp_f0_2 = func_8003CCA4(&camera->globalCtx->colCtx, &spC0, &i, &D_8015BD50);
+ temp_f0_2 = BgCheck_CameraRaycastFloor2(&camera->globalCtx->colCtx, &spC0, &i, &D_8015BD50);
if (temp_f0_2 > (keep4->unk_00 + D_8015BD50.y)) {
D_8015BD50.y = temp_f0_2 + 10.0f;
} else {
@@ -6833,7 +6836,7 @@ void Camera_Init(Camera* camera, View* view, CollisionContext* colCtx, GlobalCon
camera->setting = camera->prevSetting = 0x21;
camera->camDataIdx = camera->prevCamDataIdx = -1;
camera->mode = 0;
- camera->bgCheckId = 0x32;
+ camera->bgCheckId = BGCHECK_SCENE;
camera->unk_168 = 0x7FFF;
camera->timer = -1;
camera->unk_14C |= 0x4000;
@@ -7092,7 +7095,7 @@ s32 Camera_CheckWater(Camera* camera) {
}
if (camera->playerGroundY != camera->playerPosRot.pos.y) {
prevBgId = camera->bgCheckId;
- camera->bgCheckId = 50;
+ camera->bgCheckId = BGCHECK_SCENE;
Camera_ChangeSettingFlags(camera, CAM_SET_NORMAL3, 2);
*waterPrevCamSetting = camera->setting;
camera->bgCheckId = prevBgId;
@@ -7108,7 +7111,7 @@ s32 Camera_CheckWater(Camera* camera) {
}
if (camera->playerGroundY != camera->playerPosRot.pos.y) {
prevBgId = camera->bgCheckId;
- camera->bgCheckId = 50;
+ camera->bgCheckId = BGCHECK_SCENE;
Camera_ChangeDataIdx(camera, waterCamIdx);
*waterPrevCamSetting = camera->setting;
camera->bgCheckId = prevBgId;
@@ -7118,7 +7121,7 @@ s32 Camera_CheckWater(Camera* camera) {
osSyncPrintf("camera: water: off\n");
camera->unk_14C &= ~0x200;
prevBgId = camera->bgCheckId;
- camera->bgCheckId = 50;
+ camera->bgCheckId = BGCHECK_SCENE;
if (camera->waterPrevCamIdx < 0) {
func_80057FC4(camera);
camera->camDataIdx = -1;
@@ -7342,14 +7345,14 @@ Vec3s* Camera_Update(Vec3s* outVec, Camera* camera) {
spAC = curPlayerPosRot.pos;
spAC.y += Player_GetHeight(camera->player);
- playerGroundY = func_8003CA0C(camera->globalCtx, &camera->globalCtx->colCtx, &playerFloorPoly, &bgCheckId,
- &camera->player->actor, &spAC);
+ playerGroundY = BgCheck_EntityRaycastFloor5(camera->globalCtx, &camera->globalCtx->colCtx, &playerFloorPoly,
+ &bgCheckId, &camera->player->actor, &spAC);
if (playerGroundY != BGCHECK_Y_MIN) {
// player is above ground.
sOOBTimer = 0;
- camera->floorNorm.x = playerFloorPoly->norm.x * COLPOLY_NORM_FRAC;
- camera->floorNorm.y = playerFloorPoly->norm.y * COLPOLY_NORM_FRAC;
- camera->floorNorm.z = playerFloorPoly->norm.z * COLPOLY_NORM_FRAC;
+ camera->floorNorm.x = COLPOLY_GET_NORMAL(playerFloorPoly->normal.x);
+ camera->floorNorm.y = COLPOLY_GET_NORMAL(playerFloorPoly->normal.y);
+ camera->floorNorm.z = COLPOLY_GET_NORMAL(playerFloorPoly->normal.z);
camera->bgCheckId = bgCheckId;
camera->playerGroundY = playerGroundY;
} else {
@@ -7378,7 +7381,7 @@ Vec3s* Camera_Update(Vec3s* outVec, Camera* camera) {
camDataIdx = Camera_GetDataIdxForPoly(camera, &bgCheckId, playerFloorPoly);
if (camDataIdx != -1) {
camera->nextBGCheckId = bgCheckId;
- if (bgCheckId == 50) {
+ if (bgCheckId == BGCHECK_SCENE) {
camera->nextCamDataIdx = camDataIdx;
}
}
diff --git a/src/code/z_collision_check.c b/src/code/z_collision_check.c
index 0bb44587d..fbf8a5eba 100644
--- a/src/code/z_collision_check.c
+++ b/src/code/z_collision_check.c
@@ -1025,10 +1025,10 @@ void CollisionCheck_Draw(GlobalContext* globalCtx, CollisionCheckContext* colChk
}
}
if (AREG(24)) {
- func_80042C3C(globalCtx, &globalCtx->colCtx);
+ BgCheck_DrawDynaCollision(globalCtx, &globalCtx->colCtx);
}
if (AREG(25)) {
- func_80042FC4(globalCtx, &globalCtx->colCtx);
+ BgCheck_DrawStaticCollision(globalCtx, &globalCtx->colCtx);
}
}
}
@@ -1281,13 +1281,14 @@ s32 func_8005DF74(ColliderBody* left, ColliderBody* right) {
void func_8005DF9C(GlobalContext* globalCtx, Collider* collider, Vec3f* v) {
}
-void func_8005DFAC(GlobalContext* globalCtx, Collider* collider, Vec3f* v) {
+// Blue EffectSpark
+void func_8005DFAC(GlobalContext* globalCtx, Collider* collider, Vec3f* pos) {
static EffectSparkInit D_8015D8A0;
s32 sp24;
- D_8015D8A0.position.x = (s32)v->x;
- D_8015D8A0.position.y = (s32)v->y;
- D_8015D8A0.position.z = (s32)v->z;
+ D_8015D8A0.position.x = (s32)pos->x;
+ D_8015D8A0.position.y = (s32)pos->y;
+ D_8015D8A0.position.z = (s32)pos->z;
D_8015D8A0.uDiv = 5;
D_8015D8A0.vDiv = 5;
D_8015D8A0.colorStart[0].r = 10;
@@ -1330,13 +1331,14 @@ void func_8005DFAC(GlobalContext* globalCtx, Collider* collider, Vec3f* v) {
Effect_Add(globalCtx, &sp24, EFFECT_SPARK, 0, 1, &D_8015D8A0);
}
-void func_8005E10C(GlobalContext* globalCtx, Collider* collider, Vec3f* v) {
+// Green EffectSpark
+void func_8005E10C(GlobalContext* globalCtx, Collider* collider, Vec3f* pos) {
static EffectSparkInit D_8015DD68;
s32 sp24;
- D_8015DD68.position.x = (s32)v->x;
- D_8015DD68.position.y = (s32)v->y;
- D_8015DD68.position.z = (s32)v->z;
+ D_8015DD68.position.x = (s32)pos->x;
+ D_8015DD68.position.y = (s32)pos->y;
+ D_8015DD68.position.z = (s32)pos->z;
D_8015DD68.uDiv = 5;
D_8015DD68.vDiv = 5;
D_8015DD68.colorStart[0].r = 10;
@@ -1590,7 +1592,7 @@ void CollisionCheck_AC_JntSphVsJntSph(GlobalContext* globalCtx, CollisionCheckCo
sp60.x = rItem->dim.worldSphere.center.x;
sp60.y = rItem->dim.worldSphere.center.y;
sp60.z = rItem->dim.worldSphere.center.z;
- if (!(fabsf(sp88) < 0.008f)) {
+ if (!IS_ZERO(sp88)) {
temp_f0 = rItem->dim.worldSphere.radius / sp88;
sp78.x = (((sp6C.x - sp60.x) * temp_f0) + sp60.x);
sp78.y = (((sp6C.y - sp60.y) * temp_f0) + sp60.y);
@@ -1639,7 +1641,7 @@ void CollisionCheck_AC_JntSphVsCyl(GlobalContext* globalCtx, CollisionCheckConte
sp58.x = right->dim.pos.x;
sp58.y = right->dim.pos.y;
sp58.z = right->dim.pos.z;
- if (!(fabsf(sp7C) < 0.008f)) {
+ if (!IS_ZERO(sp7C)) {
temp_f0 = right->dim.radius / sp7C;
if (temp_f0 <= 1.0f) {
sp70.x = ((sp64.x - sp58.x) * temp_f0) + sp58.x;
@@ -1689,7 +1691,7 @@ void CollisionCheck_AC_CylVsJntSph(GlobalContext* globalCtx, CollisionCheckConte
sp70.x = rItem->dim.worldSphere.center.x;
sp70.y = rItem->dim.worldSphere.center.y;
sp70.z = rItem->dim.worldSphere.center.z;
- if (!(fabsf(sp98) < 0.008f)) {
+ if (!IS_ZERO(sp98)) {
temp_f0 = (f32)rItem->dim.worldSphere.radius / sp98;
if (temp_f0 <= 1.0f) {
sp88.x = ((sp7C.x - sp70.x) * temp_f0) + sp70.x;
@@ -1908,7 +1910,7 @@ void CollisionCheck_AC_CylVsCyl(GlobalContext* globalCtx, CollisionCheckContext*
if (Math3D_CylOutsideCylDist(&left->dim, &right->dim, &sp6C, &sp68) == 1) {
Math_Vec3s_ToVec3f(&sp50, &left->dim.pos);
Math_Vec3s_ToVec3f(&sp44, &right->dim.pos);
- if (!(fabsf(sp68) < 0.008f)) {
+ if (!IS_ZERO(sp68)) {
temp_f0 = (f32)right->dim.radius / sp68;
sp5C.y = (f32)right->dim.pos.y + (f32)right->dim.yShift + (f32)right->dim.height * 0.5f;
sp5C.x = ((f32)left->dim.pos.x - right->dim.pos.x) * temp_f0 + right->dim.pos.x;
@@ -2489,7 +2491,7 @@ void func_800614A4(Collider* left, ColliderBody* leftBody, Vec3f* leftv, Collide
leftMass = leftActor->colChkInfo.mass;
rightMass = rightActor->colChkInfo.mass;
totalMass = leftMass + rightMass;
- if (fabsf(totalMass) < 0.008f) {
+ if (IS_ZERO(totalMass)) {
totalMass = (leftMass = rightMass = 1.0f) * 2;
}
xDelta = rightv->x - leftv->x;
@@ -2525,7 +2527,7 @@ void func_800614A4(Collider* left, ColliderBody* leftBody, Vec3f* leftv, Collide
}
}
- if (!(fabsf(xzDist) < 0.008f)) {
+ if (!IS_ZERO(xzDist)) {
temp_f0 = arg6 / xzDist;
xDelta *= temp_f0;
zDelta *= temp_f0;
diff --git a/src/code/z_en_a_keep.c b/src/code/z_en_a_keep.c
index 81c1b9395..64b18aea3 100644
--- a/src/code/z_en_a_keep.c
+++ b/src/code/z_en_a_keep.c
@@ -39,8 +39,14 @@ static ColliderCylinderInit sCylinderInit = {
{ 25, 60, 0, { 0, 0, 0 } },
};
-static UNK_PTR D_8011546C[] = {
- 0x040394B0, 0x040394B0, 0x0403A120, 0x0403A480, 0x0403A7F0, 0x06000730,
+extern CollisionHeader D_040394B0;
+extern CollisionHeader D_0403A120;
+extern CollisionHeader D_0403A480;
+extern CollisionHeader D_0403A7F0;
+extern CollisionHeader D_06000730;
+
+static CollisionHeader* D_8011546C[] = {
+ &D_040394B0, &D_040394B0, &D_0403A120, &D_0403A480, &D_0403A7F0, &D_06000730,
};
static Gfx* D_80115484[] = {
@@ -53,7 +59,7 @@ void EnAObj_SetupAction(EnAObj* this, EnAObjActionFunc actionFunc) {
}
void EnAObj_Init(Actor* thisx, GlobalContext* globalCtx) {
- u32 sp34 = 0;
+ CollisionHeader* colHeader = NULL;
s32 pad;
EnAObj* this = THIS;
f32 sp28;
@@ -91,35 +97,35 @@ void EnAObj_Init(Actor* thisx, GlobalContext* globalCtx) {
ActorShape_Init(&thisx->shape, 0.0f, ActorShadow_DrawFunc_Circle, sp28);
thisx->posRot2.pos = thisx->posRot.pos;
- this->dyna.dynaPolyId = -1;
+ this->dyna.bgId = BGACTOR_NEG_ONE;
this->dyna.unk_160 = 0;
- this->dyna.unk_15C = 0;
+ this->dyna.unk_15C = DPM_UNK;
thisx->uncullZoneDownward = 1200.0f;
thisx->uncullZoneScale = 200.0f;
switch (thisx->params) {
case A_OBJ_BLOCK_LARGE:
case A_OBJ_BLOCK_HUGE:
- this->dyna.dynaPolyId = 1;
+ this->dyna.bgId = 1;
Actor_ChangeType(globalCtx, &globalCtx->actorCtx, thisx, ACTORTYPE_BG);
func_8001D5C8(this, thisx->params);
break;
case A_OBJ_BLOCK_SMALL_ROT:
case A_OBJ_BLOCK_LARGE_ROT:
- this->dyna.dynaPolyId = 3;
+ this->dyna.bgId = 3;
Actor_ChangeType(globalCtx, &globalCtx->actorCtx, thisx, ACTORTYPE_BG);
func_8001D310(this, thisx->params);
break;
case A_OBJ_UNKNOWN_6:
// clang-format off
- thisx->flags |= 0x1; this->dyna.dynaPolyId = 5; this->unk_178 = 10.0f;
+ thisx->flags |= 0x1; this->dyna.bgId = 5; this->unk_178 = 10.0f;
// clang-format on
thisx->gravity = -2.0f;
func_8001D234(this, thisx->params);
break;
case A_OBJ_GRASS_CLUMP:
case A_OBJ_TREE_STUMP:
- this->dyna.dynaPolyId = 0;
+ this->dyna.bgId = 0;
func_8001D234(this, thisx->params);
break;
case A_OBJ_SIGNPOST_OBLONG:
@@ -149,16 +155,16 @@ void EnAObj_Init(Actor* thisx, GlobalContext* globalCtx) {
thisx->colChkInfo.mass = 0xFF;
}
- if (this->dyna.dynaPolyId != -1) {
- DynaPolyInfo_Alloc(D_8011546C[this->dyna.dynaPolyId], &sp34);
- this->dyna.dynaPolyId = DynaPolyInfo_RegisterActor(globalCtx, &globalCtx->colCtx.dyna, thisx, sp34);
+ if (this->dyna.bgId != BGACTOR_NEG_ONE) {
+ CollisionHeader_GetVirtual(D_8011546C[this->dyna.bgId], &colHeader);
+ this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, thisx, colHeader);
}
}
void EnAObj_Destroy(Actor* thisx, GlobalContext* globalCtx) {
EnAObj* this = THIS;
- DynaPolyInfo_Free(globalCtx, &globalCtx->colCtx.dyna, this->dyna.dynaPolyId);
+ DynaPoly_DeleteBgActor(globalCtx, &globalCtx->colCtx.dyna, this->dyna.bgId);
switch (this->dyna.actor.params) {
case A_OBJ_SIGNPOST_OBLONG:
@@ -277,10 +283,7 @@ void func_8001D5C8(EnAObj* this, s16 params) {
void func_8001D608(EnAObj* this, GlobalContext* globalCtx) {
this->dyna.actor.speedXZ += this->dyna.unk_150;
this->dyna.actor.posRot.rot.y = this->dyna.unk_158;
-
- this->dyna.actor.speedXZ = (this->dyna.actor.speedXZ < -2.5f)
- ? -2.5f
- : ((this->dyna.actor.speedXZ > 2.5f) ? 2.5f : this->dyna.actor.speedXZ);
+ this->dyna.actor.speedXZ = CLAMP(this->dyna.actor.speedXZ, -2.5f, 2.5f);
Math_SmoothStepToF(&this->dyna.actor.speedXZ, 0.0f, 1.0f, 1.0f, 0.0f);
diff --git a/src/code/z_en_item00.c b/src/code/z_en_item00.c
index ef57cd1cd..4a67a7172 100644
--- a/src/code/z_en_item00.c
+++ b/src/code/z_en_item00.c
@@ -471,9 +471,9 @@ void EnItem00_Update(Actor* thisx, GlobalContext* globalCtx) {
if (D_80157D90 != globalCtx->gameplayFrames) {
D_80157D90_ = globalCtx->gameplayFrames;
D_80157D94 = 0;
- for (i = 0; i < 50; i++) {
- if (globalCtx->colCtx.dyna.flags[i] & 1) {
- dynaActor = globalCtx->colCtx.dyna.actorMeshArr[i].actor;
+ for (i = 0; i < BG_ACTOR_MAX; i++) {
+ if (globalCtx->colCtx.dyna.bgActorFlags[i] & 1) {
+ dynaActor = globalCtx->colCtx.dyna.bgActors[i].actor;
if ((dynaActor != NULL) && (dynaActor->update != NULL) &&
((dynaActor->posRot.pos.x != dynaActor->pos4.x) ||
(dynaActor->posRot.pos.y != dynaActor->pos4.y) ||
diff --git a/src/code/z_onepointdemo.c b/src/code/z_onepointdemo.c
index 6ba2334d6..15654cc0d 100644
--- a/src/code/z_onepointdemo.c
+++ b/src/code/z_onepointdemo.c
@@ -12,11 +12,11 @@ void func_8007C76C(Vec3f* src, Vec3s* dst) {
#pragma GLOBAL_ASM("asm/non_matchings/code/z_onepointdemo/func_8007C7A8.s")
-void func_8007C7F8(CollisionContext* colCtx, Vec3f* arg1) {
+void func_8007C7F8(CollisionContext* colCtx, Vec3f* pos) {
CollisionPoly* poly;
s32 bgId;
- func_8003C940(colCtx, &poly, &bgId, arg1);
+ BgCheck_EntityRaycastFloor3(colCtx, &poly, &bgId, pos);
}
void func_8007C820(OnePointDemoCamera* onePointCamera, s16 actionParameters, s16 initTimer,
diff --git a/src/code/z_play.c b/src/code/z_play.c
index ecce97a8e..b374801fa 100644
--- a/src/code/z_play.c
+++ b/src/code/z_play.c
@@ -1379,39 +1379,39 @@ s32 Gameplay_InCsMode(GlobalContext* globalCtx) {
}
f32 func_800BFCB8(GlobalContext* globalCtx, MtxF* mf, Vec3f* vec) {
- CollisionPoly sp50;
+ CollisionPoly poly;
f32 temp1;
f32 temp2;
f32 temp3;
- f32 sp40;
- f32 sp3C;
- f32 sp38;
- f32 sp34;
+ f32 floorY;
+ f32 nx;
+ f32 ny;
+ f32 nz;
s32 pad[5];
- sp40 = func_8003CB30(&globalCtx->colCtx, &sp50, vec, mf);
+ floorY = BgCheck_AnyRaycastFloor1(&globalCtx->colCtx, &poly, vec);
- if (sp40 > -32000.0f) {
- sp3C = sp50.norm.x * (1.0f / 32767.0f);
- sp38 = sp50.norm.y * (1.0f / 32767.0f);
- sp34 = sp50.norm.z * (1.0f / 32767.0f);
+ if (floorY > BGCHECK_Y_MIN) {
+ nx = COLPOLY_GET_NORMAL(poly.normal.x);
+ ny = COLPOLY_GET_NORMAL(poly.normal.y);
+ nz = COLPOLY_GET_NORMAL(poly.normal.z);
- temp1 = sqrtf(1.0f - SQ(sp3C));
+ temp1 = sqrtf(1.0f - SQ(nx));
if (temp1 != 0.0f) {
- temp2 = sp38 * temp1;
- temp3 = -sp34 * temp1;
+ temp2 = ny * temp1;
+ temp3 = -nz * temp1;
} else {
temp3 = 0.0f;
temp2 = 0.0f;
}
mf->xx = temp1;
- mf->xy = -sp3C * temp2;
- mf->xz = sp3C * temp3;
- mf->yx = sp3C;
- mf->yy = sp38;
- mf->yz = sp34;
+ mf->xy = -nx * temp2;
+ mf->xz = nx * temp3;
+ mf->yx = nx;
+ mf->yy = ny;
+ mf->yz = nz;
mf->zy = temp3;
mf->zz = temp2;
mf->xw = 0.0f;
@@ -1419,7 +1419,7 @@ f32 func_800BFCB8(GlobalContext* globalCtx, MtxF* mf, Vec3f* vec) {
mf->zx = 0.0f;
mf->zw = 0.0f;
mf->wx = vec->x;
- mf->wy = sp40;
+ mf->wy = floorY;
mf->wz = vec->z;
mf->ww = 1.0f;
} else {
@@ -1441,7 +1441,7 @@ f32 func_800BFCB8(GlobalContext* globalCtx, MtxF* mf, Vec3f* vec) {
mf->ww = 1.0f;
}
- return sp40;
+ return floorY;
}
void* Gameplay_LoadFile(GlobalContext* globalCtx, RomFile* file) {
@@ -1826,18 +1826,20 @@ s32 func_800C0D34(GlobalContext* globalCtx, Actor* actor, s16* yaw) {
return 1;
}
-s32 func_800C0DB4(GlobalContext* globalCtx, Vec3f* arg1) {
- WaterBox* sp3C;
- CollisionPoly* sp38;
- Vec3f sp2C;
- s32 sp28;
+s32 func_800C0DB4(GlobalContext* globalCtx, Vec3f* pos) {
+ WaterBox* waterBox;
+ CollisionPoly* poly;
+ Vec3f waterSurfacePos;
+ s32 bgId;
- sp2C = *arg1;
+ waterSurfacePos = *pos;
- if ((func_8004213C(globalCtx, &globalCtx->colCtx, sp2C.x, sp2C.z, &sp2C.y, &sp3C) == 1) && (arg1->y < sp2C.y) &&
- (func_8003C940(&globalCtx->colCtx, &sp38, &sp28, &sp2C) != -32000.0f)) {
- return 1;
+ if (WaterBox_GetSurface1(globalCtx, &globalCtx->colCtx, waterSurfacePos.x, waterSurfacePos.z, &waterSurfacePos.y,
+ &waterBox) == true &&
+ pos->y < waterSurfacePos.y &&
+ BgCheck_EntityRaycastFloor3(&globalCtx->colCtx, &poly, &bgId, &waterSurfacePos) != BGCHECK_Y_MIN) {
+ return true;
} else {
- return 0;
+ return false;
}
}
diff --git a/src/code/z_player_lib.c b/src/code/z_player_lib.c
index 1942a8b33..db619db67 100644
--- a/src/code/z_player_lib.c
+++ b/src/code/z_player_lib.c
@@ -741,7 +741,7 @@ void func_8008F87C(GlobalContext* globalCtx, Player* this, SkelAnime* skelAnime,
footprintPos.y += 15.0f;
- sp80 = func_8003C9A4(&globalCtx->colCtx, &sp88, &sp84, &this->actor, &footprintPos) + sp74;
+ sp80 = BgCheck_EntityRaycastFloor4(&globalCtx->colCtx, &sp88, &sp84, &this->actor, &footprintPos) + sp74;
if (sp98.y < sp80) {
sp70 = sp98.x - spA4.x;
@@ -783,7 +783,7 @@ void func_8008F87C(GlobalContext* globalCtx, Player* this, SkelAnime* skelAnime,
temp3 = func_80041D4C(&globalCtx->colCtx, sp88, sp84);
- if ((temp3 >= 2) && (temp3 < 4) && !func_80042108(&globalCtx->colCtx, sp88, sp84)) {
+ if ((temp3 >= 2) && (temp3 < 4) && !SurfaceType_IsWallDamage(&globalCtx->colCtx, sp88, sp84)) {
footprintPos.y = sp80;
EffectSsGFire_Spawn(globalCtx, &footprintPos);
}
@@ -1084,7 +1084,7 @@ void func_80090AFC(GlobalContext* globalCtx, Player* this, f32 arg2) {
if (1) {}
- if (func_8003E188(&globalCtx->colCtx, &sp8C, &sp80, &sp74, &sp9C, 1, 1, 1, 1, &sp98)) {
+ if (BgCheck_AnyLineTest3(&globalCtx->colCtx, &sp8C, &sp80, &sp74, &sp9C, 1, 1, 1, 1, &sp98)) {
OPEN_DISPS(globalCtx->state.gfxCtx, "../z_player_lib.c", 2572);
OVERLAY_DISP = Gfx_CallSetupDL(OVERLAY_DISP, 0x07);
diff --git a/src/code/z_room.c b/src/code/z_room.c
index ca0d6dbbd..4b802156d 100644
--- a/src/code/z_room.c
+++ b/src/code/z_room.c
@@ -389,7 +389,7 @@ BgImage* func_80096A74(PolygonType1* polygon1, GlobalContext* globalCtx) {
camera = ACTIVE_CAM;
camId = camera->camDataIdx;
// jfifid
- camId2 = func_80041C10(&globalCtx->colCtx, camId, 50)[2].y;
+ camId2 = func_80041C10(&globalCtx->colCtx, camId, BGCHECK_SCENE)[2].y;
if (camId2 >= 0) {
camId = camId2;
}
diff --git a/src/code/z_scene.c b/src/code/z_scene.c
index 7a1af1ee6..dce656a14 100644
--- a/src/code/z_scene.c
+++ b/src/code/z_scene.c
@@ -220,13 +220,13 @@ void func_80098674(GlobalContext* globalCtx, SceneCmd* cmd) {
colHeader = SEGMENTED_TO_VIRTUAL(cmd->colHeader.segment);
- colHeader->vertexArray = SEGMENTED_TO_VIRTUAL(colHeader->vertexArray);
- colHeader->polygonArray = SEGMENTED_TO_VIRTUAL(colHeader->polygonArray);
- colHeader->polygonTypes = SEGMENTED_TO_VIRTUAL(colHeader->polygonTypes);
- colHeader->cameraData = SEGMENTED_TO_VIRTUAL(colHeader->cameraData);
+ colHeader->vtxList = SEGMENTED_TO_VIRTUAL(colHeader->vtxList);
+ colHeader->polyList = SEGMENTED_TO_VIRTUAL(colHeader->polyList);
+ colHeader->surfaceTypeList = SEGMENTED_TO_VIRTUAL(colHeader->surfaceTypeList);
+ colHeader->cameraDataList = SEGMENTED_TO_VIRTUAL(colHeader->cameraDataList);
colHeader->waterBoxes = SEGMENTED_TO_VIRTUAL(colHeader->waterBoxes);
- func_8003C078(&globalCtx->colCtx, globalCtx, colHeader);
+ BgCheck_Allocate(&globalCtx->colCtx, globalCtx, colHeader);
}
// Scene Command 0x04: Room List