diff --git a/include/functions.h b/include/functions.h index f652786718..3223aa6245 100644 --- a/include/functions.h +++ b/include/functions.h @@ -2052,7 +2052,7 @@ s32 func_80124020(void); u8 Player_GetMask(GlobalContext* globalCtx); void Player_RemoveMask(GlobalContext* globalCtx); s32 func_8012405C(GlobalContext* globalCtx); -// void func_80124088(void); +s32 func_80124088(GlobalContext* globalCtx); s32 func_801240C8(Player* player); // void func_801240DC(void); // void func_80124110(void); diff --git a/spec b/spec index 18c9e5a6b5..f6871e38b9 100644 --- a/spec +++ b/spec @@ -1254,8 +1254,11 @@ beginseg name "ovl_Mir_Ray" compress include "build/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.o" - include "build/data/ovl_Mir_Ray/ovl_Mir_Ray.data.o" +#ifdef NON_MATCHING + include "build/src/overlays/actors/ovl_Mir_Ray/ovl_Mir_Ray_reloc.o" +#else include "build/data/ovl_Mir_Ray/ovl_Mir_Ray.reloc.o" +#endif endseg beginseg diff --git a/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c b/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c index f542b70861..18aafc07ad 100644 --- a/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c +++ b/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.c @@ -2,9 +2,11 @@ * File: z_mir_ray.c * Overlay: ovl_Mir_Ray * Description: Reflectible light ray (unused, somewhat broken) + * Note: This actor is unchanged from OoT, and will not work correctly */ #include "z_mir_ray.h" +#include "objects/object_mir_ray/object_mir_ray.h" #define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_20) @@ -15,7 +17,30 @@ void MirRay_Destroy(Actor* thisx, GlobalContext* globalCtx); void MirRay_Update(Actor* thisx, GlobalContext* globalCtx); void MirRay_Draw(Actor* thisx, GlobalContext* globalCtx); -#if 0 +s32 MirRay_CheckInFrustum(Vec3f* vecA, Vec3f* vecB, f32 pointx, f32 pointy, f32 pointz, s16 radiusA, s16 radiusB); + +typedef struct { + /* 0x00 */ Vec3f pos; + /* 0x0C */ MtxF mtx; + /* 0x4C */ CollisionPoly* reflectionPoly; + /* 0x50 */ u8 opacity; +} MirRayShieldReflection; // size = 0x54 + +typedef struct { + /* 0x00 */ Vec3s sourcePoint; + /* 0x06 */ Vec3s poolPoint; // point at center of light pool on floor for windows and BigMirror, same as source + // point for Cobra Mirror + /* 0x0C */ s16 sourceEndRadius; // Radius of beam frustum at the source end + /* 0x0E */ s16 poolEndRadius; // Radius of beam frustum at the pool end + /* 0x10 */ f32 unk_10; // placement of collider center along beam + /* 0x14 */ s16 unk_14; // collider radius before scaled + /* 0x16 */ s16 lgtPtMaxRad; // light point max radius + /* 0x18 */ f32 unk_18; // placement of light point between source and reflection point (pool point for windows, + // player for mirrors) + /* 0x1C */ Color_RGB8 color; + /* 0x1F */ u8 params; +} MirRayDataEntry; // size = 0x20 + const ActorInit Mir_Ray_InitVars = { ACTOR_MIR_RAY, ACTORCAT_ITEMACTION, @@ -28,64 +53,669 @@ const ActorInit Mir_Ray_InitVars = { (ActorFunc)MirRay_Draw, }; -// static ColliderQuadInit sQuadInit = { -static ColliderQuadInit D_808E3BF4 = { - { COLTYPE_NONE, AT_ON | AT_TYPE_PLAYER, AC_NONE, OC1_NONE, OC2_NONE, COLSHAPE_QUAD, }, - { ELEMTYPE_UNK0, { 0x00200000, 0x00, 0x00 }, { 0xF7CFFFFF, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_NONE, OCELEM_NONE, }, +u8 D_808E3BF0 = false; + +static ColliderQuadInit sQuadInit = { + { + COLTYPE_NONE, + AT_ON | AT_TYPE_PLAYER, + AC_NONE, + OC1_NONE, + OC2_NONE, + COLSHAPE_QUAD, + }, + { + ELEMTYPE_UNK0, + { 0x00200000, 0x00, 0x00 }, + { 0xF7CFFFFF, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_NONE, + }, { { { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } } }, }; -// static ColliderJntSphElementInit sJntSphElementsInit[1] = { -static ColliderJntSphElementInit D_808E3C44[1] = { +static ColliderJntSphElementInit sJntSphElementsInit[1] = { { - { ELEMTYPE_UNK0, { 0x00200000, 0x00, 0x00 }, { 0x00000000, 0x00, 0x00 }, TOUCH_ON | TOUCH_SFX_NORMAL, BUMP_NONE, OCELEM_NONE, }, + { + ELEMTYPE_UNK0, + { 0x00200000, 0x00, 0x00 }, + { 0x00000000, 0x00, 0x00 }, + TOUCH_ON | TOUCH_SFX_NORMAL, + BUMP_NONE, + OCELEM_NONE, + }, { 0, { { 0, 0, 0 }, 50 }, 100 }, }, }; -// static ColliderJntSphInit sJntSphInit = { -static ColliderJntSphInit D_808E3C68 = { - { COLTYPE_NONE, AT_ON | AT_TYPE_PLAYER, AC_NONE, OC1_NONE, OC2_NONE, COLSHAPE_JNTSPH, }, - 1, D_808E3C44, // sJntSphElementsInit, +static ColliderJntSphInit sJntSphInit = { + { + COLTYPE_NONE, + AT_ON | AT_TYPE_PLAYER, + AC_NONE, + OC1_NONE, + OC2_NONE, + COLSHAPE_JNTSPH, + }, + 1, + sJntSphElementsInit, }; -// static InitChainEntry sInitChain[] = { -static InitChainEntry D_808E3DB8[] = { +// Note: this data is unchanged from OoT and hardcoded for Spirit Temple, so the actor will not work at all without +// modification. + +MirRayDataEntry sMirRayData[] = { + { + { -0x488, 0x2AE, -0x370 }, + { -0x398, 0x1E0, -0x379 }, + 30, + 50, + 1.0f, + 50, + 150, + 0.8f, + { 255, 255, 255 }, + 2, + }, + { + { -0x740, 0x444, -0xBE }, + { -0x6A7, 0x349, -0xBA }, + 30, + 70, + 0.88f, + 0x36, + 150, + 0.8f, + { 255, 255, 255 }, + 2, + }, + { + { 0x557, 0x2E2, -0x35C }, + { 0x443, 0x1DC, -0x35C }, + 30, + 0x55, + 0.0f, + 0, + 150, + 0.8f, + { 255, 255, 255 }, + 0, + }, + { + { 0x898, 0x44F, -0xDC }, + { 0x7F8, 0x34B, -0xDC }, + 30, + 60, + 0.0f, + 0, + 150, + 0.8f, + { 255, 255, 255 }, + 1, + }, + { + { -0x230, 0x879, -0x136 }, + { -0x230, 0x6CF, -0x136 }, + 30, + 70, + 0.0f, + 0, + 150, + 0.8f, + { 255, 255, 255 }, + 0, + }, + { + { 0x3C, 0x70A, -0x442 }, + { 0x3C, 0x3CD, -0x442 }, + 30, + 70, + 0.0f, + 0, + 150, + 0.9f, + { 255, 255, 255 }, + 13, + }, + { + { 0x474, 0x1E0, -0x35C }, + { 0x474, 0x1E0, -0x35C }, + 30, + 30, + 1.0f, + 10, + 100, + 0.9f, + { 255, 255, 255 }, + 14, + }, + { + { -0x230, 0x6CF, -0x136 }, + { + -0x230, + 0x6CF, + -0x136, + }, + 30, + 30, + 0.0f, + 0, + 100, + 0.94f, + { 255, 255, 255 }, + 12, + }, + { + { 0x3C, 0x6CF, -0x136 }, + { 0x3C, 0x6CF, -0x136 }, + 30, + 30, + 0.0f, + 0, + 100, + 0.94f, + { 255, 255, 255 }, + 12, + }, + { + { -0x496, 0x1C0, 0x4AA }, + { -0x496, 0x94, 0x4AA }, + 50, + 100, + 1.0f, + 50, + 150, + 0.8f, + { 255, 255, 255 }, + 3, + }, +}; + +static InitChainEntry sInitChain[] = { ICHAIN_VEC3F_DIV1000(scale, 0, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneForward, 4000, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneScale, 1000, ICHAIN_CONTINUE), ICHAIN_F32(uncullZoneDownward, 1000, ICHAIN_STOP), }; +const char D_808E3DD0[] = "反射光 発生失敗"; + +void MirRay_SetupCollider(MirRay* this) { + MirRayDataEntry* dataEntry = &sMirRayData[MIRRAY_LOCATION(&this->actor)]; + f32 x = (this->poolPt.x - this->sourcePt.x) * dataEntry->unk_10; + f32 y = (this->poolPt.y - this->sourcePt.y) * dataEntry->unk_10; + f32 z = (this->poolPt.z - this->sourcePt.z) * dataEntry->unk_10; + + this->collider1.elements[0].dim.worldSphere.center.x = this->sourcePt.x + x; + this->collider1.elements[0].dim.worldSphere.center.y = this->sourcePt.y + y; + this->collider1.elements[0].dim.worldSphere.center.z = this->sourcePt.z + z; + + this->collider1.elements[0].dim.worldSphere.radius = dataEntry->unk_14 * this->collider1.elements->dim.scale; +} + +// Set up a light point between source point and reflection point. Reflection point is the pool point (for windows) or +// at the player position (for mirrors) +void MirRay_MakeShieldLight(MirRay* this, GlobalContext* globalCtx) { + Player* player = GET_PLAYER(globalCtx); + MirRayDataEntry* dataEntry = &sMirRayData[MIRRAY_LOCATION(&this->actor)]; + Vec3f reflectionPt; + Vec3s lightPt; + + if (MirRay_CheckInFrustum(&this->sourcePt, &this->poolPt, player->actor.world.pos.x, + player->actor.world.pos.y + 30.0f, player->actor.world.pos.z, this->sourceEndRad, + this->poolEndRad)) { + if (dataEntry->params & 8) { + Math_Vec3f_Diff(&player->actor.world.pos, &this->sourcePt, &reflectionPt); + } else { + Math_Vec3f_Diff(&this->poolPt, &this->sourcePt, &reflectionPt); + } + + lightPt.x = (dataEntry->unk_18 * reflectionPt.x) + this->sourcePt.x; + lightPt.y = (dataEntry->unk_18 * reflectionPt.y) + this->sourcePt.y; + lightPt.z = (dataEntry->unk_18 * reflectionPt.z) + this->sourcePt.z; + + // Fade up + Math_StepToS(&this->lightPointRad, dataEntry->lgtPtMaxRad, 6); + Lights_PointNoGlowSetInfo(&this->lightInfo, lightPt.x, lightPt.y, lightPt.z, dataEntry->color.r, + dataEntry->color.g, dataEntry->color.b, this->lightPointRad); + } else { + // Fade down + Math_StepToS(&this->lightPointRad, 0, 6); + Lights_PointSetColorAndRadius(&this->lightInfo, dataEntry->color.r, dataEntry->color.g, dataEntry->color.b, + this->lightPointRad); + } +} + +void MirRay_Init(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + MirRay* this = THIS; + MirRayDataEntry* dataEntry = &sMirRayData[MIRRAY_LOCATION(&this->actor)]; + + Actor_ProcessInitChain(&this->actor, sInitChain); + ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f); + + if (MIRRAY_LOCATION(&this->actor) >= MIRRAY_MAX) { + Actor_MarkForDeath(&this->actor); + } + + this->sourcePt.x = dataEntry->sourcePoint.x; + this->sourcePt.y = dataEntry->sourcePoint.y; + this->sourcePt.z = dataEntry->sourcePoint.z; + this->sourceEndRad = dataEntry->sourceEndRadius; + + this->poolPt.x = dataEntry->poolPoint.x; + this->poolPt.y = dataEntry->poolPoint.y; + this->poolPt.z = dataEntry->poolPoint.z; + this->poolEndRad = dataEntry->poolEndRadius; + + Lights_PointNoGlowSetInfo(&this->lightInfo, this->sourcePt.x, this->sourcePt.y, this->sourcePt.z, 255, 255, 255, + 100); + this->lightNode = LightContext_InsertLight(globalCtx, &globalCtx->lightCtx, &this->lightInfo); + + this->shieldCorners[0].x = -536.0f; + this->shieldCorners[0].y = -939.0f; + + this->shieldCorners[1].x = -1690.0f; + this->shieldCorners[1].y = 0.0f; + + this->shieldCorners[2].x = -536.0f; + this->shieldCorners[2].y = 938.0f; + + this->shieldCorners[3].x = 921.0f; + this->shieldCorners[3].y = 0.0f; + + this->shieldCorners[4].x = 758.0f; + this->shieldCorners[4].y = 800.0f; + + this->shieldCorners[5].x = 758.0f; + this->shieldCorners[5].y = -800.0f; + + if (dataEntry->params & 2) { + Collider_InitJntSph(globalCtx, &this->collider1); + Collider_SetJntSph(globalCtx, &this->collider1, &this->actor, &sJntSphInit, this->collider1Elements); + if (!(dataEntry->params & 4)) { // Beams not from mirrors + MirRay_SetupCollider(this); + } + } + + Collider_InitQuad(globalCtx, &this->collider2); + Collider_SetQuad(globalCtx, &this->collider2, &this->actor, &sQuadInit); + + if ((MIRRAY_LOCATION(&this->actor) == MIRRAY_SPIRIT_TOPROOM_CEILINGMIRROR) || + (MIRRAY_LOCATION(&this->actor) == MIRRAY_SPIRIT_TOPROOM_COBRA1) || + (MIRRAY_LOCATION(&this->actor) == MIRRAY_SPIRIT_TOPROOM_COBRA2)) { + this->actor.room = -1; + } +} + +void MirRay_Destroy(Actor* thisx, GlobalContext* globalCtx) { + MirRay* this = THIS; + + LightContext_RemoveLight(globalCtx, &globalCtx->lightCtx, this->lightNode); + + if (sMirRayData[MIRRAY_LOCATION(&this->actor)].params & 2) { + Collider_DestroyJntSph(globalCtx, &this->collider1); + } + + Collider_DestroyQuad(globalCtx, &this->collider2); +} + +void MirRay_Update(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + MirRay* this = THIS; + Player* player = GET_PLAYER(globalCtx); + + D_808E3BF0 = false; + + if (!this->unLit) { + if (sMirRayData[MIRRAY_LOCATION(&this->actor)].params & 2) { + if (sMirRayData[MIRRAY_LOCATION(&this->actor)].params & 4) { + MirRay_SetupCollider(this); + } + CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider1.base); + } + + if (this->reflectIntensity > 0.0f) { + CollisionCheck_SetAT(globalCtx, &globalCtx->colChkCtx, &this->collider2.base); + } + + MirRay_MakeShieldLight(this, globalCtx); + + if (this->reflectIntensity > 0.0f) { + func_800B8F98(&player->actor, NA_SE_IT_SHIELD_BEAM - SFX_FLAG); + } + } +} + +void MirRay_SetIntensity(MirRay* this, GlobalContext* globalCtx) { + f32 sp4C[3]; + s32 pad[4]; + Player* player = GET_PLAYER(globalCtx); + MtxF* shieldMtx = &player->shieldMf; + f32 temp_f0; + f32 temp_f0_2; + f32 temp_f2; + + this->reflectIntensity = 0.0f; + + if (MirRay_CheckInFrustum(&this->sourcePt, &this->poolPt, shieldMtx->wx, shieldMtx->wy, shieldMtx->wz, + this->sourceEndRad, this->poolEndRad)) { + temp_f0 = sqrtf(SQ(shieldMtx->zz) + (SQ(shieldMtx->zx) + SQ(shieldMtx->zy))); + if (temp_f0 == 0.0f) { + this->reflectRange = 1.0f; + } else { + this->reflectRange = 1.0f / temp_f0; + } + + if (sMirRayData[MIRRAY_LOCATION(&this->actor)].params & 1) { + this->reflectIntensity = 1.0f; + } else { + sp4C[0] = this->poolPt.x - this->sourcePt.x; + sp4C[1] = this->poolPt.y - this->sourcePt.y; + sp4C[2] = this->poolPt.z - this->sourcePt.z; + + temp_f2 = (-shieldMtx->zx * sp4C[0]) - (shieldMtx->zy * sp4C[1]) - (shieldMtx->zz * sp4C[2]); + + if (temp_f2 < 0.0f) { + temp_f0_2 = sqrtf(SQ(sp4C[0]) + SQ(sp4C[1]) + SQ(sp4C[2])); + if ((temp_f0 != 0.0f) && (temp_f0_2 != 0.0f)) { + this->reflectIntensity = -temp_f2 / (temp_f0 * temp_f0_2); + } + } + } + } +} + +// Draws six images, one for each corner of the shield, by finding the intersection of a line segment from the corner +// perpendicular to the shield with the nearest collision (if any). +void MirRay_SetupReflectionPolys(MirRay* this, GlobalContext* globalCtx, MirRayShieldReflection* reflection) { + s32 i; + Player* player = GET_PLAYER(globalCtx); + MtxF* shieldMtx = &player->shieldMf; + Vec3f posA; + Vec3f posB; + Vec3f sp70; + CollisionPoly* outPoly; + f32 sp60[3]; + + sp60[0] = -(shieldMtx->zx * this->reflectRange) * this->reflectIntensity * 400.0f; + sp60[1] = -(shieldMtx->zy * this->reflectRange) * this->reflectIntensity * 400.0f; + sp60[2] = -(shieldMtx->zz * this->reflectRange) * this->reflectIntensity * 400.0f; + + for (i = 0; i < ARRAY_COUNT(this->shieldCorners); i++) { + posA.x = + (shieldMtx->wx + (this->shieldCorners[i].x * shieldMtx->xx)) + (this->shieldCorners[i].y * (*shieldMtx).yx); + posA.y = + (shieldMtx->wy + (this->shieldCorners[i].x * shieldMtx->xy)) + (this->shieldCorners[i].y * (*shieldMtx).yy); + posA.z = + (shieldMtx->wz + (this->shieldCorners[i].x * shieldMtx->xz)) + (this->shieldCorners[i].y * (*shieldMtx).yz); + + posB.x = sp60[0] + posA.x; + posB.y = sp60[1] + posA.y; + posB.z = sp60[2] + posA.z; + + if (BgCheck_AnyLineTest1(&globalCtx->colCtx, &posA, &posB, &sp70, &outPoly, 1)) { + reflection[i].reflectionPoly = outPoly; + } else { + reflection[i].reflectionPoly = NULL; + } + } +} + +// Remove reflections that are in the same position and are sufficiently near to the same plane +void MirRay_RemoveSimilarReflections(MirRayShieldReflection* reflection) { + s32 i, j; + + for (i = 0; i < 6; i++) { + for (j = i + 1; j < 6; j++) { + if ((reflection[i].reflectionPoly != NULL) && (reflection[j].reflectionPoly != NULL)) { + if ((ABS(reflection[i].reflectionPoly->normal.x - reflection[j].reflectionPoly->normal.x) < 100) && + (ABS(reflection[i].reflectionPoly->normal.y - reflection[j].reflectionPoly->normal.y) < 100) && + (ABS(reflection[i].reflectionPoly->normal.z - reflection[j].reflectionPoly->normal.z) < 100) && + (reflection[i].reflectionPoly->dist == reflection[j].reflectionPoly->dist)) { + reflection[j].reflectionPoly = NULL; + } + } + } + } +} + +// Creates the reflected beam's collider (to interact with objects) and places and orients the shield images +#ifdef NON_MATCHING +// Beginning block re-ordered +void MirRay_ReflectedBeam(MirRay* this, GlobalContext* globalCtx, MirRayShieldReflection* reflection) { + Player* player = GET_PLAYER(globalCtx); + s32 i; + f32 temp_f0; + Vec3f vecB; + Vec3f vecD; + Vec3f sp118; + Vec3f sp10C; + Vec3f sp100; + Vec3f intersection; + f32 spE8[3]; + f32 normalVec[3]; + MtxF* shieldMtx = &player->shieldMf; + Vec3f vecA; + Vec3f vecC; + + spE8[0] = -(shieldMtx->zx * this->reflectRange) * this->reflectIntensity * 400.0f; + spE8[1] = -(shieldMtx->zy * this->reflectRange) * this->reflectIntensity * 400.0f; + spE8[2] = -(shieldMtx->zz * this->reflectRange) * this->reflectIntensity * 400.0f; + + vecB.x = shieldMtx->wx; + vecB.y = shieldMtx->wy; + vecB.z = shieldMtx->wz; + + vecD.x = spE8[0] + vecB.x; + vecD.y = spE8[1] + vecB.y; + vecD.z = spE8[2] + vecB.z; + + vecA.x = vecB.x + (shieldMtx->xx * 300.0f); + vecA.y = vecB.y + (shieldMtx->xy * 300.0f); + vecA.z = vecB.z + (shieldMtx->xz * 300.0f); + + vecC.x = vecD.x + (shieldMtx->xx * 300.0f); + vecC.y = vecD.y + (shieldMtx->xy * 300.0f); + vecC.z = vecD.z + (shieldMtx->xz * 300.0f); + + Collider_SetQuadVertices(&this->collider2, &vecA, &vecB, &vecC, &vecD); + + for (i = 0; i < 6; i++) { + if (reflection[i].reflectionPoly != NULL) { + normalVec[0] = COLPOLY_GET_NORMAL(reflection[i].reflectionPoly->normal.x); + normalVec[1] = COLPOLY_GET_NORMAL(reflection[i].reflectionPoly->normal.y); + normalVec[2] = COLPOLY_GET_NORMAL(reflection[i].reflectionPoly->normal.z); + + if (Math3D_LineSegVsPlane(normalVec[0], normalVec[1], normalVec[2], reflection[i].reflectionPoly->dist, + &vecB, &vecD, &sp118, 1)) { + + reflection[i].pos.x = sp118.x; + reflection[i].pos.y = sp118.y; + reflection[i].pos.z = sp118.z; + + temp_f0 = sqrtf(SQ(sp118.x - vecB.x) + SQ(sp118.y - vecB.y) + SQ(sp118.z - vecB.z)); + + if (temp_f0 < (this->reflectIntensity * 600.0f)) { + reflection[i].opacity = 200; + } else { + reflection[i].opacity = (s32)(800.0f - temp_f0); + } + + reflection[i].opacity = (s32)(reflection[i].opacity * 1.275f); + + sp10C.x = (shieldMtx->xx * 100.0f) + vecB.x; + sp10C.y = (shieldMtx->xy * 100.0f) + vecB.y; + sp10C.z = (shieldMtx->xz * 100.0f) + vecB.z; + + sp100.x = (spE8[0] * 4.0f) + sp10C.x; + sp100.y = (spE8[1] * 4.0f) + sp10C.y; + sp100.z = (spE8[2] * 4.0f) + sp10C.z; + + reflection[i].mtx.xx = reflection[i].mtx.yy = reflection[i].mtx.zz = reflection[i].mtx.ww = 1.0f; + + reflection[i].mtx.xy = reflection[i].mtx.xz = reflection[i].mtx.xw = reflection[i].mtx.yx = + reflection[i].mtx.yz = reflection[i].mtx.yw = reflection[i].mtx.zx = reflection[i].mtx.zy = + reflection[i].mtx.zw = reflection[i].mtx.wx = reflection[i].mtx.wy = reflection[i].mtx.wz = + 0.0f; + + if (Math3D_LineSegVsPlane(normalVec[0], normalVec[1], normalVec[2], reflection[i].reflectionPoly->dist, + &sp10C, &sp100, &intersection, 1)) { + reflection[i].mtx.xx = intersection.x - sp118.x; + reflection[i].mtx.xy = intersection.y - sp118.y; + reflection[i].mtx.xz = intersection.z - sp118.z; + } + + sp10C.x = (shieldMtx->yx * 100.0f) + vecB.x; + sp10C.y = (shieldMtx->yy * 100.0f) + vecB.y; + sp10C.z = (shieldMtx->yz * 100.0f) + vecB.z; + + sp100.x = (spE8[0] * 4.0f) + sp10C.x; + sp100.y = (spE8[1] * 4.0f) + sp10C.y; + sp100.z = (spE8[2] * 4.0f) + sp10C.z; + + if (Math3D_LineSegVsPlane(normalVec[0], normalVec[1], normalVec[2], reflection[i].reflectionPoly->dist, + &sp10C, &sp100, &intersection, 1)) { + reflection[i].mtx.yx = intersection.x - sp118.x; + reflection[i].mtx.yy = intersection.y - sp118.y; + reflection[i].mtx.yz = intersection.z - sp118.z; + } + } else { + reflection[i].reflectionPoly = NULL; + } + } + } +} +#else +void MirRay_ReflectedBeam(MirRay* this, GlobalContext* globalCtx, MirRayShieldReflection* reflection); +#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/MirRay_ReflectedBeam.s") #endif -extern ColliderQuadInit D_808E3BF4; -extern ColliderJntSphElementInit D_808E3C44[1]; -extern ColliderJntSphInit D_808E3C68; -extern InitChainEntry D_808E3DB8[]; +void MirRay_Draw(Actor* thisx, GlobalContext* globalCtx) { + s32 pad; + MirRay* this = THIS; + Player* player = GET_PLAYER(globalCtx); + MirRayShieldReflection reflection[6]; + s32 i; -extern UNK_TYPE D_060003F8; + this->reflectIntensity = 0.0f; -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/D_808E3DD0.s") + if (!D_808E3BF0 && !this->unLit && func_80124088(globalCtx)) { + Matrix_InsertMatrix(&player->shieldMf, MTXMODE_NEW); + MirRay_SetIntensity(this, globalCtx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/func_808E2600.s") + if (this->reflectIntensity <= 0.0f) { + return; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/func_808E26C8.s") + OPEN_DISPS(globalCtx->state.gfxCtx); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/MirRay_Init.s") + func_8012C2DC(globalCtx->state.gfxCtx); + Matrix_Scale(1.0f, 1.0f, this->reflectIntensity, MTXMODE_APPLY); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/MirRay_Destroy.s") + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (u8)(s8)(this->reflectIntensity * 100.0f)); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/MirRay_Update.s") + AnimatedMat_Draw(globalCtx, Lib_SegmentedToVirtual(object_mir_ray_Matanimheader_0003F8)); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/func_808E2C68.s") + gSPDisplayList(POLY_XLU_DISP++, object_mir_ray_DL_000168); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/func_808E2E1C.s") + MirRay_SetupReflectionPolys(this, globalCtx, reflection); + MirRay_RemoveSimilarReflections(reflection); + MirRay_ReflectedBeam(this, globalCtx, reflection); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/func_808E2FF8.s") + if (reflection[0].reflectionPoly == NULL) { + reflection[0].opacity = 0; + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/func_808E30FC.s") + for (i = 1; i < ARRAY_COUNT(reflection); i++) { + if (reflection[i].reflectionPoly != NULL) { + if (reflection[0].opacity < reflection[i].opacity) { + reflection[0].opacity = reflection[i].opacity; + } + } + } -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/MirRay_Draw.s") + for (i = 0; i < ARRAY_COUNT(reflection); i++) { + if (reflection[i].reflectionPoly != NULL) { + Matrix_InsertTranslation(reflection[i].pos.x, reflection[i].pos.y, reflection[i].pos.z, MTXMODE_NEW); + Matrix_Scale(0.01f, 0.01f, 0.01f, MTXMODE_APPLY); + Matrix_InsertMatrix(&reflection[i].mtx, MTXMODE_APPLY); -#pragma GLOBAL_ASM("asm/non_matchings/overlays/ovl_Mir_Ray/func_808E3984.s") + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPSetRenderMode(POLY_XLU_DISP++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_XLU_DECAL2); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, reflection[0].opacity); + gSPDisplayList(POLY_XLU_DISP++, object_mir_ray_DL_0004B0); + } + } + + D_808E3BF0 = true; + + CLOSE_DISPS(globalCtx->state.gfxCtx); + } +} + +// Computes if the Point (pointx, pointy, pointz) lies within the right conical frustum with one end centred at vecA +// with radius radiusA, the other at vecB with radius radiusB +s32 MirRay_CheckInFrustum(Vec3f* vecA, Vec3f* vecB, f32 pointx, f32 pointy, f32 pointz, s16 radiusA, s16 radiusB) { + f32 coneRadius; + f32 closestPtx; + f32 closestPty; + f32 closestPtz; + Vec3f vecdiff; + f32 dist; + Vec3f sp5C; + Vec3f sp50; + Vec3f sp44; + + vecdiff.x = vecB->x - vecA->x; + vecdiff.y = vecB->y - vecA->y; + vecdiff.z = vecB->z - vecA->z; + if (1) {} + + dist = SQ(vecdiff.x) + SQ(vecdiff.y) + SQ(vecdiff.z); + + if (dist == 0.0f) { + return false; + } + + dist = + (((pointx - vecA->x) * vecdiff.x) + ((pointy - vecA->y) * vecdiff.y) + ((pointz - vecA->z) * vecdiff.z)) / dist; + + // Closest point on line A-B to Point + closestPtx = (vecdiff.x * dist) + vecA->x; + closestPty = (vecdiff.y * dist) + vecA->y; + closestPtz = (vecdiff.z * dist) + vecA->z; + + // Diameter of the double cone on the perpendicular plane through the closest point + coneRadius = ((radiusB - radiusA) * dist) + radiusA; + + // If the Point is within the bounding double cone, check if it is in the frustum by checking whether it is between + // the bounding planes + if ((SQ(closestPtx - pointx) + SQ(closestPty - pointy) + SQ(closestPtz - pointz)) <= SQ(coneRadius)) { + if (1) {} + + // Stores the vector difference again + Math_Vec3f_Diff(vecB, vecA, &sp5C); + + sp50.x = pointx - vecA->x; + sp50.y = pointy - vecA->y; + sp50.z = pointz - vecA->z; + + if (Math3D_Parallel(&sp5C, &sp50) < 0.0f) { + return false; + } + + sp44.x = pointx - vecB->x; + sp44.y = pointy - vecB->y; + sp44.z = pointz - vecB->z; + + if (Math3D_Parallel(&sp5C, &sp44) > 0.0f) { + return false; + } + return true; + } + return false; +} diff --git a/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.h b/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.h index c03b48c6b8..4d748e3b52 100644 --- a/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.h +++ b/src/overlays/actors/ovl_Mir_Ray/z_mir_ray.h @@ -5,9 +5,39 @@ struct MirRay; +#define MIRRAY_LOCATION(thisx) ((thisx)->params) + +// Locations of light beams in sMirRayData +typedef enum { + /* 0 */ MIRRAY_SPIRIT_BOMBCHUIWAROOM_DOWNLIGHT, + /* 1 */ MIRRAY_SPIRIT_SUNBLOCKROOM_DOWNLIGHT, + /* 2 */ MIRRAY_SPIRIT_SINGLECOBRAROOM_DOWNLIGHT, + /* 3 */ MIRRAY_SPIRIT_ARMOSROOM_DOWNLIGHT, + /* 4 */ MIRRAY_SPIRIT_TOPROOM_DOWNLIGHT, + /* 5 */ MIRRAY_SPIRIT_TOPROOM_CEILINGMIRROR, + /* 6 */ MIRRAY_SPIRIT_SINGLECOBRAROOM_COBRA, + /* 7 */ MIRRAY_SPIRIT_TOPROOM_COBRA1, + /* 8 */ MIRRAY_SPIRIT_TOPROOM_COBRA2, + /* 9 */ MIRRAY_GANONSCASTLE_SPIRITTRIAL_DOWNLIGHT, + /* 10 */ MIRRAY_MAX, +} MirRayBeamLocations; + typedef struct MirRay { - /* 0x000 */ Actor actor; - /* 0x144 */ char unk_144[0x164]; + /* 0x0000 */ Actor actor; + /* 0x0144 */ ColliderJntSph collider1; + /* 0x0164 */ ColliderJntSphElement collider1Elements[1]; + /* 0x01A4 */ ColliderQuad collider2; + /* 0x0224 */ f32 reflectIntensity; // Reflection occurs if it is positive, brightness depends on it + /* 0x0228 */ Vec3f shieldCorners[6]; + /* 0x0270 */ f32 reflectRange; + /* 0x0274 */ Vec3f sourcePt; + /* 0x0280 */ Vec3f poolPt; + /* 0x028C */ s16 sourceEndRad; + /* 0x028E */ s16 poolEndRad; + /* 0x0290 */ s16 lightPointRad; + /* 0x0294 */ LightNode* lightNode; + /* 0x0298 */ LightInfo lightInfo; + /* 0x02A6 */ u8 unLit; // Conditioned on. set in Cobra? } MirRay; // size = 0x2A8 extern const ActorInit Mir_Ray_InitVars; diff --git a/tools/disasm/functions.txt b/tools/disasm/functions.txt index e1bf5f8070..8be41c5c1b 100644 --- a/tools/disasm/functions.txt +++ b/tools/disasm/functions.txt @@ -6539,17 +6539,17 @@ 0x808E2444:("func_808E2444",), 0x808E24B4:("BgCtowerRot_Update",), 0x808E24D8:("BgCtowerRot_Draw",), - 0x808E2600:("func_808E2600",), - 0x808E26C8:("func_808E26C8",), + 0x808E2600:("MirRay_SetupCollider",), + 0x808E26C8:("MirRay_MakeShieldLight",), 0x808E286C:("MirRay_Init",), 0x808E2B04:("MirRay_Destroy",), 0x808E2B7C:("MirRay_Update",), - 0x808E2C68:("func_808E2C68",), - 0x808E2E1C:("func_808E2E1C",), - 0x808E2FF8:("func_808E2FF8",), - 0x808E30FC:("func_808E30FC",), + 0x808E2C68:("MirRay_SetIntensity",), + 0x808E2E1C:("MirRay_SetupReflectionPolys",), + 0x808E2FF8:("MirRay_RemoveSimilarReflections",), + 0x808E30FC:("MirRay_ReflectedBeam",), 0x808E36A4:("MirRay_Draw",), - 0x808E3984:("func_808E3984",), + 0x808E3984:("MirRay_CheckInFrustum",), 0x808E3EF0:("EnSb_Init",), 0x808E3FF0:("EnSb_Destroy",), 0x808E401C:("EnSb_SpawnBubbles",), diff --git a/undefined_syms.txt b/undefined_syms.txt index 8182801cce..4a386640d3 100644 --- a/undefined_syms.txt +++ b/undefined_syms.txt @@ -1975,12 +1975,6 @@ D_06000D94 = 0x06000D94; D_06007650 = 0x06007650; D_0600D658 = 0x0600D658; -// ovl_Mir_Ray - -D_06000168 = 0x06000168; -D_060003F8 = 0x060003F8; -D_060004B0 = 0x060004B0; - // ovl_Mir_Ray3 D_06000168 = 0x06000168;