diff options
| author | mzxrules <mzxrules@gmail.com> | 2021-01-08 06:12:58 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-01-08 06:12:58 -0500 |
| commit | 3cef03f5ff9c0341544afec9636bd0581f87d0cc (patch) | |
| tree | 91ff5c72cadc5c647b52c285f9432f9f40e327dd /src/code | |
| parent | 209f0d21b87fa01c033a943fd8c862cb46b31315 (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.c | 93 | ||||
| -rw-r--r-- | src/code/code_80043480.c | 68 | ||||
| -rw-r--r-- | src/code/z_actor.c | 75 | ||||
| -rw-r--r-- | src/code/z_bgcheck.c | 4592 | ||||
| -rw-r--r-- | src/code/z_camera.c | 97 | ||||
| -rw-r--r-- | src/code/z_collision_check.c | 34 | ||||
| -rw-r--r-- | src/code/z_en_a_keep.c | 37 | ||||
| -rw-r--r-- | src/code/z_en_item00.c | 6 | ||||
| -rw-r--r-- | src/code/z_onepointdemo.c | 4 | ||||
| -rw-r--r-- | src/code/z_play.c | 62 | ||||
| -rw-r--r-- | src/code/z_player_lib.c | 6 | ||||
| -rw-r--r-- | src/code/z_room.c | 2 | ||||
| -rw-r--r-- | src/code/z_scene.c | 10 |
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, §or); + 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, §or); + 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(§orMin, §orMax, 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 |
