diff --git a/README.md b/README.md index c5e458976..e79367f75 100644 --- a/README.md +++ b/README.md @@ -90,9 +90,11 @@ List of every HackerOoT contributors, from most recent to oldest contribution: - HailToDodongo - CrashOverride95 - Trueffell -- Yanis42 +- Yanis002 - kurethedead - zelllll - ariahiro64 - ghost - krm01 + +New Animated Materials types based on [z64rom](https://github.com/z64dev/z64rom/blob/main/project/src/lib_user/library/SceneRender.c). Special thanks to Nokaubure, rankaisija, z64me and the other contributors from that project. diff --git a/assets/scenes/example/example_scene_main.c b/assets/scenes/example/example_scene_main.c index ff03554b6..ecc7291b1 100644 --- a/assets/scenes/example/example_scene_main.c +++ b/assets/scenes/example/example_scene_main.c @@ -20,7 +20,7 @@ SceneCmd example_scene_header00[] = { SCENE_CMD_PLAYER_ENTRY_LIST(7, example_scene_header00_playerEntryList), SCENE_CMD_CUTSCENE_DATA(gExampleCS), #if ENABLE_ANIMATED_MATERIALS - SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial), + SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial, MATERIAL_CAM_PARAMS(ANIM_MAT_CAMERA_TYPE_NONE, false)), #endif #if ENABLE_CUTSCENE_IMPROVEMENTS SCENE_CMD_ACTOR_CUTSCENE_LIST(2, debug1_scene_header00_ActorCutsceneList), @@ -222,9 +222,9 @@ AnimatedMatColorParams debug1_scene_header00_AnimatedMaterialColorParams_02 = { }; AnimatedMaterial debug1_scene_header00_AnimatedMaterial[] = { - { 1 /* 8 */, 1, debug1_scene_header00_AnimatedMaterialTexScrollParams_00 }, - { 2 /* 9 */, 1, debug1_scene_header00_AnimatedMaterialTexScrollParams_01 }, - { -3 /* 10 */, 4, &debug1_scene_header00_AnimatedMaterialColorParams_02 } + { MATERIAL_SEGMENT_NUM(0x08), ANIM_MAT_TYPE_TWO_TEX_SCROLL, debug1_scene_header00_AnimatedMaterialTexScrollParams_00 }, + { MATERIAL_SEGMENT_NUM(0x09), ANIM_MAT_TYPE_TWO_TEX_SCROLL, debug1_scene_header00_AnimatedMaterialTexScrollParams_01 }, + { LAST_MATERIAL_SEGMENT_NUM(0x0A), ANIM_MAT_TYPE_COLOR_NON_LINEAR_INTERP, &debug1_scene_header00_AnimatedMaterialColorParams_02 } }; #endif @@ -265,7 +265,7 @@ SceneCmd example_scene_header01[] = { SCENE_CMD_SPAWN_LIST(example_scene_header01_entranceList), SCENE_CMD_PLAYER_ENTRY_LIST(7, example_scene_header01_playerEntryList), #if ENABLE_ANIMATED_MATERIALS - SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial), + SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial, MATERIAL_CAM_PARAMS(ANIM_MAT_CAMERA_TYPE_NONE, false)), #endif #if ENABLE_CUTSCENE_IMPROVEMENTS SCENE_CMD_ACTOR_CUTSCENE_LIST(2, debug1_scene_header00_ActorCutsceneList), @@ -413,7 +413,7 @@ SceneCmd example_scene_header02[] = { SCENE_CMD_SPAWN_LIST(example_scene_header02_entranceList), SCENE_CMD_PLAYER_ENTRY_LIST(7, example_scene_header02_playerEntryList), #if ENABLE_ANIMATED_MATERIALS - SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial), + SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial, MATERIAL_CAM_PARAMS(ANIM_MAT_CAMERA_TYPE_NONE, false)), #endif #if ENABLE_CUTSCENE_IMPROVEMENTS SCENE_CMD_ACTOR_CUTSCENE_LIST(2, debug1_scene_header00_ActorCutsceneList), @@ -561,7 +561,7 @@ SceneCmd example_scene_header03[] = { SCENE_CMD_SPAWN_LIST(example_scene_header03_entranceList), SCENE_CMD_PLAYER_ENTRY_LIST(7, example_scene_header03_playerEntryList), #if ENABLE_ANIMATED_MATERIALS - SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial), + SCENE_CMD_ANIMATED_MATERIAL_LIST(debug1_scene_header00_AnimatedMaterial, MATERIAL_CAM_PARAMS(ANIM_MAT_CAMERA_TYPE_NONE, false)), #endif #if ENABLE_CUTSCENE_IMPROVEMENTS SCENE_CMD_ACTOR_CUTSCENE_LIST(2, debug1_scene_header00_ActorCutsceneList), diff --git a/include/actor.h b/include/actor.h index 80f9a4dcd..de18d312d 100644 --- a/include/actor.h +++ b/include/actor.h @@ -6,6 +6,7 @@ #include "animation.h" #include "z_math.h" #include "collision_check.h" +#include "animated_materials.h" #define ACTOR_NUMBER_MAX 200 @@ -247,8 +248,8 @@ typedef struct Actor { /* 0x130 */ ActorFunc update; // Update Routine. Called by `Actor_UpdateAll` /* 0x134 */ ActorFunc draw; // Draw Routine. Called by `Actor_Draw` /* 0x138 */ struct ActorOverlay* overlayEntry; // Pointer to the overlay table entry for this actor -#if DEBUG_FEATURES - /* 0x13C */ char dbgPad[0x10]; +#if ENABLE_ANIMATED_MATERIALS + /* 0x13C */ AnimatedMatContext animMatCtx; #endif } Actor; // size = 0x14C @@ -284,6 +285,9 @@ typedef struct DynaPolyActor { /* 0x15C */ u32 transformFlags; /* 0x160 */ u8 interactFlags; /* 0x162 */ s16 unk_162; +#if ENABLE_ANIMATED_MATERIALS + AnimatedMatPolyContext animMatPolyCtx; +#endif } DynaPolyActor; // size = 0x164 typedef struct BodyBreak { diff --git a/include/animated_materials.h b/include/animated_materials.h index 227752885..cfd2e1758 100644 --- a/include/animated_materials.h +++ b/include/animated_materials.h @@ -3,86 +3,321 @@ #include "ultra64.h" #include "config.h" +#include "command_macros_base.h" +#include "color.h" +#include "bgcheck.h" +#include "libc64/malloc.h" #if ENABLE_ANIMATED_MATERIALS +/* + * 0000 0000 0000 1111: type (see AnimatedMatCameraType) + * 0000 0000 0001 0000: execute on event + */ +#define MATERIAL_CAM_TYPE(params) ((params) & 0x0F) +#define MATERIAL_CAM_ON_EVENT(params) (((params) >> 4) & 1) +#define MATERIAL_CAM_PARAMS(type, onEvent) ((((onEvent) & 1) << 4) | ((type) & 0x0F)) + +#define MATERIAL_SEGMENT_NUM(n) (n) +#define LAST_MATERIAL_SEGMENT_NUM(n) -MATERIAL_SEGMENT_NUM(n) + typedef enum AnimatedMatType { - /* 0 */ ANIM_MAT_TYPE_TEX_SCROLL, - /* 1 */ ANIM_MAT_TYPE_TWO_TEX_SCROLL, - /* 2 */ ANIM_MAT_TYPE_COLOR, - /* 3 */ ANIM_MAT_TYPE_COLOR_LERP, - /* 4 */ ANIM_MAT_TYPE_COLOR_NON_LINEAR_INTERP, - /* 5 */ ANIM_MAT_TYPE_TEX_CYCLE, - /* 6 */ ANIM_MAT_TYPE_MAX + // vanilla types + /* 0 */ ANIM_MAT_TYPE_TEX_SCROLL, + /* 1 */ ANIM_MAT_TYPE_TWO_TEX_SCROLL, + /* 2 */ ANIM_MAT_TYPE_COLOR, + /* 3 */ ANIM_MAT_TYPE_COLOR_LERP, + /* 4 */ ANIM_MAT_TYPE_COLOR_NON_LINEAR_INTERP, + /* 5 */ ANIM_MAT_TYPE_TEX_CYCLE, + /* 6 */ ANIM_MAT_TYPE_NONE, + /* 7 */ ANIM_MAT_TYPE_COLOR_CYCLE, // like TYPE_COLOR except it takes a keyframe array to set draw durations + /* 8 */ ANIM_MAT_TYPE_TEX_TIMED_CYCLE, + /* 9 */ ANIM_MAT_TYPE_TEXTURE, + /* 10 */ ANIM_MAT_TYPE_MULTITEXTURE, + /* 11 */ ANIM_MAT_TYPE_EVENT, + /* 12 */ ANIM_MAT_TYPE_SURFACE_SWAP, + /* 13 */ ANIM_MAT_TYPE_OSCILLATING_TWO_TEX, + /* 14 */ ANIM_MAT_TYPE_COLOR_SWITCH, // like TYPE_TEXTURE except it's for colors + /* 15 */ ANIM_MAT_TYPE_MAX } AnimatedMatType; -typedef struct { - /* 0x0 */ u8 r; - /* 0x1 */ u8 g; - /* 0x2 */ u8 b; - /* 0x3 */ u8 a; - /* 0x4 */ u8 lodFrac; -} F3DPrimColor; // size = 0x5 +typedef enum AnimatedMatCameraType { + ANIM_MAT_CAMERA_TYPE_NONE, + ANIM_MAT_CAMERA_TYPE_SHAKE, // collapse-like screen + ANIM_MAT_CAMERA_TYPE_DISTORTION, // jabu-like screen + ANIM_MAT_CAMERA_TYPE_MAX, +} AnimatedMatCameraType; typedef struct { - /* 0x0 */ u8 r; - /* 0x1 */ u8 g; - /* 0x2 */ u8 b; - /* 0x3 */ u8 a; -} F3DEnvColor; // size = 0x4 + /* 0x00 */ u8 r; + /* 0x01 */ u8 g; + /* 0x02 */ u8 b; + /* 0x03 */ u8 a; + /* 0x04 */ u8 lodFrac; +} F3DPrimColor; // size = 0x05 typedef struct { - /* 0x0 */ u16 keyFrameLength; - /* 0x2 */ u16 keyFrameCount; - /* 0x4 */ F3DPrimColor* primColors; - /* 0x8 */ F3DEnvColor* envColors; - /* 0xC */ u16* keyFrames; + /* 0x00 */ u8 r; + /* 0x01 */ u8 g; + /* 0x02 */ u8 b; + /* 0x03 */ u8 a; +} F3DEnvColor; // size = 0x04 + +typedef struct { + /* 0x00 */ u16 keyFrameLength; + /* 0x02 */ u16 keyFrameCount; + /* 0x04 */ F3DPrimColor* primColors; + /* 0x08 */ F3DEnvColor* envColors; + /* 0x0C */ u16* keyFrames; } AnimatedMatColorParams; // size = 0x10 typedef struct { - /* 0x0 */ s8 xStep; - /* 0x1 */ s8 yStep; - /* 0x2 */ u8 width; - /* 0x3 */ u8 height; -} AnimatedMatTexScrollParams; // size = 0x4 + /* 0x00 */ s8 xStep; + /* 0x01 */ s8 yStep; + /* 0x02 */ u8 width; + /* 0x03 */ u8 height; +} AnimatedMatTexScrollParams; // size = 0x04 typedef struct { - /* 0x0 */ u16 keyFrameLength; - /* 0x4 */ TexturePtr* textureList; - /* 0x8 */ u8* textureIndexList; -} AnimatedMatTexCycleParams; // size = 0xC + /* 0x00 */ u16 keyFrameLength; + /* 0x04 */ TexturePtr* textureList; + /* 0x08 */ u8* textureIndexList; +} AnimatedMatTexCycleParams; // size = 0x0C -typedef struct { - /* 0x0 */ s8 segment; - /* 0x2 */ AnimatedMatType type; - /* 0x4 */ void* params; -} AnimatedMaterial; // size = 0x8 +typedef struct AnimatedMatTexTimedCycleKeyframe { + TexturePtr texture; // texture to draw + u16 displayTime; // how long it lasts before going on the next one +} AnimatedMatTexTimedCycleKeyframe; +typedef struct AnimatedMatTexTimedCycleParams { + u16 keyframeLength; // how many keyframes + AnimatedMatTexTimedCycleKeyframe* keyframeList; // array of keyframes +} AnimatedMatTexTimedCycleParams; + +typedef struct AnimatedMatTextureParams { + TexturePtr textures[2]; +} AnimatedMatTextureParams; + +typedef struct AnimatedMatColorSwitchParams { + F3DPrimColor primColors[2]; + F3DEnvColor envColors[2]; + u8 useEnvColor[2]; +} AnimatedMatColorSwitchParams; + +typedef struct AnimatedMatMultiTextureParams { + s16 minPrimAlpha; // minimum opacity of both textures + s16 maxPrimAlpha; // maximum opacity of both textures + s16 minEnvAlpha; // minimum opacity of texture2 + s16 maxEnvAlpha; // maximum opacity of texture2 + u8 speed; // transition/blending speed + TexturePtr texture1; // optional, texture reference (can be NULL) + TexturePtr texture2; // optional, texture reference (can be NULL) + u8 segment1; // optional, segment number of the texture reference for texture1 + u8 segment2; // optional, segment number of the texture reference for texture2 +} AnimatedMatMultiTextureParams; + +// note: the new settings will apply to all tris from the list! +typedef struct AnimatedMatSurfaceSwapParams { + SurfaceType surface; // the new surface settings + s16 surfaceType; // surface type index to change + u16 flags_vIA; // new poly flags to apply + u16 flags_vIB; // new poly flags to apply + AnimatedMatMultiTextureParams* textureParams; // required for a texture blend transition + u16 triIndices[]; // index list of the triangles to edit, -1 means the list is over +} AnimatedMatSurfaceSwapParams; + +struct GameState; struct PlayState; +struct EventScriptEntry; -Gfx* AnimatedMat_TexScroll(struct PlayState* play, AnimatedMatTexScrollParams* params); -void AnimatedMat_DrawTexScroll(struct PlayState* play, s32 segment, void* params); -Gfx* AnimatedMat_TwoLayerTexScroll(struct PlayState* play, AnimatedMatTexScrollParams* params); -void AnimatedMat_DrawTwoTexScroll(struct PlayState* play, s32 segment, void* params); -void AnimatedMat_SetColor(struct PlayState* play, s32 segment, F3DPrimColor* primColorResult, F3DEnvColor* envColor); -void AnimatedMat_DrawColor(struct PlayState* play, s32 segment, void* params); -s32 AnimatedMat_Lerp(s32 min, s32 max, f32 norm); -void AnimatedMat_DrawColorLerp(struct PlayState* play, s32 segment, void* params); -void AnimatedMat_DrawColorNonLinearInterp(struct PlayState* play, s32 segment, void* params); -void AnimatedMat_DrawTexCycle(struct PlayState* play, s32 segment, void* params); -void AnimatedMat_DrawMain(struct PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step, u32 flags); -void AnimatedMat_Draw(struct PlayState* play, AnimatedMaterial* matAnim); -void AnimatedMat_DrawOpa(struct PlayState* play, AnimatedMaterial* matAnim); -void AnimatedMat_DrawXlu(struct PlayState* play, AnimatedMaterial* matAnim); -void AnimatedMat_DrawAlpha(struct PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio); -void AnimatedMat_DrawAlphaOpa(struct PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio); -void AnimatedMat_DrawAlphaXlu(struct PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio); -void AnimatedMat_DrawStep(struct PlayState* play, AnimatedMaterial* matAnim, u32 step); -void AnimatedMat_DrawStepOpa(struct PlayState* play, AnimatedMaterial* matAnim, u32 step); -void AnimatedMat_DrawStepXlu(struct PlayState* play, AnimatedMaterial* matAnim, u32 step); -void AnimatedMat_DrawAlphaStep(struct PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step); -void AnimatedMat_DrawAlphaStepOpa(struct PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step); -void AnimatedMat_DrawAlphaStepXlu(struct PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step); +typedef struct AnimatedMaterial { + /* 0x00 */ s8 segment; + /* 0x02 */ AnimatedMatType type; + /* 0x04 */ void* params; + /* 0x08 */ struct EventScriptEntry* eventEntry; // optional +} AnimatedMaterial; + +// we need a way to revert back to the original state +// but since we're editing the scene data directly we need to allocate and populate a backup list +typedef struct CollisionPolyBackup { + SurfaceType surfaceType; + u16 flags_vIA; + u16 flags_vIB; +} CollisionPolyBackup; + +// doing it this way to save space, holds runtime informations for each running type +typedef struct AnimatedMatState { + u8 prevAllowDraw; + u8 actionType; + union { + struct { + s32 step; + }; + struct { + s32 curFrame; + u8 timer; + }; + struct { + u8 firstTime; + s16 primAlpha; + s16 envAlpha; + }; + s32 _words[2]; + }; +} AnimatedMatState; + +typedef struct AnimatedMatPolyContext { + CollisionPolyBackup* polyBackupList; + s16 triCount; +} AnimatedMatPolyContext; + +typedef struct AnimatedMatContext { + AnimatedMatState* stateList; +} AnimatedMatContext; + +void AnimatedMat_InitSurfaceSwap(struct GameState* gameState, AnimatedMatPolyContext* animMatPolyCtx, void* params); +void AnimatedMat_Init(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim); + +void AnimatedMat_DrawMain(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step, + u32 flags); + +void AnimatedMat_Draw(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, u32 gameplayFrames, AnimatedMaterial* matAnim); +void AnimatedMat_DrawOpa(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, u32 gameplayFrames, AnimatedMaterial* matAnim); +void AnimatedMat_DrawXlu(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, u32 gameplayFrames, AnimatedMaterial* matAnim); +void AnimatedMat_DrawAlpha(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, u32 gameplayFrames, AnimatedMaterial* matAnim, + f32 alphaRatio); +void AnimatedMat_DrawAlphaOpa(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, u32 gameplayFrames, AnimatedMaterial* matAnim, + f32 alphaRatio); +void AnimatedMat_DrawAlphaXlu(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, u32 gameplayFrames, AnimatedMaterial* matAnim, + f32 alphaRatio); +void AnimatedMat_DrawStep(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, u32 step); +void AnimatedMat_DrawStepOpa(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, u32 step); +void AnimatedMat_DrawStepXlu(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, u32 step); +void AnimatedMat_DrawAlphaStep(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, f32 alphaRatio, + u32 step); +void AnimatedMat_DrawAlphaStepOpa(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, f32 alphaRatio, + u32 step); +void AnimatedMat_DrawAlphaStepXlu(struct GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, f32 alphaRatio, + u32 step); + +// macros for convenience +#define ActorAnimatedMat_Init(this, play, ptr) AnimatedMat_Init(&(play)->state, &(this)->actor.animMatCtx, NULL, (ptr)) + +#define ActorAnimatedMat_Draw(this, play, ptr) \ + AnimatedMat_Draw(&(play)->state, &(this)->actor.animMatCtx, NULL, (play)->gameplayFrames, (ptr)) + +#define ActorAnimatedMat_DrawOpa(this, play, ptr) \ + AnimatedMat_DrawOpa(&(play)->state, &(this)->actor.animMatCtx, NULL, (play)->gameplayFrames, (ptr)) + +#define ActorAnimatedMat_DrawXlu(this, play, ptr) \ + AnimatedMat_DrawXlu(&(play)->state, &(this)->actor.animMatCtx, NULL, (play)->gameplayFrames, (ptr)) + +#define ActorAnimatedMat_DrawAlpha(this, play, ptr) \ + AnimatedMat_DrawAlpha(&(play)->state, &(this)->actor.animMatCtx, NULL, (play)->gameplayFrames, (ptr)) + +#define ActorAnimatedMat_DrawAlphaOpa(this, play, ptr) \ + AnimatedMat_DrawAlphaOpa(&(play)->state, &(this)->actor.animMatCtx, NULL, (play)->gameplayFrames, (ptr)) + +#define ActorAnimatedMat_DrawAlphaXlu(this, play, ptr) \ + AnimatedMat_DrawAlphaXlu(&(play)->state, &(this)->actor.animMatCtx, NULL, (play)->gameplayFrames, (ptr)) + +#define ActorAnimatedMat_DrawStep(this, play, ptr, step) \ + AnimatedMat_DrawStep(&(play)->state, &(this)->actor.animMatCtx, NULL, (ptr), (step)) + +#define ActorAnimatedMat_DrawStepOpa(this, play, ptr, step) \ + AnimatedMat_DrawStepOpa(&(play)->state, &(this)->actor.animMatCtx, NULL, (ptr), (step)) + +#define ActorAnimatedMat_DrawStepXlu(this, play, ptr, step) \ + AnimatedMat_DrawStepXlu(&(play)->state, &(this)->actor.animMatCtx, NULL, (ptr), (step)) + +#define ActorAnimatedMat_DrawAlphaStep(this, play, ptr, alphaRatio, step) \ + AnimatedMat_DrawAlphaStep(&(play)->state, &(this)->actor.animMatCtx, NULL, (ptr), (alphaRatio), (step)) + +#define ActorAnimatedMat_DrawAlphaStepOpa(this, play, ptr, alphaRatio, step) \ + AnimatedMat_DrawAlphaStepOpa(&(play)->state, &(this)->actor.animMatCtx, NULL, (ptr), (alphaRatio), (step)) + +#define ActorAnimatedMat_DrawAlphaStepXlu(this, play, ptr, alphaRatio, step) \ + AnimatedMat_DrawAlphaStepXlu(&(play)->state, &(this)->actor.animMatCtx, NULL, (ptr), (alphaRatio), (step)) + +#define ActorAnimatedMat_Destroy(this) \ + { \ + if (this->actor.animMatCtx.stateList != NULL) { \ + SYSTEM_ARENA_FREE(this->actor.animMatCtx.stateList); \ + } \ + } + +#define DynaActorAnimatedMat_Init(this, play, ptr) \ + AnimatedMat_Init(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, (ptr)) + +#define DynaActorAnimatedMat_Draw(this, play, ptr) \ + AnimatedMat_Draw(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, (play)->gameplayFrames, \ + (ptr)) + +#define DynaActorAnimatedMat_DrawOpa(this, play, ptr) \ + AnimatedMat_DrawOpa(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, \ + (play)->gameplayFrames, (ptr)) + +#define DynaActorAnimatedMat_DrawXlu(this, play, ptr) \ + AnimatedMat_DrawXlu(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, \ + (play)->gameplayFrames, (ptr)) + +#define DynaActorAnimatedMat_DrawAlpha(this, play, ptr) \ + AnimatedMat_DrawAlpha(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, \ + (play)->gameplayFrames, (ptr)) + +#define DynaActorAnimatedMat_DrawAlphaOpa(this, play, ptr) \ + AnimatedMat_DrawAlphaOpa(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, \ + (play)->gameplayFrames, (ptr)) + +#define DynaActorAnimatedMat_DrawAlphaXlu(this, play, ptr) \ + AnimatedMat_DrawAlphaXlu(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, \ + (play)->gameplayFrames, (ptr)) + +#define DynaActorAnimatedMat_DrawStep(this, play, ptr, step) \ + AnimatedMat_DrawStep(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, (ptr), (step)) + +#define DynaActorAnimatedMat_DrawStepOpa(this, play, ptr, step) \ + AnimatedMat_DrawStepOpa(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, (ptr), (step)) + +#define DynaActorAnimatedMat_DrawStepXlu(this, play, ptr, step) \ + AnimatedMat_DrawStepXlu(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, (ptr), (step)) + +#define DynaActorAnimatedMat_DrawAlphaStep(this, play, ptr, alphaRatio, step) \ + AnimatedMat_DrawAlphaStep(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, (ptr), \ + (alphaRatio), (step)) + +#define DynaActorAnimatedMat_DrawAlphaStepOpa(this, play, ptr, alphaRatio, step) \ + AnimatedMat_DrawAlphaStepOpa(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, (ptr), \ + (alphaRatio), (step)) + +#define DynaActorAnimatedMat_DrawAlphaStepXlu(this, play, ptr, alphaRatio, step) \ + AnimatedMat_DrawAlphaStepXlu(&(play)->state, &(this)->actor.animMatCtx, &(this)->dyna.animMatPolyCtx, (ptr), \ + (alphaRatio), (step)) + +#define DynaActorAnimatedMat_Destroy(this) \ + { \ + if (this->dyna.actor.animMatCtx.stateList != NULL) { \ + SYSTEM_ARENA_FREE(this->dyna.actor.animMatCtx.stateList); \ + } \ + \ + if (this->dyna.animMatPolyCtx.polyBackupList != NULL) { \ + SYSTEM_ARENA_FREE(this->dyna.animMatPolyCtx.polyBackupList); \ + } \ + } #endif diff --git a/include/event_manager.h b/include/event_manager.h new file mode 100644 index 000000000..90f4c07df --- /dev/null +++ b/include/event_manager.h @@ -0,0 +1,252 @@ +#ifndef EVENT_MANAGER_H +#define EVENT_MANAGER_H + +#include "ultra64.h" +#include "config.h" +#include "command_macros_base.h" + +typedef enum EventCondition { + EVENT_COND_NONE, + EVENT_COND_EQUAL, // b == a + EVENT_COND_DIFF, // b != a + EVENT_COND_INFERIOR, // b < a + EVENT_COND_SUPERIOR, // b > a + EVENT_COND_INFERIOR_EQ, // b <= a + EVENT_COND_SUPERIOR_EQ, // b >= a +} EventCondition; + +typedef enum EventFlagType { + EVENT_FLAG_TYPE_SWITCH_FLAG, + EVENT_FLAG_TYPE_EVENTCHKINF_FLAG, + EVENT_FLAG_TYPE_INF_FLAG, + EVENT_FLAG_TYPE_COLLECTIBLE_FLAG, + EVENT_FLAG_TYPE_TREASURE_FLAG, + EVENT_FLAG_TYPE_TEMPCLEAR_FLAG, + EVENT_FLAG_TYPE_CLEAR_FLAG, + EVENT_FLAG_TYPE_MAX, +} EventFlagType; + +typedef enum EventInvType { + EVENT_INV_TYPE_ITEMS, + EVENT_INV_TYPE_EQUIPMENT, + EVENT_INV_TYPE_QUEST, + EVENT_INV_TYPE_DUNGEON_ITEMS, + EVENT_INV_TYPE_DUNGEON_KEYS, + EVENT_INV_TYPE_GS_TOKENS, + EVENT_INV_TYPE_MAX, +} EventInvType; + +typedef enum EventGameType { + EVENT_GAME_TYPE_AGE, + EVENT_GAME_TYPE_HEALTH, + EVENT_GAME_TYPE_RUPEES, + EVENT_GAME_TYPE_MAGIC, + EVENT_GAME_TYPE_INVENTORY, + EVENT_GAME_TYPE_MAX, +} EventGameType; + +typedef enum EventTimeType { + EVENT_TIME_TYPE_CLOCK, + EVENT_TIME_TYPE_CONDITIONAL, + EVENT_TIME_TYPE_DAY, + EVENT_TIME_TYPE_NIGHT, + EVENT_TIME_TYPE_MAX, +} EventTimeType; + +// only used by the system using this +//! TODO: add a type that can let a draw to complete its loop before freezing +typedef enum EventActionType { + EVENT_ACTION_TYPE_NONE, // no special behavior + EVENT_ACTION_TYPE_INVERTED, // inverts the event behavior + EVENT_ACTION_TYPE_INVERTED_KEEP, // same as above but allows to continue to draw the last state +} EventActionType; + +typedef enum EventType { + EVENT_TYPE_NONE, + EVENT_TYPE_FLAG, + EVENT_TYPE_GAME, + EVENT_TYPE_TIME, + EVENT_TYPE_MAX, +} EventType; + +typedef union EventData { + s32 i; + f32 f; + s16 s[2]; + s8 b[4]; +} EventData; + +typedef union EventFlag { + struct { + u32 type; // see EventFlagType + u32 flag; + }; + s32 _words[2]; +} EventFlag; + +typedef union EventGame { + struct { + u8 type; // see EventGameType + u8 condType; // see EventCondition + union { + // EVENT_GAME_TYPE_AGE + s8 age; + + // EVENT_GAME_TYPE_HEALTH + s16 health; + + // EVENT_GAME_TYPE_RUPEES + s16 rupees; + + // EVENT_GAME_TYPE_MAGIC + s8 magic; + + // EVENT_GAME_TYPE_INVENTORY + struct { + u8 type; // see EventInvType + union { + u8 itemId; + u8 upgradeType; + u8 unused; + u8 sceneId; + u8 questItem; + }; + union { + // EVENT_INV_TYPE_ITEMS and EVENT_INV_TYPE_DUNGEON_KEYS + struct { + u8 obtained; + union { + s8 amount; // EVENT_INV_TYPE_ITEMS: -1 means no ammo check + + // EVENT_INV_TYPE_EQUIPMENT + u8 swordHealth; // -1 means no sword health check + u8 upgradeValue; + }; + }; + + // EVENT_INV_TYPE_DUNGEON_ITEMS + + // EVENT_INV_TYPE_GS_TOKENS + s16 gsTokens; + }; + } inventory; + }; + }; + s32 _words[2]; +} EventGame; + +typedef union EventTime { + struct { + u8 type; // see EventTimeType + u8 isClock; // set to true to check for a specific time range + union { + u8 isRange; + u8 nightFlag; // 0 for day, 1 for night + }; + struct { + u8 condType; + u8 hour; + u8 minute; + } clocks[2]; + }; + s32 _words[3]; +} EventTime; + +typedef struct EventScriptEntry { + EventData* script; // list of events to process, must be the same size as keyframeList + u8 actionType; // see EventActionType +} EventScriptEntry; + +struct GameState; + +u8 EventManager_GetFreezeType(void); +u8 EventManager_ProcessScript(struct GameState* gameState, EventScriptEntry* eventEntry); + +// useful macros to declare an event entry + +// generic flag macro +#define EVENT_FLAG(type, flag) EVENT_TYPE_FLAG, CMD_W((type)), CMD_W((flag)) + +// specific flag macros +#define EVENT_SWITCH_FLAG(flag) EVENT_FLAG(EVENT_FLAG_TYPE_SWITCH_FLAG, (flag)) +#define EVENT_EVENTCHKINF_FLAG(flag) EVENT_FLAG(EVENT_FLAG_TYPE_EVENTCHKINF_FLAG, (flag)) +#define EVENT_INF_FLAG(flag) EVENT_FLAG(EVENT_FLAG_TYPE_INF_FLAG, (flag)) +#define EVENT_COLLECTIBLE_FLAG(flag) EVENT_FLAG(EVENT_FLAG_TYPE_COLLECTIBLE_FLAG, (flag)) +#define EVENT_TREASURE_FLAG(flag) EVENT_FLAG(EVENT_FLAG_TYPE_TREASURE_FLAG, (flag)) +#define EVENT_TEMPCLEAR_FLAG(flag) EVENT_FLAG(EVENT_FLAG_TYPE_TEMPCLEAR_FLAG, (flag)) +#define EVENT_CLEAR_FLAG(flag) EVENT_FLAG(EVENT_FLAG_TYPE_CLEAR_FLAG, (flag)) + +// age macro +#define EVENT_AGE(age) EVENT_TYPE_GAME, CMD_BBBB(EVENT_GAME_TYPE_AGE, 0, (age), 0), CMD_W(0) + +// health macro +#define EVENT_HEALTH(condType, amount) \ + EVENT_TYPE_GAME, CMD_BBBB(EVENT_GAME_TYPE_HEALTH, (condType), 0, (amount)), CMD_W(0) + +// rupees macro +#define EVENT_RUPEES(condType, amount) \ + EVENT_TYPE_GAME, CMD_BBBB(EVENT_GAME_TYPE_RUPEES, (condType), 0, (amount)), CMD_W(0) + +// magic macro +#define EVENT_MAGIC(condType, amount) \ + EVENT_TYPE_GAME, CMD_BBBB(EVENT_GAME_TYPE_MAGIC, (condType), 0, (amount)), CMD_W(0) + +// generic item macro +#define EVENT_ITEM_BASE(condType, itemId, obtained, amount) \ + EVENT_TYPE_GAME, CMD_BBBB(EVENT_GAME_TYPE_INVENTORY, (condType), EVENT_INV_TYPE_ITEMS, (itemId)), \ + CMD_BBH((obtained), (amount), 0) + +// item macro (either the player has the item or not) +#define EVENT_ITEM(itemId, obtained) EVENT_ITEM_BASE(EVENT_COND_NONE, itemId, obtained, -1) + +// ammo macro (same as above but also check the amount) +#define EVENT_ITEM_AMMO(condType, itemId, amount) EVENT_ITEM_BASE(condType, itemId, true, amount) + +// generic equipment macro +#define EVENT_EQUIPMENT_BASE(condType, itemIdOrUpgradeType, obtained, healthOrUpgrade) \ + EVENT_TYPE_GAME, CMD_BBBB(EVENT_GAME_TYPE_INVENTORY, (condType), EVENT_INV_TYPE_EQUIPMENT, (itemIdOrUpgradeType)), \ + CMD_BBH((obtained), (healthOrUpgrade), 0) + +// equipment macro (either the player has the equipment or not) +#define EVENT_EQUIPMENT(itemId, obtained) EVENT_EQUIPMENT_BASE(EVENT_COND_NONE, itemId, obtained, -1) + +// biggoron sword macro (same as above but also check the sword's health) +#define EVENT_EQUIPMENT_BGS(condType, swordHealth) \ + EVENT_EQUIPMENT_BASE(condType, ITEM_SWORD_BIGGORON, true, swordHealth) + +// upgrade macro +#define EVENT_EQUIPMENT_UPG(condType, upgradeType, upgradeValue) \ + EVENT_EQUIPMENT_BASE(condType, upgradeType, true, upgradeValue) + +// quest items +#define EVENT_QUEST_ITEM(questItem, obtained) \ + EVENT_TYPE_GAME, CMD_BBBB(EVENT_GAME_TYPE_INVENTORY, EVENT_COND_NONE, EVENT_INV_TYPE_QUEST, (questItem)), \ + CMD_BBH((obtained), 0, 0) + +// skulltula tokens +#define EVENT_GS_TOKEN(condType, gsTokens) \ + EVENT_TYPE_GAME, CMD_BBBB(EVENT_GAME_TYPE_INVENTORY, (condType), EVENT_INV_TYPE_GS_TOKENS, 0), CMD_HH((gsTokens), 0) + +// generic time macro +#define EVENT_TIME(type, isClock, isRangeOrNightFlag, condType1, hour1, minute1, condType2, hour2, minute2) \ + EVENT_TYPE_TIME, CMD_BBBB((type), (isClock), (isRangeOrNightFlag), (condType1)), \ + CMD_BBBB((hour1), (minute1), (condType2), (hour2)), CMD_BBH((minute2), 0, 0) + +// specific time of day +#define EVENT_TIME_CLOCK(condType, hour, minute) \ + EVENT_TIME(EVENT_TIME_TYPE_CLOCK, true, false, condType, hour, minute, 0, 0, 0) + +// conditional clock (for example: time1 != CLOCK_TIME(10, 0) && time2 < CLOCK_TIME(15, 0) +#define EVENT_TIME_CONDITIONAL(condType1, hour1, minute1, condType2, hour2, minute2) \ + EVENT_TIME(EVENT_TIME_TYPE_CONDITIONAL, true, true, condType1, hour1, minute1, condType2, hour2, minute2) + +// check if this is currently daytime +#define EVENT_TIME_DAY() EVENT_TIME(EVENT_TIME_TYPE_DAY, false, 0, 0, 0, 0, 0, 0, 0) + +// checks if the this is currently nighttime +#define EVENT_TIME_NIGHT() EVENT_TIME(EVENT_TIME_TYPE_NIGHT, false, 1, 0, 0, 0, 0, 0, 0) + +// the process will end whenever this is the next type (or if an unknown type is found) +#define EVENT_END() EVENT_TYPE_NONE + +#endif diff --git a/include/gfx.h b/include/gfx.h index 5860f50b9..1af292f81 100644 --- a/include/gfx.h +++ b/include/gfx.h @@ -133,6 +133,7 @@ void Graph_ThreadEntry(void*); extern u64 gMojiFontTLUTs[4][4]; // original name: "moji_tlut" extern u64 gMojiFontTex[]; // original name: "font_ff" +extern Gfx* gPrevTaskWorkBuffer; /** * `x` vertex x diff --git a/include/play_state.h b/include/play_state.h index ed3481fed..9cde99927 100644 --- a/include/play_state.h +++ b/include/play_state.h @@ -129,6 +129,9 @@ typedef struct PlayState { /* 0x1242C */ SceneTableEntry* loadedScene; #if ENABLE_ANIMATED_MATERIALS AnimatedMaterial* sceneMaterialAnims; + AnimatedMatContext sceneAnimMatCtx; + AnimatedMatPolyContext sceneAnimMatPolyCtx; + u16 sceneMaterialAnimCamParams; #endif #if ENABLE_CUTSCENE_IMPROVEMENTS ActorCsCamInfo* actorCsCamList; diff --git a/include/scene.h b/include/scene.h index bbd5d7404..ca1fe0127 100644 --- a/include/scene.h +++ b/include/scene.h @@ -236,9 +236,9 @@ typedef struct SCmdOccPlaneCandList { #endif #if ENABLE_ANIMATED_MATERIALS -typedef struct { +typedef struct SCmdTextureAnimations { /* 0x0 */ u8 code; - /* 0x1 */ u8 data1; + /* 0x2 */ u8 camParams; /* 0x4 */ void* segment; } SCmdTextureAnimations; // size = 0x8 #endif @@ -603,8 +603,8 @@ typedef enum SceneCommandTypeID { #endif #if ENABLE_ANIMATED_MATERIALS -#define SCENE_CMD_ANIMATED_MATERIAL_LIST(matAnimList) \ - { SCENE_CMD_ID_ANIMATED_MATERIAL_LIST, 0, CMD_PTR(matAnimList) } +#define SCENE_CMD_ANIMATED_MATERIAL_LIST(matAnimList, camParams) \ + { SCENE_CMD_ID_ANIMATED_MATERIAL_LIST, camParams, CMD_PTR(matAnimList) } #endif #if ENABLE_CUTSCENE_IMPROVEMENTS diff --git a/include/sys_matrix.h b/include/sys_matrix.h index 4917bc83b..093019255 100644 --- a/include/sys_matrix.h +++ b/include/sys_matrix.h @@ -64,8 +64,8 @@ Mtx* Matrix_Finalize(struct GraphicsContext* gfxCtx); #endif -#define MATRIX_FINALIZE_AND_LOAD(pkt, gfxCtx, file, line) \ - gSPMatrix(pkt, MATRIX_FINALIZE(gfxCtx, file, line), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW) +#define MATRIX_FINALIZE_AND_LOAD(pkt, gfxCtx, ...) \ + gSPMatrix(pkt, MATRIX_FINALIZE(gfxCtx, __FILE__, __LINE__), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW) /* Vector operations */ diff --git a/spec/spec b/spec/spec index a2535f78b..dec12359c 100644 --- a/spec/spec +++ b/spec/spec @@ -835,6 +835,7 @@ beginseg include "$(BUILD_DIR)/src/code/rainbow.o" include "$(BUILD_DIR)/src/code/helpers.o" + include "$(BUILD_DIR)/src/code/event_manager.o" #if ENABLE_ANIMATED_MATERIALS include "$(BUILD_DIR)/src/code/animated_materials.o" #endif diff --git a/src/code/animated_materials.c b/src/code/animated_materials.c index 186ff15fd..39820a598 100644 --- a/src/code/animated_materials.c +++ b/src/code/animated_materials.c @@ -3,85 +3,185 @@ #include "config.h" #include "gfx.h" #include "segmented_address.h" +#include "event_manager.h" +#include "printf.h" +#include "array_count.h" +#include "attributes.h" #include "play_state.h" +#include "save.h" +#include "z_lib.h" +#include "sys_matrix.h" +#include "libc64/malloc.h" + +extern Gfx* gPrevTaskWorkBuffer; #if ENABLE_ANIMATED_MATERIALS -static s32 sMatAnimStep; -static u32 sMatAnimFlags; -static f32 sMatAnimAlphaRatio; +extern void func_8009BEEC(PlayState* play); + +static s32 sMatAnimStep = 0; +static s32 sScrollStep = 0; +static s32 sPrevMatAnimStep = 0; +static u32 sMatAnimFlags = 0; +static f32 sMatAnimAlphaRatio = 0.0f; + +void AnimatedMat_Init(GameState* gameState, AnimatedMatContext* animMatCtx, AnimatedMatPolyContext* animMatPolyCtx, + AnimatedMaterial* matAnim) { + u8 arrayCount = 0; + + memset(animMatCtx, 0, sizeof(AnimatedMatContext)); + animMatCtx->stateList = NULL; + + if (matAnim != NULL && matAnim->segment != 0) { + s32 segment; + + do { + segment = matAnim->segment; + + if (matAnim->type == ANIM_MAT_TYPE_SURFACE_SWAP) { + AnimatedMat_InitSurfaceSwap(gameState, animMatPolyCtx, SEGMENTED_TO_VIRTUAL(matAnim->params)); + } + + matAnim++; + arrayCount++; + } while (segment >= 0); + } + + if (arrayCount != 0) { + animMatCtx->stateList = SYSTEM_ARENA_MALLOC(sizeof(AnimatedMatState) * arrayCount); + ASSERT(animMatCtx->stateList != NULL, "animMatCtx->stateList is NULL :(", __FILE__, __LINE__); + memset(animMatCtx->stateList, 0, sizeof(AnimatedMatState) * arrayCount); + } +} + +void AnimatedMat_SetSegment(GameState* gameState, u8 segment, void* data) { + OPEN_DISPS(gameState->gfxCtx); + + if (sMatAnimFlags & 1) { + gSPSegment(POLY_OPA_DISP++, segment, data); + } + + if (sMatAnimFlags & 2) { + gSPSegment(POLY_XLU_DISP++, segment, data); + } + + CLOSE_DISPS(gameState->gfxCtx); +} + +void AnimatedMat_SetDisplayList(GameState* gameState, Gfx** ppDisplayList, u8 segment, void* data) { + OPEN_DISPS(gameState->gfxCtx); + + gSPDisplayList((*ppDisplayList)++, data); + + CLOSE_DISPS(gameState->gfxCtx); +} + +void AnimatedMat_SetDefaultDL(GameState* gameState, Gfx** ppDisplayList, u8 envAlpha) { + OPEN_DISPS(gameState->gfxCtx); + + gSPDisplayList((*ppDisplayList)++, gEmptyDL); + gDPPipeSync((*ppDisplayList)++); + gDPSetPrimColor((*ppDisplayList)++, 0, 0, 255, 255, 255, 255); + gDPSetEnvColor((*ppDisplayList)++, 128, 128, 128, envAlpha); + + CLOSE_DISPS(gameState->gfxCtx); +} + +void AnimatedMat_UpdateStep(AnimatedMatState* matState) { + if (matState->step == sPrevMatAnimStep) { + matState->step = sMatAnimStep; + } else if (matState->step != sMatAnimStep) { + matState->step++; + } +} + +// returning false means the caller will return early +u8 AnimatedMat_ProcessFreeze(AnimatedMatState* matState, u8 allowDraw) { + if (matState->actionType == EVENT_ACTION_TYPE_INVERTED || matState->actionType == EVENT_ACTION_TYPE_INVERTED_KEEP) { + if (matState->actionType == EVENT_ACTION_TYPE_INVERTED && allowDraw) { + return false; + } + + if (!allowDraw) { + AnimatedMat_UpdateStep(matState); + } + } else { + if (!allowDraw) { + return false; + } + + AnimatedMat_UpdateStep(matState); + } + + return true; +} /** * Returns a pointer to a single layer texture scroll displaylist. */ -Gfx* AnimatedMat_TexScroll(PlayState* play, AnimatedMatTexScrollParams* params) { - return Gfx_TexScroll(play->state.gfxCtx, params->xStep * sMatAnimStep, -(params->yStep * sMatAnimStep), - params->width, params->height); +Gfx* AnimatedMat_TexScroll(GameState* gameState, AnimatedMatTexScrollParams* params, s32 step) { + return Gfx_TexScroll(gameState->gfxCtx, params->xStep * step, -(params->yStep * step), params->width, + params->height); } /** * Animated Material Type 0: * Scrolls a single layer texture using the provided `AnimatedMatTexScrollParams`. */ -void AnimatedMat_DrawTexScroll(PlayState* play, s32 segment, void* params) { +void AnimatedMat_DrawTexScroll(GameState* gameState, AnimatedMatState* matState, Gfx** ppDisplayList, s32 segment, + void* params, u8 allowDraw) { AnimatedMatTexScrollParams* texScrollParams = (AnimatedMatTexScrollParams*)params; - Gfx* texScrollDList = AnimatedMat_TexScroll(play, texScrollParams); - OPEN_DISPS(play->state.gfxCtx); - - if (sMatAnimFlags & 1) { - gSPSegment(POLY_OPA_DISP++, segment, texScrollDList); + if (!AnimatedMat_ProcessFreeze(matState, allowDraw)) { + return; } - if (sMatAnimFlags & 2) { - gSPSegment(POLY_XLU_DISP++, segment, texScrollDList); - } - - CLOSE_DISPS(play->state.gfxCtx); + AnimatedMat_SetDisplayList(gameState, ppDisplayList, segment, + AnimatedMat_TexScroll(gameState, texScrollParams, matState->step)); } /** * Returns a pointer to a two layer texture scroll displaylist. */ -Gfx* AnimatedMat_TwoLayerTexScroll(PlayState* play, AnimatedMatTexScrollParams* params) { - return Gfx_TwoTexScroll(play->state.gfxCtx, 0, params[0].xStep * sMatAnimStep, -(params[0].yStep * sMatAnimStep), - params[0].width, params[0].height, 1, params[1].xStep * sMatAnimStep, - -(params[1].yStep * sMatAnimStep), params[1].width, params[1].height); +Gfx* AnimatedMat_TwoLayerTexScroll(GameState* gameState, AnimatedMatTexScrollParams* params, s32 step, u8 oscillating) { + if (oscillating) { + return Gfx_TwoTexScroll(gameState->gfxCtx, 0, 1023 - ((params[0].xStep * step) % 1024), + -(params[0].yStep * step), params[0].width, params[0].height, 1, params[1].xStep * step, + (u32)(32 * (1.0f * Math_SinS((-(params[1].yStep * step) * 500)))), params[1].width, + params[1].height); + } + + return Gfx_TwoTexScroll(gameState->gfxCtx, 0, params[0].xStep * step, -(params[0].yStep * step), params[0].width, + params[0].height, 1, params[1].xStep * step, -(params[1].yStep * step), params[1].width, + params[1].height); } /** * Animated Material Type 1: * Scrolls a two layer texture using the provided `AnimatedMatTexScrollParams`. */ -void AnimatedMat_DrawTwoTexScroll(PlayState* play, s32 segment, void* params) { +void AnimatedMat_DrawTwoTexScroll(GameState* gameState, AnimatedMatState* matState, Gfx** ppDisplayList, s32 segment, + void* params, u8 allowDraw, u8 oscillating) { AnimatedMatTexScrollParams* texScrollParams = (AnimatedMatTexScrollParams*)params; - Gfx* texScrollDList = AnimatedMat_TwoLayerTexScroll(play, texScrollParams); - OPEN_DISPS(play->state.gfxCtx); - - if (sMatAnimFlags & 1) { - gSPSegment(POLY_OPA_DISP++, segment, texScrollDList); + if (!AnimatedMat_ProcessFreeze(matState, allowDraw)) { + return; } - if (sMatAnimFlags & 2) { - gSPSegment(POLY_XLU_DISP++, segment, texScrollDList); - } - - CLOSE_DISPS(play->state.gfxCtx); + AnimatedMat_SetDisplayList(gameState, ppDisplayList, segment, + AnimatedMat_TwoLayerTexScroll(gameState, texScrollParams, matState->step, oscillating)); } /** * Generates a displaylist that sets the prim and env color, and stores it in the provided segment ID. */ -void AnimatedMat_SetColor(PlayState* play, s32 segment, F3DPrimColor* primColorResult, F3DEnvColor* envColor) { - Gfx* gfx = GRAPH_ALLOC(play->state.gfxCtx, 3 * sizeof(Gfx)); +void AnimatedMat_SetColor(GameState* gameState, Gfx** ppDisplayList, s32 segment, F3DPrimColor* primColorResult, + F3DEnvColor* envColor) { + Gfx* gfx = GRAPH_ALLOC(gameState->gfxCtx, 3 * sizeof(Gfx)); - OPEN_DISPS(play->state.gfxCtx); + AnimatedMat_SetDisplayList(gameState, ppDisplayList, segment, gfx); - // clang-format off - if (sMatAnimFlags & 1) { gSPSegment(POLY_OPA_DISP++, segment, gfx); } - if (sMatAnimFlags & 2) { gSPSegment(POLY_XLU_DISP++, segment, gfx); } - // clang-format on + OPEN_DISPS(gameState->gfxCtx); gDPSetPrimColor(gfx++, 0, primColorResult->lodFrac, primColorResult->r, primColorResult->g, primColorResult->b, (u8)(primColorResult->a * sMatAnimAlphaRatio)); @@ -92,25 +192,32 @@ void AnimatedMat_SetColor(PlayState* play, s32 segment, F3DPrimColor* primColorR gSPEndDisplayList(gfx++); - CLOSE_DISPS(play->state.gfxCtx); + CLOSE_DISPS(gameState->gfxCtx); } /** * Animated Material Type 2: * Color key frame animation without linear interpolation. */ -void AnimatedMat_DrawColor(PlayState* play, s32 segment, void* params) { +void AnimatedMat_DrawColor(GameState* gameState, AnimatedMatState* matState, Gfx** ppDisplayList, s32 segment, + void* params, u8 allowDraw) { AnimatedMatColorParams* colorAnimParams = (AnimatedMatColorParams*)params; F3DPrimColor* primColor = SEGMENTED_TO_VIRTUAL(colorAnimParams->primColors); F3DEnvColor* envColor; - s32 curFrame = sMatAnimStep % colorAnimParams->keyFrameLength; + s32 curFrame; + + if (!AnimatedMat_ProcessFreeze(matState, allowDraw)) { + return; + } + + curFrame = matState->step % colorAnimParams->keyFrameLength; primColor += curFrame; envColor = (colorAnimParams->envColors != NULL) ? (F3DEnvColor*)SEGMENTED_TO_VIRTUAL(colorAnimParams->envColors) + curFrame : NULL; - AnimatedMat_SetColor(play, segment, primColor, envColor); + AnimatedMat_SetColor(gameState, ppDisplayList, segment, primColor, envColor); } /** @@ -124,12 +231,13 @@ s32 AnimatedMat_Lerp(s32 min, s32 max, f32 norm) { * Animated Material Type 3: * Color key frame animation with linear interpolation. */ -void AnimatedMat_DrawColorLerp(PlayState* play, s32 segment, void* params) { +void AnimatedMat_DrawColorLerp(GameState* gameState, AnimatedMatState* matState, Gfx** ppDisplayList, s32 segment, + void* params, u8 allowDraw) { AnimatedMatColorParams* colorAnimParams = (AnimatedMatColorParams*)params; F3DPrimColor* primColorMax = SEGMENTED_TO_VIRTUAL(colorAnimParams->primColors); F3DEnvColor* envColorMax; u16* keyFrames = SEGMENTED_TO_VIRTUAL(colorAnimParams->keyFrames); - s32 curFrame = sMatAnimStep % colorAnimParams->keyFrameLength; + s32 curFrame; s32 endFrame; s32 relativeFrame; // relative to the start frame s32 startFrame; @@ -140,6 +248,12 @@ void AnimatedMat_DrawColorLerp(PlayState* play, s32 segment, void* params) { F3DEnvColor envColorResult; s32 i; + if (!AnimatedMat_ProcessFreeze(matState, allowDraw)) { + return; + } + + curFrame = matState->step % colorAnimParams->keyFrameLength; + keyFrames++; i = 1; @@ -176,19 +290,21 @@ void AnimatedMat_DrawColorLerp(PlayState* play, s32 segment, void* params) { envColorMax = NULL; } - AnimatedMat_SetColor(play, segment, &primColorResult, (envColorMax != NULL) ? &envColorResult : NULL); + AnimatedMat_SetColor(gameState, ppDisplayList, segment, &primColorResult, + (envColorMax != NULL) ? &envColorResult : NULL); } /** * Animated Material Type 4: * Color key frame animation with non-linear interpolation. */ -void AnimatedMat_DrawColorNonLinearInterp(PlayState* play, s32 segment, void* params) { +void AnimatedMat_DrawColorNonLinearInterp(GameState* gameState, AnimatedMatState* matState, Gfx** ppDisplayList, + s32 segment, void* params, u8 allowDraw) { AnimatedMatColorParams* colorAnimParams = (AnimatedMatColorParams*)params; F3DPrimColor* primColorCur = SEGMENTED_TO_VIRTUAL(colorAnimParams->primColors); F3DEnvColor* envColorCur = SEGMENTED_TO_VIRTUAL(colorAnimParams->envColors); u16* keyFrames = SEGMENTED_TO_VIRTUAL(colorAnimParams->keyFrames); - f32 curFrame = sMatAnimStep % colorAnimParams->keyFrameLength; + f32 curFrame = 0.0f; F3DPrimColor primColorResult; F3DEnvColor envColorResult; f32 x[50]; @@ -213,6 +329,12 @@ void AnimatedMat_DrawColorNonLinearInterp(PlayState* play, s32 segment, void* pa f32* fxEnvAPtr = fxEnvA; s32 i; + if (!AnimatedMat_ProcessFreeze(matState, allowDraw)) { + return; + } + + curFrame = matState->step % colorAnimParams->keyFrameLength; + for (i = 0; i < colorAnimParams->keyFrameCount; i++) { *xPtr = *keyFrames; *fxPrimRPtr = primColorCur->r; @@ -261,145 +383,581 @@ void AnimatedMat_DrawColorNonLinearInterp(PlayState* play, s32 segment, void* pa envColorCur = NULL; } - AnimatedMat_SetColor(play, segment, &primColorResult, (envColorCur != NULL) ? &envColorResult : NULL); + AnimatedMat_SetColor(gameState, ppDisplayList, segment, &primColorResult, + (envColorCur != NULL) ? &envColorResult : NULL); } /** * Animated Material Type 5: * Cycles between a list of textures (imagine like a GIF) */ -void AnimatedMat_DrawTexCycle(PlayState* play, s32 segment, void* params) { +void AnimatedMat_DrawTexCycle(GameState* gameState, AnimatedMatState* matState, s32 segment, void* params, + u8 allowDraw) { AnimatedMatTexCycleParams* texAnimParams = params; TexturePtr* texList = SEGMENTED_TO_VIRTUAL(texAnimParams->textureList); u8* texId = SEGMENTED_TO_VIRTUAL(texAnimParams->textureIndexList); - s32 curFrame = sMatAnimStep % texAnimParams->keyFrameLength; - TexturePtr tex = SEGMENTED_TO_VIRTUAL(texList[texId[curFrame]]); + TexturePtr tex = SEGMENTED_TO_VIRTUAL(texList[texId[matState->curFrame]]); - OPEN_DISPS(play->state.gfxCtx); - - if (sMatAnimFlags & 1) { - gSPSegment(POLY_OPA_DISP++, segment, tex); + if (!allowDraw) { + AnimatedMat_SetSegment(gameState, segment, tex); + return; } - if (sMatAnimFlags & 2) { - gSPSegment(POLY_XLU_DISP++, segment, tex); + matState->curFrame = sMatAnimStep % texAnimParams->keyFrameLength; + AnimatedMat_SetSegment(gameState, segment, tex); +} + +void AnimatedMat_DrawColorCycle(GameState* gameState, AnimatedMatState* matState, Gfx** ppDisplayList, s32 segment, + void* params, u8 allowDraw) { + AnimatedMatColorParams* colorAnimParams = (AnimatedMatColorParams*)params; + F3DPrimColor* primColors = SEGMENTED_TO_VIRTUAL(colorAnimParams->primColors); + F3DEnvColor* envColor = NULL; + u16* keyFrames = SEGMENTED_TO_VIRTUAL(colorAnimParams->keyFrames); + + if (!allowDraw) { + AnimatedMat_SetDefaultDL(gameState, ppDisplayList, 128); + return; } - CLOSE_DISPS(play->state.gfxCtx); + // reset values if we reach the end + if (matState->curFrame >= colorAnimParams->keyFrameLength) { + matState->curFrame = 0; + matState->timer = 0; + } + + // draw the color + if (colorAnimParams->envColors != NULL) { + envColor = SEGMENTED_TO_VIRTUAL(colorAnimParams->envColors) + matState->curFrame; + } + + AnimatedMat_SetColor(gameState, ppDisplayList, segment, &primColors[matState->curFrame], envColor); + + // finally, increase the timer until we reach the target then go to the next keyframe and reset the timer + if (matState->timer < keyFrames[matState->curFrame]) { + matState->timer++; + } else { + matState->curFrame++; + matState->timer = 0; + } +} + +void AnimatedMat_DrawTexTimedCycle(GameState* gameState, AnimatedMatState* matState, s32 segment, void* params, + u8 allowDraw) { + AnimatedMatTexTimedCycleParams* animParams = params; + AnimatedMatTexTimedCycleKeyframe* keyframeList = SEGMENTED_TO_VIRTUAL(animParams->keyframeList); + u16 targetTime; + TexturePtr texture; + + if (matState->curFrame >= animParams->keyframeLength) { + matState->curFrame = 0; + matState->timer = 0; + } + + AnimatedMat_SetSegment(gameState, segment, SEGMENTED_TO_VIRTUAL(keyframeList[matState->curFrame].texture)); + + if (allowDraw) { + if (matState->timer < keyframeList[matState->curFrame].displayTime) { + matState->timer++; + } else { + matState->curFrame++; + matState->timer = 0; + } + } +} + +void AnimatedMat_DrawTexture(GameState* gameState, AnimatedMatState* matState, s32 segment, void* params, + u8 allowDraw) { + AnimatedMatTextureParams* animParams = params; + AnimatedMat_SetSegment(gameState, segment, SEGMENTED_TO_VIRTUAL(animParams->textures[allowDraw == true])); +} + +void AnimatedMat_SetMaxAlpha(s16* pAlpha, s16 max, s8 speed) { + if (max == -1) { + return; + } + + if ((*pAlpha + speed) <= max) { + if (*pAlpha <= max) { + *pAlpha += speed; + } + } else { + *pAlpha = max; + } +} + +void AnimatedMat_SetMinAlpha(s16* pAlpha, s16 min, s8 speed) { + if (min == -1) { + return; + } + + if ((*pAlpha - speed) > min) { + if (*pAlpha > min) { + *pAlpha -= speed; + } + } else { + *pAlpha = min; + } +} + +void AnimatedMat_DrawMultiTexture(GameState* gameState, AnimatedMatState* matState, s32 segment, void* params, + u8 allowDraw) { + AnimatedMatMultiTextureParams* animParams = params; + s16 primAlpha = animParams->maxPrimAlpha; + s16 envAlpha = animParams->maxEnvAlpha; + u8 doBlend = animParams->speed > 0; + + if (animParams->texture1 != NULL && animParams->segment1 > 0) { + AnimatedMat_SetSegment(gameState, animParams->segment1, SEGMENTED_TO_VIRTUAL(animParams->texture1)); + } + + if (animParams->texture2 != NULL && animParams->segment2 > 0) { + AnimatedMat_SetSegment(gameState, animParams->segment2, SEGMENTED_TO_VIRTUAL(animParams->texture2)); + } + + if (allowDraw) { + if (matState->firstTime) { + matState->firstTime = false; + } + + if (doBlend) { + AnimatedMat_SetMinAlpha(&matState->primAlpha, animParams->minPrimAlpha, animParams->speed); + AnimatedMat_SetMaxAlpha(&matState->envAlpha, animParams->maxEnvAlpha, animParams->speed); + } else { + envAlpha = animParams->maxEnvAlpha; + } + } else if (doBlend) { + if (matState->firstTime) { + matState->primAlpha = 255; + + if (animParams->maxPrimAlpha != -1) { + matState->primAlpha = animParams->maxPrimAlpha; + } + } else { + AnimatedMat_SetMaxAlpha(&matState->primAlpha, animParams->maxPrimAlpha, animParams->speed); + AnimatedMat_SetMinAlpha(&matState->envAlpha, animParams->minEnvAlpha, animParams->speed); + } + } else { + envAlpha = animParams->minEnvAlpha; + } + + if (doBlend) { + primAlpha = 255 - matState->primAlpha; + envAlpha = 255 - matState->envAlpha; + } + + OPEN_DISPS(gameState->gfxCtx); + + if (segment >= 0x08 && segment <= 0x0D) { + Gfx* displayListHead = GRAPH_ALLOC(gameState->gfxCtx, 8 * sizeof(Gfx)); + + gSPSegment(POLY_OPA_DISP++, segment, displayListHead); + gDPPipeSync(displayListHead++); + gDPSetPrimColor(displayListHead++, 0, 0, 255, 255, 255, primAlpha); + gDPSetEnvColor(displayListHead++, 128, 128, 128, envAlpha); + gSPEndDisplayList(displayListHead++); + } + + CLOSE_DISPS(gameState->gfxCtx); +} + +void AnimatedMat_DrawEvent(GameState* gameState, AnimatedMatState* matState, Gfx** ppDisplayList, s32 segment, + UNUSED void* params, u8 allowDraw) { + Matrix_Push(); + + OPEN_DISPS(gameState->gfxCtx); + + if (allowDraw) { + Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_NEW); + } else { + Matrix_Scale(0.0f, 0.0f, 0.0f, MTXMODE_NEW); + } + + Gfx* displayListHead = GRAPH_ALLOC(gameState->gfxCtx, 3 * sizeof(Gfx)); + gSPSegment((*ppDisplayList)++, segment, displayListHead); + gDPPipeSync(displayListHead++); + MATRIX_FINALIZE_AND_LOAD(displayListHead++, gameState->gfxCtx); + gSPEndDisplayList(displayListHead++); + + CLOSE_DISPS(gameState->gfxCtx); + + Matrix_Pop(); +} + +void AnimatedMat_InitSurfaceSwap(GameState* gameState, AnimatedMatPolyContext* animMatPolyCtx, void* params) { + PlayState* play = (PlayState*)gameState; + AnimatedMatSurfaceSwapParams* animParams = params; + SurfaceType* curSurface; + + if (animMatPolyCtx == NULL) { + PRINTF("[HackerOoT:Warning]: Animated Material Collision Poly Context is NULL\n"); + return; + } + + animMatPolyCtx->polyBackupList = NULL; + animMatPolyCtx->triCount = 0; + + if (animParams->triIndices[0] == (u16)-1) { + animMatPolyCtx->polyBackupList = SYSTEM_ARENA_MALLOC(sizeof(CollisionPolyBackup)); + ASSERT(animMatPolyCtx->polyBackupList != NULL, "animMatPolyCtx->polyBackupList is NULL...", __FILE__, __LINE__); + + curSurface = &play->colCtx.colHeader->surfaceTypeList[animParams->surfaceType]; + animMatPolyCtx->polyBackupList[0].surfaceType.data[0] = curSurface->data[0]; + animMatPolyCtx->polyBackupList[0].surfaceType.data[1] = curSurface->data[1]; + } else { + u16* triList = animParams->triIndices; + s32 i; + + // figure out how many entries the list contains + while (*triList != (u16)-1) { + animMatPolyCtx->triCount++; + triList++; + } + + // allocate the list + animMatPolyCtx->polyBackupList = SYSTEM_ARENA_MALLOC(sizeof(CollisionPolyBackup) * animMatPolyCtx->triCount); + ASSERT(animMatPolyCtx->polyBackupList != NULL, "animMatPolyCtx->polyBackupList is NULL!!!", __FILE__, __LINE__); + + // create the backup + for (i = 0; i < animMatPolyCtx->triCount; i++) { + CollisionPoly* curPoly = &play->colCtx.colHeader->polyList[animParams->triIndices[i]]; + curSurface = &play->colCtx.colHeader->surfaceTypeList[curPoly->type]; + + animMatPolyCtx->polyBackupList[i].surfaceType.data[0] = curSurface->data[0]; + animMatPolyCtx->polyBackupList[i].surfaceType.data[1] = curSurface->data[1]; + animMatPolyCtx->polyBackupList[i].flags_vIA = curPoly->flags_vIA; + animMatPolyCtx->polyBackupList[i].flags_vIB = curPoly->flags_vIB; + } + } + + ASSERT(animMatPolyCtx->polyBackupList != NULL, "animMatPolyCtx->polyBackupList is NULL???", __FILE__, __LINE__); +} + +void AnimatedMat_SetSurfaceType(GameState* gameState, AnimatedMatPolyContext* animMatPolyCtx, + AnimatedMatSurfaceSwapParams* animParams, s32 index, u16 type, u8 allowDraw) { + SurfaceType* curSurface = &((PlayState*)gameState)->colCtx.colHeader->surfaceTypeList[type]; + + if (allowDraw) { + curSurface->data[0] = animParams->surface.data[0]; + curSurface->data[1] = animParams->surface.data[1]; + } else { + curSurface->data[0] = animMatPolyCtx->polyBackupList[index].surfaceType.data[0]; + curSurface->data[1] = animMatPolyCtx->polyBackupList[index].surfaceType.data[1]; + } +} + +void AnimatedMat_SetCollisionPolyFlags(GameState* gameState, AnimatedMatPolyContext* animMatPolyCtx, + AnimatedMatSurfaceSwapParams* animParams, s32 index, u8 allowDraw) { + CollisionPoly* curPoly = &((PlayState*)gameState)->colCtx.colHeader->polyList[animParams->triIndices[index]]; + + if (allowDraw) { + curPoly->flags_vIA = + COLPOLY_VTX(COLPOLY_VTX_INDEX(animMatPolyCtx->polyBackupList[index].flags_vIA), animParams->flags_vIA); + curPoly->flags_vIB = + COLPOLY_VTX(COLPOLY_VTX_INDEX(animMatPolyCtx->polyBackupList[index].flags_vIB), animParams->flags_vIB); + } else { + curPoly->flags_vIA = animMatPolyCtx->polyBackupList[index].flags_vIA; + curPoly->flags_vIB = animMatPolyCtx->polyBackupList[index].flags_vIB; + } +} + +void AnimatedMat_DrawSurfaceSwap(GameState* gameState, AnimatedMatState* matState, + AnimatedMatPolyContext* animMatPolyCtx, s32 segment, void* params, u8 allowDraw) { + AnimatedMatSurfaceSwapParams* animParams = params; + + if (gSaveContext.gameMode == GAMEMODE_NORMAL) { + PlayState* play = (PlayState*)gameState; + CollisionPoly* curPoly; + u16* triList = animParams->triIndices; + s32 i; + + if (matState->prevAllowDraw != allowDraw) { + if (animMatPolyCtx->triCount == 0) { + AnimatedMat_SetSurfaceType(gameState, animMatPolyCtx, animParams, 0, animParams->surfaceType, + allowDraw); + } else { + for (i = 0; i < animMatPolyCtx->triCount; i++) { + curPoly = &play->colCtx.colHeader->polyList[animParams->triIndices[i]]; + + AnimatedMat_SetSurfaceType(gameState, animMatPolyCtx, animParams, i, curPoly->type, allowDraw); + AnimatedMat_SetCollisionPolyFlags(gameState, animMatPolyCtx, animParams, i, allowDraw); + } + } + + matState->prevAllowDraw = allowDraw; + } + } + + if (animParams->textureParams != NULL) { + AnimatedMat_DrawMultiTexture(gameState, matState, segment, SEGMENTED_TO_VIRTUAL(animParams->textureParams), + allowDraw); + } +} + +void AnimatedMat_DrawEventColor(GameState* gameState, AnimatedMatState* matState, Gfx** ppDisplayList, s32 segment, + void* params, u8 allowDraw) { + AnimatedMatColorSwitchParams* animParams = params; + F3DPrimColor* primColor = &animParams->primColors[allowDraw == true]; + F3DEnvColor* envColor = NULL; + + if (animParams->useEnvColor[allowDraw == true]) { + envColor = &animParams->envColors[allowDraw == true]; + } + + AnimatedMat_SetColor(gameState, ppDisplayList, segment, primColor, envColor); +} + +void AnimatedMat_ScreenDistortion(PlayState* play) { + static s16 D_8012A39C = 538; + static s16 D_8012A3A0 = 4272; + f32 temp; + + D_8012A39C += 1820; + D_8012A3A0 += 1820; + + temp = 0.020000001f; + View_SetDistortionOrientation(&play->view, + ((360.00018f / 65535.0f) * (M_PI / 180.0f)) * temp * Math_CosS(D_8012A39C), + ((360.00018f / 65535.0f) * (M_PI / 180.0f)) * temp * Math_SinS(D_8012A39C), + ((360.00018f / 65535.0f) * (M_PI / 180.0f)) * temp * Math_SinS(D_8012A3A0)); + View_SetDistortionScale(&play->view, 1.f + (0.79999995f * temp * Math_SinS(D_8012A3A0)), + 1.f + (0.39999998f * temp * Math_CosS(D_8012A3A0)), + 1.f + (1 * temp * Math_CosS(D_8012A39C))); + View_SetDistortionSpeed(&play->view, 0.95f); } /** * This is the main function that handles the animated material system. * There are six different animated material types, which should be set in the provided `AnimatedMaterial`. */ -void AnimatedMat_DrawMain(PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step, u32 flags) { - static void (*sMatAnimDrawHandlers[ANIM_MAT_TYPE_MAX])(PlayState*, s32 segment, void* params) = { - AnimatedMat_DrawTexScroll, // ANIM_MAT_TYPE_TEX_SCROLL - AnimatedMat_DrawTwoTexScroll, // ANIM_MAT_TYPE_TWO_TEX_SCROLL - AnimatedMat_DrawColor, // ANIM_MAT_TYPE_COLOR - AnimatedMat_DrawColorLerp, // ANIM_MAT_TYPE_COLOR_LERP - AnimatedMat_DrawColorNonLinearInterp, // ANIM_MAT_TYPE_COLOR_NON_LINEAR_INTERP - AnimatedMat_DrawTexCycle, // ANIM_MAT_TYPE_TEX_CYCLE - }; +void AnimatedMat_DrawMain(GameState* gameState, AnimatedMatContext* animMatCtx, AnimatedMatPolyContext* animMatPolyCtx, + AnimatedMaterial* matAnim, f32 alphaRatio, u32 step, u32 flags) { s32 segmentAbs; s32 segment; + Gfx* pDisplayList = NULL; + Gfx* displayListHead = NULL; + s32 prevSegment = 0; sMatAnimAlphaRatio = alphaRatio; sMatAnimStep = step; sMatAnimFlags = flags; - if ((matAnim != NULL) && (matAnim->segment != 0)) { + if (matAnim != NULL && matAnim->segment != 0) { + s32 i = 0; + do { + void* params = SEGMENTED_TO_VIRTUAL(matAnim->params); + u8 allowDraw = true; + AnimatedMatState* matState = &animMatCtx->stateList[i]; + + OPEN_DISPS(gameState->gfxCtx); + segment = matAnim->segment; - segmentAbs = ABS(segment) + 7; - sMatAnimDrawHandlers[matAnim->type](play, segmentAbs, SEGMENTED_TO_VIRTUAL(matAnim->params)); + segmentAbs = ABS(segment); + + if (prevSegment != segmentAbs) { + displayListHead = pDisplayList = GRAPH_ALLOC(gameState->gfxCtx, sizeof(Gfx) * 0x20); + prevSegment = segmentAbs; + } + + AnimatedMat_SetSegment(gameState, segmentAbs, displayListHead); + gDPPipeSync(pDisplayList++); + + matState->actionType = EVENT_ACTION_TYPE_NONE; + if (matAnim->eventEntry != NULL) { + allowDraw = EventManager_ProcessScript(gameState, SEGMENTED_TO_VIRTUAL(matAnim->eventEntry)); + matState->actionType = EventManager_GetFreezeType(); + } + + // process camera/screen effects + if (gSaveContext.gameMode == GAMEMODE_NORMAL) { + PlayState* play = (PlayState*)gameState; + u16 camParams = play->sceneMaterialAnimCamParams; + s16 camType = MATERIAL_CAM_TYPE(camParams); + u8 onEvent = MATERIAL_CAM_ON_EVENT(camParams); + + if (!onEvent || allowDraw) { + if (camType != ANIM_MAT_CAMERA_TYPE_NONE) { + + switch (camType) { + case ANIM_MAT_CAMERA_TYPE_SHAKE: + func_8009BEEC(play); + break; + case ANIM_MAT_CAMERA_TYPE_DISTORTION: + AnimatedMat_ScreenDistortion(play); + break; + default: + break; + } + } + } + } + + switch (matAnim->type) { + case ANIM_MAT_TYPE_TEX_SCROLL: + AnimatedMat_DrawTexScroll(gameState, matState, &pDisplayList, segmentAbs, params, allowDraw); + break; + case ANIM_MAT_TYPE_TWO_TEX_SCROLL: + AnimatedMat_DrawTwoTexScroll(gameState, matState, &pDisplayList, segmentAbs, params, allowDraw, + false); + break; + case ANIM_MAT_TYPE_COLOR: + AnimatedMat_DrawColor(gameState, matState, &pDisplayList, segmentAbs, params, allowDraw); + break; + case ANIM_MAT_TYPE_COLOR_LERP: + AnimatedMat_DrawColorLerp(gameState, matState, &pDisplayList, segmentAbs, params, allowDraw); + break; + case ANIM_MAT_TYPE_COLOR_NON_LINEAR_INTERP: + AnimatedMat_DrawColorNonLinearInterp(gameState, matState, &pDisplayList, segmentAbs, params, + allowDraw); + break; + case ANIM_MAT_TYPE_COLOR_CYCLE: + AnimatedMat_DrawColorCycle(gameState, matState, &pDisplayList, segmentAbs, params, allowDraw); + break; + case ANIM_MAT_TYPE_EVENT: + AnimatedMat_DrawEvent(gameState, matState, &pDisplayList, segmentAbs, NULL, allowDraw); + break; + case ANIM_MAT_TYPE_OSCILLATING_TWO_TEX: + AnimatedMat_DrawTwoTexScroll(gameState, matState, &pDisplayList, segmentAbs, params, allowDraw, + true); + break; + case ANIM_MAT_TYPE_TEX_CYCLE: + AnimatedMat_DrawTexCycle(gameState, matState, segmentAbs, params, allowDraw); + break; + case ANIM_MAT_TYPE_TEX_TIMED_CYCLE: + AnimatedMat_DrawTexTimedCycle(gameState, matState, segmentAbs, params, allowDraw); + break; + case ANIM_MAT_TYPE_TEXTURE: + AnimatedMat_DrawTexture(gameState, matState, segmentAbs, params, allowDraw); + break; + case ANIM_MAT_TYPE_MULTITEXTURE: + AnimatedMat_DrawMultiTexture(gameState, matState, segmentAbs, params, allowDraw); + break; + case ANIM_MAT_TYPE_SURFACE_SWAP: + AnimatedMat_DrawSurfaceSwap(gameState, matState, animMatPolyCtx, segmentAbs, params, allowDraw); + break; + case ANIM_MAT_TYPE_COLOR_SWITCH: + AnimatedMat_DrawEventColor(gameState, matState, &pDisplayList, segmentAbs, params, allowDraw); + break; + default: + AnimatedMat_SetDefaultDL(gameState, &pDisplayList, 128); + break; + } + matAnim++; + if (pDisplayList != NULL && prevSegment != ABS(matAnim->segment)) { + gSPEndDisplayList(pDisplayList++); + } + + CLOSE_DISPS(gameState->gfxCtx); + + i++; } while (segment >= 0); } + + if (sPrevMatAnimStep != sMatAnimStep) { + sPrevMatAnimStep = sMatAnimStep; + } } /** * Draws an animated material to both OPA and XLU buffers. */ -void AnimatedMat_Draw(PlayState* play, AnimatedMaterial* matAnim) { - AnimatedMat_DrawMain(play, matAnim, 1, play->gameplayFrames, 3); +void AnimatedMat_Draw(GameState* gameState, AnimatedMatContext* animMatCtx, AnimatedMatPolyContext* animMatPolyCtx, + u32 gameplayFrames, AnimatedMaterial* matAnim) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, 1, gameplayFrames, 3); } /** * Draws an animated material to only the OPA buffer. */ -void AnimatedMat_DrawOpa(PlayState* play, AnimatedMaterial* matAnim) { - AnimatedMat_DrawMain(play, matAnim, 1, play->gameplayFrames, 1); +void AnimatedMat_DrawOpa(GameState* gameState, AnimatedMatContext* animMatCtx, AnimatedMatPolyContext* animMatPolyCtx, + u32 gameplayFrames, AnimatedMaterial* matAnim) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, 1, gameplayFrames, 1); } /** * Draws an animated material to only the XLU buffer. */ -void AnimatedMat_DrawXlu(PlayState* play, AnimatedMaterial* matAnim) { - AnimatedMat_DrawMain(play, matAnim, 1, play->gameplayFrames, 2); +void AnimatedMat_DrawXlu(GameState* gameState, AnimatedMatContext* animMatCtx, AnimatedMatPolyContext* animMatPolyCtx, + u32 gameplayFrames, AnimatedMaterial* matAnim) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, 1, gameplayFrames, 2); } /** * Draws an animated material with an alpha ratio (0.0 - 1.0) both OPA and XLU buffers. */ -void AnimatedMat_DrawAlpha(PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio) { - AnimatedMat_DrawMain(play, matAnim, alphaRatio, play->gameplayFrames, 3); +void AnimatedMat_DrawAlpha(GameState* gameState, AnimatedMatContext* animMatCtx, AnimatedMatPolyContext* animMatPolyCtx, + u32 gameplayFrames, AnimatedMaterial* matAnim, f32 alphaRatio) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, alphaRatio, gameplayFrames, 3); } /** * Draws an animated material with an alpha ratio (0.0 - 1.0) to only the OPA buffer. */ -void AnimatedMat_DrawAlphaOpa(PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio) { - AnimatedMat_DrawMain(play, matAnim, alphaRatio, play->gameplayFrames, 1); +void AnimatedMat_DrawAlphaOpa(GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, u32 gameplayFrames, AnimatedMaterial* matAnim, + f32 alphaRatio) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, alphaRatio, gameplayFrames, 1); } /** * Draws an animated material with an alpha ratio (0.0 - 1.0) to only the XLU buffer. */ -void AnimatedMat_DrawAlphaXlu(PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio) { - AnimatedMat_DrawMain(play, matAnim, alphaRatio, play->gameplayFrames, 2); +void AnimatedMat_DrawAlphaXlu(GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, u32 gameplayFrames, AnimatedMaterial* matAnim, + f32 alphaRatio) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, alphaRatio, gameplayFrames, 2); } /** * Draws an animated material with a step to both the OPA and XLU buffers. */ -void AnimatedMat_DrawStep(PlayState* play, AnimatedMaterial* matAnim, u32 step) { - AnimatedMat_DrawMain(play, matAnim, 1, step, 3); +void AnimatedMat_DrawStep(GameState* gameState, AnimatedMatContext* animMatCtx, AnimatedMatPolyContext* animMatPolyCtx, + AnimatedMaterial* matAnim, u32 step) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, 1, step, 3); } /** * Draws an animated material with a step to only the OPA buffer. */ -void AnimatedMat_DrawStepOpa(PlayState* play, AnimatedMaterial* matAnim, u32 step) { - AnimatedMat_DrawMain(play, matAnim, 1, step, 1); +void AnimatedMat_DrawStepOpa(GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, u32 step) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, 1, step, 1); } /** * Draws an animated material with a step to only the XLU buffer. */ -void AnimatedMat_DrawStepXlu(PlayState* play, AnimatedMaterial* matAnim, u32 step) { - AnimatedMat_DrawMain(play, matAnim, 1, step, 2); +void AnimatedMat_DrawStepXlu(GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, u32 step) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, 1, step, 2); } /** * Draws an animated material with an alpha ratio (0.0 - 1.0) and a step to both the OPA and XLU buffers. */ -void AnimatedMat_DrawAlphaStep(PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step) { - AnimatedMat_DrawMain(play, matAnim, alphaRatio, step, 3); +void AnimatedMat_DrawAlphaStep(GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, f32 alphaRatio, + u32 step) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, alphaRatio, step, 3); } /** * Draws an animated material with an alpha ratio (0.0 - 1.0) and a step to only the OPA buffer. */ -void AnimatedMat_DrawAlphaStepOpa(PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step) { - AnimatedMat_DrawMain(play, matAnim, alphaRatio, step, 1); +void AnimatedMat_DrawAlphaStepOpa(GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, f32 alphaRatio, + u32 step) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, alphaRatio, step, 1); } /** * Draws an animated material with an alpha ratio (0.0 - 1.0) and a step to only the XLU buffer. */ -void AnimatedMat_DrawAlphaStepXlu(PlayState* play, AnimatedMaterial* matAnim, f32 alphaRatio, u32 step) { - AnimatedMat_DrawMain(play, matAnim, alphaRatio, step, 2); +void AnimatedMat_DrawAlphaStepXlu(GameState* gameState, AnimatedMatContext* animMatCtx, + AnimatedMatPolyContext* animMatPolyCtx, AnimatedMaterial* matAnim, f32 alphaRatio, + u32 step) { + AnimatedMat_DrawMain(gameState, animMatCtx, animMatPolyCtx, matAnim, alphaRatio, step, 2); } #endif diff --git a/src/code/event_manager.c b/src/code/event_manager.c new file mode 100644 index 000000000..bd140b453 --- /dev/null +++ b/src/code/event_manager.c @@ -0,0 +1,275 @@ +#include "segmented_address.h" +#include "play_state.h" +#include "printf.h" +#include "save.h" +#include "array_count.h" +#include "event_manager.h" + +#define STRINGIFY(s) #s +#define EXPAND_AND_STRINGIFY(s) STRINGIFY(s) +#define log(...) PRINTF("Line " EXPAND_AND_STRINGIFY(__LINE__) " - " __VA_ARGS__); + +static u8 EventManager_UnsignedCondition(u8 condType, u32 a, u32 b); +static u8 EventManager_SignedCondition(u8 condType, s32 a, s32 b); +static void EventManager_ProcessFlag(GameState* gameState, EventFlag* event, u8* pabFlags); +static void EventManager_ProcessGame(GameState* gameState, EventGame* event, u8* pabGame); +static void EventManager_ProcessTime(GameState* gameState, EventTime* event, u8* pabTime); +static u8 EventManager_Validate(u8* pabType, u8 length); + +static u8 sEventActionType = EVENT_ACTION_TYPE_NONE; + +// probably dumb +#define EventManager_ConditionImpl(condType, a, b) \ + { \ + switch ((condType)) { \ + case EVENT_COND_EQUAL: \ + return (b) == (a); \ + case EVENT_COND_DIFF: \ + return (b) != (a); \ + case EVENT_COND_INFERIOR: \ + return (b) < (a); \ + case EVENT_COND_SUPERIOR: \ + return (b) > (a); \ + case EVENT_COND_INFERIOR_EQ: \ + return (b) <= (a); \ + case EVENT_COND_SUPERIOR_EQ: \ + return (b) >= (a); \ + default: \ + break; \ + } \ + } + +// most likely unnecessary but to make sure it's fine +static u8 EventManager_UnsignedCondition(u8 condType, u32 a, u32 b) { + EventManager_ConditionImpl(condType, a, b); + return true; +} + +static u8 EventManager_SignedCondition(u8 condType, s32 a, s32 b) { + EventManager_ConditionImpl(condType, a, b); + return true; +} + +// performs the necessary checks to handle flag events +static void EventManager_ProcessFlag(GameState* gameState, EventFlag* event, u8* pabFlags) { + PlayState* play = (PlayState*)gameState; + u8 allowDraw = true; + + // make sure this is the play state + if (gSaveContext.gameMode == GAMEMODE_NORMAL) { + switch (event->type) { + case EVENT_FLAG_TYPE_SWITCH_FLAG: + allowDraw = Flags_GetSwitch(play, event->flag) != 0; + break; + case EVENT_FLAG_TYPE_EVENTCHKINF_FLAG: + allowDraw = Flags_GetEventChkInf(event->flag) != 0; + break; + case EVENT_FLAG_TYPE_INF_FLAG: + allowDraw = Flags_GetInfTable(event->flag) != 0; + break; + case EVENT_FLAG_TYPE_COLLECTIBLE_FLAG: + allowDraw = Flags_GetCollectible(play, event->flag) != 0; + break; + case EVENT_FLAG_TYPE_TREASURE_FLAG: + allowDraw = Flags_GetTreasure(play, event->flag) != 0; + break; + case EVENT_FLAG_TYPE_TEMPCLEAR_FLAG: + allowDraw = Flags_GetTempClear(play, event->flag) != 0; + break; + case EVENT_FLAG_TYPE_CLEAR_FLAG: + allowDraw = Flags_GetClear(play, event->flag) != 0; + break; + default: + break; + } + } + + pabFlags[event->type] = allowDraw; +} + +// performs the necessary checks to handle game events +static void EventManager_ProcessGame(GameState* gameState, EventGame* event, u8* pabGame) { + u8 allowDraw = true; + u8 value; + + switch (event->type) { + case EVENT_GAME_TYPE_AGE: + allowDraw = event->age == gSaveContext.save.linkAge; + break; + case EVENT_GAME_TYPE_HEALTH: + allowDraw = + EventManager_SignedCondition(event->condType, event->health, gSaveContext.save.info.playerData.health); + break; + case EVENT_GAME_TYPE_RUPEES: + allowDraw = + EventManager_SignedCondition(event->condType, event->rupees, gSaveContext.save.info.playerData.rupees); + break; + case EVENT_GAME_TYPE_MAGIC: + allowDraw = + EventManager_SignedCondition(event->condType, event->magic, gSaveContext.save.info.playerData.magic); + break; + case EVENT_GAME_TYPE_INVENTORY: + if (event->inventory.itemId == ITEM_NONE) { + break; + } + + switch (event->inventory.type) { + case EVENT_INV_TYPE_ITEMS: + value = gSaveContext.save.info.inventory.items[event->inventory.itemId]; + allowDraw = event->inventory.obtained ? value != ITEM_NONE : value == ITEM_NONE; + + if (event->inventory.amount >= 0) { + allowDraw = allowDraw && EventManager_SignedCondition(event->condType, event->inventory.amount, + AMMO(event->inventory.itemId)); + } + break; + case EVENT_INV_TYPE_EQUIPMENT: + // swords, shields, tunics and boots + if (event->inventory.itemId >= ITEM_SWORD_KOKIRI && event->inventory.itemId <= ITEM_BOOTS_HOVER) { + u8 itemId = event->inventory.itemId - ITEM_SWORD_KOKIRI; + value = CHECK_OWNED_EQUIP(itemId / 3, itemId % 3); + allowDraw = event->inventory.obtained ? value : !value; + + if (event->inventory.itemId == ITEM_SWORD_BIGGORON && event->inventory.swordHealth != (u8)-1) { + allowDraw = allowDraw && + EventManager_UnsignedCondition(event->condType, event->inventory.swordHealth, + gSaveContext.save.info.playerData.swordHealth); + } + + break; + } + + // upgrades + if (event->inventory.upgradeType < UPG_MAX) { + allowDraw = EventManager_UnsignedCondition(event->condType, event->inventory.upgradeValue, + CUR_UPG_VALUE(event->inventory.upgradeType)); + break; + } + break; + case EVENT_INV_TYPE_QUEST: + value = CHECK_QUEST_ITEM(event->inventory.questItem); + allowDraw = event->inventory.obtained ? value : !value; + break; + //! TODO: improve how dungeon items are handled in the game + // case EVENT_INV_TYPE_DUNGEON_ITEMS: + // break; + // case EVENT_INV_TYPE_DUNGEON_KEYS: + // if (event->inventory.sceneId < ARRAY_COUNT(gSaveContext.save.info.inventory.dungeonKeys)) { + // allowDraw = EventManager_SignedCondition(event->condType, event->inventory.amount, + // gSaveContext.save.info.inventory.dungeonKeys[event->inventory.sceneId]); + // } + // break; + case EVENT_INV_TYPE_GS_TOKENS: + if (!CHECK_QUEST_ITEM(QUEST_SKULL_TOKEN)) { + allowDraw = false; + break; + } + + allowDraw = EventManager_SignedCondition(event->condType, event->inventory.gsTokens, + gSaveContext.save.info.inventory.gsTokens); + break; + default: + break; + } + break; + default: + break; + } + + pabGame[event->type] = allowDraw; +} + +// performs the necessary checks to handle time events +static void EventManager_ProcessTime(GameState* gameState, EventTime* event, u8* pabTime) { + u8 allowDraw = true; + + if (event->isClock) { + allowDraw = EventManager_UnsignedCondition(event->clocks[0].condType, + CLOCK_TIME(event->clocks[0].hour, event->clocks[0].minute), + gSaveContext.save.dayTime); + + if (event->isRange) { + allowDraw = + allowDraw && EventManager_UnsignedCondition(event->clocks[1].condType, + CLOCK_TIME(event->clocks[1].hour, event->clocks[1].minute), + gSaveContext.save.dayTime); + } + } else { + allowDraw = event->nightFlag == gSaveContext.save.nightFlag; + } + + pabTime[event->type] = allowDraw; +} + +// returns false if a bool is in the array +static u8 EventManager_Validate(u8* pabType, u8 length) { + u8 i; + + for (i = 0; i < length; i++) { + if (!pabType[i]) { + return false; + } + } + + return true; +} + +u8 EventManager_GetFreezeType(void) { + return sEventActionType; +} + +// returns true when it should draw, otherwise returns false +u8 EventManager_ProcessScript(GameState* gameState, EventScriptEntry* eventEntry) { + static u8 abFlag[EVENT_FLAG_TYPE_MAX]; + static u8 abGame[EVENT_GAME_TYPE_MAX]; + static u8 abTime[EVENT_TIME_TYPE_MAX]; + u8* script; + s32 eventType; + s32 i; + + script = SEGMENTED_TO_VIRTUAL(eventEntry->script); + sEventActionType = eventEntry->actionType; + + memset(abFlag, true, sizeof(abFlag)); + memset(abGame, true, sizeof(abGame)); + memset(abTime, true, sizeof(abTime)); + + do { + memcpy(&eventType, script, sizeof(eventType)); + script += sizeof(eventType); + + switch (eventType) { + case EVENT_TYPE_NONE: + break; + case EVENT_TYPE_FLAG: + EventManager_ProcessFlag(gameState, (void*)script, abFlag); + script += sizeof(EventFlag); + break; + case EVENT_TYPE_GAME: + EventManager_ProcessGame(gameState, (void*)script, abGame); + script += sizeof(EventGame); + break; + case EVENT_TYPE_TIME: + EventManager_ProcessTime(gameState, (void*)script, abTime); + script += sizeof(EventTime); + break; + default: + eventType = EVENT_TYPE_NONE; + break; + } + } while (eventType != EVENT_TYPE_NONE); + + if (!EventManager_Validate(abFlag, ARRAY_COUNT(abFlag))) { + return false; + } + + if (!EventManager_Validate(abGame, ARRAY_COUNT(abGame))) { + return false; + } + + if (!EventManager_Validate(abTime, ARRAY_COUNT(abTime))) { + return false; + } + + return true; +} diff --git a/src/code/graph.c b/src/code/graph.c index 4ae2e5f35..3afbb22ee 100644 --- a/src/code/graph.c +++ b/src/code/graph.c @@ -72,6 +72,8 @@ UCodeInfo D_8012D248[3] = { { UCODE_TYPE_S2DEX, gspS2DEX2d_fifoTextStart }, }; +Gfx* gPrevTaskWorkBuffer = NULL; + void Graph_FaultClient(void) { void* nextFb = osViGetNextFramebuffer(); void* newFb = (SysCfb_GetFbPtr(0) != nextFb) ? SysCfb_GetFbPtr(0) : SysCfb_GetFbPtr(1); @@ -210,7 +212,6 @@ void Graph_Destroy(GraphicsContext* gfxCtx) { void Graph_TaskSet00(GraphicsContext* gfxCtx) { #if DEBUG_FEATURES - static Gfx* sPrevTaskWorkBuffer = NULL; #endif OSTask_t* task = &gfxCtx->task.list.t; OSScTask* scTask = &gfxCtx->task; @@ -236,11 +237,11 @@ void Graph_TaskSet00(GraphicsContext* gfxCtx) { LogUtils_LogHexDump(gGfxSPTaskYieldBuffer, sizeof(gGfxSPTaskYieldBuffer)); SREG(6) = -1; - if (sPrevTaskWorkBuffer != NULL) { + if (gPrevTaskWorkBuffer != NULL) { R_HREG_MODE = HREG_MODE_UCODE_DISAS; R_UCODE_DISAS_TOGGLE = 1; R_UCODE_DISAS_LOG_LEVEL = 2; - Graph_DisassembleUCode(sPrevTaskWorkBuffer); + Graph_DisassembleUCode(gPrevTaskWorkBuffer); } #endif @@ -250,7 +251,7 @@ void Graph_TaskSet00(GraphicsContext* gfxCtx) { osRecvMesg(&gfxCtx->queue, &msg, OS_MESG_NOBLOCK); #if DEBUG_FEATURES - sPrevTaskWorkBuffer = gfxCtx->workBuffer; + gPrevTaskWorkBuffer = gfxCtx->workBuffer; #endif } diff --git a/src/code/z_actor.c b/src/code/z_actor.c index ccfe8add5..9937843dc 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -983,6 +983,12 @@ void Actor_Destroy(Actor* actor, PlayState* play) { PRINTF(T("Actorクラス デストラクトがありません [%s]\n", "No Actor class destruct [%s]\n") ACTOR_RST, name); #endif } + +#if ENABLE_ANIMATED_MATERIALS + if (actor->animMatCtx.stateList != NULL) { + SYSTEM_ARENA_FREE(actor->animMatCtx.stateList); + } +#endif } /** diff --git a/src/code/z_kankyo.c b/src/code/z_kankyo.c index 2cc24c454..78ad1fffd 100644 --- a/src/code/z_kankyo.c +++ b/src/code/z_kankyo.c @@ -469,9 +469,6 @@ void Environment_Init(PlayState* play2, EnvironmentContext* envCtx, s32 unused) sLightningBolts[i].state = LIGHTNING_BOLT_INACTIVE; } - play->roomCtx.drawParams[0] = 0; - play->roomCtx.drawParams[1] = 0; - for (i = 0; i < ARRAY_COUNT(play->csCtx.actorCues); i++) { play->csCtx.actorCues[i] = NULL; } @@ -1009,21 +1006,20 @@ void Environment_Update(PlayState* play, EnvironmentContext* envCtx, LightContex } #if CAN_SHOW_TIME_INFOS - if (R_ENABLE_ARENA_DBG != 0 || CREG(2) != 0) { - Gfx* displayList; - Gfx* prevDisplayList; + Gfx* displayList; + Gfx* prevDisplayList; - OPEN_DISPS(play->state.gfxCtx, "../z_kankyo.c", 1682); + OPEN_DISPS(play->state.gfxCtx, "../z_kankyo.c", 1682); - prevDisplayList = POLY_OPA_DISP; - displayList = Gfx_Open(POLY_OPA_DISP); - gSPDisplayList(OVERLAY_DISP++, displayList); - Environment_PrintDebugInfo(play, &displayList); - gSPEndDisplayList(displayList++); - Gfx_Close(prevDisplayList, displayList); - POLY_OPA_DISP = displayList; - CLOSE_DISPS(play->state.gfxCtx, "../z_kankyo.c", 1690); - } + prevDisplayList = POLY_OPA_DISP; + displayList = Gfx_Open(POLY_OPA_DISP); + gSPDisplayList(OVERLAY_DISP++, displayList); + Environment_PrintDebugInfo(play, &displayList); + gSPEndDisplayList(displayList++); + Gfx_Close(prevDisplayList, displayList); + POLY_OPA_DISP = displayList; + + CLOSE_DISPS(play->state.gfxCtx, "../z_kankyo.c", 1690); #endif if ((envCtx->lightSettingOverride != LIGHT_SETTING_OVERRIDE_NONE) && diff --git a/src/code/z_play.c b/src/code/z_play.c index 9808ec18d..8e8584172 100644 --- a/src/code/z_play.c +++ b/src/code/z_play.c @@ -50,6 +50,7 @@ #include "occlusionplanes.h" #include "libu64/gfxprint.h" #include "debug.h" +#include "animated_materials.h" #if CAN_INCLUDE_EXAMPLE_SCENE #include "assets/scenes/example/example_scene.h" @@ -269,6 +270,16 @@ void Play_Destroy(GameState* thisx) { this->state.gfxCtx->callback = NULL; this->state.gfxCtx->callbackParam = NULL; +#if ENABLE_ANIMATED_MATERIALS + if (this->sceneAnimMatCtx.stateList != NULL) { + SYSTEM_ARENA_FREE(this->sceneAnimMatCtx.stateList); + } + + if (this->sceneAnimMatPolyCtx.polyBackupList != NULL) { + SYSTEM_ARENA_FREE(this->sceneAnimMatPolyCtx.polyBackupList); + } +#endif + #if IS_MOTION_BLUR_ENABLED Play_DestroyMotionBlur(); #endif @@ -1881,6 +1892,9 @@ void Play_InitScene(PlayState* this, s32 spawn) { #if ENABLE_ANIMATED_MATERIALS this->sceneMaterialAnims = NULL; + this->sceneMaterialAnimCamParams = MATERIAL_CAM_PARAMS(ANIM_MAT_CAMERA_TYPE_NONE, false); + this->sceneAnimMatCtx.stateList = NULL; + this->sceneAnimMatPolyCtx.polyBackupList = NULL; #endif #if ENABLE_CUTSCENE_IMPROVEMENTS @@ -1897,6 +1911,10 @@ void Play_InitScene(PlayState* this, s32 spawn) { gSaveContext.worldMapArea = WORLD_MAP_AREA_HYRULE_FIELD; Scene_ExecuteCommands(this, this->sceneSegment); Play_InitEnvironment(this, this->skyboxId); + +#if ENABLE_ANIMATED_MATERIALS + AnimatedMat_Init(&this->state, &this->sceneAnimMatCtx, &this->sceneAnimMatPolyCtx, this->sceneMaterialAnims); +#endif } void Play_SpawnScene(PlayState* this, s32 sceneId, s32 spawn) { diff --git a/src/code/z_scene.c b/src/code/z_scene.c index 479b1099c..5140cdb83 100644 --- a/src/code/z_scene.c +++ b/src/code/z_scene.c @@ -526,6 +526,7 @@ void Scene_SetTransitionForNextEntrance(PlayState* play) { #if ENABLE_ANIMATED_MATERIALS void Scene_CommandAnimatedMaterials(PlayState* play, SceneCmd* cmd) { play->sceneMaterialAnims = SEGMENTED_TO_VIRTUAL(cmd->textureAnimations.segment); + play->sceneMaterialAnimCamParams = cmd->textureAnimations.camParams; } #endif diff --git a/src/code/z_scene_table.c b/src/code/z_scene_table.c index f6ce52eff..107bba035 100644 --- a/src/code/z_scene_table.c +++ b/src/code/z_scene_table.c @@ -1754,7 +1754,8 @@ void Scene_DrawConfigBesitu(PlayState* play) { * Allows the usage of the animated material system in scenes. */ void Scene_DrawConfigMatAnim(PlayState* play) { - AnimatedMat_Draw(play, play->sceneMaterialAnims); + AnimatedMat_Draw(&play->state, &play->sceneAnimMatCtx, &play->sceneAnimMatPolyCtx, play->gameplayFrames, + play->sceneMaterialAnims); } /** @@ -1762,7 +1763,8 @@ void Scene_DrawConfigMatAnim(PlayState* play) { * rather than always animating like `Scene_DrawConfigMatAnim`. */ void Scene_DrawConfigMatAnimManualStep(PlayState* play) { - AnimatedMat_DrawStep(play, play->sceneMaterialAnims, play->roomCtx.drawParams[0]); + AnimatedMat_DrawStep(&play->state, &play->sceneAnimMatCtx, &play->sceneAnimMatPolyCtx, play->sceneMaterialAnims, + play->roomCtx.drawParams[0]); } #endif