diff --git a/lib/rt64 b/lib/rt64 index cbab135..00aecb3 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit cbab135a3133313085cf515d2067f7b037a88a52 +Subproject commit 00aecb38ac2f4563e81980445399e1c84c64e5bc diff --git a/patches/effect_transform_tagging.c b/patches/effect_transform_tagging.c index 70f269f..f2c333e 100644 --- a/patches/effect_transform_tagging.c +++ b/patches/effect_transform_tagging.c @@ -1,78 +1,9 @@ #include "patches.h" #include "transform_ids.h" -#include "overlays/actors/ovl_En_Test7/z_en_test7.h" #include "overlays/actors/ovl_Object_Kankyo/z_object_kankyo.h" #include "overlays/actors/ovl_Eff_Stk/z_eff_stk.h" #include "z64effect.h" -// Decomp renames, TODO update decomp and remove these -#define gSoaringWarpCsWindCapsuleTexAnim gameplay_keep_Matanimheader_0815D0 -#define gSoaringWarpCsWindCapsuleDL gameplay_keep_DL_080FC8 -#define EnTest7_DrawFeathers func_80AF14FC - -void EnTest7_DrawFeathers(PlayState* play2, OwlWarpFeather* feathers); -s32 func_80AF31D0(PlayState* play, SkeletonInfo* skeletonInfo, s32 limbIndex, Gfx** dList, u8* flags, Actor* thisx, - Vec3f* scale, Vec3s* rot, Vec3f* pos); - -extern AnimatedMaterial gSoaringWarpCsWindCapsuleTexAnim; -extern Gfx gSoaringWarpCsWindCapsuleDL[]; - -void EnTest7_Draw(Actor* thisx, PlayState* play) { - s32 pad[2]; - EnTest7* this = (EnTest7*)thisx; - s32 sp40; - - OPEN_DISPS(play->state.gfxCtx); - - // Draw wings - if (this->flags & OWL_WARP_FLAGS_DRAW_WINGS) { - Mtx* mtx = GRAPH_ALLOC(play->state.gfxCtx, this->skeletonInfo.unk_18->unk_1 * sizeof(Mtx)); - - if (mtx == NULL) { - return; - } - // func_80AF31D0 is an overlay symbol, so its addresses need to be offset to get the actual loaded vram address. - // TODO remove this once the recompiler is able to handle overlay symbols automatically for patch functions. - OverrideKeyframeDrawScaled func_80AF31D0_relocated = (OverrideKeyframeDrawScaled)actor_relocate(thisx, func_80AF31D0); - - // @recomp Push the matrix group for the song of soaring's wings. - gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, SOARING_WINGS_TRANSFORM_ID, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW); - - func_8018450C(play, &this->skeletonInfo, mtx, func_80AF31D0_relocated, NULL, &this->actor); - - // @recomp Pop the wings matrix group. - gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW); - } - - // Draw windCapsule encasing that surrounds player after wings - if (this->flags & OWL_WARP_FLAGS_DRAW_WIND_CAPSULE) { - // @recomp Push the matrix group for the song of soaring's capsule. - gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, SOARING_CAPSULE_TRANSFORM_ID, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW); - - Matrix_Push(); - Matrix_Translate(0.0f, 4000.0f, 0.0f, MTXMODE_APPLY); - Matrix_RotateZYX(0, this->windCapsule.yaw, 0, MTXMODE_APPLY); - Matrix_Scale(this->windCapsule.xzScale * 100.0f, this->windCapsule.yScale * 100.0f, - this->windCapsule.xzScale * 100.0f, MTXMODE_APPLY); - sp40 = this->windCapsule.unk_00; - AnimatedMat_DrawStep(play, Lib_SegmentedToVirtual(&gSoaringWarpCsWindCapsuleTexAnim), sp40); - Gfx_DrawDListXlu(play, gSoaringWarpCsWindCapsuleDL); - - // @recomp Pop the capsule matrix group. - gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); - Matrix_Pop(); - } - - EnTest7_DrawFeathers(play, this->feathers); - - if (this->flags & OWL_WARP_FLAGS_DRAW_LENS_FLARE) { - Environment_DrawLensFlare(play, &play->envCtx, &play->view, play->state.gfxCtx, this->actor.world.pos, 70.0f, - 5.0f, 0, false); - } - - CLOSE_DISPS(play->state.gfxCtx); -} - extern f32 D_808DE5B0; extern Gfx gEffDust5Tex[]; extern Gfx gEffDustDL[]; diff --git a/patches/particle_transform_tagging.c b/patches/particle_transform_tagging.c index b119c79..0f6a6a1 100644 --- a/patches/particle_transform_tagging.c +++ b/patches/particle_transform_tagging.c @@ -2,6 +2,7 @@ #include "transform_ids.h" #include "overlays/actors/ovl_En_Hanabi/z_en_hanabi.h" #include "overlays/actors/ovl_Demo_Kankyo/z_demo_kankyo.h" +#include "overlays/actors/ovl_En_Water_Effect/z_en_water_effect.h" extern EffectSsInfo sEffectSsInfo; @@ -382,3 +383,149 @@ void DemoKankyo_DrawMoonAndGiant(Actor* thisx, PlayState* play2) { CLOSE_DISPS(gfxCtx); } } + +static Vec3f D_80A5AFB0 = { 0.0f, 0.0f, 0.0f }; +static Vec3f D_80A5AFBC = { 0.0f, -1.0f, 0.0f }; + +// The byte after unk_01 in EnWaterEffectStruct is unused, so we'll use it as a respawn flag. +#define WATER_EFFECT_RESPAWNED(ptr) (&(ptr)->unk_01)[1] + +// @recomp Mark respawned water effect particles so they can be skipped for the first frame. +void func_80A599E8(EnWaterEffect* this, Vec3f* arg1, u8 arg2) { + s16 i; + EnWaterEffectStruct* ptr = &this->unk_144[0]; + + for (i = 0; i < ARRAY_COUNT(this->unk_144); i++, ptr++) { + if (ptr->unk_00 == 0) { + ptr->unk_00 = 4; + // @recomp Use an unused byte to mark that this particle was respawned. + WATER_EFFECT_RESPAWNED(ptr) = true; + ptr->unk_04 = *arg1; + + ptr->unk_1C = D_80A5AFB0; + ptr->unk_10 = D_80A5AFB0; + + if ((arg2 == 0) || (arg2 == 2)) { + ptr->unk_1C.y = -1.0f; + } + + if (arg2 >= 2) { + if (arg2 == 2) { + ptr->unk_10.x = Rand_CenteredFloat(10.0f); + ptr->unk_10.y = Rand_ZeroFloat(3.0f) + 5.0f; + ptr->unk_10.z = Rand_CenteredFloat(10.0f); + } + ptr->unk_2C.z = 0.0017f; + ptr->unk_2C.x = 0.003f; + ptr->unk_2C.y = 0.0018f; + } else { + ptr->unk_2C.z = 0.003f; + ptr->unk_2C.x = 0.003f; + ptr->unk_2C.y = 0.003f; + } + ptr->unk_38 = 255.0f; + ptr->unk_28 = Rand_ZeroFloat(0x10000); + ptr->unk_3C = 255; + ptr->unk_01 = Rand_ZeroFloat(200.0f); + ptr->unk_2A = arg2; + break; + } + } +} + +extern Gfx object_water_effect_DL_004340[]; +extern Gfx object_water_effect_DL_0043E8[]; +extern Gfx gameplay_keep_DL_06AB30[]; + +// @recomp Tag the transforms for falling fire rocks. +void func_80A5A184(Actor* thisx, PlayState* play2) { + PlayState* play = play2; + EnWaterEffect* this = (EnWaterEffect*)thisx; + GraphicsContext* gfxCtx = play->state.gfxCtx; + EnWaterEffectStruct* ptr = &this->unk_144[0]; + u8 flag = false; + s16 i; + + OPEN_DISPS(gfxCtx); + + Gfx_SetupDL25_Opa(play->state.gfxCtx); + Gfx_SetupDL25_Xlu(play->state.gfxCtx); + + for (i = 0; i < ARRAY_COUNT(this->unk_144); i++, ptr++) { + if (ptr->unk_00 == 4) { + if (!flag) { + gSPDisplayList(POLY_XLU_DISP++, object_water_effect_DL_004340); + gDPSetEnvColor(POLY_XLU_DISP++, 255, 10, 0, 0); + POLY_OPA_DISP = Gfx_SetFog(POLY_OPA_DISP, 255, 0, 0, 255, 500, 3600); + flag++; + } + + gDPSetPrimColor(POLY_XLU_DISP++, 0x80, 0x80, (u8)ptr->unk_38, 0, 0, (u8)ptr->unk_3C); + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, 0, 0x20, 0x40, 1, 0, (ptr->unk_01 * -20) & 0x1FF, + 0x20, 0x80)); + + Matrix_Translate(ptr->unk_04.x, ptr->unk_04.y, ptr->unk_04.z, MTXMODE_NEW); + + if (ptr->unk_2A >= 2) { + Matrix_ReplaceRotation(&play->billboardMtxF); + } else { + Matrix_RotateYS(Camera_GetInputDirYaw(GET_ACTIVE_CAM(play)), MTXMODE_APPLY); + } + + Matrix_Scale(ptr->unk_2C.x, ptr->unk_2C.y, 1.0f, MTXMODE_APPLY); + + if ((i & 1) != 0) { + Matrix_RotateYF(M_PI, MTXMODE_APPLY); + } + + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + // @recomp Tag the matrix group. Skip all interpolation if this particle just respawned. Otherwise, + // skip rotation interpolation if there was a camera cut since this is a billboard. + if (WATER_EFFECT_RESPAWNED(ptr)) { + gEXMatrixGroupDecomposedSkipAll(POLY_XLU_DISP++, actor_transform_id(thisx) + (i * 2) + 0, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + } + else if (camera_was_skipped()) { + gEXMatrixGroupDecomposedSkipRot(POLY_XLU_DISP++, actor_transform_id(thisx) + (i * 2) + 0, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + } + else { + gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, actor_transform_id(thisx) + (i * 2) + 0, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + } + + gSPDisplayList(POLY_XLU_DISP++, object_water_effect_DL_0043E8); + + // @recomp Pop the matrix group. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + + if ((ptr->unk_2A & 1) == 0) { + Matrix_Translate(ptr->unk_04.x, ptr->unk_04.y + 5.0f, ptr->unk_04.z, MTXMODE_NEW); + Matrix_RotateXS(ptr->unk_28, MTXMODE_APPLY); + Matrix_Scale(ptr->unk_2C.z, ptr->unk_2C.z, ptr->unk_2C.z, MTXMODE_APPLY); + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + + // @recomp Tag the matrix group. Skip all interpolation if the base particle just respawned. + if (WATER_EFFECT_RESPAWNED(ptr)) { + gEXMatrixGroupDecomposedSkipAll(POLY_OPA_DISP++, actor_transform_id(thisx) + (i * 2) + 1, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW); + } + else { + gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, actor_transform_id(thisx) + (i * 2) + 1, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW); + } + + gSPDisplayList(POLY_OPA_DISP++, gameplay_keep_DL_06AB30); + + // @recomp Pop the matrix group. + gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW); + } + + // @recomp Clear the respawned state of this particle. + WATER_EFFECT_RESPAWNED(ptr) = false; + } + } + + POLY_OPA_DISP = Play_SetFog(play, POLY_OPA_DISP); + + CLOSE_DISPS(gfxCtx); +} diff --git a/patches/patches.h b/patches/patches.h index f339196..e1934b3 100644 --- a/patches/patches.h +++ b/patches/patches.h @@ -16,6 +16,9 @@ #include "global.h" #include "rt64_extended_gbi.h" +#define gEXMatrixGroupNoInterpolation(cmd, push, proj, edit) \ + gEXMatrixGroup(cmd, G_EX_ID_IGNORE, G_EX_INTERPOLATE_SIMPLE, push, proj, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_ORDER_LINEAR, edit) + #define gEXMatrixGroupInterpolateOnlyTiles(cmd, push, proj, edit) \ gEXMatrixGroup(cmd, G_EX_ID_IGNORE, G_EX_INTERPOLATE_SIMPLE, push, proj, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_SKIP, G_EX_COMPONENT_INTERPOLATE, G_EX_ORDER_LINEAR, edit) diff --git a/patches/song_transform_tagging.c b/patches/song_transform_tagging.c new file mode 100644 index 0000000..619d57b --- /dev/null +++ b/patches/song_transform_tagging.c @@ -0,0 +1,184 @@ +#include "patches.h" +#include "transform_ids.h" +#include "overlays/actors/ovl_En_Test6/z_en_test6.h" +#include "overlays/actors/ovl_En_Test7/z_en_test7.h" + +// Decomp renames, TODO update decomp and remove these +#define gSoaringWarpCsWindCapsuleTexAnim gameplay_keep_Matanimheader_0815D0 +#define gSoaringWarpCsWindCapsuleDL gameplay_keep_DL_080FC8 +#define EnTest7_DrawFeathers func_80AF14FC + +void EnTest7_DrawFeathers(PlayState* play2, OwlWarpFeather* feathers); +s32 func_80AF31D0(PlayState* play, SkeletonInfo* skeletonInfo, s32 limbIndex, Gfx** dList, u8* flags, Actor* thisx, + Vec3f* scale, Vec3s* rot, Vec3f* pos); + +extern AnimatedMaterial gSoaringWarpCsWindCapsuleTexAnim; +extern Gfx gSoaringWarpCsWindCapsuleDL[]; + +void EnTest7_Draw(Actor* thisx, PlayState* play) { + s32 pad[2]; + EnTest7* this = (EnTest7*)thisx; + s32 sp40; + + OPEN_DISPS(play->state.gfxCtx); + + // Draw wings + if (this->flags & OWL_WARP_FLAGS_DRAW_WINGS) { + Mtx* mtx = GRAPH_ALLOC(play->state.gfxCtx, this->skeletonInfo.unk_18->unk_1 * sizeof(Mtx)); + + if (mtx == NULL) { + return; + } + // func_80AF31D0 is an overlay symbol, so its addresses need to be offset to get the actual loaded vram address. + // TODO remove this once the recompiler is able to handle overlay symbols automatically for patch functions. + OverrideKeyframeDrawScaled func_80AF31D0_relocated = (OverrideKeyframeDrawScaled)actor_relocate(thisx, func_80AF31D0); + + // @recomp Push the matrix group for the song of soaring's wings. + gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, SOARING_WINGS_TRANSFORM_ID, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW); + + func_8018450C(play, &this->skeletonInfo, mtx, func_80AF31D0_relocated, NULL, &this->actor); + + // @recomp Pop the wings matrix group. + gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW); + } + + // Draw windCapsule encasing that surrounds player after wings + if (this->flags & OWL_WARP_FLAGS_DRAW_WIND_CAPSULE) { + // @recomp Push the matrix group for the song of soaring's capsule. + gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, SOARING_CAPSULE_TRANSFORM_ID, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_ALLOW); + + Matrix_Push(); + Matrix_Translate(0.0f, 4000.0f, 0.0f, MTXMODE_APPLY); + Matrix_RotateZYX(0, this->windCapsule.yaw, 0, MTXMODE_APPLY); + Matrix_Scale(this->windCapsule.xzScale * 100.0f, this->windCapsule.yScale * 100.0f, + this->windCapsule.xzScale * 100.0f, MTXMODE_APPLY); + sp40 = this->windCapsule.unk_00; + AnimatedMat_DrawStep(play, Lib_SegmentedToVirtual(&gSoaringWarpCsWindCapsuleTexAnim), sp40); + Gfx_DrawDListXlu(play, gSoaringWarpCsWindCapsuleDL); + + // @recomp Pop the capsule matrix group. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + Matrix_Pop(); + } + + EnTest7_DrawFeathers(play, this->feathers); + + if (this->flags & OWL_WARP_FLAGS_DRAW_LENS_FLARE) { + Environment_DrawLensFlare(play, &play->envCtx, &play->view, play->state.gfxCtx, this->actor.world.pos, 70.0f, + 5.0f, 0, false); + } + + CLOSE_DISPS(play->state.gfxCtx); +} + +extern Gfx gSongOfTimeClockDL[]; + +struct SoTCsAmmoDrops; + +typedef void (*SoTCsAmmoDropDrawFunc)(EnTest6*, PlayState*, struct SoTCsAmmoDrops*); + +typedef enum SoTCsAmmoDropType { + /* 0 */ SOTCS_AMMO_DROP_NONE, + /* 1 */ SOTCS_AMMO_DROP_ARROWS, + /* 2 */ SOTCS_AMMO_DROP_BOMB, + /* 3 */ SOTCS_AMMO_DROP_DEKU_NUT, + /* 4 */ SOTCS_AMMO_DROP_DEKU_STICK, + /* 5 */ SOTCS_AMMO_DROP_RUPEE_GREEN, + /* 6 */ SOTCS_AMMO_DROP_RUPEE_BLUE +} SoTCsAmmoDropType; + +typedef struct SoTCsAmmoDrops { + /* 0x00 */ SoTCsAmmoDropType type; + /* 0x04 */ f32 scale; + /* 0x08 */ Vec3f pos; + /* 0x14 */ SoTCsAmmoDropDrawFunc draw; +} SoTCsAmmoDrops; // size = 0x18 + +extern SoTCsAmmoDrops sSoTCsAmmoDrops[12]; + +/** + * Draws clocks in a double spiral above and below player + */ +void EnTest6_DrawThreeDayResetSoTCutscene(EnTest6* this, PlayState* play) { + s16 clock1Yaw; + s16 clock2Yaw; + s16 angle; + s32 i; + Vec3f clockPos; + + OPEN_DISPS(play->state.gfxCtx); + + this->gfx = POLY_OPA_DISP; + clockPos.y = 0.0f; + + clock1Yaw = this->clockAngle; + clock2Yaw = clock1Yaw + 0x4E20 + (s32)(0x2EE0 * Math_SinS(play->state.frames)); + // The `& 0x3C` ensures the angle only updates once every 4 frames + angle = (play->state.frames & 0x3C) * 1024; + angle *= this->clockSpeed / 200.0f; + this->clockAngle += (s16)this->clockSpeed; + this->clockRingRotZ = (s16)((this->clockSpeed / 200.0f) * 256.0f); + + // Draw 2 clocks per loop + for (i = 0; i < (SOTCS_RESET_NUM_CLOCKS / 2); i++) { + // Clock 1 + clock1Yaw += 0x1000; + clockPos.x = Math_CosS(clock1Yaw) * this->clockDist; + clockPos.z = Math_SinS(clock1Yaw) * this->clockDist; + Matrix_Translate(clockPos.x, clockPos.y, clockPos.z, MTXMODE_NEW); + Matrix_RotateXS(0x4000, MTXMODE_APPLY); + Matrix_Scale(0.8f, 0.8f, 0.8f, MTXMODE_APPLY); + Matrix_RotateZS(angle, MTXMODE_APPLY); + + gSPMatrix(this->gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPSetPrimColor(this->gfx++, 0, 0xFF, 28, 28, 28, 255); + gDPSetEnvColor(this->gfx++, 255, 255, 255, 255); + gDPSetRenderMode(this->gfx++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_OPA_SURF2); + + // @recomp Tag the clock's matrix. + gEXMatrixGroupDecomposedSkipRot(this->gfx++, actor_transform_id(&this->actor) + (2 * i) + 0, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + + gSPDisplayList(this->gfx++, gSongOfTimeClockDL); + + // @recomp Pop the clock's matrix group. + gEXPopMatrixGroup(this->gfx++, G_MTX_MODELVIEW); + + // Clock 2 + clock2Yaw += 0x1000; + clockPos.x = Math_CosS(clock2Yaw) * this->clockDist; + clockPos.z = Math_SinS(clock2Yaw) * this->clockDist; + Matrix_Translate(clockPos.x, clockPos.y, clockPos.z, MTXMODE_NEW); + Matrix_RotateXS(0x4000, MTXMODE_APPLY); + Matrix_Scale(0.8f, 0.8f, 0.8f, MTXMODE_APPLY); + Matrix_RotateZS(-angle, MTXMODE_APPLY); + + gSPMatrix(this->gfx++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gDPSetPrimColor(this->gfx++, 0, 0xFF, 28, 28, 28, 255); + gDPSetEnvColor(this->gfx++, 255, 255, 255, 255); + gDPSetRenderMode(this->gfx++, G_RM_FOG_SHADE_A, G_RM_AA_ZB_OPA_SURF2); + + // @recomp Tag the clock's matrix. + gEXMatrixGroupDecomposedSkipRot(this->gfx++, actor_transform_id(&this->actor) + (2 * i) + 1, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + + gSPDisplayList(this->gfx++, gSongOfTimeClockDL); + + // @recomp Pop the clock's matrix group. + gEXPopMatrixGroup(this->gfx++, G_MTX_MODELVIEW); + + clockPos.y -= this->speed; + angle += this->clockRingRotZ; + } + + POLY_OPA_DISP = this->gfx; + + // @recomp Manual relocation, TODO remove when automated. + SoTCsAmmoDrops* sSoTCsAmmoDrops_reloc = (SoTCsAmmoDrops*)actor_relocate(&this->actor, sSoTCsAmmoDrops); + + for (i = 0; i < ARRAY_COUNT(sSoTCsAmmoDrops); i++) { + if (sSoTCsAmmoDrops_reloc[i].scale > 0.0f) { + sSoTCsAmmoDrops_reloc[i].draw(this, play, &sSoTCsAmmoDrops_reloc[i]); + } + } + + CLOSE_DISPS(play->state.gfxCtx); +} diff --git a/patches/specific_actor_transform_tagging.c b/patches/specific_actor_transform_tagging.c index f880fa7..ea12ed0 100644 --- a/patches/specific_actor_transform_tagging.c +++ b/patches/specific_actor_transform_tagging.c @@ -7,6 +7,7 @@ #include "overlays/actors/ovl_En_Water_Effect/z_en_water_effect.h" #include "overlays/actors/ovl_En_Osn/z_en_osn.h" #include "overlays/actors/ovl_En_Fall2/z_en_fall2.h" +#include "overlays/actors/ovl_Obj_Entotu/z_obj_entotu.h" extern EnTanron2* D_80BB8458[82]; extern Boss04* D_80BB8450; @@ -956,3 +957,114 @@ void func_800A6A40(EnItem00* this, PlayState* play) { actor_set_custom_flag_1(&this->actor); } } + +extern Vtx ovl_Obj_Entotu_Vtx_000D10[7]; +extern Gfx object_f53_obj_DL_001C00[]; + +// @recomp Skip rotation interpolation for the Clock Town chimney's smoke when the camera skips interolation. +void func_80A34B28(ObjEntotu* this, PlayState* play) { + u8 sp57; + u8 sp56; + s32 i; + + this->unk_1B8.y += 1.8f; + this->unk_1B8.z += 0.6f; + sp57 = 0x7F - (u8)this->unk_1B8.y; + sp56 = 0x7F - (u8)this->unk_1B8.z; + + this->unk_1B8.x = CLAMP(this->unk_1B8.x, 0.0f, 1.0f); + + // @recomp Manual relocation, TODO remove when automated. + Vtx* verts = (Vtx*)actor_relocate(&this->actor, ovl_Obj_Entotu_Vtx_000D10); + for (i = 0; i < ARRAY_COUNT(ovl_Obj_Entotu_Vtx_000D10); i++) { + this->unk_148[i].v.cn[3] = verts[i].v.cn[3] * this->unk_1B8.x; + } + + if (this->unk_1B8.x > 0.0f) { + Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW); + this->actor.shape.rot.y = BINANG_ROT180(Camera_GetCamDirYaw(GET_ACTIVE_CAM(play))); + Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY); + Matrix_Scale(0.1f, 0.1f, 0.0f, MTXMODE_APPLY); + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL25_Opa(play->state.gfxCtx); + + // @recomp Tag the matrix, skipping rotation if the camera skipped interpolation this frame. + if (camera_was_skipped()) { + gEXMatrixGroupDecomposedSkipRot(POLY_XLU_DISP++, actor_transform_id(&this->actor), G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + } + else { + gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, actor_transform_id(&this->actor), G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + } + + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, sp57, 0x20, 0x20, 1, 0, sp56, 0x20, 0x20)); + gSPSegment(POLY_XLU_DISP++, 0x09, Lib_SegmentedToVirtual(this->unk_148)); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, object_f53_obj_DL_001C00); + + // @recomp Pop the matrix group. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + + CLOSE_DISPS(play->state.gfxCtx); + } +} + +extern Gfx object_f53_obj_DL_000158[]; + +// @recomp Skip rotation interpolation for the Clock Town chimney when the camera skips interolation. +void func_80A34A44(ObjEntotu* this, PlayState* play) { + Matrix_Translate(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW); + this->actor.shape.rot.y = BINANG_ROT180(Camera_GetCamDirYaw(GET_ACTIVE_CAM(play))); + Matrix_RotateYS(this->actor.shape.rot.y, MTXMODE_APPLY); + Matrix_Scale(0.1f, 0.1f, 0.0f, MTXMODE_APPLY); + + OPEN_DISPS(play->state.gfxCtx); + + Gfx_SetupDL25_Opa(play->state.gfxCtx); + + // @recomp Tag the matrix, skipping rotation if the camera skipped interpolation this frame. + if (camera_was_skipped()) { + gEXMatrixGroupDecomposedSkipRot(POLY_OPA_DISP++, actor_transform_id(&this->actor) + 1, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + } + else { + gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, actor_transform_id(&this->actor) + 1, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + } + + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, object_f53_obj_DL_000158); + + // @recomp Pop the matrix group. + gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW); + + CLOSE_DISPS(play->state.gfxCtx); +} + +void Environment_DrawRainImpl(PlayState* play, View* view, GraphicsContext* gfxCtx); + +// @recomp Skip interpolation for the splashes that raindrops make. +void Environment_DrawRain(PlayState* play, View* view, GraphicsContext* gfxCtx) { + if (!(GET_ACTIVE_CAM(play)->stateFlags & CAM_STATE_UNDERWATER) && + (play->envCtx.precipitation[PRECIP_SNOW_CUR] == 0)) { + + // @recomp Open the displaylists and skip interpolation for rain. + OPEN_DISPS(gfxCtx); + gEXMatrixGroupNoInterpolation(POLY_XLU_DISP++, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + + if (play->envCtx.precipitation[PRECIP_SOS_MAX] != 0) { + if (play->envCtx.precipitation[PRECIP_SNOW_CUR] == 0) { + Environment_DrawRainImpl(play, view, gfxCtx); + } + } else if (!(GET_ACTIVE_CAM(play)->stateFlags & CAM_STATE_UNDERWATER)) { + if ((Environment_GetStormState(play) != STORM_STATE_OFF) && + (play->envCtx.precipitation[PRECIP_SNOW_CUR] == 0)) { + Environment_DrawRainImpl(play, view, gfxCtx); + } + } + + // @recomp Pop the matrix group and close the displaylists. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + CLOSE_DISPS(gfxCtx); + } +}