1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-07-12 02:44:54 +00:00

Merge commit 'b2d80568b9' into doc_pause_menu

This commit is contained in:
Dragorn421 2024-08-01 21:29:29 +02:00
commit dc599911db
No known key found for this signature in database
GPG key ID: 381AEBAF3D429335
78 changed files with 5742 additions and 5952 deletions

View file

@ -1,4 +1,4 @@
#include "global.h"
#include "ultra64.h"
/**
* memcpy: copies `len` bytes from memory starting at `src` to memory starting at `dest`. Expects the memory

View file

@ -48,9 +48,9 @@
// just above (the exact upper bound depends on the block numbers assigned to
// extern variables declared in headers).
#if OOT_DEBUG
#pragma increment_block_number 20
#pragma increment_block_number 0
#else
#pragma increment_block_number 25
#pragma increment_block_number 20
#endif
void FaultDrawer_Init(void);

View file

@ -1,4 +1,4 @@
#include "global.h"
#include "ultra64.h"
/**
* Computes one `x` modulo `y` for floats.

View file

@ -1,4 +1,5 @@
#include "global.h"
#include "z64math.h"
#include "macros.h"
s32 gUseAtanContFrac;

View file

@ -41,7 +41,7 @@
*
* @note Original name: qrand.c
*/
#include "ultra64.h"
#include "rand.h"
#define RAND_MULTIPLIER 1664525
#define RAND_INCREMENT 1013904223

View file

@ -1,4 +1,4 @@
#include "global.h"
#include "sys_math.h"
f32 sFactorialTbl[] = { 1.0f, 1.0f, 2.0f, 6.0f, 24.0f, 120.0f, 720.0f,
5040.0f, 40320.0f, 362880.0f, 3628800.0f, 39916800.0f, 479001600.0f };

View file

@ -1,9 +1,13 @@
#include "global.h"
#include "ultra64.h"
#include "z_lib.h"
#include "z64math.h"
#include "terminal.h"
#include "macros.h"
#include "sys_math3d.h"
// For retail BSS ordering, the block number of cbf in Math3D_CylVsCylOverlapCenterDist
// must be 0.
#pragma increment_block_number 187
#pragma increment_block_number 111
s32 Math3D_LineVsLineClosestTwoPoints(Vec3f* lineAPointA, Vec3f* lineAPointB, Vec3f* lineBPointA, Vec3f* lineBPointB,
Vec3f* lineAClosestToB, Vec3f* lineBClosestToA);
@ -2147,11 +2151,3 @@ s32 Math3D_YZInSphere(Sphere16* sphere, f32 y, f32 z) {
}
return false;
}
#if OOT_DEBUG
void Math3D_DrawSphere(PlayState* play, Sphere16* sph) {
}
void Math3D_DrawCylinder(PlayState* play, Cylinder16* cyl) {
}
#endif

View file

@ -0,0 +1,7 @@
#include "z64.h"
void Math3D_DrawSphere(PlayState* play, Sphere16* sph) {
}
void Math3D_DrawCylinder(PlayState* play, Cylinder16* cyl) {
}

View file

@ -1,4 +1,5 @@
#include "global.h"
#include "z64math.h"
#include "macros.h"
static u16 sAtan2Tbl[] = {
0x0000, 0x000A, 0x0014, 0x001F, 0x0029, 0x0033, 0x003D, 0x0047, 0x0051, 0x005C, 0x0066, 0x0070, 0x007A, 0x0084,

View file

@ -2452,7 +2452,7 @@ void Actor_DrawLensActors(PlayState* play, s32 numInvisibleActors, Actor** invis
gDPPipeSync(POLY_XLU_DISP++);
if (play->roomCtx.curRoom.lensMode == LENS_MODE_HIDE_ACTORS) {
if (play->roomCtx.curRoom.lensMode == LENS_MODE_SHOW_ACTORS) {
// Update both the color frame buffer and the z-buffer
gDPSetOtherMode(POLY_XLU_DISP++,
G_AD_DISABLE | G_CD_MAGICSQ | G_CK_NONE | G_TC_FILT | G_TF_BILERP | G_TT_NONE | G_TL_TILE |
@ -2501,7 +2501,7 @@ void Actor_DrawLensActors(PlayState* play, s32 numInvisibleActors, Actor** invis
// "Magic lens invisible Actor display END"
gDPNoOpString(POLY_OPA_DISP++, "魔法のメガネ 見えないc表示 END", numInvisibleActors);
if (play->roomCtx.curRoom.lensMode != LENS_MODE_HIDE_ACTORS) {
if (play->roomCtx.curRoom.lensMode != LENS_MODE_SHOW_ACTORS) {
// Draw the lens overlay to the color frame buffer
gDPNoOpString(POLY_OPA_DISP++, "青い眼鏡(外側)", 0); // "Blue spectacles (exterior)"
@ -2596,7 +2596,7 @@ void func_800315AC(PlayState* play, ActorContext* actorCtx) {
if (!OOT_DEBUG || (HREG(64) != 1) || ((HREG(65) != -1) && (HREG(65) != HREG(66))) || (HREG(71) == 0)) {
if ((actor->init == NULL) && (actor->draw != NULL) && (actor->flags & (ACTOR_FLAG_5 | ACTOR_FLAG_6))) {
if ((actor->flags & ACTOR_FLAG_REACT_TO_LENS) &&
((play->roomCtx.curRoom.lensMode == LENS_MODE_HIDE_ACTORS) || play->actorCtx.lensActive ||
((play->roomCtx.curRoom.lensMode == LENS_MODE_SHOW_ACTORS) || play->actorCtx.lensActive ||
(actor->room != play->roomCtx.curRoom.num))) {
ASSERT(invisibleActorCounter < INVISIBLE_ACTOR_MAX,
"invisible_actor_counter < INVISIBLE_ACTOR_MAX", "../z_actor.c", 6464);

View file

@ -2360,9 +2360,6 @@ void CollisionCheck_ATTrisVsACTris(PlayState* play, CollisionCheckContext* colCh
#if OOT_DEBUG
static s8 sBssDummy7;
static s8 sBssDummy8;
static s8 sBssDummy9;
static s8 sBssDummy10;
#endif
void CollisionCheck_ATTrisVsACQuad(PlayState* play, CollisionCheckContext* colChkCtx, Collider* atCol,
@ -3329,12 +3326,10 @@ void Collider_SetTrisDim(PlayState* play, ColliderTris* tris, s32 elemIndex, Col
}
#if OOT_DEBUG
// Due to an unknown reason, bss ordering changed between the 2 static Vec3f variables in the function below.
// In order to reproduce this behavior, we need a specific number of bss variables in the file before that point.
// For this, we introduce a certain amount of dummy variables throughout the file, which we fit inside padding added
// by the compiler between structs like TriNorm and/or Vec3f, so they don't take space in bss.
static s8 sBssDummy11;
static s8 sBssDummy12;
// The two static Vec3f variables in the function below cross a block index rollover, causing a bss order swap.
//! In order to replicate this behavior, we declare a certain amount of sBssDummy variables throughout the file, which
//! we fit inside padding added by the compiler between structs like TriNorm and/or Vec3f, so they don't take space in
//! bss.
#endif
/**

View file

@ -115,6 +115,8 @@ void* sUnusedEntranceCsList[] = {
gDekuTreeIntroCs, gJabuJabuIntroCs, gDcOpeningCs, gMinuetCs, gIceCavernSerenadeCs, gTowerBarrierCs,
};
#pragma increment_block_number 254
// Stores the frame the relevant cam data was last applied on
u16 gCamAtSplinePointsAppliedFrame;
u16 gCamEyePointAppliedFrame;

View file

@ -13,8 +13,7 @@ void GameOver_FadeInLights(PlayState* play) {
}
}
// This variable cannot be moved into this file as all of z_message_PAL rodata is in the way
extern s16 gGameOverTimer;
s16 sGameOverTimer = 0;
void GameOver_Update(PlayState* play) {
GameOverContext* gameOverCtx = &play->gameOverCtx;
@ -74,7 +73,7 @@ void GameOver_Update(PlayState* play) {
gSaveContext.hudVisibilityModeTimer = 0; // false, HUD_VISIBILITY_NO_CHANGE
Environment_InitGameOverLights(play);
gGameOverTimer = 20;
sGameOverTimer = 20;
if (1) {}
rumbleStrength = R_GAME_OVER_RUMBLE_STRENGTH;
@ -92,9 +91,9 @@ void GameOver_Update(PlayState* play) {
break;
case GAMEOVER_DEATH_DELAY_MENU:
gGameOverTimer--;
sGameOverTimer--;
if (gGameOverTimer == 0) {
if (sGameOverTimer == 0) {
play->pauseCtx.state = PAUSE_STATE_8;
gameOverCtx->state++;
Rumble_Reset();
@ -103,13 +102,13 @@ void GameOver_Update(PlayState* play) {
case GAMEOVER_REVIVE_START:
gameOverCtx->state++;
gGameOverTimer = 0;
sGameOverTimer = 0;
Environment_InitGameOverLights(play);
Letterbox_SetSizeTarget(32);
return;
case GAMEOVER_REVIVE_RUMBLE:
gGameOverTimer = 50;
sGameOverTimer = 50;
gameOverCtx->state++;
if (1) {}
@ -123,28 +122,28 @@ void GameOver_Update(PlayState* play) {
break;
case GAMEOVER_REVIVE_WAIT_GROUND:
gGameOverTimer--;
sGameOverTimer--;
if (gGameOverTimer == 0) {
gGameOverTimer = 64;
if (sGameOverTimer == 0) {
sGameOverTimer = 64;
gameOverCtx->state++;
}
break;
case GAMEOVER_REVIVE_WAIT_FAIRY:
gGameOverTimer--;
sGameOverTimer--;
if (gGameOverTimer == 0) {
gGameOverTimer = 50;
if (sGameOverTimer == 0) {
sGameOverTimer = 50;
gameOverCtx->state++;
}
break;
case GAMEOVER_REVIVE_FADE_OUT:
Environment_FadeOutGameOverLights(play);
gGameOverTimer--;
sGameOverTimer--;
if (gGameOverTimer == 0) {
if (sGameOverTimer == 0) {
gameOverCtx->state = GAMEOVER_INACTIVE;
}
break;

View file

@ -7,7 +7,7 @@
// For retail BSS ordering, the block number of sLensFlareUnused must be lower
// than the extern variables declared in the header (e.g. gLightningStrike)
// while the block number of sNGameOverLightNode must be higher.
#pragma increment_block_number 80
#pragma increment_block_number 78
typedef enum {
/* 0x00 */ LIGHTNING_BOLT_START,
@ -215,7 +215,7 @@ s16 sSunDepthTestY;
// These variables could be moved farther down in the file to reduce the amount
// of block number padding here, but currently this causes BSS ordering issues
// for debug.
#pragma increment_block_number 230
#pragma increment_block_number 227
LightNode* sNGameOverLightNode;
LightInfo sNGameOverLightInfo;

View file

@ -1,4 +1,11 @@
#include "global.h"
#include "ultra64.h"
#include "z_lib.h"
#include "ichain.h"
#include "regs.h"
#include "macros.h"
#include "sys_math.h"
#include "rand.h"
#include "sfx.h"
/**
* memset: sets `len` bytes to `val` starting at address `dest`.
@ -334,7 +341,7 @@ void (*sInitChainHandlers[])(u8* ptr, InitChainEntry* ichain) = {
IChain_Apply_Vec3f, IChain_Apply_Vec3fdiv1000, IChain_Apply_Vec3s,
};
void Actor_ProcessInitChain(Actor* actor, InitChainEntry* ichain) {
void Actor_ProcessInitChain(struct Actor* actor, InitChainEntry* ichain) {
do {
sInitChainHandlers[ichain->type]((u8*)actor, ichain);
} while ((ichain++)->cont);

View file

@ -3358,12 +3358,3 @@ void Message_SetTables(void) {
sFraMessageEntryTablePtr = sFraMessageEntryTable;
sStaffMessageEntryTablePtr = sStaffMessageEntryTable;
}
#if OOT_DEBUG
// Appears to be file padding
UNK_TYPE D_80153D7C = 0x00000000;
#endif
// This should be part of z_game_over.c, but cannot be moved there as the entire
// late_rodata section of this file is in the way
s16 gGameOverTimer = 0;

View file

@ -1,4 +1,6 @@
#include "global.h"
#include "z64math.h"
#include "fp_math.h"
#include "z_lib.h"
/**
* Calculates the distances between `a` and `b`

View file

@ -284,7 +284,7 @@ void Play_Init(GameState* thisx) {
Effect_InitContext(this);
EffectSs_InitInfo(this, 0x55);
CollisionCheck_InitContext(this, &this->colChkCtx);
AnimationContext_Reset(&this->animationCtx);
AnimTaskQueue_Reset(&this->animTaskQueue);
Cutscene_InitContext(this, &this->csCtx);
if (gSaveContext.nextCutsceneIndex != 0xFFEF) {
@ -454,7 +454,7 @@ void Play_Init(GameState* thisx) {
gSaveContext.seqId = this->sequenceCtx.seqId;
gSaveContext.natureAmbienceId = this->sequenceCtx.natureAmbienceId;
func_8002DF18(this, GET_PLAYER(this));
AnimationContext_Update(this, &this->animationCtx);
AnimTaskQueue_Update(this, &this->animTaskQueue);
gSaveContext.respawnFlag = 0;
#if OOT_DEBUG
@ -883,7 +883,7 @@ void Play_Update(PlayState* this) {
isPaused = IS_PAUSED(&this->pauseCtx);
PLAY_LOG(3555);
AnimationContext_Reset(&this->animationCtx);
AnimTaskQueue_Reset(&this->animTaskQueue);
if (!OOT_DEBUG) {}
@ -1000,7 +1000,7 @@ void Play_Update(PlayState* this) {
Interface_Update(this);
PLAY_LOG(3765);
AnimationContext_Update(this, &this->animationCtx);
AnimTaskQueue_Update(this, &this->animTaskQueue);
PLAY_LOG(3771);
SfxSource_UpdateAll(this);

View file

@ -1125,7 +1125,8 @@ s32 Player_OverrideLimbDrawGameplayCommon(PlayState* play, s32 limbIndex, Gfx**
sCurBodyPartPos = &this->bodyPartsPos[0] - 1;
if (!LINK_IS_ADULT) {
if (!(this->skelAnime.moveFlags & ANIM_FLAG_PLAYER_2) || (this->skelAnime.moveFlags & ANIM_FLAG_0)) {
if (!(this->skelAnime.moveFlags & ANIM_FLAG_PLAYER_2) ||
(this->skelAnime.moveFlags & ANIM_FLAG_UPDATE_XZ)) {
pos->x *= 0.64f;
pos->z *= 0.64f;
}

View file

@ -9,9 +9,6 @@ s32 SkelAnime_LoopFull(SkelAnime* skelAnime);
s32 SkelAnime_Once(SkelAnime* skelAnime);
s32 SkelAnime_LoopPartial(SkelAnime* skelAnime);
static u32 sDisableAnimQueueFlags = 0;
static u32 sAnimQueueFlags;
/**
* Draw a limb of type `LodLimb`
* Near or far display list is specified via `lod`
@ -798,39 +795,64 @@ void SkelAnime_InterpFrameTable(s32 limbCount, Vec3s* dst, Vec3s* start, Vec3s*
}
}
static u32 sDisabledTransformTaskGroups = 0;
static u32 sCurAnimTaskGroup;
/**
* zeroes out the current request count
* Clear the current task queue. The discarded tasks will then not be processed.
*/
void AnimationContext_Reset(AnimationContext* animationCtx) {
animationCtx->animationCount = 0;
void AnimTaskQueue_Reset(AnimTaskQueue* animTaskQueue) {
animTaskQueue->count = 0;
}
/**
* Shifts the queue flag to the next queue
* Changes `sCurAnimTaskGroup` to the next group number.
*
* Task groups allow for disabling "transformative" tasks for a defined group.
* For more information see `AnimTaskQueue_DisableTransformTasksForGroup`.
*
* Note that `sCurAnimTaskGroup` is not a whole number that increments, it is handled at the bit-level.
* Every time the group number changes, a single bit moves 1 position to the left. This is an implementation detail
* that allows for `sDisabledTransformTaskGroups` to compare against a set of bit flags.
*/
void AnimationContext_SetNextQueue(PlayState* play) {
sAnimQueueFlags <<= 1;
void AnimTaskQueue_SetNextGroup(PlayState* play) {
sCurAnimTaskGroup <<= 1;
}
/**
* Disables the current animation queue. Only load and move actor requests will be processed for that queue.
* Marks the current task group as disabled so that "transformative" tasks are skipped.
* A transformative task is one that will alter the appearance of an animation.
* These include Copy, Interp, CopyUsingMap, and CopyUsingMapInverted.
*
* LoadPlayerFrame and ActorMove, which don't alter the appearance of an existing animation,
* will always run even if a group has its transformative tasks disabled.
*/
void AnimationContext_DisableQueue(PlayState* play) {
sDisableAnimQueueFlags |= sAnimQueueFlags;
void AnimTaskQueue_DisableTransformTasksForGroup(PlayState* play) {
sDisabledTransformTaskGroups |= sCurAnimTaskGroup;
}
AnimationEntry* AnimationContext_AddEntry(AnimationContext* animationCtx, AnimationType type) {
AnimationEntry* entry;
s16 index = animationCtx->animationCount;
/**
* Creates a new task and adds it to the queue, if there is room for it.
*
* The `type` value for the task gets set here, but all other
* initialization must be handled by the caller.
*
* @return a pointer to the task, or NULL if it could not be added
*/
AnimTask* AnimTaskQueue_NewTask(AnimTaskQueue* animTaskQueue, s32 type) {
AnimTask* task;
s16 taskNumber = animTaskQueue->count;
if (index >= ANIMATION_ENTRY_MAX) {
if (taskNumber >= ANIM_TASK_QUEUE_MAX) {
return NULL;
}
animationCtx->animationCount = index + 1;
entry = &animationCtx->entries[index];
entry->type = type;
return entry;
animTaskQueue->count = taskNumber + 1;
task = &animTaskQueue->tasks[taskNumber];
task->type = type;
return task;
}
#define LINK_ANIMATION_OFFSET(addr, offset) \
@ -838,205 +860,230 @@ AnimationEntry* AnimationContext_AddEntry(AnimationContext* animationCtx, Animat
(offset))
/**
* Requests loading frame data from the Link animation into frameTable
* Creates a task which will load a single frame of animation data from the link_animetion file.
* The asynchronous DMA request to load the data is made as soon as the task is created.
* When the task is processed later in the AnimTaskQueue, it will wait for the DMA to finish.
*/
void AnimationContext_SetLoadFrame(PlayState* play, LinkAnimationHeader* animation, s32 frame, s32 limbCount,
Vec3s* frameTable) {
AnimationEntry* entry = AnimationContext_AddEntry(&play->animationCtx, ANIMENTRY_LOADFRAME);
void AnimTaskQueue_AddLoadPlayerFrame(PlayState* play, LinkAnimationHeader* animation, s32 frame, s32 limbCount,
Vec3s* frameTable) {
AnimTask* task = AnimTaskQueue_NewTask(&play->animTaskQueue, ANIMTASK_LOAD_PLAYER_FRAME);
if (entry != NULL) {
if (task != NULL) {
LinkAnimationHeader* linkAnimHeader = SEGMENTED_TO_VIRTUAL(animation);
s32 pad;
osCreateMesgQueue(&entry->data.load.msgQueue, &entry->data.load.msg, 1);
DMA_REQUEST_ASYNC(&entry->data.load.req, frameTable,
osCreateMesgQueue(&task->data.loadPlayerFrame.msgQueue, &task->data.loadPlayerFrame.msg, 1);
DMA_REQUEST_ASYNC(&task->data.loadPlayerFrame.req, frameTable,
LINK_ANIMATION_OFFSET(linkAnimHeader->segment, ((sizeof(Vec3s) * limbCount + 2) * frame)),
sizeof(Vec3s) * limbCount + 2, 0, &entry->data.load.msgQueue, NULL, "../z_skelanime.c", 2004);
sizeof(Vec3s) * limbCount + 2, 0, &task->data.loadPlayerFrame.msgQueue, NULL,
"../z_skelanime.c", 2004);
}
}
/**
* Requests copying all vectors from src frame table into dst frame table
* Creates a task which will copy all vectors from the `src` frame table to the `dest` frame table.
*
* Note: This task is "transformative", meaning it will alter the appearance of an animation.
* If this task's group is included in `sDisabledTransformTaskGroups`, this task will be skipped for that frame.
*/
void AnimationContext_SetCopyAll(PlayState* play, s32 vecCount, Vec3s* dst, Vec3s* src) {
AnimationEntry* entry = AnimationContext_AddEntry(&play->animationCtx, ANIMENTRY_COPYALL);
void AnimTaskQueue_AddCopy(PlayState* play, s32 vecCount, Vec3s* dest, Vec3s* src) {
AnimTask* task = AnimTaskQueue_NewTask(&play->animTaskQueue, ANIMTASK_COPY);
if (entry != NULL) {
entry->data.copy.queueFlag = sAnimQueueFlags;
entry->data.copy.vecCount = vecCount;
entry->data.copy.dst = dst;
entry->data.copy.src = src;
if (task != NULL) {
task->data.copy.group = sCurAnimTaskGroup;
task->data.copy.vecCount = vecCount;
task->data.copy.dest = dest;
task->data.copy.src = src;
}
}
/**
* Requests interpolating between base and mod frame tables with the given weight, placing the result in base
* Creates a task which will interpolate between the `base` and `mod` frame tables.
* The result of the interpolation will be placed in the original `base` table.
*
* Note: This task is "transformative", meaning it will alter the appearance of an animation.
* If this task's group is included in `sDisabledTransformTaskGroups`, this task will be skipped for that frame.
*/
void AnimationContext_SetInterp(PlayState* play, s32 vecCount, Vec3s* base, Vec3s* mod, f32 weight) {
AnimationEntry* entry = AnimationContext_AddEntry(&play->animationCtx, ANIMENTRY_INTERP);
void AnimTaskQueue_AddInterp(PlayState* play, s32 vecCount, Vec3s* base, Vec3s* mod, f32 weight) {
AnimTask* task = AnimTaskQueue_NewTask(&play->animTaskQueue, ANIMTASK_INTERP);
if (entry != NULL) {
entry->data.interp.queueFlag = sAnimQueueFlags;
entry->data.interp.vecCount = vecCount;
entry->data.interp.base = base;
entry->data.interp.mod = mod;
entry->data.interp.weight = weight;
if (task != NULL) {
task->data.interp.group = sCurAnimTaskGroup;
task->data.interp.vecCount = vecCount;
task->data.interp.base = base;
task->data.interp.mod = mod;
task->data.interp.weight = weight;
}
}
/**
* Requests copying vectors from src frame table to dst frame table whose copy flag is true
* Creates a task which will copy specified vectors from the `src` frame table to the `dest` frame table.
* Exactly which vectors will be copied is specified by the `limbCopyMap`.
*
* The copy map is an array of true/false flags that specify which limbs should have their data copied.
* Each index of the map corresponds to a limb number in the skeleton.
* Every limb that has `true` listed will have its data copied.
*
* Note: This task is "transformative", meaning it will alter the appearance of an animation.
* If this task's group is included in `sDisabledTransformTaskGroups`, this task will be skipped for that frame.
*/
void AnimationContext_SetCopyTrue(PlayState* play, s32 vecCount, Vec3s* dst, Vec3s* src, u8* copyFlag) {
AnimationEntry* entry = AnimationContext_AddEntry(&play->animationCtx, ANIMENTRY_COPYTRUE);
void AnimTaskQueue_AddCopyUsingMap(PlayState* play, s32 vecCount, Vec3s* dest, Vec3s* src, u8* limbCopyMap) {
AnimTask* task = AnimTaskQueue_NewTask(&play->animTaskQueue, ANIMTASK_COPY_USING_MAP);
if (entry != NULL) {
entry->data.copy1.queueFlag = sAnimQueueFlags;
entry->data.copy1.vecCount = vecCount;
entry->data.copy1.dst = dst;
entry->data.copy1.src = src;
entry->data.copy1.copyFlag = copyFlag;
if (task != NULL) {
task->data.copyUsingMap.group = sCurAnimTaskGroup;
task->data.copyUsingMap.vecCount = vecCount;
task->data.copyUsingMap.dest = dest;
task->data.copyUsingMap.src = src;
task->data.copyUsingMap.limbCopyMap = limbCopyMap;
}
}
/**
* Requests copying vectors from src frame table to dst frame table whose copy flag is false
* Identical to `AnimTaskQueue_AddCopyUsingMap`, except the meaning of the flags in the `limbCopyMap` are inverted.
* Any entry that specifies `false` will be copied, and any entry that specifies `true` will not.
*
* Note: This task is "transformative", meaning it will alter the appearance of an animation.
* If this task's group is included in `sDisabledTransformTaskGroups`, this task will be skipped for that frame.
*/
void AnimationContext_SetCopyFalse(PlayState* play, s32 vecCount, Vec3s* dst, Vec3s* src, u8* copyFlag) {
AnimationEntry* entry = AnimationContext_AddEntry(&play->animationCtx, ANIMENTRY_COPYFALSE);
void AnimTaskQueue_AddCopyUsingMapInverted(PlayState* play, s32 vecCount, Vec3s* dest, Vec3s* src, u8* limbCopyMap) {
AnimTask* task = AnimTaskQueue_NewTask(&play->animTaskQueue, ANIMTASK_COPY_USING_MAP_INVERTED);
if (entry != NULL) {
entry->data.copy0.queueFlag = sAnimQueueFlags;
entry->data.copy0.vecCount = vecCount;
entry->data.copy0.dst = dst;
entry->data.copy0.src = src;
entry->data.copy0.copyFlag = copyFlag;
if (task != NULL) {
task->data.copyUsingMapInverted.group = sCurAnimTaskGroup;
task->data.copyUsingMapInverted.vecCount = vecCount;
task->data.copyUsingMapInverted.dest = dest;
task->data.copyUsingMapInverted.src = src;
task->data.copyUsingMapInverted.limbCopyMap = limbCopyMap;
}
}
/**
* Requests moving an actor according to the translation of its root limb
* Creates a task which will move an actor according to the translation of its root limb for the current frame.
*/
void AnimationContext_SetMoveActor(PlayState* play, Actor* actor, SkelAnime* skelAnime, f32 moveDiffScaleY) {
AnimationEntry* entry = AnimationContext_AddEntry(&play->animationCtx, ANIMENTRY_MOVEACTOR);
void AnimTaskQueue_AddActorMove(PlayState* play, Actor* actor, SkelAnime* skelAnime, f32 moveDiffScaleY) {
AnimTask* task = AnimTaskQueue_NewTask(&play->animTaskQueue, ANIMTASK_ACTOR_MOVE);
if (entry != NULL) {
entry->data.move.actor = actor;
entry->data.move.skelAnime = skelAnime;
entry->data.move.diffScaleY = moveDiffScaleY;
if (task != NULL) {
task->data.actorMove.actor = actor;
task->data.actorMove.skelAnime = skelAnime;
task->data.actorMove.diffScaleY = moveDiffScaleY;
}
}
/**
* Receives the request for Link's animation frame data
* Wait for the DMA request submitted by `AnimTaskQueue_AddLoadPlayerFrame` to complete.
*/
void AnimationContext_LoadFrame(PlayState* play, AnimationEntryData* data) {
AnimEntryLoadFrame* entry = &data->load;
void AnimTask_LoadPlayerFrame(PlayState* play, AnimTaskData* data) {
AnimTaskLoadPlayerFrame* task = &data->loadPlayerFrame;
osRecvMesg(&entry->msgQueue, NULL, OS_MESG_BLOCK);
osRecvMesg(&task->msgQueue, NULL, OS_MESG_BLOCK);
}
/**
* If the entry's queue is enabled, copies all vectors from src frame table to dst frame table
* Copy all data from the `src` frame table to the `dest` table.
*/
void AnimationContext_CopyAll(PlayState* play, AnimationEntryData* data) {
AnimEntryCopyAll* entry = &data->copy;
void AnimTask_Copy(PlayState* play, AnimTaskData* data) {
AnimTaskCopy* task = &data->copy;
if (!(entry->queueFlag & sDisableAnimQueueFlags)) {
Vec3s* dst = entry->dst;
Vec3s* src = entry->src;
if (!(task->group & sDisabledTransformTaskGroups)) {
Vec3s* dest = task->dest;
Vec3s* src = task->src;
s32 i;
for (i = 0; i < entry->vecCount; i++) {
*dst++ = *src++;
for (i = 0; i < task->vecCount; i++) {
*dest++ = *src++;
}
}
}
/**
* If the entry's queue is enabled, interpolates between the base and mod frame tables, placing the result in base
* Interpolate between the `base` and `mod` frame tables.
*/
void AnimationContext_Interp(PlayState* play, AnimationEntryData* data) {
AnimEntryInterp* entry = &data->interp;
void AnimTask_Interp(PlayState* play, AnimTaskData* data) {
AnimTaskInterp* task = &data->interp;
if (!(entry->queueFlag & sDisableAnimQueueFlags)) {
SkelAnime_InterpFrameTable(entry->vecCount, entry->base, entry->base, entry->mod, entry->weight);
if (!(task->group & sDisabledTransformTaskGroups)) {
SkelAnime_InterpFrameTable(task->vecCount, task->base, task->base, task->mod, task->weight);
}
}
/**
* If the entry's queue is enabled, copies all vectors from src frame table to dst frame table whose copy flag is true
* Copy all data from the `src` frame table to the `dest` table according to the copy map.
*/
void AnimationContext_CopyTrue(PlayState* play, AnimationEntryData* data) {
AnimEntryCopyTrue* entry = &data->copy1;
void AnimTask_CopyUsingMap(PlayState* play, AnimTaskData* data) {
AnimTaskCopyUsingMap* task = &data->copyUsingMap;
if (!(entry->queueFlag & sDisableAnimQueueFlags)) {
Vec3s* dst = entry->dst;
Vec3s* src = entry->src;
u8* copyFlag = entry->copyFlag;
if (!(task->group & sDisabledTransformTaskGroups)) {
Vec3s* dest = task->dest;
Vec3s* src = task->src;
u8* limbCopyMap = task->limbCopyMap;
s32 i;
for (i = 0; i < entry->vecCount; i++, dst++, src++) {
if (*copyFlag++) {
*dst = *src;
for (i = 0; i < task->vecCount; i++, dest++, src++) {
if (*limbCopyMap++) {
*dest = *src;
}
}
}
}
/**
* If the entry's queue is enabled, copies all vectors from src frame table to dst frame table whose copy flag is false
* Copy all data from the `src` frame table to the `dest` table according to the inverted copy map.
*/
void AnimationContext_CopyFalse(PlayState* play, AnimationEntryData* data) {
AnimEntryCopyFalse* entry = &data->copy0;
void AnimTask_CopyUsingMapInverted(PlayState* play, AnimTaskData* data) {
AnimTaskCopyUsingMapInverted* task = &data->copyUsingMapInverted;
if (!(entry->queueFlag & sDisableAnimQueueFlags)) {
Vec3s* dst = entry->dst;
Vec3s* src = entry->src;
u8* copyFlag = entry->copyFlag;
if (!(task->group & sDisabledTransformTaskGroups)) {
Vec3s* dest = task->dest;
Vec3s* src = task->src;
u8* limbCopyMap = task->limbCopyMap;
s32 i;
for (i = 0; i < entry->vecCount; i++, dst++, src++) {
if (!(*copyFlag++)) {
*dst = *src;
for (i = 0; i < task->vecCount; i++, dest++, src++) {
if (!(*limbCopyMap++)) {
*dest = *src;
}
}
}
}
/**
* Moves an actor according to the translation of its root limb
* Move an actor according to the translation of its root limb for the current animation frame.
*/
void AnimationContext_MoveActor(PlayState* play, AnimationEntryData* data) {
AnimEntryMoveActor* entry = &data->move;
Actor* actor = entry->actor;
void AnimTask_ActorMove(PlayState* play, AnimTaskData* data) {
AnimTaskActorMove* task = &data->actorMove;
Actor* actor = task->actor;
Vec3f diff;
SkelAnime_UpdateTranslation(entry->skelAnime, &diff, actor->shape.rot.y);
SkelAnime_UpdateTranslation(task->skelAnime, &diff, actor->shape.rot.y);
actor->world.pos.x += diff.x * actor->scale.x;
actor->world.pos.y += diff.y * actor->scale.y * entry->diffScaleY;
actor->world.pos.y += diff.y * actor->scale.y * task->diffScaleY;
actor->world.pos.z += diff.z * actor->scale.z;
}
typedef void (*AnimationEntryCallback)(struct PlayState* play, AnimationEntryData* data);
typedef void (*AnimTaskFunc)(struct PlayState* play, AnimTaskData* data);
/**
* Performs all requests in the animation queue, then resets the queue flags.
* Update the AnimTaskQueue, processing all tasks in order.
* Variables related to anim task groups are then reset for the next frame.
*/
void AnimationContext_Update(PlayState* play, AnimationContext* animationCtx) {
static AnimationEntryCallback animFuncs[] = {
AnimationContext_LoadFrame, AnimationContext_CopyAll, AnimationContext_Interp,
AnimationContext_CopyTrue, AnimationContext_CopyFalse, AnimationContext_MoveActor,
void AnimTaskQueue_Update(PlayState* play, AnimTaskQueue* animTaskQueue) {
static AnimTaskFunc animTaskFuncs[] = {
AnimTask_LoadPlayerFrame, AnimTask_Copy, AnimTask_Interp, AnimTask_CopyUsingMap,
AnimTask_CopyUsingMapInverted, AnimTask_ActorMove,
};
AnimationEntry* entry = animationCtx->entries;
AnimTask* task = animTaskQueue->tasks;
for (; animationCtx->animationCount != 0; animationCtx->animationCount--) {
animFuncs[entry->type](play, &entry->data);
entry++;
while (animTaskQueue->count != 0) {
animTaskFuncs[task->type](play, &task->data);
task++;
animTaskQueue->count--;
}
sAnimQueueFlags = 1;
sDisableAnimQueueFlags = 0;
sCurAnimTaskGroup = 1 << 0;
sDisabledTransformTaskGroups = 0;
}
/**
@ -1125,8 +1172,8 @@ s32 LinkAnimation_Morph(PlayState* play, SkelAnime* skelAnime) {
LinkAnimation_SetUpdateFunction(skelAnime);
}
AnimationContext_SetInterp(play, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable,
1.0f - (skelAnime->morphWeight / prevMorphWeight));
AnimTaskQueue_AddInterp(play, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable,
1.0f - (skelAnime->morphWeight / prevMorphWeight));
return 0;
}
@ -1135,8 +1182,8 @@ s32 LinkAnimation_Morph(PlayState* play, SkelAnime* skelAnime) {
* jointTable and morphTable
*/
void LinkAnimation_AnimateFrame(PlayState* play, SkelAnime* skelAnime) {
AnimationContext_SetLoadFrame(play, skelAnime->animation, skelAnime->curFrame, skelAnime->limbCount,
skelAnime->jointTable);
AnimTaskQueue_AddLoadPlayerFrame(play, skelAnime->animation, skelAnime->curFrame, skelAnime->limbCount,
skelAnime->jointTable);
if (skelAnime->morphWeight != 0) {
f32 updateRate = R_UPDATE_RATE * 0.5f;
@ -1144,8 +1191,8 @@ void LinkAnimation_AnimateFrame(PlayState* play, SkelAnime* skelAnime) {
if (skelAnime->morphWeight <= 0.0f) {
skelAnime->morphWeight = 0.0f;
} else {
AnimationContext_SetInterp(play, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable,
skelAnime->morphWeight);
AnimTaskQueue_AddInterp(play, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable,
skelAnime->morphWeight);
}
}
}
@ -1212,14 +1259,14 @@ void LinkAnimation_Change(PlayState* play, SkelAnime* skelAnime, LinkAnimationHe
morphFrames = -morphFrames;
} else {
skelAnime->update.link = LinkAnimation_Morph;
AnimationContext_SetLoadFrame(play, animation, (s32)startFrame, skelAnime->limbCount,
skelAnime->morphTable);
AnimTaskQueue_AddLoadPlayerFrame(play, animation, (s32)startFrame, skelAnime->limbCount,
skelAnime->morphTable);
}
skelAnime->morphWeight = 1.0f;
skelAnime->morphRate = 1.0f / morphFrames;
} else {
LinkAnimation_SetUpdateFunction(skelAnime);
AnimationContext_SetLoadFrame(play, animation, (s32)startFrame, skelAnime->limbCount, skelAnime->jointTable);
AnimTaskQueue_AddLoadPlayerFrame(play, animation, (s32)startFrame, skelAnime->limbCount, skelAnime->jointTable);
skelAnime->morphWeight = 0.0f;
}
@ -1270,7 +1317,7 @@ void LinkAnimation_PlayLoopSetSpeed(PlayState* play, SkelAnime* skelAnime, LinkA
* Requests copying jointTable to morphTable
*/
void LinkAnimation_CopyJointToMorph(PlayState* play, SkelAnime* skelAnime) {
AnimationContext_SetCopyAll(play, skelAnime->limbCount, skelAnime->morphTable, skelAnime->jointTable);
AnimTaskQueue_AddCopy(play, skelAnime->limbCount, skelAnime->morphTable, skelAnime->jointTable);
}
/**
@ -1278,28 +1325,28 @@ void LinkAnimation_CopyJointToMorph(PlayState* play, SkelAnime* skelAnime) {
* unused
*/
void LinkAnimation_CopyMorphToJoint(PlayState* play, SkelAnime* skelAnime) {
AnimationContext_SetCopyAll(play, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable);
AnimTaskQueue_AddCopy(play, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable);
}
/**
* Requests loading frame data from the Link animation into morphTable
*/
void LinkAnimation_LoadToMorph(PlayState* play, SkelAnime* skelAnime, LinkAnimationHeader* animation, f32 frame) {
AnimationContext_SetLoadFrame(play, animation, (s32)frame, skelAnime->limbCount, skelAnime->morphTable);
AnimTaskQueue_AddLoadPlayerFrame(play, animation, (s32)frame, skelAnime->limbCount, skelAnime->morphTable);
}
/**
* Requests loading frame data from the Link animation into jointTable
*/
void LinkAnimation_LoadToJoint(PlayState* play, SkelAnime* skelAnime, LinkAnimationHeader* animation, f32 frame) {
AnimationContext_SetLoadFrame(play, animation, (s32)frame, skelAnime->limbCount, skelAnime->jointTable);
AnimTaskQueue_AddLoadPlayerFrame(play, animation, (s32)frame, skelAnime->limbCount, skelAnime->jointTable);
}
/**
* Requests interpolating between jointTable and morphTable, placing the result in jointTable
*/
void LinkAnimation_InterpJointMorph(PlayState* play, SkelAnime* skelAnime, f32 weight) {
AnimationContext_SetInterp(play, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable, weight);
AnimTaskQueue_AddInterp(play, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable, weight);
}
/**
@ -1309,12 +1356,12 @@ void LinkAnimation_BlendToJoint(PlayState* play, SkelAnime* skelAnime, LinkAnima
LinkAnimationHeader* animation2, f32 frame2, f32 blendWeight, Vec3s* blendTable) {
Vec3s* alignedBlendTable;
AnimationContext_SetLoadFrame(play, animation1, (s32)frame1, skelAnime->limbCount, skelAnime->jointTable);
AnimTaskQueue_AddLoadPlayerFrame(play, animation1, (s32)frame1, skelAnime->limbCount, skelAnime->jointTable);
alignedBlendTable = (Vec3s*)ALIGN16((uintptr_t)blendTable);
AnimationContext_SetLoadFrame(play, animation2, (s32)frame2, skelAnime->limbCount, alignedBlendTable);
AnimationContext_SetInterp(play, skelAnime->limbCount, skelAnime->jointTable, alignedBlendTable, blendWeight);
AnimTaskQueue_AddLoadPlayerFrame(play, animation2, (s32)frame2, skelAnime->limbCount, alignedBlendTable);
AnimTaskQueue_AddInterp(play, skelAnime->limbCount, skelAnime->jointTable, alignedBlendTable, blendWeight);
}
/**
@ -1324,12 +1371,12 @@ void LinkAnimation_BlendToMorph(PlayState* play, SkelAnime* skelAnime, LinkAnima
LinkAnimationHeader* animation2, f32 frame2, f32 blendWeight, Vec3s* blendTable) {
Vec3s* alignedBlendTable;
AnimationContext_SetLoadFrame(play, animation1, (s32)frame1, skelAnime->limbCount, skelAnime->morphTable);
AnimTaskQueue_AddLoadPlayerFrame(play, animation1, (s32)frame1, skelAnime->limbCount, skelAnime->morphTable);
alignedBlendTable = (Vec3s*)ALIGN16((uintptr_t)blendTable);
AnimationContext_SetLoadFrame(play, animation2, (s32)frame2, skelAnime->limbCount, alignedBlendTable);
AnimationContext_SetInterp(play, skelAnime->limbCount, skelAnime->morphTable, alignedBlendTable, blendWeight);
AnimTaskQueue_AddLoadPlayerFrame(play, animation2, (s32)frame2, skelAnime->limbCount, alignedBlendTable);
AnimTaskQueue_AddInterp(play, skelAnime->limbCount, skelAnime->morphTable, alignedBlendTable, blendWeight);
}
/**
@ -1791,6 +1838,7 @@ void SkelAnime_UpdateTranslation(SkelAnime* skelAnime, Vec3f* diff, s16 angle) {
f32 sin;
f32 cos;
// If `ANIM_FLAG_UPDATE_XZ` behaved as expected, it would also be checked here
if (skelAnime->moveFlags & ANIM_FLAG_NO_MOVE) {
diff->x = diff->z = 0.0f;
} else {
@ -1800,6 +1848,7 @@ void SkelAnime_UpdateTranslation(SkelAnime* skelAnime, Vec3f* diff, s16 angle) {
cos = Math_CosS(angle);
diff->x = x * cos + z * sin;
diff->z = z * cos - x * sin;
x = skelAnime->prevTransl.x;
z = skelAnime->prevTransl.z;
sin = Math_SinS(skelAnime->prevRot);
@ -1809,22 +1858,27 @@ void SkelAnime_UpdateTranslation(SkelAnime* skelAnime, Vec3f* diff, s16 angle) {
}
skelAnime->prevRot = angle;
skelAnime->prevTransl.x = skelAnime->jointTable[0].x;
skelAnime->jointTable[0].x = skelAnime->baseTransl.x;
skelAnime->prevTransl.z = skelAnime->jointTable[0].z;
skelAnime->jointTable[0].z = skelAnime->baseTransl.z;
if (skelAnime->moveFlags & ANIM_FLAG_UPDATE_Y) {
if (skelAnime->moveFlags & ANIM_FLAG_NO_MOVE) {
diff->y = 0.0f;
} else {
diff->y = skelAnime->jointTable[0].y - skelAnime->prevTransl.y;
}
skelAnime->prevTransl.y = skelAnime->jointTable[0].y;
skelAnime->jointTable[0].y = skelAnime->baseTransl.y;
} else {
diff->y = 0.0f;
skelAnime->prevTransl.y = skelAnime->jointTable[0].y;
}
skelAnime->moveFlags &= ~ANIM_FLAG_NO_MOVE;
}