diff --git a/lib/rt64 b/lib/rt64 index 00aecb3..404f38c 160000 --- a/lib/rt64 +++ b/lib/rt64 @@ -1 +1 @@ -Subproject commit 00aecb38ac2f4563e81980445399e1c84c64e5bc +Subproject commit 404f38c8061b40f19d92febe172d035dc9a82a3e diff --git a/patches/effect_transform_tagging.c b/patches/effect_transform_tagging.c index f2c333e..bd7ffd7 100644 --- a/patches/effect_transform_tagging.c +++ b/patches/effect_transform_tagging.c @@ -2,6 +2,7 @@ #include "transform_ids.h" #include "overlays/actors/ovl_Object_Kankyo/z_object_kankyo.h" #include "overlays/actors/ovl_Eff_Stk/z_eff_stk.h" +#include "overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h" #include "z64effect.h" extern f32 D_808DE5B0; @@ -434,3 +435,319 @@ void EffStk_Draw(Actor* thisx, PlayState* play) { CLOSE_DISPS(play->state.gfxCtx); } + + +typedef enum { + /* 0x00 */ CLEAR_TAG_EFFECT_AVAILABLE, + /* 0x01 */ CLEAR_TAG_EFFECT_DEBRIS, + /* 0x02 */ CLEAR_TAG_EFFECT_FIRE, // never set to, remnant of OoT + /* 0x03 */ CLEAR_TAG_EFFECT_SMOKE, + /* 0x04 */ CLEAR_TAG_EFFECT_FLASH, + /* 0x05 */ CLEAR_TAG_EFFECT_LIGHT_RAYS, + /* 0x06 */ CLEAR_TAG_EFFECT_SHOCKWAVE, + /* 0x07 */ CLEAR_TAG_EFFECT_SPLASH, + /* 0x08 */ CLEAR_TAG_EFFECT_ISOLATED_SMOKE +} ClearTagEffectType; + +extern Gfx gClearTagDebrisEffectMaterialDL[]; +extern Gfx gClearTagDebrisEffectDL[]; +extern Gfx gEffShockwaveDL[]; +extern Gfx gClearTagFlashEffectGroundDL[]; +extern Gfx gClearTagFireEffectMaterialDL[]; +extern Gfx gClearTagFireEffectDL[]; +extern Gfx gClearTagFireEffectMaterialDL[]; +extern Gfx gClearTagFireEffectDL[]; +extern Gfx gClearTagFlashEffectDL[]; +extern Gfx gClearTagLightRayEffectMaterialDL[]; +extern Gfx gClearTagLightRayEffectDL[]; +extern Gfx gEffWaterSplashDL[]; + +extern u64 gEffWaterSplash1Tex[]; +extern u64 gEffWaterSplash2Tex[]; +extern u64 gEffWaterSplash3Tex[]; +extern u64 gEffWaterSplash4Tex[]; +extern u64 gEffWaterSplash5Tex[]; +extern u64 gEffWaterSplash6Tex[]; +extern u64 gEffWaterSplash7Tex[]; +extern u64 gEffWaterSplash8Tex[]; + +static TexturePtr sWaterSplashTextures[] = { + gEffWaterSplash1Tex, + gEffWaterSplash2Tex, + gEffWaterSplash3Tex, + gEffWaterSplash4Tex, + gEffWaterSplash5Tex, + gEffWaterSplash6Tex, + gEffWaterSplash7Tex, + gEffWaterSplash8Tex, + NULL, + NULL, + NULL, +}; + +/** + * Draws all effects. + * Each effect type is drawn before the next. The function will apply a material that + * applies to all effects of that type while drawing the first effect of that type. + */ +// @recomp Patched to tag matrices. +void EnClearTag_DrawEffects(Actor* thisx, PlayState* play) { + u8 isMaterialApplied = false; + s16 i; + s16 j; + Vec3f vec; + WaterBox* waterBox; + f32 ySurface; + MtxF mtxF; + GraphicsContext* gfxCtx = play->state.gfxCtx; + EnClearTag* this = (EnClearTag*)thisx; + EnClearTagEffect* effect = this->effect; + EnClearTagEffect* firstEffect = this->effect; + + OPEN_DISPS(gfxCtx); + + Gfx_SetupDL25_Opa(play->state.gfxCtx); + Gfx_SetupDL25_Xlu(play->state.gfxCtx); + + // Draw all Debris effects. + for (i = 0; i < ARRAY_COUNT(this->effect); i++, effect++) { + if (effect->type == CLEAR_TAG_EFFECT_DEBRIS) { + // Apply the debris effect material if it has not already been applied. + if (!isMaterialApplied) { + isMaterialApplied++; + // @recomp Manual relocation, TODO remove when automated. + gSPDisplayList(POLY_OPA_DISP++, actor_relocate(thisx, gClearTagDebrisEffectMaterialDL)); + } + + // Draw the debris effect. + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_Scale(effect->scale, effect->scale, effect->scale, MTXMODE_APPLY); + Matrix_RotateYF(effect->rotationY, MTXMODE_APPLY); + Matrix_RotateXFApply(effect->rotationX); + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + // @recomp Tag the matrix. + gEXMatrixGroupDecomposedNormal(POLY_OPA_DISP++, actor_transform_id(thisx) + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + // @recomp Manual relocation, TODO remove when automated. + gSPDisplayList(POLY_OPA_DISP++, actor_relocate(thisx, gClearTagDebrisEffectDL)); + // @recomp Pop the matrix tag. + gEXPopMatrixGroup(POLY_OPA_DISP++, G_MTX_MODELVIEW); + } + } + + // Draw all Shockwave effects. + effect = firstEffect; + if (this->actor.floorPoly != NULL) { + for (i = 0; i < ARRAY_COUNT(this->effect); i++, effect++) { + if (effect->type == CLEAR_TAG_EFFECT_SHOCKWAVE) { + // Draw the shockwave effect. + gDPPipeSync(POLY_XLU_DISP++); + gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, (s8)effect->primColor.a); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, (s8)effect->primColor.a); + func_800C0094(this->actor.floorPoly, effect->pos.x, effect->pos.y, effect->pos.z, &mtxF); + Matrix_Put(&mtxF); + Matrix_Scale(effect->scale, 1.0f, effect->scale, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + // @recomp Tag the matrix. + gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, actor_transform_id(thisx) + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + gSPDisplayList(POLY_XLU_DISP++, gEffShockwaveDL); + // @recomp Pop the matrix tag. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + } + } + } + + // Draw all ground flash effects. + effect = firstEffect; + isMaterialApplied = false; + if (this->actor.floorPoly != NULL) { + for (i = 0; i < ARRAY_COUNT(this->effect); i++, effect++) { + if (effect->type == CLEAR_TAG_EFFECT_FLASH) { + // Apply the flash ground effect material if it has not already been applied. + if (!isMaterialApplied) { + gDPPipeSync(POLY_XLU_DISP++); + gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 200, 0); + isMaterialApplied++; + } + + // Draw the ground flash effect. + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 200, (s8)(effect->primColor.a * 0.7f)); + func_800C0094(this->actor.floorPoly, effect->pos.x, this->actor.floorHeight, effect->pos.z, &mtxF); + Matrix_Put(&mtxF); + Matrix_Scale(effect->scale * 3.0f, 1.0f, effect->scale * 3.0f, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + // @recomp Tag the matrix. + gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, actor_transform_id(thisx) + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + // @recomp Manual relocation, TODO remove when automated. + gSPDisplayList(POLY_XLU_DISP++, actor_relocate(thisx, gClearTagFlashEffectGroundDL)); + // @recomp Pop the matrix tag. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + } + } + } + + // Draw all smoke effects. + effect = firstEffect; + isMaterialApplied = false; + for (i = 0; i < ARRAY_COUNT(this->effect); i++, effect++) { + if ((effect->type == CLEAR_TAG_EFFECT_SMOKE) || (effect->type == CLEAR_TAG_EFFECT_ISOLATED_SMOKE)) { + // Apply the smoke effect material if it has not already been applied. + if (!isMaterialApplied) { + // @recomp Manual relocation, TODO remove when automated. + gSPDisplayList(POLY_XLU_DISP++, actor_relocate(thisx, gClearTagFireEffectMaterialDL)); + isMaterialApplied++; + } + + // Draw the smoke effect. + gDPPipeSync(POLY_XLU_DISP++); + gDPSetEnvColor(POLY_XLU_DISP++, (s8)effect->envColor.r, (s8)effect->envColor.g, (s8)effect->envColor.b, + 128); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, (s8)effect->primColor.r, (s8)effect->primColor.g, + (s8)effect->primColor.b, (s8)effect->primColor.a); + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, -effect->actionTimer * 5, 32, 64, 1, 0, 0, 32, 32)); + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_ReplaceRotation(&play->billboardMtxF); + Matrix_Scale(effect->smokeScaleX * effect->scale, effect->smokeScaleY * effect->scale, 1.0f, MTXMODE_APPLY); + Matrix_Translate(0.0f, 20.0f, 0.0f, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + // @recomp Tag the matrix. + gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, actor_transform_id(thisx) + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + // @recomp Manual relocation, TODO remove when automated. + gSPDisplayList(POLY_XLU_DISP++, actor_relocate(thisx, gClearTagFireEffectDL)); + // @recomp Pop the matrix tag. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + } + } + + // Draw all fire effects. + effect = firstEffect; + isMaterialApplied = false; + for (i = 0; i < ARRAY_COUNT(this->effect); i++, effect++) { + if (effect->type == CLEAR_TAG_EFFECT_FIRE) { + // Apply the fire effect material if it has not already been applied. + if (!isMaterialApplied) { + // @recomp Manual relocation, TODO remove when automated. + gSPDisplayList(POLY_XLU_DISP++, actor_relocate(thisx, gClearTagFireEffectMaterialDL)); + gDPSetEnvColor(POLY_XLU_DISP++, 255, 215, 255, 128); + isMaterialApplied++; + } + + // Draw the fire effect. + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 200, 20, 0, (s8)effect->primColor.a); + gSPSegment(POLY_XLU_DISP++, 0x08, + Gfx_TwoTexScroll(play->state.gfxCtx, 0, 0, -effect->actionTimer * 15, 32, 64, 1, 0, 0, 32, 32)); + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_ReplaceRotation(&play->billboardMtxF); + Matrix_Scale(effect->scale, effect->scale, 1.0f, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + // @recomp Tag the matrix. + gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, actor_transform_id(thisx) + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + // @recomp Manual relocation, TODO remove when automated. + gSPDisplayList(POLY_XLU_DISP++, actor_relocate(thisx, gClearTagFireEffectDL)); + // @recomp Pop the matrix tag. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + } + } + + // Draw all flash billboard effects. + effect = firstEffect; + isMaterialApplied = false; + for (i = 0; i < ARRAY_COUNT(this->effect); i++, effect++) { + if (effect->type == CLEAR_TAG_EFFECT_FLASH) { + // Apply the flash billboard effect material if it has not already been applied. + if (!isMaterialApplied) { + gDPPipeSync(POLY_XLU_DISP++); + gDPSetEnvColor(POLY_XLU_DISP++, this->flashEnvColor.r, this->flashEnvColor.g, this->flashEnvColor.b, 0); + isMaterialApplied++; + } + + // Draw the flash billboard effect. + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 200, (s8)effect->primColor.a); + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_ReplaceRotation(&play->billboardMtxF); + Matrix_Scale(2.0f * effect->scale, 2.0f * effect->scale, 1.0f, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + // @recomp Tag the matrix. + gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, actor_transform_id(thisx) + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + // @recomp Manual relocation, TODO remove when automated. + gSPDisplayList(POLY_XLU_DISP++, actor_relocate(thisx, gClearTagFlashEffectDL)); + // @recomp Pop the matrix tag. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + } + } + + // Draw all light ray effects. + effect = firstEffect; + isMaterialApplied = false; + for (i = 0; i < ARRAY_COUNT(this->effect); i++, effect++) { + if (effect->type == CLEAR_TAG_EFFECT_LIGHT_RAYS) { + // Apply the light ray effect material if it has not already been applied. + if (!isMaterialApplied) { + gDPPipeSync(POLY_XLU_DISP++); + gDPSetEnvColor(POLY_XLU_DISP++, (u8)effect->envColor.r, (u8)effect->envColor.g, (u8)effect->envColor.b, + 0); + // @recomp Manual relocation, TODO remove when automated. + gSPDisplayList(POLY_XLU_DISP++, actor_relocate(thisx, gClearTagLightRayEffectMaterialDL)); + isMaterialApplied++; + } + + // Draw the light ray effect. + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, (u8)effect->primColor.r, (u8)effect->primColor.g, + (u8)effect->primColor.b, (u8)effect->primColor.a); + Matrix_Translate(effect->pos.x, effect->pos.y, effect->pos.z, MTXMODE_NEW); + Matrix_RotateYF(effect->rotationY, MTXMODE_APPLY); + Matrix_RotateXFApply(effect->rotationX); + Matrix_RotateZF(effect->rotationZ, MTXMODE_APPLY); + Matrix_Scale(effect->scale * 0.5f, effect->scale * 0.5f, effect->maxScale * effect->scale, MTXMODE_APPLY); + Matrix_RotateXFApply(M_PI / 2); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + // @recomp Tag the matrix. + gEXMatrixGroupDecomposedNormal(POLY_XLU_DISP++, actor_transform_id(thisx) + i, G_EX_PUSH, G_MTX_MODELVIEW, G_EX_EDIT_NONE); + // @recomp Manual relocation, TODO remove when automated. + gSPDisplayList(POLY_XLU_DISP++, actor_relocate(thisx, gClearTagLightRayEffectDL)); + // @recomp Pop the matrix tag. + gEXPopMatrixGroup(POLY_XLU_DISP++, G_MTX_MODELVIEW); + } + } + + // Draw all splash effects. + effect = firstEffect; + for (i = 0; i < ARRAY_COUNT(this->effect); i++, effect++) { + if (effect->type == CLEAR_TAG_EFFECT_SPLASH) { + gDPPipeSync(POLY_XLU_DISP++); + gDPSetEnvColor(POLY_XLU_DISP++, 255, 255, 255, 200); + gDPSetPrimColor(POLY_XLU_DISP++, 0, 0, 255, 255, 255, 200); + gSPSegment(POLY_XLU_DISP++, 0x08, Lib_SegmentedToVirtual(sWaterSplashTextures[effect->actionTimer])); + Gfx_SetupDL61_Xlu(gfxCtx); + gSPClearGeometryMode(POLY_XLU_DISP++, G_CULL_BACK); + isMaterialApplied++; + + // Apply material 16 times along a circle to give the appearance of a splash + for (j = 0; j < 16; j++) { + Matrix_RotateYF(2.0f * (j * M_PI) * (1.0f / 16.0f), MTXMODE_NEW); + Matrix_MultVecZ(effect->maxScale, &vec); + /** + * 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 + */ + ySurface = effect->pos.y; + if (WaterBox_GetSurface1(play, &play->colCtx, effect->pos.x + vec.x, effect->pos.z + vec.z, &ySurface, + &waterBox)) { + if ((effect->pos.y - ySurface) < 200.0f) { + // Draw the splash effect. + Matrix_Translate(effect->pos.x + vec.x, ySurface, effect->pos.z + vec.z, MTXMODE_NEW); + Matrix_RotateYF(2.0f * (j * M_PI) * (1.0f / 16.0f), MTXMODE_APPLY); + Matrix_RotateXFApply(effect->rotationX); + Matrix_Scale(effect->scale, effect->scale, effect->scale, MTXMODE_APPLY); + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + // @recomp TODO figure out a way to tag these without increasing the allocated IDs per actor. + gSPDisplayList(POLY_XLU_DISP++, gEffWaterSplashDL); + } + } + } + } + } + + CLOSE_DISPS(play->state.gfxCtx); +} diff --git a/patches/item_transform_tagging.c b/patches/item_transform_tagging.c index c6f34d1..57f183b 100644 --- a/patches/item_transform_tagging.c +++ b/patches/item_transform_tagging.c @@ -182,10 +182,8 @@ void Player_DrawGameplay(PlayState* play, Player* this, s32 lod, Gfx* cullDList, } } - // @recomp Manually relocate Player_PostLimbDrawGameplay. - // TODO remove this when the recompiler can relocate patch code. Player_DrawImpl(play, this->skelAnime.skeleton, this->skelAnime.jointTable, this->skelAnime.dListCount, lod, - this->transformation, 0, this->actor.shape.face, overrideLimbDraw, (PostLimbDrawFlex)actor_relocate(&this->actor, Player_PostLimbDrawGameplay), + this->transformation, 0, this->actor.shape.face, overrideLimbDraw, Player_PostLimbDrawGameplay, &this->actor); CLOSE_DISPS(play->state.gfxCtx); diff --git a/patches/patches.h b/patches/patches.h index d84d554..ca010ae 100644 --- a/patches/patches.h +++ b/patches/patches.h @@ -51,8 +51,14 @@ int recomp_printf(const char* fmt, ...); float recomp_powf(float, float); static inline void* actor_relocate(Actor* actor, void* addr) { - return (void*)((uintptr_t)addr - - (intptr_t)((uintptr_t)actor->overlayEntry->vramStart - (uintptr_t)actor->overlayEntry->loadedRamAddr)); + if ((uintptr_t)addr >= 0x80800000) { + return (void*)((uintptr_t)addr - + (intptr_t)((uintptr_t)actor->overlayEntry->vramStart - (uintptr_t)actor->overlayEntry->loadedRamAddr)); + } + else { + recomp_printf("Not an overlay address!: 0x%08X 0x%08X 0x%08X\n", (u32)addr, (u32)actor->overlayEntry->vramStart, (u32)actor->overlayEntry->loadedRamAddr); + return addr; + } } typedef enum {