diff options
| author | Lucas Shaw <49287729+shawlucas@users.noreply.github.com> | 2021-10-24 10:59:14 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-10-24 10:59:14 -0400 |
| commit | dcf44596d2c335c1ad82ea50f7e7d934e6bc1e52 (patch) | |
| tree | 59946691d9d64724244a98332a1350a5dca3f8b7 /src/code | |
| parent | 961913f18fb677ac6f95f0ab08c30bedaa616ec2 (diff) | |
Animation system updated, some more boot files decompiled (+6%), z_fcurve_data_skelanime decompiled (1 non-matching), some asm files split, etc (#89)
* Progress on various files
* gfxprint stuff
* split some rodata, add iconv for rodata string parsing
* z_std_dma rodata
* 2 nonmatchings in gfxprint
* mtxuty-cvt ok
* more
* match a function in idle.c
* progress
* Cleanup
* Rename BgPolygon to CollisionPoly
* progress
* some effect stuff
* more effect progress
* updates
* made suggested changes
* z_effect_soft_sprite_old_init mostly ok
* remove old effects enum
* gamealloc.c OK
* added more files
* motor.c almost done
* motor.c OK
* updates
* migration of two files
* listalloc.c oK
* z_fcurve_data_skelanime split
* z_fcurve_data_skelanime.c decompiled
* more files split
* z_malloc.c OK
* contpfs.c OK
* fault.c rodata migrated
* migrated fault_drawer rodata
* update
* update preprocess.py
* renamed functions in z_skelanime
* started z_skelanime cleanup
* like halfway through fixing z_skelanime
* animation system updated to meet oot standards
* remove unused animation structs
* rename matrix structs to fit oot
* Add -woff 712
* fix diff_settings.py because i accidentally broke it before
* fixed merge conflict, doesn't match though
* It matches now
* Updates
* Fixed warnings...added gcc code syntax checking
* Remove gcc check, added in Tharo's PR
* warnings fixed (i think)
* fixed all warnings i think
* ok
* not sure what to do
* Fix all warnings i think (z_en_a_keep needs some file cleanup thouguh)
* it matches if i do this
* remove comment
* accidentally put osPfsFreeBlocks in epilinkhandle.c
* memcmp -> bcmp
* change u32 size to size_t size, delete string.h because it caused unnecessary confusion with defining size_t twice
* format.sh
* MTXMODE_NEW and MTXMODE_APPLY to matrix functions
* Made suggested changes
* pragma sFaultDrawerFont instead of including in repo
* add some functions to functions.h
* Bss reordering fixed in z_collision_check...added hack to disasm.py
* Updated z_en_a_keep.c
* Missed suggestion in EnAObj_Destroy
* .
* update z_fcurve_Data_skelanime and z_skelanime with suggestions
* devmgr.c ok
* minor changes
* Addressed comments
* remove redundant file
* gfxp -> dlist in game.c
* updated actorfixer.py
* fixed warnings in z_malloc
* Change void* back to Actor*
* format
* Add the soft_sprit comments back
* Rename SV->Flex
* remove .common
* run format
* Update src/code/z_skelanime.c
* u32 channel
Co-authored-by: Lucas Shaw <lucas.shaw1123@gmail.com>
Co-authored-by: angie <angheloalf95@gmail.com>
Co-authored-by: Kenix3 <kenixwhisperwind@gmail.com>
Diffstat (limited to 'src/code')
30 files changed, 1804 insertions, 1213 deletions
diff --git a/src/code/PreRender.c b/src/code/PreRender.c index bdf4d326c..0afb1df68 100644 --- a/src/code/PreRender.c +++ b/src/code/PreRender.c @@ -17,7 +17,7 @@ void PreRender_SetValuesSave(PreRender* this, u32 width, u32 height, void* fbuf, void PreRender_Init(PreRender* this) { bzero(this, sizeof(PreRender)); - func_80174AA0(&this->alloc); + ListAlloc_Init(&this->alloc); } /** @@ -35,7 +35,7 @@ void PreRender_SetValues(PreRender* this, u32 width, u32 height, void* fbuf, voi } void PreRender_Destroy(PreRender* this) { - func_80174BA0(&this->alloc); + ListAlloc_FreeAll(&this->alloc); } void func_8016FDB8(PreRender* this, Gfx** gfxp, void* buf, void* bufSave, u32 arg4) { diff --git a/src/code/TwoHeadArena.c b/src/code/TwoHeadArena.c index b4262e3c6..83d5be3d1 100644 --- a/src/code/TwoHeadArena.c +++ b/src/code/TwoHeadArena.c @@ -12,7 +12,7 @@ void* THA_GetTail(TwoHeadArena* tha) { return tha->tail; } -void* THA_AllocStart(TwoHeadArena* tha, u32 size) { +void* THA_AllocStart(TwoHeadArena* tha, size_t size) { void* start = tha->head; tha->head = (u32)tha->head + size; @@ -23,7 +23,7 @@ void* THA_AllocStart1(TwoHeadArena* tha) { return THA_AllocStart(tha, 1); } -void* THA_AllocEnd(TwoHeadArena* tha, u32 size) { +void* THA_AllocEnd(TwoHeadArena* tha, size_t size) { u32 mask; if (size >= 0x10) { @@ -42,14 +42,14 @@ void* THA_AllocEnd(TwoHeadArena* tha, u32 size) { return tha->tail; } -void* THA_AllocEndAlign16(TwoHeadArena* tha, u32 size) { +void* THA_AllocEndAlign16(TwoHeadArena* tha, size_t size) { u32 mask = ~0xF; tha->tail = (((u32)tha->tail & mask) - size) & mask; return tha->tail; } -void* THA_AllocEndAlign(TwoHeadArena* tha, u32 size, u32 mask) { +void* THA_AllocEndAlign(TwoHeadArena* tha, size_t size, u32 mask) { tha->tail = (((u32)tha->tail & mask) - size) & mask; return tha->tail; } @@ -67,7 +67,7 @@ void THA_Init(TwoHeadArena* tha) { tha->tail = (u32)tha->bufp + tha->size; } -void THA_Ct(TwoHeadArena* tha, void* ptr, u32 size) { +void THA_Ct(TwoHeadArena* tha, void* ptr, size_t size) { bzero(tha, sizeof(TwoHeadArena)); tha->bufp = ptr; tha->size = size; diff --git a/src/code/TwoHeadGfxArena.c b/src/code/TwoHeadGfxArena.c index 81a3a383b..2f1629765 100644 --- a/src/code/TwoHeadGfxArena.c +++ b/src/code/TwoHeadGfxArena.c @@ -1,6 +1,6 @@ #include "global.h" -void THGA_Ct(TwoHeadGfxArena* thga, Gfx* start, u32 size) { +void THGA_Ct(TwoHeadGfxArena* thga, Gfx* start, size_t size) { THA_Ct((TwoHeadArena*)thga, start, size); } @@ -44,7 +44,7 @@ Gfx* THGA_AllocStart8Wrapper(TwoHeadGfxArena* thga) { return THGA_AllocStart8(thga); } -Gfx* THGA_AllocEnd(TwoHeadGfxArena* thga, u32 size) { +Gfx* THGA_AllocEnd(TwoHeadGfxArena* thga, size_t size) { return THA_AllocEnd((TwoHeadArena*)thga, size); } diff --git a/src/code/code_800F23E0.c b/src/code/code_800F23E0.c deleted file mode 100644 index 008a95db3..000000000 --- a/src/code/code_800F23E0.c +++ /dev/null @@ -1,5 +0,0 @@ -#include "global.h" - -#pragma GLOBAL_ASM("asm/non_matchings/code/code_800F23E0/func_800F23E0.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/code_800F23E0/func_800F2478.s") diff --git a/src/code/code_80122660.c b/src/code/code_80122660.c deleted file mode 100644 index 7c0da2932..000000000 --- a/src/code/code_80122660.c +++ /dev/null @@ -1,5 +0,0 @@ -#include "global.h" - -#pragma GLOBAL_ASM("asm/non_matchings/code/code_80122660/func_80122660.s") - -#pragma GLOBAL_ASM("asm/non_matchings/code/code_80122660/func_80122670.s") diff --git a/src/code/game.c b/src/code/game.c index eb26dee8a..a90fc7ac2 100644 --- a/src/code/game.c +++ b/src/code/game.c @@ -22,7 +22,7 @@ void Game_SetFramerateDivisor(GameState* gameState, s32 divisor) { } void GameState_SetFBFilter(Gfx** gfx, u32 arg1) { - Gfx* _gfx = *gfx; + Gfx* dlist = *gfx; if ((R_FB_FILTER_TYPE > 0) && (R_FB_FILTER_TYPE < 5)) { D_801F8010.type = R_FB_FILTER_TYPE; @@ -30,7 +30,7 @@ void GameState_SetFBFilter(Gfx** gfx, u32 arg1) { D_801F8010.color.g = R_FB_FILTER_PRIM_COLOR(1); D_801F8010.color.b = R_FB_FILTER_PRIM_COLOR(2); D_801F8010.color.a = R_FB_FILTER_A; - func_80140D10(&D_801F8010, &_gfx, arg1); + func_80140D10(&D_801F8010, &dlist, arg1); } else { if ((R_FB_FILTER_TYPE == 5) || (R_FB_FILTER_TYPE == 6)) { D_801F8020.useRgba = (R_FB_FILTER_TYPE == 6); @@ -42,7 +42,7 @@ void GameState_SetFBFilter(Gfx** gfx, u32 arg1) { D_801F8020.envColor.g = R_FB_FILTER_ENV_COLOR(1); D_801F8020.envColor.b = R_FB_FILTER_ENV_COLOR(2); D_801F8020.envColor.a = R_FB_FILTER_A; - func_80142100(&D_801F8020, &_gfx, arg1); + func_80142100(&D_801F8020, &dlist, arg1); } else { if (R_FB_FILTER_TYPE == 7) { sMonoColors.unk_00 = 0; @@ -54,27 +54,24 @@ void GameState_SetFBFilter(Gfx** gfx, u32 arg1) { sMonoColors.envColor.g = R_FB_FILTER_ENV_COLOR(1); sMonoColors.envColor.b = R_FB_FILTER_ENV_COLOR(2); sMonoColors.envColor.a = R_FB_FILTER_A; - VisMono_Draw(&sMonoColors, &_gfx, arg1); + VisMono_Draw(&sMonoColors, &dlist, arg1); } } } - *gfx = _gfx; + *gfx = dlist; } -void Game_Nop80173534(GameState* gamestate) { - ; +void Game_Nop80173534(GameState* gameState) { } -void GameState_Draw(GameState* gamestate, GraphicsContext* gfxCtx) { +void GameState_Draw(GameState* gameState, GraphicsContext* gfxCtx) { Gfx* nextDisplayList; Gfx* polyOpa; OPEN_DISPS(gfxCtx); - polyOpa = POLY_OPA_DISP; - nextDisplayList = Graph_GfxPlusOne(POLY_OPA_DISP); - + nextDisplayList = Graph_GfxPlusOne(polyOpa = POLY_OPA_DISP); gSPDisplayList(OVERLAY_DISP++, nextDisplayList); if (R_FB_FILTER_TYPE && R_FB_FILTER_ENV_COLOR(3) == 0) { @@ -98,119 +95,123 @@ void GameState_Draw(GameState* gamestate, GraphicsContext* gfxCtx) { if (R_ENABLE_ARENA_DBG != 0) { SpeedMeter_DrawTimeEntries(&D_801F7FF0, gfxCtx); - SpeedMeter_DrawAllocEntries(&D_801F7FF0, gfxCtx, gamestate); + SpeedMeter_DrawAllocEntries(&D_801F7FF0, gfxCtx, gameState); } CLOSE_DISPS(gfxCtx); } -void Game_ResetSegments(GraphicsContext* gfxCtx) { - gSPSegment(gfxCtx->polyOpa.p++, 0, 0); - gSPSegment(gfxCtx->polyOpa.p++, 0xF, gfxCtx->framebuffer); - gSPSegment(gfxCtx->polyXlu.p++, 0, 0); - gSPSegment(gfxCtx->polyXlu.p++, 0xF, gfxCtx->framebuffer); - gSPSegment(gfxCtx->overlay.p++, 0, 0); - gSPSegment(gfxCtx->overlay.p++, 0xF, gfxCtx->framebuffer); +void GameState_SetFrameBuffer(GraphicsContext* gfxCtx) { + OPEN_DISPS(gfxCtx); + + gSPSegment(POLY_OPA_DISP++, 0, NULL); + gSPSegment(POLY_OPA_DISP++, 0xF, gfxCtx->framebuffer); + gSPSegment(POLY_XLU_DISP++, 0, NULL); + gSPSegment(POLY_XLU_DISP++, 0xF, gfxCtx->framebuffer); + gSPSegment(OVERLAY_DISP++, 0, NULL); + gSPSegment(OVERLAY_DISP++, 0xF, gfxCtx->framebuffer); + + CLOSE_DISPS(gfxCtx); } void func_801736DC(GraphicsContext* gfxCtx) { Gfx* nextDisplayList; - Gfx* _polyOpa; + Gfx* polyOpa; + + OPEN_DISPS(gfxCtx); - nextDisplayList = Graph_GfxPlusOne(_polyOpa = gfxCtx->polyOpa.p); - gSPDisplayList(gfxCtx->overlay.p++, nextDisplayList); + nextDisplayList = Graph_GfxPlusOne(polyOpa = gfxCtx->polyOpa.p); + gSPDisplayList(OVERLAY_DISP++, nextDisplayList); gSPEndDisplayList(nextDisplayList++); - Graph_BranchDlist(_polyOpa, nextDisplayList); + Graph_BranchDlist(polyOpa, nextDisplayList); + + POLY_OPA_DISP = nextDisplayList; - gfxCtx->polyOpa.p = nextDisplayList; + CLOSE_DISPS(gfxCtx); } -void Game_UpdateInput(GameState* gamestate) { - Padmgr_GetInput(gamestate->input, 1); +void Game_UpdateInput(GameState* gameState) { + Padmgr_GetInput(gameState->input, 1); } -void Game_Update(GameState* gamestate) { - GraphicsContext* _gCtx; - _gCtx = gamestate->gfxCtx; +void Game_Update(GameState* gameState) { + GraphicsContext* gfxCtx = gameState->gfxCtx; - Game_ResetSegments(gamestate->gfxCtx); + GameState_SetFrameBuffer(gameState->gfxCtx); - gamestate->main(gamestate); + gameState->main(gameState); if (R_PAUSE_MENU_MODE != 2) { - GameState_Draw(gamestate, _gCtx); - func_801736DC(_gCtx); + GameState_Draw(gameState, gfxCtx); + func_801736DC(gfxCtx); } } -void Game_IncrementFrameCount(GameState* gamestate) { - Game_Nop80173534(gamestate); - gamestate->frames++; +void Game_IncrementFrameCount(GameState* gameState) { + Game_Nop80173534(gameState); + gameState->frames++; } -void Game_InitHeap(GameState* gamestate, u32 size) { - GameState* _ctx; - void* buf; - - _ctx = gamestate; - buf = Gamealloc_Alloc(&_ctx->alloc, size); +void GameState_InitArena(GameState* gameState, size_t size) { + GameAlloc* alloc = &gameState->alloc; + void* buf = GameAlloc_Malloc(alloc, size); if (buf) { - THA_Ct(&gamestate->heap, buf, size); + THA_Ct(&gameState->heap, buf, size); return; } - THA_Ct(&gamestate->heap, NULL, 0); - __assert("../game.c", 0x40B); + THA_Ct(&gameState->heap, NULL, 0); + __assert("../game.c", 1035); } -void Game_ResizeHeap(GameState* gamestate, u32 size) { +void GameState_Realloc(GameState* gameState, size_t size) { GameAlloc* alloc; - void* buf; - u32 systemMaxFree; - u32 bytesFree; - u32 bytesAllocated; + void* gameArena; + size_t systemMaxFree; + size_t bytesFree; + size_t bytesAllocated; void* heapStart; - heapStart = gamestate->heap.bufp; - alloc = &gamestate->alloc; - THA_Dt(&gamestate->heap); - Gamealloc_Free(alloc, heapStart); + heapStart = gameState->heap.bufp; + alloc = &gameState->alloc; + THA_Dt(&gameState->heap); + GameAlloc_Free(alloc, heapStart); SystemArena_AnalyzeArena(&systemMaxFree, &bytesFree, &bytesAllocated); size = ((systemMaxFree - (sizeof(ArenaNode))) < size) ? (0) : (size); - if (!size) { + if (size == 0) { size = systemMaxFree - (sizeof(ArenaNode)); } - if ((buf = Gamealloc_Alloc(alloc, size)) != NULL) { - THA_Ct(&gamestate->heap, buf, size); + if ((gameArena = GameAlloc_Malloc(alloc, size)) != NULL) { + THA_Ct(&gameState->heap, gameArena, size); } else { - THA_Ct(&gamestate->heap, 0, 0); - __assert("../game.c", 0x432); + THA_Ct(&gameState->heap, 0, 0); + __assert("../game.c", 1074); } } -void Game_StateInit(GameState* gamestate, GameStateFunc gameStateInit, GraphicsContext* gfxCtx) { - gamestate->gfxCtx = gfxCtx; - gamestate->frames = 0U; - gamestate->main = NULL; - gamestate->destroy = NULL; - gamestate->running = 1; - gfxCtx->unk274 = D_801FBB88; +void GameState_Init(GameState* gameState, GameStateFunc init, GraphicsContext* gfxCtx) { + gameState->gfxCtx = gfxCtx; + gameState->frames = 0U; + gameState->main = NULL; + gameState->destroy = NULL; + gameState->running = 1; + gfxCtx->viMode = D_801FBB88; gfxCtx->viConfigFeatures = gViConfigFeatures; gfxCtx->viConfigXScale = gViConfigXScale; gfxCtx->viConfigYScale = gViConfigYScale; - gamestate->nextGameStateInit = NULL; - gamestate->nextGameStateSize = 0U; + gameState->nextGameStateInit = NULL; + gameState->nextGameStateSize = 0U; { s32 requiredScopeTemp; - Gamealloc_Init(&gamestate->alloc); - Game_InitHeap(gamestate, 0x100000); - Game_SetFramerateDivisor(gamestate, 3); + GameAlloc_Init(&gameState->alloc); + GameState_InitArena(gameState, 0x100000); + Game_SetFramerateDivisor(gameState, 3); - gameStateInit(gamestate); + init(gameState); func_80140CE0(&D_801F8010); func_801420C0(&D_801F8020); @@ -219,17 +220,17 @@ void Game_StateInit(GameState* gamestate, GameStateFunc gameStateInit, GraphicsC func_801773A0(&D_801F7FF0); func_8013ED9C(); - osSendMesg(&gamestate->gfxCtx->unk5C, NULL, 1); + osSendMesg(&gameState->gfxCtx->unk5C, NULL, 1); } } -void Game_StateFini(GameState* gamestate) { +void GameState_Destroy(GameState* gameState) { func_80172BC0(); func_8019E014(); - osRecvMesg(&gamestate->gfxCtx->unk5C, 0, 1); + osRecvMesg(&gameState->gfxCtx->unk5C, NULL, OS_MESG_BLOCK); - if (gamestate->destroy != 0) { - gamestate->destroy(gamestate); + if (gameState->destroy != NULL) { + gameState->destroy(gameState); } func_8013EDD0(); @@ -238,28 +239,28 @@ void Game_StateFini(GameState* gamestate) { func_801420F4(&D_801F8020); func_80141900(&sMonoColors); func_80140900(&D_801F8048); - THA_Dt(&gamestate->heap); - Gamealloc_FreeAll(&gamestate->alloc); + THA_Dt(&gameState->heap); + GameAlloc_Cleanup(&gameState->alloc); } -GameStateFunc Game_GetNextStateInit(GameState* gamestate) { - return gamestate->nextGameStateInit; +GameStateFunc GameState_GetNextStateInit(GameState* gameState) { + return gameState->nextGameStateInit; } -u32 Game_GetNextStateSize(GameState* gamestate) { - return gamestate->nextGameStateSize; +size_t Game_GetNextStateSize(GameState* gameState) { + return gameState->nextGameStateSize; } -u32 Game_GetShouldContinue(GameState* gamestate) { - return gamestate->running; +u32 GameState_IsRunning(GameState* gameState) { + return gameState->running; } -s32 Game_GetHeapFreeSize(GameState* gamestate) { - return THA_GetSize(&gamestate->heap); +s32 GameState_GetArenaSize(GameState* gameState) { + return THA_GetSize(&gameState->heap); } -s32 func_80173B48(GameState* gamestate) { - s32 result; - result = OS_CYCLES_TO_NSEC(gamestate->framerateDivisor * sIrqMgrRetraceTime) - OS_CYCLES_TO_NSEC(D_801FBAF0); +s32 func_80173B48(GameState* gameState) { + s32 result = OS_CYCLES_TO_NSEC(gameState->framerateDivisor * sIrqMgrRetraceTime) - OS_CYCLES_TO_NSEC(D_801FBAF0); + return result; } diff --git a/src/code/gamealloc.c b/src/code/gamealloc.c index 34d595f79..541f9125b 100644 --- a/src/code/gamealloc.c +++ b/src/code/gamealloc.c @@ -1,11 +1,59 @@ #include "global.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/gamealloc/func_80173BF0.s") +void GameAlloc_Log(GameAlloc* this) { + GameAllocEntry* iter; -#pragma GLOBAL_ASM("asm/non_matchings/code/gamealloc/Gamealloc_Alloc.s") + iter = this->base.next; + while (iter != &this->base) { + iter = iter->next; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/gamealloc/Gamealloc_Free.s") +void* GameAlloc_Malloc(GameAlloc* this, size_t size) { + GameAllocEntry* ptr = SystemArena_Malloc(size + sizeof(GameAllocEntry)); -#pragma GLOBAL_ASM("asm/non_matchings/code/gamealloc/Gamealloc_FreeAll.s") + if (ptr != NULL) { + ptr->size = size; + ptr->prev = this->head; + this->head->next = ptr; + this->head = ptr; + ptr->next = &this->base; + this->base.prev = this->head; + return ptr + 1; + } else { + return NULL; + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/gamealloc/Gamealloc_Init.s") +void GameAlloc_Free(GameAlloc* this, void* data) { + GameAllocEntry* ptr; + + if (data != NULL) { + ptr = &((GameAllocEntry*)data)[-1]; + ptr->prev->next = ptr->next; + ptr->next->prev = ptr->prev; + this->head = this->base.prev; + SystemArena_Free(ptr); + } +} + +void GameAlloc_Cleanup(GameAlloc* this) { + GameAllocEntry* next = this->base.next; + GameAllocEntry* cur; + + while (&this->base != next) { + cur = next; + next = next->next; + SystemArena_Free(cur); + } + + this->head = &this->base; + this->base.next = &this->base; + this->base.prev = &this->base; +} + +void GameAlloc_Init(GameAlloc* this) { + this->head = &this->base; + this->base.next = &this->base; + this->base.prev = &this->base; +} diff --git a/src/code/listalloc.c b/src/code/listalloc.c index 3880806a1..da294a109 100644 --- a/src/code/listalloc.c +++ b/src/code/listalloc.c @@ -1,9 +1,62 @@ #include "global.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/listalloc/func_80174AA0.s") +ListAlloc* ListAlloc_Init(ListAlloc* this) { + this->prev = NULL; + this->next = NULL; + return this; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/listalloc/func_80174AB4.s") +void* ListAlloc_Alloc(ListAlloc* this, size_t size) { + ListAlloc* ptr = SystemArena_Malloc(size + sizeof(ListAlloc)); + ListAlloc* next; -#pragma GLOBAL_ASM("asm/non_matchings/code/listalloc/func_80174B20.s") + if (ptr == NULL) { + return NULL; + } -#pragma GLOBAL_ASM("asm/non_matchings/code/listalloc/func_80174BA0.s") + next = this->next; + if (next != NULL) { + next->next = ptr; + } + + ptr->prev = next; + ptr->next = NULL; + this->next = ptr; + + if (this->prev == NULL) { + this->prev = ptr; + } + + return (u8*)ptr + sizeof(ListAlloc); +} + +void ListAlloc_Free(ListAlloc* this, void* data) { + ListAlloc* ptr = &((ListAlloc*)data)[-1]; + + if (ptr->prev != NULL) { + ptr->prev->next = ptr->next; + } + + if (ptr->next != NULL) { + ptr->next->prev = ptr->prev; + } + + if (this->prev == ptr) { + this->prev = ptr->next; + } + + if (this->next == ptr) { + this->next = ptr->prev; + } + + SystemArena_Free(ptr); +} + +void ListAlloc_FreeAll(ListAlloc* this) { + ListAlloc* iter = this->prev; + + while (iter != NULL) { + ListAlloc_Free(this, (u8*)iter + sizeof(ListAlloc)); + iter = this->prev; + } +} diff --git a/src/code/main.c b/src/code/main.c index a2b859991..59ffb6a32 100644 --- a/src/code/main.c +++ b/src/code/main.c @@ -28,36 +28,36 @@ void Main(void* arg) { R_ENABLE_ARENA_DBG = 0; - osCreateMesgQueue(&siEventCallbackQueue, siEventCallbackBuffer, ARRAY_COUNT(siEventCallbackBuffer)); - osSetEventMesg(OS_EVENT_SI, &siEventCallbackQueue, NULL); + osCreateMesgQueue(&sSiIntMsgQ, sSiIntMsgBuf, ARRAY_COUNT(sSiIntMsgBuf)); + osSetEventMesg(OS_EVENT_SI, &sSiIntMsgQ, NULL); - osCreateMesgQueue(&mainIrqmgrCallbackQueue, mainIrqCallbackBuffer, ARRAY_COUNT(mainIrqCallbackBuffer)); + osCreateMesgQueue(&irqMgrMsgQ, irqMgrMsgBuf, ARRAY_COUNT(irqMgrMsgBuf)); StackCheck_Init(&schedStackEntry, schedStack, schedStack + sizeof(schedStack), 0, 0x100, "sched"); Sched_Init(&gSchedContext, schedStack + sizeof(schedStack), Z_PRIORITY_SCHED, D_8009B290, 1, &gIrqMgr); CIC6105_AddRomInfoFaultPage(); - IrqMgr_AddClient(&gIrqMgr, &mainIrqmgrCallbackNode, &mainIrqmgrCallbackQueue); + IrqMgr_AddClient(&gIrqMgr, &irqClient, &irqMgrMsgQ); StackCheck_Init(&audioStackEntry, audioStack, audioStack + sizeof(audioStack), 0, 0x100, "audio"); AudioMgr_Init(&audioContext, audioStack + sizeof(audioStack), Z_PRIORITY_AUDIOMGR, 0xA, &gSchedContext, &gIrqMgr); StackCheck_Init(&padmgrStackEntry, padmgrStack, padmgrStack + sizeof(padmgrStack), 0, 0x100, "padmgr"); - Padmgr_Start(&siEventCallbackQueue, &gIrqMgr, 7, Z_PRIORITY_PADMGR, padmgrStack + sizeof(padmgrStack)); + PadMgr_Init(&sSiIntMsgQ, &gIrqMgr, 7, Z_PRIORITY_PADMGR, padmgrStack + sizeof(padmgrStack)); AudioMgr_Unlock(&audioContext); - StackCheck_Init(&graphStackEntry, graphStack, graphStack + sizeof(graphStack), 0, 0x100, "graph"); - osCreateThread(&graphOSThread, Z_THREAD_ID_GRAPH, Graph_ThreadEntry, arg, graphStack + sizeof(graphStack), + StackCheck_Init(&sGraphStackInfo, sGraphStack, sGraphStack + sizeof(sGraphStack), 0, 0x100, "graph"); + osCreateThread(&sGraphThread, Z_THREAD_ID_GRAPH, Graph_ThreadEntry, arg, sGraphStack + sizeof(sGraphStack), Z_PRIORITY_GRAPH); - osStartThread(&graphOSThread); + osStartThread(&sGraphThread); exit = false; while (!exit) { msg = NULL; - osRecvMesg(&mainIrqmgrCallbackQueue, (OSMesg)&msg, OS_MESG_BLOCK); + osRecvMesg(&irqMgrMsgQ, (OSMesg)&msg, OS_MESG_BLOCK); if (msg == NULL) { break; } @@ -72,6 +72,6 @@ void Main(void* arg) { } } - IrqMgr_RemoveClient(&gIrqMgr, &mainIrqmgrCallbackNode); - osDestroyThread(&graphOSThread); + IrqMgr_RemoveClient(&gIrqMgr, &irqClient); + osDestroyThread(&sGraphThread); } diff --git a/src/code/padmgr.c b/src/code/padmgr.c index 65b9d0ff4..a8ef1db15 100644 --- a/src/code/padmgr.c +++ b/src/code/padmgr.c @@ -54,4 +54,4 @@ #pragma GLOBAL_ASM("asm/non_matchings/code/padmgr/Padmgr_ThreadEntry.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/padmgr/Padmgr_Start.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/padmgr/PadMgr_Init.s") diff --git a/src/code/sys_matrix.c b/src/code/sys_matrix.c index cab2e563a..a4d5b9379 100644 --- a/src/code/sys_matrix.c +++ b/src/code/sys_matrix.c @@ -1,92 +1,92 @@ #include "global.h" -void SysMatrix_StateAlloc(GameState* gamestate) { - sMatrixStack = (MtxF*)THA_AllocEndAlign16(&gamestate->heap, 0x500); +void Matrix_StateAlloc(GameState* gameState) { + sMatrixStack = (MtxF*)THA_AllocEndAlign16(&gameState->heap, 0x500); sCurrentMatrix = sMatrixStack; } -void SysMatrix_StatePush(void) { +void Matrix_StatePush(void) { MtxF* prev = sCurrentMatrix; sCurrentMatrix++; Matrix_MtxFCopy(sCurrentMatrix, prev); } -void SysMatrix_StatePop(void) { +void Matrix_StatePop(void) { sCurrentMatrix--; } -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_CopyCurrentState.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_CopyCurrentState.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_SetCurrentState.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_SetCurrentState.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_GetCurrentState.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_GetCurrentState.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_InsertMatrix.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_InsertMatrix.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_InsertTranslation.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_InsertTranslation.s") #pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_Scale.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_InsertXRotation_s.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_InsertXRotation_s.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_InsertXRotation_f.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_InsertXRotation_f.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_RotateStateAroundXAxis.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_RotateStateAroundXAxis.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_SetStateXRotation.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_SetStateXRotation.s") #pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_RotateY.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_InsertYRotation_f.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_InsertYRotation_f.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_InsertZRotation_s.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_InsertZRotation_s.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_InsertZRotation_f.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_InsertZRotation_f.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_InsertRotation.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_InsertRotation.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_RotateAndTranslateState.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_JointPosition.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_SetStateRotationAndTranslation.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_SetStateRotationAndTranslation.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_ToRSPMatrix.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_ToRSPMatrix.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_GetStateAsRSPMatrix.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_ToMtx.s") #pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_NewMtx.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_AppendToPolyOpaDisp.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_AppendToPolyOpaDisp.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_MultiplyVector3fByState.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_MultiplyVector3fByState.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_GetStateTranslation.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_GetStateTranslation.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_GetStateTranslationAndScaledX.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_GetStateTranslationAndScaledX.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_GetStateTranslationAndScaledY.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_GetStateTranslationAndScaledY.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_GetStateTranslationAndScaledZ.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_GetStateTranslationAndScaledZ.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_MultiplyVector3fXZByCurrentState.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_MultiplyVector3fXZByCurrentState.s") #pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_MtxFCopy.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_FromRSPMatrix.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_FromRSPMatrix.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_MultiplyVector3fByMatrix.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_MultiplyVector3fByMatrix.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_TransposeXYZ.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_TransposeXYZ.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_NormalizeXYZ.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_NormalizeXYZ.s") #pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/func_8018219C.s") #pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/func_801822C4.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_InsertRotationAroundUnitVector_f.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_InsertRotationAroundUnitVector_f.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/SysMatrix_InsertRotationAroundUnitVector_s.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/Matrix_InsertRotationAroundUnitVector_s.s") #pragma GLOBAL_ASM("asm/non_matchings/code/sys_matrix/func_80182C90.s") diff --git a/src/code/z_DLF.c b/src/code/z_DLF.c index 1ae43c91d..688a5af15 100644 --- a/src/code/z_DLF.c +++ b/src/code/z_DLF.c @@ -1,5 +1,5 @@ #include "global.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/z_DLF/DLF_LoadGameState.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/z_DLF/Overlay_LoadGameState.s") -#pragma GLOBAL_ASM("asm/non_matchings/code/z_DLF/DLF_FreeGameState.s") +#pragma GLOBAL_ASM("asm/non_matchings/code/z_DLF/Overlay_FreeGameState.s") diff --git a/src/code/z_actor.c b/src/code/z_actor.c index 2f1277057..8d87e539b 100644 --- a/src/code/z_actor.c +++ b/src/code/z_actor.c @@ -53,7 +53,7 @@ void ActorShadow_Draw(Actor* actor, Lights* lights, GlobalContext* globalCtx, Gf } func_800C0094(actor->floorPoly, actor->world.pos.x, actor->floorHeight, actor->world.pos.z, &mtx); - SysMatrix_SetCurrentState(&mtx); + Matrix_SetCurrentState(&mtx); if (dlist != D_04076BC0) { Matrix_RotateY((f32)actor->shape.rot.y * (M_PI / 32768), MTXMODE_APPLY); @@ -117,7 +117,7 @@ void func_800B40E0(GlobalContext* globalCtx, Light* light, MtxF* arg2, s32 arg3, sp58 = Math_FAtan2F(light->l.dir[0], light->l.dir[2]); arg6 *= (4.5f - (light->l.dir[1] * 0.035f)); arg6 = (arg6 < 1.0f) ? 1.0f : arg6; - SysMatrix_SetCurrentState(arg2); + Matrix_SetCurrentState(arg2); Matrix_RotateY(sp58, MTXMODE_APPLY); Matrix_Scale(arg5, 1.0f, arg5 * arg6, MTXMODE_APPLY); @@ -744,7 +744,7 @@ void Actor_FreeOverlay(ActorOverlay* entry) { if ((entry->allocType & 1) != 0) { entry->loadedRamAddr = NULL; } else { - zelda_free(ramAddr); + ZeldaArena_Free(ramAddr); entry->loadedRamAddr = NULL; } } diff --git a/src/code/z_actor_dlftbls.c b/src/code/z_actor_dlftbls.c index 4165e4c9b..f33fcd538 100644 --- a/src/code/z_actor_dlftbls.c +++ b/src/code/z_actor_dlftbls.c @@ -736,7 +736,7 @@ void* ActorOverlayTable_FaultAddrConv(void* arg0, void* arg1) { s32 i; u8* ramStart; u8* ramEnd; - u32 size; + size_t size; u32 offset; for (i = 0; i < gMaxActorId; i++, overlayEntry++) { diff --git a/src/code/z_collision_check.c b/src/code/z_collision_check.c index 6ea0b2fcf..059fbce09 100644 --- a/src/code/z_collision_check.c +++ b/src/code/z_collision_check.c @@ -327,7 +327,7 @@ s32 Collider_FreeJntSph(GlobalContext* globalCtx, ColliderJntSph* collider) { collider->count = 0; if (collider->elements != NULL) { - zelda_free(collider->elements); + ZeldaArena_Free(collider->elements); } collider->elements = NULL; return 1; @@ -359,7 +359,7 @@ s32 Collider_SetJntSphToActor(GlobalContext* globalCtx, ColliderJntSph* collider Collider_SetBaseToActor(globalCtx, &collider->base, &src->base); collider->count = src->count; - collider->elements = zelda_malloc(src->count * sizeof(ColliderJntSphElement)); + collider->elements = ZeldaArena_Malloc(src->count * sizeof(ColliderJntSphElement)); if (collider->elements == NULL) { collider->count = 0; @@ -385,7 +385,7 @@ s32 Collider_SetJntSphAllocType1(GlobalContext* globalCtx, ColliderJntSph* spher Collider_SetBaseType1(globalCtx, &sphereGroup->base, actor, &src->base); sphereGroup->count = src->count; - sphereGroup->elements = zelda_malloc(src->count * sizeof(ColliderJntSphElement)); + sphereGroup->elements = ZeldaArena_Malloc(src->count * sizeof(ColliderJntSphElement)); if (sphereGroup->elements == NULL) { sphereGroup->count = 0; @@ -681,7 +681,7 @@ s32 Collider_FreeTris(GlobalContext* globalCtx, ColliderTris* tris) { tris->count = 0; if (tris->elements != NULL) { - zelda_free(tris->elements); + ZeldaArena_Free(tris->elements); } tris->elements = NULL; @@ -714,7 +714,7 @@ s32 Collider_SetTrisAllocType1(GlobalContext* globalCtx, ColliderTris* tris, Act Collider_SetBaseType1(globalCtx, &tris->base, actor, &src->base); tris->count = src->count; - tris->elements = zelda_malloc(tris->count * sizeof(ColliderTrisElement)); + tris->elements = ZeldaArena_Malloc(tris->count * sizeof(ColliderTrisElement)); if (tris->elements == NULL) { tris->count = 0; @@ -3691,7 +3691,7 @@ void Collider_UpdateSpheres(s32 limb, ColliderJntSph* collider) { D_801EE1C0.x = collider->elements[i].dim.modelSphere.center.x; D_801EE1C0.y = collider->elements[i].dim.modelSphere.center.y; D_801EE1C0.z = collider->elements[i].dim.modelSphere.center.z; - SysMatrix_MultiplyVector3fByState(&D_801EE1C0, &D_801EE1D0); + Matrix_MultiplyVector3fByState(&D_801EE1C0, &D_801EE1D0); collider->elements[i].dim.worldSphere.center.x = D_801EE1D0.x; collider->elements[i].dim.worldSphere.center.y = D_801EE1D0.y; collider->elements[i].dim.worldSphere.center.z = D_801EE1D0.z; @@ -3733,7 +3733,7 @@ void Collider_UpdateSphere(s32 limb, ColliderSphere* collider) { D_801EE1E0.x = collider->dim.modelSphere.center.x; D_801EE1E0.y = collider->dim.modelSphere.center.y; D_801EE1E0.z = collider->dim.modelSphere.center.z; - SysMatrix_MultiplyVector3fByState(&D_801EE1E0, &D_801EE1F0); + Matrix_MultiplyVector3fByState(&D_801EE1E0, &D_801EE1F0); collider->dim.worldSphere.center.x = D_801EE1F0.x; collider->dim.worldSphere.center.y = D_801EE1F0.y; collider->dim.worldSphere.center.z = D_801EE1F0.z; diff --git a/src/code/z_eff_footmark.c b/src/code/z_eff_footmark.c index ba2c79f71..d246aaffa 100644 --- a/src/code/z_eff_footmark.c +++ b/src/code/z_eff_footmark.c @@ -106,8 +106,8 @@ void EffFootmark_Draw(GlobalContext* globalCtx) { for (footmark = globalCtx->footprintInfo, i = 0; i < 100; i++, footmark++) { if (footmark->actor != NULL) { - SysMatrix_SetCurrentState(&footmark->displayMatrix); - Matrix_Scale(footmark->size * 0.00390625f * 0.7f, 1, footmark->size * 0.00390625f, 1); + Matrix_SetCurrentState(&footmark->displayMatrix); + Matrix_Scale(footmark->size * (1.0f / 0x100) * 0.7f, 1, footmark->size * (1.0f / 0x100), MTXMODE_APPLY); gSPMatrix(gfxCtx->polyXlu.p++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD); diff --git a/src/code/z_effect_soft_sprite.c b/src/code/z_effect_soft_sprite.c index 0ed19c050..47c2202f1 100644 --- a/src/code/z_effect_soft_sprite.c +++ b/src/code/z_effect_soft_sprite.c @@ -41,7 +41,7 @@ void EffectSS_Clear(GlobalContext* globalCtx) { for (i = 0; i < EFFECT_SS_MAX; i++) { addr = overlay->loadedRamAddr; if (addr != NULL) { - zelda_free(addr); + ZeldaArena_Free(addr); } overlay->loadedRamAddr = 0; @@ -175,7 +175,7 @@ void EffectSs_Spawn(GlobalContext* globalCtx, s32 type, s32 priority, void* init initInfo = entry->initInfo; } else { if (entry->loadedRamAddr == NULL) { - entry->loadedRamAddr = zelda_mallocR(overlaySize); + entry->loadedRamAddr = ZeldaArena_MallocR(overlaySize); if (entry->loadedRamAddr == NULL) { return; diff --git a/src/code/z_effect_soft_sprite_old_init.c b/src/code/z_effect_soft_sprite_old_init.c index aa461153c..cf27d2251 100644 --- a/src/code/z_effect_soft_sprite_old_init.c +++ b/src/code/z_effect_soft_sprite_old_init.c @@ -403,7 +403,7 @@ void EffectSsGSpk_SpawnSmall(GlobalContext* globalCtx, Actor* actor, Vec3f* pos, // EffectSsDFire Spawn Functions void EffectSsDFire_Spawn(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velocity, Vec3f* accel, s16 scale, s16 scaleStep, - s16 alpha, s16 fadeDelay, s16 life, s32 arg9) { + s16 alpha, s16 fadeDelay, s16 arg8, s32 life) { EffectSsDFireInitParams initParams; Math_Vec3f_Copy(&initParams.pos, pos); @@ -413,8 +413,8 @@ void EffectSsDFire_Spawn(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velocity, initParams.scaleStep = scaleStep; initParams.alpha = alpha; initParams.fadeDelay = fadeDelay; + initParams.unk_2C = arg8; initParams.life = life; - initParams.unk_30 = arg9; EffectSs_Spawn(globalCtx, EFFECT_SS_D_FIRE, 128, &initParams); } @@ -535,8 +535,8 @@ void EffectSsDtBubble_SpawnCustomColor(GlobalContext* globalCtx, Vec3f* pos, Vec /** * Spawn a single fragment * - * Notes: - * - if a display list is not provided, D_0400C0D0 (wilted deku fragment) will be used as default + * * Notes: + * - if a display list is not provided, an unknown default will be used as default * - the unused arg does not do anything, any value can be passed here * - due to how life is implemented it is capped at 200. Any value over 200 is accepted, but the fragment will * only live for 200 frames @@ -960,6 +960,7 @@ void EffectSsExtra_Spawn(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velocity, } // EffectSsDeadDb Spawn Functions + void EffectSsDeadDb_Spawn(GlobalContext* globalCtx, Vec3f* pos, Vec3f* velocity, Vec3f* accel, Color_RGBA8* prim, Color_RGBA8* env, s16 scale, s16 scaleStep, s32 unk) { EffectSsDeadDbInitParams initParams; diff --git a/src/code/z_en_a_keep.c b/src/code/z_en_a_keep.c index fbd323885..d5125d249 100644 --- a/src/code/z_en_a_keep.c +++ b/src/code/z_en_a_keep.c @@ -1,48 +1,57 @@ #include "global.h" -void EnAObj_Init(ActorEnAObj* this, GlobalContext* globalCtx) { - ActorEnAObj* s0 = (ActorEnAObj*)this; - s0->base.textId = ((s0->base.params >> 8) & 0xFF) | 0x300; - s0->base.params = (s0->base.params & 0xFF) - 9; - Actor_ProcessInitChain((Actor*)s0, &enAObjInitVar); - ActorShape_Init(&s0->base.shape, 0, (ActorShadowFunc)func_800B3FC0, 12); - Collider_InitAndSetCylinder(globalCtx, &s0->collision, (Actor*)s0, &enAObjCylinderInit); - Collider_UpdateCylinder((Actor*)s0, &s0->collision); - s0->base.colChkInfo.mass = 255; - s0->update = (ActorFunc)EnAObj_Update1; +#define THIS ((EnAObj*)thisx) + +void EnAObj_Update1(EnAObj* this, GlobalContext* globalCtx); +void EnAObj_Update2(EnAObj* this, GlobalContext* globalCtx); + +void EnAObj_Init(Actor* thisx, GlobalContext* globalCtx) { + EnAObj* this = THIS; + + this->actor.textId = ((this->actor.params >> 8) & 0xFF) | 0x300; + this->actor.params = (this->actor.params & 0xFF) - 9; + Actor_ProcessInitChain(&this->actor, &enAObjInitVar); + ActorShape_Init(&this->actor.shape, 0, func_800B3FC0, 12); + Collider_InitAndSetCylinder(globalCtx, &this->collision, &this->actor, &enAObjCylinderInit); + Collider_UpdateCylinder(&this->actor, &this->collision); + this->actor.colChkInfo.mass = 255; + this->actionFunc = EnAObj_Update1; } -void EnAObj_Destroy(ActorEnAObj* this, GlobalContext* globalCtx) { - ColliderCylinder* a2 = &this->collision; - Collider_DestroyCylinder(globalCtx, a2); +void EnAObj_Destroy(Actor* thisx, GlobalContext* globalCtx) { + EnAObj* this = THIS; + + Collider_DestroyCylinder(globalCtx, &this->collision); } -void EnAObj_Update1(ActorEnAObj* this, GlobalContext* globalCtx) { - s16 v0; - s32 v1; - if (func_800B84D0((Actor*)this, globalCtx) != 0) { - this->update = (ActorFunc)EnAObj_Update2; +void EnAObj_Update1(EnAObj* this, GlobalContext* globalCtx) { + s32 yawDiff; + + if (func_800B84D0(&this->actor, globalCtx)) { + this->actionFunc = EnAObj_Update2; } else { - v0 = this->base.yawTowardsPlayer - this->base.shape.rot.y; - v1 = (v0 < 0) ? -v0 : v0; - if ((v1 < 10240) || ((this->base.params == 1) && (v1 > 22528))) { - func_800B863C((Actor*)this, globalCtx); + yawDiff = ABS_ALT((s16)(this->actor.yawTowardsPlayer - this->actor.shape.rot.y)); + + if ((yawDiff < 0x2800) || ((this->actor.params == 1) && (yawDiff > 0x5800))) { + func_800B863C(&this->actor, globalCtx); } } } -void EnAObj_Update2(ActorEnAObj* this, GlobalContext* globalCtx) { - if (func_800B867C((Actor*)this, globalCtx) != 0) { - this->update = (ActorFunc)EnAObj_Update1; +void EnAObj_Update2(EnAObj* this, GlobalContext* globalCtx) { + if (func_800B867C(&this->actor, globalCtx)) { + this->actionFunc = EnAObj_Update1; } } -void EnAObj_Update(ActorEnAObj* this, GlobalContext* globalCtx) { - (this->update)((Actor*)this, (GlobalContext*)globalCtx); - Actor_SetHeight((Actor*)this, 45.0f); - CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, (Collider*)&this->collision); +void EnAObj_Update(Actor* thisx, GlobalContext* globalCtx) { + EnAObj* this = THIS; + + this->actionFunc(this, globalCtx); + Actor_SetHeight(&this->actor, 45.0f); + CollisionCheck_SetOC(globalCtx, &globalCtx->colChkCtx, &this->collision.base); } -void EnAObj_Draw(ActorEnAObj* this, GlobalContext* globalCtx) { - func_800BDFC0(globalCtx, enAObjDisplayLists[this->base.params]); +void EnAObj_Draw(Actor* thisx, GlobalContext* globalCtx) { + func_800BDFC0(globalCtx, enAObjDisplayLists[thisx->params]); } diff --git a/src/code/z_en_item00.c b/src/code/z_en_item00.c index 0a412c2da..acae2e0ce 100644 --- a/src/code/z_en_item00.c +++ b/src/code/z_en_item00.c @@ -660,7 +660,7 @@ void EnItem00_Draw(Actor* thisx, GlobalContext* globalCtx) { this->unk152 = -2; } } else { - Matrix_Scale(16.0f, 16.0f, 16.0f, 1); + Matrix_Scale(16.0f, 16.0f, 16.0f, MTXMODE_APPLY); GetItem_Draw(globalCtx, 8); } break; @@ -785,7 +785,7 @@ void EnItem00_DrawHeartContainer(EnItem00* actor, GlobalContext* globalCtx) { OPEN_DISPS(globalCtx->state.gfxCtx); func_8012C2DC(globalCtx->state.gfxCtx); - Matrix_Scale(20.0f, 20.0f, 20.0f, 1); + Matrix_Scale(20.0f, 20.0f, 20.0f, MTXMODE_APPLY); gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_MODELVIEW | G_MTX_LOAD); diff --git a/src/code/z_fcurve_data.c b/src/code/z_fcurve_data.c new file mode 100644 index 000000000..a0bf887e1 --- /dev/null +++ b/src/code/z_fcurve_data.c @@ -0,0 +1,5 @@ +#include "global.h" + +#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data/func_800F23E0.s") + +#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data/func_800F2478.s") diff --git a/src/code/z_fcurve_data_skelanime.c b/src/code/z_fcurve_data_skelanime.c index 79439550d..c6ee50d87 100644 --- a/src/code/z_fcurve_data_skelanime.c +++ b/src/code/z_fcurve_data_skelanime.c @@ -1,15 +1,181 @@ #include "global.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data_skelanime/func_800F2620.s") +void SkelCurve_Clear(SkelAnimeCurve* skelCurve) { + skelCurve->limbCount = 0; + skelCurve->limbList = NULL; + skelCurve->transUpdIdx = NULL; + skelCurve->animCurFrame = 0.0f; + skelCurve->animSpeed = 0.0f; + skelCurve->animFinalFrame = 0.0f; + skelCurve->unk0C = 0.0f; + skelCurve->transforms = NULL; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data_skelanime/func_800F2650.s") +s32 SkelCurve_Init(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve, SkelCurveLimbList* limbListSeg, + TransformUpdateIndex* transUpdIdx) { + SkelCurveLimb** limbs; + SkelCurveLimbList* limbList = (SkelCurveLimbList*)Lib_SegmentedToVirtual(limbListSeg); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data_skelanime/func_800F26C0.s") + skelCurve->limbCount = limbList->limbCount; + skelCurve->limbList = (SkelCurveLimb**)Lib_SegmentedToVirtual(limbList->limbs); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data_skelanime/func_800F26F0.s") + skelCurve->transforms = ZeldaArena_Malloc(sizeof(*skelCurve->transforms) * skelCurve->limbCount); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data_skelanime/func_800F2728.s") + do { + skelCurve->animCurFrame = 0.0f; + } while (0); + return 1; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data_skelanime/func_800F29A0.s") +void SkelCurve_Destroy(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve) { + if (skelCurve->transforms != NULL) { + ZeldaArena_Free(skelCurve->transforms); + } +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data_skelanime/func_800F2CD8.s") +void SkelCurve_SetAnim(SkelAnimeCurve* skelCurve, TransformUpdateIndex* transUpdIdx, f32 arg2, f32 animFinalFrame, + f32 animCurFrame, f32 animSpeed) { + skelCurve->unk0C = arg2 - skelCurve->animSpeed; + skelCurve->animFinalFrame = animFinalFrame; + skelCurve->animCurFrame = animCurFrame; + skelCurve->animSpeed = animSpeed; + skelCurve->transUpdIdx = transUpdIdx; +} + +#ifdef NON_MATCHING +/* Should be functionally equivalent, also migrating rodata makes it a lot cleaner */ +s32 SkelCurve_Update(GlobalContext* globalCtx, SkelAnimeCurve* skelCurve) { + s16* transforms; + u8* transformRefIdx; + TransformUpdateIndex* transformIndex; + u16* transformCopyValues; + s32 i; + s32 ret = 0; + s32 k; + TransformData* transData; + f32 transformValue; + s32 j; + + transformIndex = Lib_SegmentedToVirtual(skelCurve->transUpdIdx); + transformRefIdx = Lib_SegmentedToVirtual(transformIndex->refIndex); + transData = Lib_SegmentedToVirtual(transformIndex->transformData); + transformCopyValues = Lib_SegmentedToVirtual(transformIndex->copyValues); + transforms = (s16*)skelCurve->transforms; + + skelCurve->animCurFrame += skelCurve->animSpeed * (globalCtx->state.framerateDivisor * 0.5f); + + if ((skelCurve->animSpeed >= 0.0f && skelCurve->animCurFrame > skelCurve->animFinalFrame) || + (skelCurve->animSpeed < 0.0f && skelCurve->animCurFrame < skelCurve->animFinalFrame)) { + skelCurve->animCurFrame = skelCurve->animFinalFrame; + ret = 1; + } + + for (i = 0; i < skelCurve->limbCount; i++) { + for (j = 0; j < 3; j++) { + for (k = 0; k < 3; k++, transformRefIdx++, transforms++) { + if (*transformRefIdx == 0) { + transformValue = *transformCopyValues; + *transforms = transformValue; + transformCopyValues++; + } else { + transformValue = func_800F2478(skelCurve->animCurFrame, transData, *transformRefIdx); + transData += *transformRefIdx; + if (j == 0) { + *transforms = transformValue * 1024.0f; + } else if (j == 1) { + *transforms = transformValue * (32768.0f / 180.0f); + } else { + *transforms = transformValue * 100.0f; + } + } + } + } + } + + return ret; +} +#else +#pragma GLOBAL_ASM("asm/non_matchings/code/z_fcurve_data_skelanime/SkelCurve_Update.s") +#endif + +void SkelCurve_DrawLimb(GlobalContext* globalCtx, s32 limbIndex, SkelAnimeCurve* skelCurve, + OverrideCurveLimbDraw overrideLimbDraw, PostCurveLimbDraw postLimbDraw, s32 lod, Actor* thisx) { + SkelCurveLimb* limb = (SkelCurveLimb*)Lib_SegmentedToVirtual(skelCurve->limbList[limbIndex]); + + OPEN_DISPS(globalCtx->state.gfxCtx); + + Matrix_StatePush(); + + if (overrideLimbDraw == NULL || + (overrideLimbDraw != NULL && overrideLimbDraw(globalCtx, skelCurve, limbIndex, thisx))) { + Vec3f scale; + Vec3s rot; + Vec3f pos; + Gfx* dList; + Vec3s* transform = (Vec3s*)&skelCurve->transforms[limbIndex]; + + scale.x = transform->x / 1024.0f; + scale.y = transform->y / 1024.0f; + scale.z = transform->z / 1024.0f; + transform++; + rot.x = transform->x; + rot.y = transform->y; + rot.z = transform->z; + transform++; + pos.x = transform->x; + pos.y = transform->y; + pos.z = transform->z; + + Matrix_JointPosition(&pos, &rot); + Matrix_Scale(scale.x, scale.y, scale.z, MTXMODE_APPLY); + + if (lod == 0) { + s32 pad1; + + dList = limb->dList[0]; + if (dList != NULL) { + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), + G_MTX_LOAD | G_MTX_NOPUSH | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, dList); + } + } else if (lod == 1) { + s32 pad2; + + dList = limb->dList[0]; + if (dList != NULL) { + gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), + G_MTX_LOAD | G_MTX_NOPUSH | G_MTX_MODELVIEW); + gSPDisplayList(POLY_OPA_DISP++, dList); + } + dList = limb->dList[1]; + if (dList != NULL) { + gSPMatrix(POLY_XLU_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), + G_MTX_LOAD | G_MTX_NOPUSH | G_MTX_MODELVIEW); + gSPDisplayList(POLY_XLU_DISP++, dList); + } + } + } + + if (postLimbDraw != NULL) { + postLimbDraw(globalCtx, skelCurve, limbIndex, thisx); + } + + if (limb->firstChildIdx != LIMB_DONE) { + SkelCurve_DrawLimb(globalCtx, limb->firstChildIdx, skelCurve, overrideLimbDraw, postLimbDraw, lod, thisx); + } + + Matrix_StatePop(); + + if (limb->nextLimbIdx != LIMB_DONE) { + SkelCurve_DrawLimb(globalCtx, limb->nextLimbIdx, skelCurve, overrideLimbDraw, postLimbDraw, lod, thisx); + } + + CLOSE_DISPS(globalCtx->state.gfxCtx); +} + +void SkelCurve_Draw(Actor* actor, GlobalContext* globalCtx, SkelAnimeCurve* skelCurve, + OverrideCurveLimbDraw overrideLimbDraw, PostCurveLimbDraw postLimbDraw, s32 lod, Actor* thisx) { + if (skelCurve->transforms != NULL) { + SkelCurve_DrawLimb(globalCtx, 0, skelCurve, overrideLimbDraw, postLimbDraw, lod, thisx); + } +} diff --git a/src/code/z_lights.c b/src/code/z_lights.c index 3e2e041b3..80d3f7131 100644 --- a/src/code/z_lights.c +++ b/src/code/z_lights.c @@ -432,7 +432,7 @@ void Lights_DrawGlow(GlobalContext* globalCtx) { gDPSetPrimColor(dl++, 0, 0, params->color[0], params->color[1], params->color[2], 50); - SysMatrix_InsertTranslation(params->x, params->y, params->z, 0); + Matrix_InsertTranslation(params->x, params->y, params->z, MTXMODE_NEW); Matrix_Scale(scale, scale, scale, MTXMODE_APPLY); gSPMatrix(dl++, Matrix_NewMtx(globalCtx->state.gfxCtx), diff --git a/src/code/z_malloc.c b/src/code/z_malloc.c index f99519e9b..8d0bba44a 100644 --- a/src/code/z_malloc.c +++ b/src/code/z_malloc.c @@ -1,21 +1,54 @@ #include "global.h" -#pragma GLOBAL_ASM("asm/non_matchings/code/z_malloc/zelda_malloc.s") +void* ZeldaArena_Malloc(size_t size) { + void* ptr = __osMalloc(&sZeldaArena, size); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_malloc/zelda_mallocR.s") + return ptr; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_malloc/zelda_realloc.s") +void* ZeldaArena_MallocR(size_t size) { + void* ptr = __osMallocR(&sZeldaArena, size); -#pragma GLOBAL_ASM("asm/non_matchings/code/z_malloc/zelda_free.s") + return ptr; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_malloc/zelda_calloc.s") +void* ZeldaArena_Realloc(void* ptr, size_t newSize) { + ptr = __osRealloc(&sZeldaArena, ptr, newSize); + return ptr; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_malloc/MainHeap_AnalyzeArena.s") +void ZeldaArena_Free(void* ptr) { + __osFree(&sZeldaArena, ptr); +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_malloc/MainHeap_Check.s") +void* ZeldaArena_Calloc(u32 num, size_t size) { + void* ret; + u32 n = num * size; -#pragma GLOBAL_ASM("asm/non_matchings/code/z_malloc/MainHeap_Init.s") + ret = __osMalloc(&sZeldaArena, n); + if (ret != NULL) { + bzero(ret, n); + } -#pragma GLOBAL_ASM("asm/non_matchings/code/z_malloc/MainHeap_Cleanup.s") + return ret; +} -#pragma GLOBAL_ASM("asm/non_matchings/code/z_malloc/MainHeap_IsInitialized.s") +void ZeldaArena_GetSizes(size_t* outMaxFree, size_t* outFree, size_t* outAlloc) { + __osAnalyzeArena(&sZeldaArena, outMaxFree, outFree, outAlloc); +} + +void ZeldaArena_Check() { + __osCheckArena(&sZeldaArena); +} + +void ZeldaArena_Init(void* start, size_t size) { + __osMallocInit(&sZeldaArena, start, size); +} + +void ZeldaArena_Cleanup() { + __osMallocCleanup(&sZeldaArena); +} + +u8 ZeldaArena_IsInitialized() { + return __osMallocIsInitalized(&sZeldaArena); +} diff --git a/src/code/z_pause.c b/src/code/z_pause.c new file mode 100644 index 000000000..44be6238a --- /dev/null +++ b/src/code/z_pause.c @@ -0,0 +1,5 @@ +#include "global.h" + +#pragma GLOBAL_ASM("asm/non_matchings/code/z_pause/func_80122660.s") + +#pragma GLOBAL_ASM("asm/non_matchings/code/z_pause/func_80122670.s") diff --git a/src/code/z_room.c b/src/code/z_room.c index 5f900ea87..5163f1f29 100644 --- a/src/code/z_room.c +++ b/src/code/z_room.c @@ -77,7 +77,7 @@ void Room_Init(GlobalContext* globalCtx, RoomContext* roomCtx) { #ifdef NON_MATCHING s32 Room_StartRoomTransition(GlobalContext* globalCtx, RoomContext* roomCtx, s32 index) { - u32 size; + size_t size; // XXX: this should use a branch-likely if (roomCtx->unk31 == 0) { diff --git a/src/code/z_scene.c b/src/code/z_scene.c index e77144528..b744af5d0 100644 --- a/src/code/z_scene.c +++ b/src/code/z_scene.c @@ -1,7 +1,7 @@ #include "global.h" s32 Object_Spawn(ObjectContext* objectCtx, s16 id) { - u32 size; + size_t size; objectCtx->status[objectCtx->num].id = id; size = objectFileTable[id].vromEnd - objectFileTable[id].vromStart; @@ -23,8 +23,8 @@ s32 Object_Spawn(ObjectContext* objectCtx, s16 id) { return objectCtx->num - 1; } -void Object_InitBank(GameState* gamestate, ObjectContext* objectCtx) { - GlobalContext* globalCtx = (GlobalContext*)gamestate; +void Object_InitBank(GameState* gameState, ObjectContext* objectCtx) { + GlobalContext* globalCtx = (GlobalContext*)gameState; s32 pad; u32 spaceSize; s32 i; @@ -49,7 +49,7 @@ void Object_InitBank(GameState* gamestate, ObjectContext* objectCtx) { for (i = 0; i < OBJECT_EXCHANGE_BANK_MAX; i++) { objectCtx->status[i].id = 0; } // clang-format on - objectCtx->spaceStart = objectCtx->status[0].segment = THA_AllocEndAlign16(&gamestate->heap, spaceSize); + objectCtx->spaceStart = objectCtx->status[0].segment = THA_AllocEndAlign16(&gameState->heap, spaceSize); objectCtx->spaceEnd = (void*)((u32)objectCtx->spaceStart + spaceSize); objectCtx->mainKeepIndex = Object_Spawn(objectCtx, GAMEPLAY_KEEP); @@ -60,7 +60,7 @@ void Object_UpdateBank(ObjectContext* objectCtx) { s32 i; ObjectStatus* status = &objectCtx->status[0]; RomFile* objectFile; - u32 size; + size_t size; for (i = 0; i < objectCtx->num; i++) { if (status->id < 0) { @@ -354,7 +354,7 @@ s32 Scene_LoadAreaTextures(GlobalContext* globalCtx, s32 fileIndex) { { SEGMENT_ROM_START(scene_texture_08), SEGMENT_ROM_END(scene_texture_08) }, }; u32 vromStart = sceneTextureFiles[fileIndex].vromStart; - u32 size = sceneTextureFiles[fileIndex].vromEnd - vromStart; + size_t size = sceneTextureFiles[fileIndex].vromEnd - vromStart; if (size != 0) { globalCtx->roomCtx.unk74 = THA_AllocEndAlign16(&globalCtx->state.heap, size); diff --git a/src/code/z_skelanime.c b/src/code/z_skelanime.c index 16428023a..4cd9734f6 100644 --- a/src/code/z_skelanime.c +++ b/src/code/z_skelanime.c @@ -1,63 +1,57 @@ #include "global.h" -s32 func_80136288(GlobalContext* globalCtx, SkelAnime* skelAnime); -s32 func_8013631C(GlobalContext* globalCtx, SkelAnime* skelAnime); -s32 func_8013702C(SkelAnime* skelAnime); -s32 func_801370B0(SkelAnime* skelAnime); -s32 func_8013713C(SkelAnime* skelAnime); -void SkelAnime_ChangeAnimDefaultRepeat(SkelAnime* skelAnime, AnimationHeader* animationSeg); -void func_80137748(SkelAnime* skelAnime, Vec3f* pos, s16 angle); -void SkelAnime_ChangeLinkAnim(GlobalContext* globalCtx, SkelAnime* skelAnime, - LinkAnimationHeader* linkAnimationHeaderSeg, f32 playbackSpeed, f32 frame, f32 frameCount, - u8 animationMode, f32 transitionRate); -void SkelAnime_CopyVec3s(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src); -void SkelAnime_LinkAnimetionLoaded(GlobalContext* globalCtx, AnimationEntryType0* entry); -void SkelAnime_AnimationType1Loaded(GlobalContext* globalCtx, AnimationEntryType1* entry); -void SkelAnime_AnimationType2Loaded(GlobalContext* globalCtx, AnimationEntryType2* entry); -void SkelAnime_AnimationType3Loaded(GlobalContext* globalCtx, AnimationEntryType3* entry); -void SkelAnime_AnimationType4Loaded(GlobalContext* globalCtx, AnimationEntryType4* entry); -void SkelAnime_AnimationType5Loaded(GlobalContext* globalCtx, AnimationEntryType5* entry); +#define ANIM_INTERP 1 + +s32 LinkAnimation_Loop(GlobalContext* globalCtx, SkelAnime* skelAnime); +s32 LinkAnimation_Once(GlobalContext* globalCtx, SkelAnime* skelAnime); +s32 SkelAnime_LoopFull(SkelAnime* skelAnime); +s32 SkelAnime_LoopPartial(SkelAnime* skelAnime); +s32 SkelAnime_Once(SkelAnime* skelAnime); +void Animation_PlayLoop(SkelAnime* skelAnime, AnimationHeader* animationSeg); +void SkelAnime_UpdateTranslation(SkelAnime* skelAnime, Vec3f* pos, s16 angle); +void LinkAnimation_Change(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* linkAnimetionEntrySeg, + f32 playbackSpeed, f32 frame, f32 frameCount, u8 animationMode, f32 transitionRate); +void SkelAnime_CopyFrameTable(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src); static AnimationEntryCallback sAnimationLoadDone[] = { - (AnimationEntryCallback)SkelAnime_LinkAnimetionLoaded, (AnimationEntryCallback)SkelAnime_AnimationType1Loaded, - (AnimationEntryCallback)SkelAnime_AnimationType2Loaded, (AnimationEntryCallback)SkelAnime_AnimationType3Loaded, - (AnimationEntryCallback)SkelAnime_AnimationType4Loaded, (AnimationEntryCallback)SkelAnime_AnimationType5Loaded, + AnimationContext_LoadFrame, AnimationContext_CopyAll, AnimationContext_Interp, + AnimationContext_CopyTrue, AnimationContext_CopyFalse, AnimationContext_MoveActor, }; -s32 D_801F5AB0; -s32 D_801F5AB4; +s32 sAnimQueueFlags; +s32 sDisableAnimQueueFlags; /* * Draws the limb at `limbIndex` with a level of detail display lists index by `dListIndex` */ -void SkelAnime_LodDrawLimb(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* limbDrawTable, - OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, s32 dListIndex) { - StandardLimb* limbEntry; +void SkelAnime_DrawLimbLod(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* jointTable, + OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor, s32 lod) { + LodLimb* limb; Gfx* dList; Vec3f pos; Vec3s rot; - GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; - s32 pad; - SysMatrix_StatePush(); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); + OPEN_DISPS(globalCtx->state.gfxCtx); + + Matrix_StatePush(); + limb = (LodLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); limbIndex++; - rot = limbDrawTable[limbIndex]; + rot = jointTable[limbIndex]; - pos.x = limbEntry->translation.x; - pos.y = limbEntry->translation.y; - pos.z = limbEntry->translation.z; + pos.x = limb->jointPos.x; + pos.y = limb->jointPos.y; + pos.z = limb->jointPos.z; - dList = limbEntry->displayLists[dListIndex]; + dList = limb->dLists[lod]; if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList, &pos, &rot, actor) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); + Matrix_JointPosition(&pos, &rot); if (dList != NULL) { - Gfx* polyTemp = gfxCtx->polyOpa.p; + Gfx* polyTemp = POLY_OPA_DISP; - gSPMatrix(polyTemp, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); + gSPMatrix(&polyTemp[0], Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); - gSPDisplayList(polyTemp + 1, dList); - gfxCtx->polyOpa.p = polyTemp + 2; + gSPDisplayList(&polyTemp[1], dList); + POLY_OPA_DISP = &polyTemp[2]; } } @@ -65,58 +59,58 @@ void SkelAnime_LodDrawLimb(GlobalContext* globalCtx, s32 limbIndex, void** skele postLimbDraw(globalCtx, limbIndex, &dList, &rot, actor); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - SkelAnime_LodDrawLimb(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, dListIndex); + if (limb->child != LIMB_DONE) { + SkelAnime_DrawLimbLod(globalCtx, limb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor, lod); } - SysMatrix_StatePop(); + Matrix_StatePop(); - if (limbEntry->nextLimbIndex != LIMB_DONE) { - SkelAnime_LodDrawLimb(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, dListIndex); + if (limb->sibling != LIMB_DONE) { + SkelAnime_DrawLimbLod(globalCtx, limb->sibling, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor, + lod); } + + CLOSE_DISPS(globalCtx->state.gfxCtx); } -/* - * Draws the Skeleton described by `skeleton` with a level of detail display list indexed by `dListIndex` +/** + * Draw all limbs of type `LodLimb` in a given skeleton + * Near or far display list is specified via `lod` */ -void SkelAnime_LodDraw(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDrawTable, - OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, s32 dListIndex) { - StandardLimb* limbEntry; +void SkelAnime_DrawLod(GlobalContext* globalCtx, void** skeleton, Vec3s* jointTable, + OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor, s32 lod) { + LodLimb* rootLimb; s32 pad; Gfx* dList; Vec3f pos; Vec3s rot; - GraphicsContext* gfxCtx; - s32 pad2; if (skeleton == NULL) { return; } - gfxCtx = globalCtx->state.gfxCtx; + OPEN_DISPS(globalCtx->state.gfxCtx); - SysMatrix_StatePush(); + Matrix_StatePush(); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[0]); - pos.x = limbDrawTable[0].x; - pos.y = limbDrawTable[0].y; - pos.z = limbDrawTable[0].z; + rootLimb = (LodLimb*)Lib_SegmentedToVirtual(skeleton[0]); + pos.x = jointTable[0].x; + pos.y = jointTable[0].y; + pos.z = jointTable[0].z; - rot = limbDrawTable[1]; - dList = limbEntry->displayLists[dListIndex]; + rot = jointTable[1]; + dList = rootLimb->dLists[lod]; - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList, &pos, &rot, actor) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, 1, &dList, &pos, &rot, actor)) { + Matrix_JointPosition(&pos, &rot); if (dList != NULL) { - Gfx* polyTemp = gfxCtx->polyOpa.p; + Gfx* polyTemp = POLY_OPA_DISP; - gSPMatrix(polyTemp, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); + gSPMatrix(&polyTemp[0], Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); - gSPDisplayList(polyTemp + 1, dList); + gSPDisplayList(&polyTemp[1], dList); - gfxCtx->polyOpa.p = polyTemp + 2; + POLY_OPA_DISP = &polyTemp[2]; } } @@ -124,167 +118,169 @@ void SkelAnime_LodDraw(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDra postLimbDraw(globalCtx, 1, &dList, &rot, actor); } - if (limbEntry->firstChildIndex != 0xFF) { - SkelAnime_LodDrawLimb(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, dListIndex); + if (rootLimb->child != LIMB_DONE) { + SkelAnime_DrawLimbLod(globalCtx, rootLimb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor, + lod); } - SysMatrix_StatePop(); + Matrix_StatePop(); + + CLOSE_DISPS(globalCtx->state.gfxCtx); } -/* - * Draws the limb at `limbIndex` with a level of detail display lists index by `dListIndex`, Limb matrices come - * from a dynamic allocation from the graph arena. - */ -void SkelAnime_LodDrawLimbSV(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* limbDrawTable, - OverrideLimbDrawSV overrideLimbDraw, PostLimbDrawSV postLimbDraw, Actor* actor, - s32 dListIndex, RSPMatrix** mtx) { - StandardLimb* limbEntry; - Gfx* dList[2]; +/** + * Draw a limb of type `LodLimb` contained within a flexible skeleton + * Near or far display list is specified via `lod` + */ +void SkelAnime_DrawFlexLimbLod(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* jointTable, + OverrideLimbDrawFlex overrideLimbDraw, PostLimbDrawFlex postLimbDraw, Actor* actor, + s32 lod, Mtx** mtx) { + LodLimb* limb; + Gfx* newDList; + Gfx* limbDList; Vec3f pos; Vec3s rot; - GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; - s32 pad; - SysMatrix_StatePush(); + OPEN_DISPS(globalCtx->state.gfxCtx); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); + Matrix_StatePush(); + + limb = (LodLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); limbIndex++; - rot = limbDrawTable[limbIndex]; - - pos.x = limbEntry->translation.x; - pos.y = limbEntry->translation.y; - pos.z = limbEntry->translation.z; - // Double assignment here would not work. - dList[0] = limbEntry->displayLists[dListIndex]; - dList[1] = dList[0]; - - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList[1], &pos, &rot, actor) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); - if (dList[1] != NULL) { - SysMatrix_GetStateAsRSPMatrix(*mtx); - gSPMatrix(gfxCtx->polyOpa.p++, *mtx, G_MTX_LOAD); - gSPDisplayList(gfxCtx->polyOpa.p++, dList[1]); + rot = jointTable[limbIndex]; + + pos.x = limb->jointPos.x; + pos.y = limb->jointPos.y; + pos.z = limb->jointPos.z; + + newDList = limbDList = limb->dLists[lod]; + + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, limbIndex, &newDList, &pos, &rot, actor)) { + Matrix_JointPosition(&pos, &rot); + if (newDList != NULL) { + Matrix_ToMtx(*mtx); + gSPMatrix(POLY_OPA_DISP++, *mtx, G_MTX_LOAD); + gSPDisplayList(POLY_OPA_DISP++, newDList); (*mtx)++; - } else if (dList[0] != NULL) { - SysMatrix_GetStateAsRSPMatrix(*mtx); + } else if (limbDList != NULL) { + Matrix_ToMtx(*mtx); (*mtx)++; } } if (postLimbDraw != NULL) { - postLimbDraw(globalCtx, limbIndex, &dList[1], &dList[0], &rot, actor); + postLimbDraw(globalCtx, limbIndex, &newDList, &limbDList, &rot, actor); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - SkelAnime_LodDrawLimbSV(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, dListIndex, mtx); + if (limb->child != LIMB_DONE) { + SkelAnime_DrawFlexLimbLod(globalCtx, limb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor, + lod, mtx); } - SysMatrix_StatePop(); + Matrix_StatePop(); - if (limbEntry->nextLimbIndex != LIMB_DONE) { - SkelAnime_LodDrawLimbSV(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, dListIndex, mtx); + if (limb->sibling != LIMB_DONE) { + SkelAnime_DrawFlexLimbLod(globalCtx, limb->sibling, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor, + lod, mtx); } + + CLOSE_DISPS(globalCtx->state.gfxCtx); } -/* - * Draws the Skeleton described by `skeleton` with a level of detail display list indexed by `dListIndex` - * Matricies for the limbs are dynamically allocted from the graph arena. The dynamic allocation occurs - * because the Skeleton is too large to be supported by the normal matrix stack. - */ -void SkelAnime_LodDrawSV(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDrawTable, s32 dListCount, - OverrideLimbDrawSV overrideLimbDraw, PostLimbDrawSV postLimbDraw, Actor* actor, - s32 dListIndex) { - StandardLimb* limbEntry; +/** + * Draws all limbs of type `LodLimb` in a given flexible skeleton + * Limbs in a flexible skeleton have meshes that can stretch to line up with other limbs. + * An array of matrices is dynamically allocated so each limb can access any transform to ensure its meshes line up. + */ +void SkelAnime_DrawFlexLod(GlobalContext* globalCtx, void** skeleton, Vec3s* jointTable, s32 dListCount, + OverrideLimbDrawFlex overrideLimbDraw, PostLimbDrawFlex postLimbDraw, Actor* actor, + s32 lod) { + LodLimb* rootLimb; s32 pad; - Gfx* dList[2]; + Gfx* newDList; + Gfx* limbDList; Vec3f pos; Vec3s rot; - RSPMatrix* mtx; - GraphicsContext* gfxCtx; - s32 pad2; - - mtx = (RSPMatrix*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(RSPMatrix) * dListCount)); + Mtx* mtx = (Mtx*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(Mtx) * dListCount)); if (skeleton == NULL) { return; } - gfxCtx = globalCtx->state.gfxCtx; + OPEN_DISPS(globalCtx->state.gfxCtx); - gSPSegment(gfxCtx->polyOpa.p++, 0xD, mtx); - SysMatrix_StatePush(); + gSPSegment(POLY_OPA_DISP++, 0xD, mtx); + Matrix_StatePush(); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[0]); - pos.x = limbDrawTable[0].x; - pos.y = limbDrawTable[0].y; - pos.z = limbDrawTable[0].z; + rootLimb = (LodLimb*)Lib_SegmentedToVirtual(skeleton[0]); + pos.x = jointTable[0].x; + pos.y = jointTable[0].y; + pos.z = jointTable[0].z; - rot = limbDrawTable[1]; + rot = jointTable[1]; - dList[0] = limbEntry->displayLists[dListIndex]; - dList[1] = dList[0]; + newDList = limbDList = rootLimb->dLists[lod]; - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList[1], &pos, &rot, actor) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); - if (dList[1] != NULL) { - Gfx* polyTemp = gfxCtx->polyOpa.p; + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, 1, &newDList, &pos, &rot, actor)) { + Matrix_JointPosition(&pos, &rot); + if (newDList != NULL) { + Gfx* polyTemp = POLY_OPA_DISP; - gSPMatrix(polyTemp, SysMatrix_GetStateAsRSPMatrix(mtx), G_MTX_LOAD); - gSPDisplayList(polyTemp + 1, dList[1]); - gfxCtx->polyOpa.p = polyTemp + 2; + gSPMatrix(&polyTemp[0], Matrix_ToMtx(mtx), G_MTX_LOAD); + gSPDisplayList(&polyTemp[1], newDList); + POLY_OPA_DISP = &polyTemp[2]; mtx++; - } else if (dList[0] != NULL) { - SysMatrix_GetStateAsRSPMatrix(mtx); + } else if (limbDList != NULL) { + Matrix_ToMtx(mtx); mtx++; } } if (postLimbDraw != NULL) { - postLimbDraw(globalCtx, 1, &dList[1], &dList[0], &rot, actor); + postLimbDraw(globalCtx, 1, &newDList, &limbDList, &rot, actor); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - SkelAnime_LodDrawLimbSV(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, dListIndex, &mtx); + if (rootLimb->child != LIMB_DONE) { + SkelAnime_DrawFlexLimbLod(globalCtx, rootLimb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, + actor, lod, &mtx); } - SysMatrix_StatePop(); + Matrix_StatePop(); + + CLOSE_DISPS(globalCtx->state.gfxCtx); } /* * Draws the limb of the Skeleton `skeleton` at `limbIndex` */ -void SkelAnime_DrawLimb(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* limbDrawTable, - OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor) { - StandardLimb* limbEntry; +void SkelAnime_DrawLimbOpa(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* jointTable, + OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor) { + StandardLimb* limb; Gfx* dList; Vec3f pos; Vec3s rot; - GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; - s32 pad; - SysMatrix_StatePush(); + OPEN_DISPS(globalCtx->state.gfxCtx); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); - limbIndex++; - rot = limbDrawTable[limbIndex]; - pos.x = limbEntry->translation.x; - pos.y = limbEntry->translation.y; - pos.z = limbEntry->translation.z; - dList = limbEntry->displayLists[0]; + Matrix_StatePush(); - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList, &pos, &rot, actor) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); + limb = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); + limbIndex++; + rot = jointTable[limbIndex]; + pos.x = limb->jointPos.x; + pos.y = limb->jointPos.y; + pos.z = limb->jointPos.z; + dList = limb->dList; + + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, limbIndex, &dList, &pos, &rot, actor)) { + Matrix_JointPosition(&pos, &rot); if (dList != NULL) { - Gfx* polyTemp = gfxCtx->polyOpa.p; + Gfx* polyTemp = POLY_OPA_DISP; - gSPMatrix(polyTemp, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); - gSPDisplayList(polyTemp + 1, dList); - gfxCtx->polyOpa.p = polyTemp + 2; + gSPMatrix(&polyTemp[0], Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); + gSPDisplayList(&polyTemp[1], dList); + POLY_OPA_DISP = &polyTemp[2]; } } @@ -292,53 +288,54 @@ void SkelAnime_DrawLimb(GlobalContext* globalCtx, s32 limbIndex, void** skeleton postLimbDraw(globalCtx, limbIndex, &dList, &rot, actor); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - SkelAnime_DrawLimb(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor); + if (limb->child != LIMB_DONE) { + SkelAnime_DrawLimbOpa(globalCtx, limb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor); } - SysMatrix_StatePop(); + Matrix_StatePop(); - if (limbEntry->nextLimbIndex != LIMB_DONE) { - SkelAnime_DrawLimb(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw, postLimbDraw, - actor); + if (limb->sibling != LIMB_DONE) { + SkelAnime_DrawLimbOpa(globalCtx, limb->sibling, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor); } + + CLOSE_DISPS(globalCtx->state.gfxCtx); } -void SkelAnime_Draw(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDrawTable, OverrideLimbDraw overrideLimbDraw, - PostLimbDraw postLimbDraw, Actor* actor) { +/** + * Draw all limbs of type `StandardLimb` in a given skeleton to the polyOpa buffer + */ +void SkelAnime_DrawOpa(GlobalContext* globalCtx, void** skeleton, Vec3s* jointTable, + OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor) { StandardLimb* rootLimb; s32 pad; Gfx* dList; Vec3f pos; Vec3s rot; - GraphicsContext* gfxCtx; - s32 pad2; if (skeleton == NULL) { return; } - gfxCtx = globalCtx->state.gfxCtx; + OPEN_DISPS(globalCtx->state.gfxCtx); - SysMatrix_StatePush(); - rootLimb = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[0]); + Matrix_StatePush(); + rootLimb = Lib_SegmentedToVirtual(skeleton[0]); - pos.x = limbDrawTable[0].x; - pos.y = limbDrawTable[0].y; - pos.z = limbDrawTable[0].z; + pos.x = jointTable[0].x; + pos.y = jointTable[0].y; + pos.z = jointTable[0].z; - rot = limbDrawTable[1]; - dList = rootLimb->displayLists[0]; + rot = jointTable[1]; + dList = rootLimb->dList; - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList, &pos, &rot, actor) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, 1, &dList, &pos, &rot, actor)) { + Matrix_JointPosition(&pos, &rot); if (dList != NULL) { - Gfx* polyTemp = gfxCtx->polyOpa.p; + Gfx* polyTemp = POLY_OPA_DISP; - gSPMatrix(polyTemp, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); - gSPDisplayList(polyTemp + 1, dList); - gfxCtx->polyOpa.p = polyTemp + 2; + gSPMatrix(&polyTemp[0], Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); + gSPDisplayList(&polyTemp[1], dList); + POLY_OPA_DISP = &polyTemp[2]; } } @@ -346,318 +343,333 @@ void SkelAnime_Draw(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDrawTa postLimbDraw(globalCtx, 1, &dList, &rot, actor); } - if (rootLimb->firstChildIndex != LIMB_DONE) { - SkelAnime_DrawLimb(globalCtx, rootLimb->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor); + if (rootLimb->child != LIMB_DONE) { + SkelAnime_DrawLimbOpa(globalCtx, rootLimb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor); } - SysMatrix_StatePop(); + Matrix_StatePop(); + + CLOSE_DISPS(globalCtx->state.gfxCtx); } -void SkelAnime_DrawLimbSV(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* limbDrawTable, - OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, - RSPMatrix** limbMatricies) { - StandardLimb* limbEntry; - Gfx* dList[2]; +void SkelAnime_DrawFlexLimbOpa(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* jointTable, + OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor, + Mtx** limbMatricies) { + StandardLimb* limb; + Gfx* newDList; + Gfx* limbDList; Vec3f pos; Vec3s rot; - GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; - s32 pad; - SysMatrix_StatePush(); + OPEN_DISPS(globalCtx->state.gfxCtx); + + Matrix_StatePush(); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); + limb = Lib_SegmentedToVirtual(skeleton[limbIndex]); limbIndex++; - rot = limbDrawTable[limbIndex]; + rot = jointTable[limbIndex]; - pos.x = limbEntry->translation.x; - pos.y = limbEntry->translation.y; - pos.z = limbEntry->translation.z; + pos.x = limb->jointPos.x; + pos.y = limb->jointPos.y; + pos.z = limb->jointPos.z; - dList[0] = limbEntry->displayLists[0]; - dList[1] = dList[0]; + newDList = limbDList = limb->dList; - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList[1], &pos, &rot, actor) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); - if (dList[1] != NULL) { - SysMatrix_GetStateAsRSPMatrix(*limbMatricies); - gSPMatrix(gfxCtx->polyOpa.p++, *limbMatricies, G_MTX_LOAD); - gSPDisplayList(gfxCtx->polyOpa.p++, dList[1]); + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, limbIndex, &newDList, &pos, &rot, actor)) { + Matrix_JointPosition(&pos, &rot); + if (newDList != NULL) { + Matrix_ToMtx(*limbMatricies); + gSPMatrix(POLY_OPA_DISP++, *limbMatricies, G_MTX_LOAD); + gSPDisplayList(POLY_OPA_DISP++, newDList); (*limbMatricies)++; - } else if (dList[0] != NULL) { - SysMatrix_GetStateAsRSPMatrix(*limbMatricies); + } else if (limbDList != NULL) { + Matrix_ToMtx(*limbMatricies); (*limbMatricies)++; } } if (postLimbDraw != NULL) { - postLimbDraw(globalCtx, limbIndex, &dList[0], &rot, actor); + postLimbDraw(globalCtx, limbIndex, &limbDList, &rot, actor); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - SkelAnime_DrawLimbSV(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, limbMatricies); + if (limb->child != LIMB_DONE) { + SkelAnime_DrawFlexLimbOpa(globalCtx, limb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor, + limbMatricies); } - SysMatrix_StatePop(); + Matrix_StatePop(); - if (limbEntry->nextLimbIndex != LIMB_DONE) { - SkelAnime_DrawLimbSV(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, limbMatricies); + if (limb->sibling != LIMB_DONE) { + SkelAnime_DrawFlexLimbOpa(globalCtx, limb->sibling, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor, + limbMatricies); } + + CLOSE_DISPS(globalCtx->state.gfxCtx); } -void SkelAnime_DrawSV(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDrawTable, s32 dListCount, - OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor) { - StandardLimb* limbEntry; +/** + * Draw all limbs of type `StandardLimb` in a given flexible skeleton to the polyOpa buffer + * Limbs in a flexible skeleton have meshes that can stretch to line up with other limbs. + * An array of matrices is dynamically allocated so each limb can access any transform to ensure its meshes line up. + */ +void SkelAnime_DrawFlexOpa(GlobalContext* globalCtx, void** skeleton, Vec3s* jointTable, s32 dListCount, + OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, Actor* actor) { + StandardLimb* rootLimb; s32 pad; - Gfx* dList[2]; + Gfx* newDList; + Gfx* limbDList; Vec3f pos; Vec3s rot; - RSPMatrix* mtx; - GraphicsContext* gfxCtx; - s32 pad2; - - mtx = (RSPMatrix*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(RSPMatrix) * dListCount)); + Mtx* mtx = (Mtx*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(Mtx) * dListCount)); if (skeleton == NULL) { return; } - gfxCtx = globalCtx->state.gfxCtx; + OPEN_DISPS(globalCtx->state.gfxCtx); - gSPSegment(gfxCtx->polyOpa.p++, 0xD, mtx); + gSPSegment(POLY_OPA_DISP++, 0xD, mtx); - SysMatrix_StatePush(); + Matrix_StatePush(); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[0]); + rootLimb = Lib_SegmentedToVirtual(skeleton[0]); - pos.x = limbDrawTable[0].x; - pos.y = limbDrawTable[0].y; - pos.z = limbDrawTable[0].z; - rot = limbDrawTable[1]; + pos.x = jointTable[0].x; + pos.y = jointTable[0].y; + pos.z = jointTable[0].z; + rot = jointTable[1]; - dList[0] = limbEntry->displayLists[0]; - dList[1] = dList[0]; + newDList = limbDList = rootLimb->dList; - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList[1], &pos, &rot, actor) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); - if (dList[1] != NULL) { - Gfx* polyTemp = gfxCtx->polyOpa.p; + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, 1, &newDList, &pos, &rot, actor)) { + Matrix_JointPosition(&pos, &rot); + if (newDList != NULL) { + Gfx* polyTemp = POLY_OPA_DISP; - gSPMatrix(polyTemp, SysMatrix_GetStateAsRSPMatrix(mtx), G_MTX_LOAD); - gSPDisplayList(polyTemp + 1, dList[1]); - gfxCtx->polyOpa.p = polyTemp + 2; + gSPMatrix(&polyTemp[0], Matrix_ToMtx(mtx), G_MTX_LOAD); + gSPDisplayList(&polyTemp[1], newDList); + POLY_OPA_DISP = &polyTemp[2]; mtx++; } else { - if (dList[0] != NULL) { - SysMatrix_GetStateAsRSPMatrix(mtx); + if (limbDList != NULL) { + Matrix_ToMtx(mtx); mtx++; } } } if (postLimbDraw != NULL) { - postLimbDraw(globalCtx, 1, &dList[0], &rot, actor); + postLimbDraw(globalCtx, 1, &limbDList, &rot, actor); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - SkelAnime_DrawLimbSV(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, &mtx); + if (rootLimb->child != LIMB_DONE) { + SkelAnime_DrawFlexLimbOpa(globalCtx, rootLimb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, + actor, &mtx); } - SysMatrix_StatePop(); + Matrix_StatePop(); + + CLOSE_DISPS(globalCtx->state.gfxCtx); } -void func_80134148(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* limbDrawTable, - OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, UnkActorDraw unkDraw, Actor* actor, - RSPMatrix** mtx) { - StandardLimb* limbEntry; - Gfx* dList[2]; +void func_80134148(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* jointTable, + OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, UnkActorDraw unkDraw, + Actor* actor, Mtx** mtx) { + StandardLimb* limb; + Gfx* newDList; + Gfx* limbDList; Vec3f pos; Vec3s rot; - GraphicsContext* gfxCtx = globalCtx->state.gfxCtx; - s32 pad2; - SysMatrix_StatePush(); + OPEN_DISPS(globalCtx->state.gfxCtx); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); + Matrix_StatePush(); + + limb = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); limbIndex++; - rot = limbDrawTable[limbIndex]; - pos.x = limbEntry->translation.x; - pos.y = limbEntry->translation.y; - pos.z = limbEntry->translation.z; + rot = jointTable[limbIndex]; + pos.x = limb->jointPos.x; + pos.y = limb->jointPos.y; + pos.z = limb->jointPos.z; + + newDList = limbDList = limb->dList; - dList[0] = limbEntry->displayLists[0]; - dList[1] = dList[0]; + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, limbIndex, &newDList, &pos, &rot, actor)) { + Matrix_JointPosition(&pos, &rot); + Matrix_StatePush(); - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList[1], &pos, &rot, actor) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); - SysMatrix_StatePush(); + //! @bug Does not check unkDraw is not NULL before calling it. unkDraw(globalCtx, limbIndex, actor); - if (dList[1] != NULL) { - Gfx* polyTemp = gfxCtx->polyOpa.p; + if (newDList != NULL) { + Gfx* polyTemp = POLY_OPA_DISP; - gSPMatrix(polyTemp, SysMatrix_GetStateAsRSPMatrix(*mtx), G_MTX_LOAD); - gSPDisplayList(polyTemp + 1, dList[1]); - gfxCtx->polyOpa.p = polyTemp + 2; + gSPMatrix(&polyTemp[0], Matrix_ToMtx(*mtx), G_MTX_LOAD); + gSPDisplayList(&polyTemp[1], newDList); + POLY_OPA_DISP = &polyTemp[2]; (*mtx)++; } else { - if (dList[0] != NULL) { - SysMatrix_GetStateAsRSPMatrix(*mtx); + if (limbDList != NULL) { + Matrix_ToMtx(*mtx); (*mtx)++; } } - SysMatrix_StatePop(); + Matrix_StatePop(); } if (postLimbDraw != NULL) { - postLimbDraw(globalCtx, limbIndex, &dList[0], &rot, actor); + postLimbDraw(globalCtx, limbIndex, &limbDList, &rot, actor); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - func_80134148(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, postLimbDraw, - unkDraw, actor, mtx); + if (limb->child != LIMB_DONE) { + func_80134148(globalCtx, limb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, unkDraw, actor, + mtx); } - SysMatrix_StatePop(); + Matrix_StatePop(); - if (limbEntry->nextLimbIndex != LIMB_DONE) { - func_80134148(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw, postLimbDraw, - unkDraw, actor, mtx); + if (limb->sibling != LIMB_DONE) { + func_80134148(globalCtx, limb->sibling, skeleton, jointTable, overrideLimbDraw, postLimbDraw, unkDraw, actor, + mtx); } + + CLOSE_DISPS(globalCtx->state.gfxCtx); } -void func_801343C0(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDrawTable, s32 dListCount, - OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, UnkActorDraw unkDraw, Actor* actor) { - StandardLimb* limbEntry; +void func_801343C0(GlobalContext* globalCtx, void** skeleton, Vec3s* jointTable, s32 dListCount, + OverrideLimbDrawOpa overrideLimbDraw, PostLimbDrawOpa postLimbDraw, UnkActorDraw unkDraw, + Actor* actor) { + StandardLimb* rootLimb; s32 pad; - Gfx* dList[2]; + Gfx* newDList; + Gfx* limbDList; Vec3f pos; Vec3s rot; - RSPMatrix* mtx; - GraphicsContext* gfxCtx; - s32 pad2; + Mtx* mtx; if (skeleton == NULL) { return; } - gfxCtx = globalCtx->state.gfxCtx; + OPEN_DISPS(globalCtx->state.gfxCtx); - mtx = (RSPMatrix*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(RSPMatrix) * dListCount)); + mtx = (Mtx*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(Mtx) * dListCount)); - gSPSegment(gfxCtx->polyOpa.p++, 0xD, mtx); + gSPSegment(POLY_OPA_DISP++, 0xD, mtx); - SysMatrix_StatePush(); + Matrix_StatePush(); + + rootLimb = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[0]); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[0]); + pos.x = jointTable[0].x; + pos.y = jointTable[0].y; + pos.z = jointTable[0].z; + rot = jointTable[1]; - pos.x = limbDrawTable[0].x; - pos.y = limbDrawTable[0].y; - pos.z = limbDrawTable[0].z; - rot = limbDrawTable[1]; + newDList = limbDList = rootLimb->dList; - dList[0] = limbEntry->displayLists[0]; - dList[1] = dList[0]; + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, 1, &newDList, &pos, &rot, actor)) { + Matrix_JointPosition(&pos, &rot); + Matrix_StatePush(); - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList[1], &pos, &rot, actor) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); - SysMatrix_StatePush(); + //! @bug Does not check unkDraw is not NULL before calling it. unkDraw(globalCtx, 1, actor); - if (dList[1] != NULL) { - Gfx* polyTemp = gfxCtx->polyOpa.p; - gSPMatrix(polyTemp, SysMatrix_GetStateAsRSPMatrix(mtx), G_MTX_LOAD); - gSPDisplayList(polyTemp + 1, dList[1]); - gfxCtx->polyOpa.p = polyTemp + 2; + if (newDList != NULL) { + Gfx* polyTemp = POLY_OPA_DISP; + + gSPMatrix(&polyTemp[0], Matrix_ToMtx(mtx), G_MTX_LOAD); + gSPDisplayList(&polyTemp[1], newDList); + POLY_OPA_DISP = &polyTemp[2]; mtx++; } else { - if (dList[0] != NULL) { - SysMatrix_GetStateAsRSPMatrix(mtx++); + if (limbDList != NULL) { + Matrix_ToMtx(mtx++); } } - SysMatrix_StatePop(); + Matrix_StatePop(); } if (postLimbDraw != NULL) { - postLimbDraw(globalCtx, 1, &dList[0], &rot, actor); + postLimbDraw(globalCtx, 1, &limbDList, &rot, actor); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - func_80134148(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, postLimbDraw, - unkDraw, actor, &mtx); + if (rootLimb->child != LIMB_DONE) { + func_80134148(globalCtx, rootLimb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, unkDraw, actor, + &mtx); } - SysMatrix_StatePop(); + Matrix_StatePop(); + + CLOSE_DISPS(globalCtx->state.gfxCtx); } -/* - * Copies the rotation values from the rotation value table, indexed by the rotation index table - * When a rotation index is >= the animation limit, the output rotation value is copied from the frame's - * rotation value list, otherwise it is copied from the initial rotation value list - */ -void SkelAnime_AnimateFrame(AnimationHeader* animationSeg, s32 currentFrame, s32 limbCount, Vec3s* dst) { - AnimationHeader* animationHeader = Lib_SegmentedToVirtual(animationSeg); - JointIndex* index = Lib_SegmentedToVirtual(animationHeader->jointIndices); - AnimationRotationValue* rotationValueTable = Lib_SegmentedToVirtual(animationHeader->frameData); - AnimationRotationValue* frameRotationValueTable = &rotationValueTable[currentFrame]; +/** + * Copies frame data from the frame data table, indexed by the joint index table. + * Indices below staticIndexMax are copied from that entry in the static frame data table. + * Indices above staticIndexMax are offsets to a frame data array indexed by the frame. + */ +void SkelAnime_GetFrameData(AnimationHeader* animation, s32 frame, s32 limbCount, Vec3s* frameTable) { + AnimationHeader* animHeader = Lib_SegmentedToVirtual(animation); + JointIndex* jointIndices = Lib_SegmentedToVirtual(animHeader->jointIndices); + s16* frameData = Lib_SegmentedToVirtual(animHeader->frameData); + s16* dynamicData = &frameData[frame]; s32 i; - u16 limit = animationHeader->staticIndexMax; + u16 staticIndexMax = animHeader->staticIndexMax; for (i = 0; i < limbCount; i++) { // Debug prints here, this is needed to prevent loop unrolling if (0) { if (0) {}; } - dst->x = index->x >= limit ? frameRotationValueTable[index->x] : rotationValueTable[index->x]; - dst->y = index->y >= limit ? frameRotationValueTable[index->y] : rotationValueTable[index->y]; - dst->z = index->z >= limit ? frameRotationValueTable[index->z] : rotationValueTable[index->z]; - index++, dst++; + frameTable->x = jointIndices->x >= staticIndexMax ? dynamicData[jointIndices->x] : frameData[jointIndices->x]; + frameTable->y = jointIndices->y >= staticIndexMax ? dynamicData[jointIndices->y] : frameData[jointIndices->y]; + frameTable->z = jointIndices->z >= staticIndexMax ? dynamicData[jointIndices->z] : frameData[jointIndices->z]; + jointIndices++, frameTable++; } } -s16 SkelAnime_GetTotalFrames(AnimationHeaderCommon* animationSeg) { - AnimationHeaderCommon* animation = Lib_SegmentedToVirtual(animationSeg); - return animation->frameCount; +s16 Animation_GetLength(void* animation) { + AnimationHeaderCommon* common = Lib_SegmentedToVirtual(animation); + + return common->frameCount; } -s16 SkelAnime_GetFrameCount(AnimationHeaderCommon* animationSeg) { - AnimationHeaderCommon* animation = Lib_SegmentedToVirtual(animationSeg); +s16 Animation_GetLastFrame(void* animation) { + AnimationHeaderCommon* common = Lib_SegmentedToVirtual(animation); - return (u16)animation->frameCount - 1; + return (u16)common->frameCount - 1; } /* * Draws the Skeleton `skeleton`'s limb at index `limbIndex`. Appends all generated graphics commands to * `gfx`. Returns a pointer to the next gfx to be appended to. */ -Gfx* SkelAnime_Draw2Limb(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* limbDrawTable, - OverrideLimbDraw2 overrideLimbDraw, PostLimbDraw2 postLimbDraw, Actor* actor, Gfx* gfx) { - StandardLimb* limbEntry; +Gfx* SkelAnime_DrawLimb(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* jointTable, + OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, Gfx* gfx) { + StandardLimb* limb; Gfx* dList; Vec3f pos; Vec3s rot; - SysMatrix_StatePush(); + Matrix_StatePush(); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); + limb = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); limbIndex++; - rot = limbDrawTable[limbIndex]; - pos.x = limbEntry->translation.x; - pos.y = limbEntry->translation.y; - pos.z = limbEntry->translation.z; + rot = jointTable[limbIndex]; + pos.x = limb->jointPos.x; + pos.y = limb->jointPos.y; + pos.z = limb->jointPos.z; - dList = limbEntry->displayLists[0]; + dList = limb->dList; - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList, &pos, &rot, actor, &gfx) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, limbIndex, &dList, &pos, &rot, actor, &gfx)) { + Matrix_JointPosition(&pos, &rot); if (dList != NULL) { - gSPMatrix(gfx, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); - gSPDisplayList(gfx + 1, dList); - gfx = gfx + 2; + gSPMatrix(&gfx[0], Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); + gSPDisplayList(&gfx[1], dList); + gfx = &gfx[2]; } } @@ -665,16 +677,16 @@ Gfx* SkelAnime_Draw2Limb(GlobalContext* globalCtx, s32 limbIndex, void** skeleto postLimbDraw(globalCtx, limbIndex, &dList, &rot, actor, &gfx); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - gfx = SkelAnime_Draw2Limb(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, gfx); + if (limb->child != LIMB_DONE) { + gfx = SkelAnime_DrawLimb(globalCtx, limb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor, + gfx); } - SysMatrix_StatePop(); + Matrix_StatePop(); - if (limbEntry->nextLimbIndex != LIMB_DONE) { - gfx = SkelAnime_Draw2Limb(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, gfx); + if (limb->sibling != LIMB_DONE) { + gfx = SkelAnime_DrawLimb(globalCtx, limb->sibling, skeleton, jointTable, overrideLimbDraw, postLimbDraw, actor, + gfx); } return gfx; @@ -684,9 +696,9 @@ Gfx* SkelAnime_Draw2Limb(GlobalContext* globalCtx, s32 limbIndex, void** skeleto * Draws the Skeleton `skeleton` Appends all generated graphics to `gfx`, and returns a pointer to the * next gfx to be appended to. */ -Gfx* SkelAnime_Draw2(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDrawTable, - OverrideLimbDraw2 overrideLimbDraw, PostLimbDraw2 postLimbDraw, Actor* actor, Gfx* gfx) { - StandardLimb* limbEntry; +Gfx* SkelAnime_Draw(GlobalContext* globalCtx, void** skeleton, Vec3s* jointTable, OverrideLimbDraw overrideLimbDraw, + PostLimbDraw postLimbDraw, Actor* actor, Gfx* gfx) { + StandardLimb* rootLimb; s32 pad; Gfx* dList; Vec3f pos; @@ -696,23 +708,24 @@ Gfx* SkelAnime_Draw2(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDrawT return NULL; } - SysMatrix_StatePush(); + Matrix_StatePush(); + + rootLimb = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[0]); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[0]); + pos.x = jointTable[0].x; + pos.y = jointTable[0].y; + pos.z = jointTable[0].z; - pos.x = limbDrawTable[0].x; - pos.y = limbDrawTable[0].y; - pos.z = limbDrawTable[0].z; - rot = limbDrawTable[1]; + rot = jointTable[1]; - dList = limbEntry->displayLists[0]; + dList = rootLimb->dList; - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList, &pos, &rot, actor, &gfx) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, 1, &dList, &pos, &rot, actor, &gfx)) { + Matrix_JointPosition(&pos, &rot); if (dList != NULL) { - gSPMatrix(gfx, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); - gSPDisplayList(gfx + 1, dList); - gfx = gfx + 2; + gSPMatrix(&gfx[0], Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_LOAD); + gSPDisplayList(&gfx[1], dList); + gfx = &gfx[2]; } } @@ -720,202 +733,285 @@ Gfx* SkelAnime_Draw2(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDrawT postLimbDraw(globalCtx, 1, &dList, &rot, actor, &gfx); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - gfx = SkelAnime_Draw2Limb(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, gfx); + if (rootLimb->child != LIMB_DONE) { + gfx = SkelAnime_DrawLimb(globalCtx, rootLimb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, + actor, gfx); } - SysMatrix_StatePop(); + Matrix_StatePop(); return gfx; } -/* - * Draws the Skeleton `skeleton` Appends all generated graphics to `gfx`, and returns a pointer to the - * next gfx to be appended to. Allocates matricies for display lists on the graph heap. - */ -Gfx* SkelAnime_DrawLimbSV2(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* limbDrawTable, - OverrideLimbDraw2 overrideLimbDraw, PostLimbDraw2 postLimbDraw, Actor* actor, - RSPMatrix** mtx, Gfx* gfx) { - StandardLimb* limbEntry; - Gfx* dList1; - Gfx* dList2; +/** + * Draw a limb of type `StandardLimb` contained within a flexible skeleton to the specified display buffer + */ +Gfx* SkelAnime_DrawFlexLimb(GlobalContext* globalCtx, s32 limbIndex, void** skeleton, Vec3s* jointTable, + OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, Mtx** mtx, + Gfx* gfx) { + StandardLimb* limb; + Gfx* newDList; + Gfx* limbDList; Vec3f pos; Vec3s rot; - SysMatrix_StatePush(); + Matrix_StatePush(); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); + limb = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[limbIndex]); limbIndex++; - rot = limbDrawTable[limbIndex]; + rot = jointTable[limbIndex]; - pos.x = limbEntry->translation.x; - pos.y = limbEntry->translation.y; - pos.z = limbEntry->translation.z; + pos.x = limb->jointPos.x; + pos.y = limb->jointPos.y; + pos.z = limb->jointPos.z; - dList1 = dList2 = limbEntry->displayLists[0]; + newDList = limbDList = limb->dList; - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, limbIndex, &dList1, &pos, &rot, actor, &gfx) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); - if (dList1 != NULL) { - gSPMatrix(gfx, SysMatrix_GetStateAsRSPMatrix(*mtx), G_MTX_LOAD); - gSPDisplayList(gfx + 1, dList1); - gfx = gfx + 2; + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, limbIndex, &newDList, &pos, &rot, actor, &gfx)) { + Matrix_JointPosition(&pos, &rot); + if (newDList != NULL) { + gSPMatrix(&gfx[0], Matrix_ToMtx(*mtx), G_MTX_LOAD); + gSPDisplayList(&gfx[1], newDList); + gfx = &gfx[2]; (*mtx)++; } else { - if (dList2 != NULL) { - SysMatrix_GetStateAsRSPMatrix(*mtx); + if (limbDList != NULL) { + Matrix_ToMtx(*mtx); (*mtx)++; } } } if (postLimbDraw != NULL) { - postLimbDraw(globalCtx, limbIndex, &dList2, &rot, actor, &gfx); + postLimbDraw(globalCtx, limbIndex, &limbDList, &rot, actor, &gfx); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - gfx = SkelAnime_DrawLimbSV2(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, mtx, gfx); + if (limb->child != LIMB_DONE) { + gfx = SkelAnime_DrawFlexLimb(globalCtx, limb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, + actor, mtx, gfx); } - SysMatrix_StatePop(); + Matrix_StatePop(); - if (limbEntry->nextLimbIndex != LIMB_DONE) { - gfx = SkelAnime_DrawLimbSV2(globalCtx, limbEntry->nextLimbIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, mtx, gfx); + if (limb->sibling != LIMB_DONE) { + gfx = SkelAnime_DrawFlexLimb(globalCtx, limb->sibling, skeleton, jointTable, overrideLimbDraw, postLimbDraw, + actor, mtx, gfx); } return gfx; } -Gfx* SkelAnime_DrawSV2(GlobalContext* globalCtx, void** skeleton, Vec3s* limbDrawTable, s32 dListCount, - OverrideLimbDraw2 overrideLimbDraw, PostLimbDraw2 postLimbDraw, Actor* actor, Gfx* gfx) { - StandardLimb* limbEntry; +/** + * Draw all limbs of type `StandardLimb` in a given flexible skeleton to the specified display buffer + * Limbs in a flexible skeleton have meshes that can stretch to line up with other limbs. + * An array of matrices is dynamically allocated so each limb can access any transform to ensure its meshes line up. + */ +Gfx* SkelAnime_DrawFlex(GlobalContext* globalCtx, void** skeleton, Vec3s* jointTable, s32 dListCount, + OverrideLimbDraw overrideLimbDraw, PostLimbDraw postLimbDraw, Actor* actor, Gfx* gfx) { + StandardLimb* rootLimb; s32 pad; - Gfx* dList1; - Gfx* dList2; + Gfx* newDList; + Gfx* limbDList; Vec3f pos; Vec3s rot; - RSPMatrix* mtx; + Mtx* mtx; if (skeleton == NULL) { return NULL; } - mtx = (RSPMatrix*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(RSPMatrix) * dListCount)); + mtx = (Mtx*)GRAPH_ALLOC(globalCtx->state.gfxCtx, ALIGN16(sizeof(Mtx) * dListCount)); gSPSegment(gfx++, 0xD, mtx); - SysMatrix_StatePush(); + Matrix_StatePush(); - limbEntry = (StandardLimb*)Lib_SegmentedToVirtual(skeleton[0]); + rootLimb = Lib_SegmentedToVirtual(skeleton[0]); - pos.x = limbDrawTable[0].x; - pos.y = limbDrawTable[0].y; - pos.z = limbDrawTable[0].z; + pos.x = jointTable[0].x; + pos.y = jointTable[0].y; + pos.z = jointTable[0].z; - rot = limbDrawTable[1]; + rot = jointTable[1]; - dList1 = dList2 = limbEntry->displayLists[0]; + newDList = limbDList = rootLimb->dList; - if ((overrideLimbDraw == NULL) || (overrideLimbDraw(globalCtx, 1, &dList1, &pos, &rot, actor, &gfx) == 0)) { - SysMatrix_RotateAndTranslateState(&pos, &rot); - if (dList1 != NULL) { - gSPMatrix(gfx, SysMatrix_GetStateAsRSPMatrix(mtx), G_MTX_LOAD); - gSPDisplayList(gfx + 1, dList1); - gfx = gfx + 2; + if ((overrideLimbDraw == NULL) || !overrideLimbDraw(globalCtx, 1, &newDList, &pos, &rot, actor, &gfx)) { + Matrix_JointPosition(&pos, &rot); + if (newDList != NULL) { + gSPMatrix(&gfx[0], Matrix_ToMtx(mtx), G_MTX_LOAD); + gSPDisplayList(&gfx[1], newDList); + gfx = &gfx[2]; mtx++; } else { - if (dList2 != NULL) { - SysMatrix_GetStateAsRSPMatrix(mtx); + if (limbDList != NULL) { + Matrix_ToMtx(mtx); mtx++; } } } if (postLimbDraw != NULL) { - postLimbDraw(globalCtx, 1, &dList2, &rot, actor, &gfx); + postLimbDraw(globalCtx, 1, &limbDList, &rot, actor, &gfx); } - if (limbEntry->firstChildIndex != LIMB_DONE) { - gfx = SkelAnime_DrawLimbSV2(globalCtx, limbEntry->firstChildIndex, skeleton, limbDrawTable, overrideLimbDraw, - postLimbDraw, actor, &mtx, gfx); + if (rootLimb->child != LIMB_DONE) { + gfx = SkelAnime_DrawFlexLimb(globalCtx, rootLimb->child, skeleton, jointTable, overrideLimbDraw, postLimbDraw, + actor, &mtx, gfx); } - SysMatrix_StatePop(); + Matrix_StatePop(); return gfx; } -// Function is unused. -#pragma GLOBAL_ASM("asm/non_matchings/code/z_skelanime/func_80134FFC.s") +/** + * Unpacks frame data for the animation at the given frame into frameTable + * Used by the legacy animation format + */ +#ifdef NON_MATCHING +// equivalent, minor reordering +s16 SkelAnime_GetFrameDataLegacy(LegacyAnimationHeader* animation, s32 frame, Vec3s* frameTable) { + LegacyAnimationHeader* animHeader = Lib_SegmentedToVirtual(animation); + s16 limbCount = animHeader->limbCount; + JointKey* key = Lib_SegmentedToVirtual(animHeader->jointKey); + s16* frameData = Lib_SegmentedToVirtual(animHeader->frameData); + s16* staticData = &frameData[0]; + s16* dynamicData = &frameData[frame]; + s32 i; -s16 func_801353D4(AnimationHeaderCommon* animationSeg) { - AnimationHeaderCommon* animation = Lib_SegmentedToVirtual(animationSeg); + /** + *Equivalent to the following, but the compiler optimizes the loop in a way I can't replicate + */ + /* + for(i = 0, frameTable++, key++; i < limbCount + 1; i++, key++, frameTable++) { + frameTable->x = frame < key->xMax ? dynamicData[key->x] : staticData[key->x]; + frameTable->y = frame < key->yMax ? dynamicData[key->y] : staticData[key->y]; + frameTable->z = frame < key->zMax ? dynamicData[key->z] : staticData[key->z]; + } + */ + frameTable->x = frame < key->xMax ? dynamicData[key->x] : staticData[key->x]; + frameTable->y = frame < key->yMax ? dynamicData[key->y] : staticData[key->y]; + frameTable->z = frame < key->zMax ? dynamicData[key->z] : staticData[key->z]; + + i = 1; + frameTable++; + key++; + + if (limbCount & 1) {} + + if (limbCount > 0) { + if (limbCount & 1) { + i++; + frameTable->x = frame < key->xMax ? dynamicData[key->x] : staticData[key->x]; + frameTable->y = frame < key->yMax ? dynamicData[key->y] : staticData[key->y]; + frameTable->z = frame < key->zMax ? dynamicData[key->z] : staticData[key->z]; + key++; + frameTable++; + if (limbCount + 1 == i) { + goto ret; + } + } + do { + i += 2; + frameTable->x = frame < key->xMax ? dynamicData[key->x] : staticData[key->x]; + frameTable->y = frame < key->yMax ? dynamicData[key->y] : staticData[key->y]; + frameTable->z = frame < key->zMax ? dynamicData[key->z] : staticData[key->z]; + key++; + frameTable++; + frameTable->x = frame < key->xMax ? dynamicData[key->x] : staticData[key->x]; + frameTable->y = frame < key->yMax ? dynamicData[key->y] : staticData[key->y]; + frameTable->z = frame < key->zMax ? dynamicData[key->z] : staticData[key->z]; + key++; + frameTable++; + } while (i != limbCount + 1); + } + +ret: + return limbCount; +} +#else +#pragma GLOBAL_ASM("asm/non_matchings/code/z_skelanime/SkelAnime_GetFrameData2.s") +#endif + +/** + * Used by legacy animation format + */ +s16 Animation_GetLimbCount2(LegacyAnimationHeader* animation) { + LegacyAnimationHeader* animHeader = Lib_SegmentedToVirtual(animation); - return animation->unk02; + return animHeader->limbCount; } -/* - * Appears to be unused anywhere in the game. Appears to be a clone of - * SkelAnime_GetTotalFrames +/** + * Used by legacy animation format */ -s16 SkelAnime_GetTotalFrames2(AnimationHeaderCommon* animationSeg) { - AnimationHeaderCommon* animation = Lib_SegmentedToVirtual(animationSeg); +s16 Animation_GetLength2(LegacyAnimationHeader* animation) { + LegacyAnimationHeader* animHeader = Lib_SegmentedToVirtual(animation); - return animation->frameCount; + return animHeader->frameCount; } -/* - * Appears to be unused anywhere in the game. Appears to be a clone of - * SkelAnime_GetFrameCount +/** + * Used by legacy animation format */ -s16 SkelAnime_GetFrameCount2(AnimationHeaderCommon* animationSeg) { - AnimationHeaderCommon* animation = Lib_SegmentedToVirtual(animationSeg); +s16 Animation_GetLastFrame2(LegacyAnimationHeader* animation) { + AnimationHeaderCommon* animHeader = Lib_SegmentedToVirtual(animation); - return animation->frameCount - 1; + return animHeader->frameCount - 1; } -void SkelAnime_InterpolateVec3s(s32 limbCount, Vec3s* dst, Vec3s* vec2, Vec3s* vec3, f32 unkf) { +/** + * Linearly interpolates the start and tactoret frame tables with the given weight, putting the result in dst + */ +void SkelAnime_InterpFrameTable(s32 limbCount, Vec3s* dst, Vec3s* start, Vec3s* tactoret, f32 weight) { s32 i; - s16 dist; - s16 temp2; - - if (unkf < 1.0f) { - for (i = 0; i < limbCount; i++, dst++, vec2++, vec3++) { - temp2 = vec2->x; - dist = vec3->x - temp2; - dst->x = (s16)(dist * unkf) + temp2; - temp2 = vec2->y; - dist = vec3->y - temp2; - dst->y = (s16)(dist * unkf) + temp2; - temp2 = vec2->z; - dist = vec3->z - temp2; - dst->z = (s16)(dist * unkf) + temp2; + s16 diff; + s16 base; + + if (weight < 1.0f) { + for (i = 0; i < limbCount; i++, dst++, start++, tactoret++) { + base = start->x; + diff = tactoret->x - base; + dst->x = (s16)(diff * weight) + base; + base = start->y; + diff = tactoret->y - base; + dst->y = (s16)(diff * weight) + base; + base = start->z; + diff = tactoret->z - base; + dst->z = (s16)(diff * weight) + base; } } else { - for (i = 0; i < limbCount; i++, dst++, vec3++) { - dst->x = vec3->x; - dst->y = vec3->y; - dst->z = vec3->z; + for (i = 0; i < limbCount; i++, dst++, tactoret++) { + dst->x = tactoret->x; + dst->y = tactoret->y; + dst->z = tactoret->z; } } } -void SkelAnime_AnimationCtxReset(AnimationContext* animationCtx) { +/** + * Zeroes out the current request count + */ +void AnimationContext_Reset(AnimationContext* animationCtx) { animationCtx->animationCount = 0; } -void func_801358D4(GlobalContext* globalCtx) { - D_801F5AB0 *= 2; +/** + * Shifts the queue flag to the next queue + */ +void AnimationContext_SetNextQueue(GlobalContext* globalCtx) { + sAnimQueueFlags <<= 1; } -void func_801358F4(GlobalContext* globalCtx) { - D_801F5AB4 |= D_801F5AB0; +/** + * Disables the current animation queue. Only load and move actor requests will be processed for that queue. + */ +void AnimationContext_DisableQueue(GlobalContext* globalCtx) { + sDisableAnimQueueFlags |= sAnimQueueFlags; } -AnimationEntry* SkelAnime_NextEntry(AnimationContext* animationCtx, AnimationType type) { +AnimationEntry* AnimationContext_AddEntry(AnimationContext* animationCtx, AnimationType type) { AnimationEntry* entry; s16 index = animationCtx->animationCount; @@ -929,807 +1025,991 @@ AnimationEntry* SkelAnime_NextEntry(AnimationContext* animationCtx, AnimationTyp return entry; } -/* - * The next 6 functions are coordinate with the AnimationType enum +/** + * Requests loading frame data from the Link animation into frameTable */ - -void SkelAnime_LoadLinkAnimetion(GlobalContext* globalCtx, LinkAnimationHeader* linkAnimetionSeg, s32 frame, - s32 limbCount, void* ram) { - AnimationEntry* entry; - LinkAnimationHeader* LinkAnimationHeader; - s32 pad; - - entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_LINKANIMETION); +void AnimationContext_SetLoadFrame(GlobalContext* globalCtx, LinkAnimationHeader* animation, s32 frame, s32 limbCount, + Vec3s* frameTable) { + AnimationEntry* entry = AnimationContext_AddEntry(&globalCtx->animationCtx, ANIMATION_LINKANIMETION); if (entry != NULL) { - LinkAnimationHeader = Lib_SegmentedToVirtual(linkAnimetionSeg); - osCreateMesgQueue(&entry->types.type0.msgQueue, &entry->types.type0.msg, 1); - DmaMgr_SendRequestImpl( - &entry->types.type0.req, ram, - LINK_ANIMETION_OFFSET(LinkAnimationHeader->segment, (sizeof(Vec3s) * limbCount + 2) * frame), - sizeof(Vec3s) * limbCount + 2, 0, &entry->types.type0.msgQueue, NULL); + LinkAnimationHeader* linkAnimHeader = (LinkAnimationHeader*)Lib_SegmentedToVirtual(animation); + u32 ram = frameTable; + + osCreateMesgQueue(&entry->data.load.msgQueue, &entry->data.load.msg, 1); + DmaMgr_SendRequestImpl(&entry->data.load.req, ram, + LINK_ANIMETION_OFFSET(linkAnimHeader->segment, (sizeof(Vec3s) * limbCount + 2) * frame), + sizeof(Vec3s) * limbCount + 2, 0, &entry->data.load.msgQueue, NULL); } } -void SkelAnime_LoadAnimationType1(GlobalContext* globalCtx, s32 vecCount, Vec3s* dst, Vec3s* src) { - AnimationEntry* entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_TYPE1); +/** + * Requests copying all vectors from src frame table into dst frame table + */ +void AnimationContext_SetCopyAll(GlobalContext* globalCtx, s32 vecCount, Vec3s* dst, Vec3s* src) { + AnimationEntry* entry = AnimationContext_AddEntry(&globalCtx->animationCtx, ANIMENTRY_COPYALL); if (entry != NULL) { - entry->types.type1.unk00 = D_801F5AB0; - entry->types.type1.vecCount = vecCount; - entry->types.type1.dst = dst; - entry->types.type1.src = src; + entry->data.copy.queueFlag = sAnimQueueFlags; + entry->data.copy.vecCount = vecCount; + entry->data.copy.dst = dst; + entry->data.copy.src = src; } } -void SkelAnime_LoadAnimationType2(GlobalContext* globalCtx, s32 limbCount, Vec3s* arg2, Vec3s* arg3, f32 arg4) { - AnimationEntry* entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_TYPE2); +/** + * Requests interpolating between base and mod frame tables with the given weight, placing the result in base + */ +void AnimationContext_SetInterp(GlobalContext* globalCtx, s32 vecCount, Vec3s* base, Vec3s* mod, f32 weight) { + AnimationEntry* entry = AnimationContext_AddEntry(&globalCtx->animationCtx, ANIMENTRY_INTERP); if (entry != NULL) { - entry->types.type2.unk00 = D_801F5AB0; - entry->types.type2.limbCount = limbCount; - entry->types.type2.unk04 = arg2; - entry->types.type2.unk08 = arg3; - entry->types.type2.unk0C = arg4; + 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; } } -void SkelAnime_LoadAnimationType3(GlobalContext* globalCtx, s32 vecCount, Vec3s* dst, Vec3s* src, u8* index) { - AnimationEntry* entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_TYPE3); +/** + * Requests copying vectors from src frame table to dst frame table whose load flag is true + */ +void AnimationContext_SetCopyTrue(GlobalContext* globalCtx, s32 vecCount, Vec3s* dst, Vec3s* src, u8* copyFlag) { + AnimationEntry* entry = AnimationContext_AddEntry(&globalCtx->animationCtx, ANIMENTRY_COPYTRUE); if (entry != NULL) { - entry->types.type3.unk00 = D_801F5AB0; - entry->types.type3.vecCount = vecCount; - entry->types.type3.dst = dst; - entry->types.type3.src = src; - entry->types.type3.index = index; + 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; } } -void SkelAnime_LoadAnimationType4(GlobalContext* globalCtx, s32 vecCount, Vec3s* dst, Vec3s* src, u8* index) { - AnimationEntry* entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_TYPE4); +/** + * Requests copying vectors from src frame table to dst frame table whose load flag is false + */ +void AnimationContext_SetCopyFalse(GlobalContext* globalCtx, s32 vecCount, Vec3s* dst, Vec3s* src, u8* copyFlag) { + AnimationEntry* entry = AnimationContext_AddEntry(&globalCtx->animationCtx, ANIMENTRY_COPYFALSE); if (entry != NULL) { - entry->types.type4.unk00 = D_801F5AB0; - entry->types.type4.vecCount = vecCount; - entry->types.type4.dst = dst; - entry->types.type4.src = src; - entry->types.type4.index = index; + 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; } } -void SkelAnime_LoadAnimationType5(GlobalContext* globalCtx, Actor* actor, SkelAnime* skelAnime, f32 arg3) { - AnimationEntry* entry = SkelAnime_NextEntry(&globalCtx->animationCtx, ANIMATION_TYPE5); +/** + * Requests moving an actor according to the translation of its root limb + */ +void AnimationContext_SetMoveActor(GlobalContext* globalCtx, Actor* actor, SkelAnime* skelAnime, f32 actor3) { + AnimationEntry* entry = AnimationContext_AddEntry(&globalCtx->animationCtx, ANIMENTRY_MOVEACTOR); if (entry != NULL) { - entry->types.type5.actor = actor; - entry->types.type5.skelAnime = skelAnime; - entry->types.type5.unk08 = arg3; + entry->data.move.actor = actor; + entry->data.move.skelAnime = skelAnime; + entry->data.move.unk08 = actor3; } } -/* The next functions are callbacks to loading animations */ +/** + * Receives the request for Link's animation frame data + */ +void AnimationContext_LoadFrame(GlobalContext* globalCtx, AnimationEntryData* data) { + AnimEntryLoadFrame* entry = &data->load; -void SkelAnime_LinkAnimetionLoaded(GlobalContext* globalCtx, AnimationEntryType0* entry) { osRecvMesg(&entry->msgQueue, NULL, OS_MESG_BLOCK); } -void SkelAnime_AnimationType1Loaded(GlobalContext* globalCtx, AnimationEntryType1* entry) { - s32 i; - Vec3s* dst; - Vec3s* src; - AnimationEntryRaw* genericEntry = (AnimationEntryRaw*)entry; +/** + * If the entry's queue is enabled, copies all vectors from src frame table to dst frame table + */ +void AnimationContext_CopyAll(GlobalContext* globalCtx, AnimationEntryData* data) { + AnimEntryCopyAll* entry = &data->copy; - if ((genericEntry->raw[0] & D_801F5AB4) != 0) { - return; - } + if (!(entry->queueFlag & sDisableAnimQueueFlags)) { + Vec3s* dst = entry->dst; + Vec3s* src = entry->src; + s32 i; - for (dst = entry->dst, src = entry->src, i = 0; i < genericEntry->raw[1]; i++) { - *dst++ = *src++; + for (i = 0; i < entry->vecCount; i++) { + *dst++ = *src++; + } } } -void SkelAnime_AnimationType2Loaded(GlobalContext* globalCtx, AnimationEntryType2* entry) { - if ((entry->unk00 & D_801F5AB4) == 0) { - SkelAnime_InterpolateVec3s(entry->limbCount, entry->unk04, entry->unk04, entry->unk08, entry->unk0C); +/** + * If the entry's queue is enabled, interpolates between the base and mod frame tables, placing the result in base + */ +void AnimationContext_Interp(GlobalContext* globalCtx, AnimationEntryData* data) { + AnimEntryInterp* entry = &data->interp; + + if (!(entry->queueFlag & sDisableAnimQueueFlags)) { + SkelAnime_InterpFrameTable(entry->vecCount, entry->base, entry->base, entry->mod, entry->weight); } } -void SkelAnime_AnimationType3Loaded(GlobalContext* globalCtx, AnimationEntryType3* entry) { - s32 i; - Vec3s* dst; - Vec3s* src; - u8* index; - AnimationEntryRaw* rawEntry = (AnimationEntryRaw*)entry; - - if ((rawEntry->raw[0] & D_801F5AB4) == 0) { - for (dst = entry->dst, src = entry->src, index = entry->index, i = 0; i < rawEntry->raw[1]; i++, dst++, src++) { - if (*index++) { +/** + * If the entry's queue is enabled, copies all vectors from src frame table to dst frame table whose copy flag is true + */ +void AnimationContext_CopyTrue(GlobalContext* globalCtx, AnimationEntryData* data) { + AnimEntryCopyTrue* entry = &data->copy1; + + if (!(entry->queueFlag & sDisableAnimQueueFlags)) { + Vec3s* dst = entry->dst; + Vec3s* src = entry->src; + u8* copyFlag = entry->copyFlag; + s32 i; + + for (i = 0; i < entry->vecCount; i++, dst++, src++) { + if (*copyFlag++) { *dst = *src; } } } } -void SkelAnime_AnimationType4Loaded(GlobalContext* globalCtx, AnimationEntryType4* entry) { - s32 i; - Vec3s* dst; - Vec3s* src; - u8* index; - AnimationEntryRaw* rawEntry = (AnimationEntryRaw*)entry; - - if ((rawEntry->raw[0] & D_801F5AB4) == 0) { - for (dst = entry->dst, src = entry->src, index = entry->index, i = 0; i < rawEntry->raw[1]; i++, dst++, src++) { - if (*index++ < 1U) { +/** + * If the entry's queue is enabled, copies all vectors from src frame table to dst frame table whose copy flag is false + */ +void AnimationContext_CopyFalse(GlobalContext* globalCtx, AnimationEntryData* data) { + AnimEntryCopyFalse* entry = &data->copy0; + + if (!(entry->queueFlag & sDisableAnimQueueFlags)) { + Vec3s* dst = entry->dst; + Vec3s* src = entry->src; + u8* copyFlag = entry->copyFlag; + s32 i; + + for (i = 0; i < entry->vecCount; i++, dst++, src++) { + if (!(*copyFlag++)) { *dst = *src; } } } } -void SkelAnime_AnimationType5Loaded(GlobalContext* globalCtx, AnimationEntryType5* entry) { - s32 pad; +/** + * Moves an actor according to the translation of its root limb + */ +void AnimationContext_MoveActor(GlobalContext* globalCtx, AnimationEntryData* data) { + AnimEntryMoveActor* entry = &data->move; Actor* actor = entry->actor; - Vec3f pos; + Vec3f diff; - func_80137748(entry->skelAnime, &pos, actor->shape.rot.y); - actor->world.pos.x += (pos.x * actor->scale.x) * entry->unk08; - actor->world.pos.y += (pos.y * actor->scale.y) * entry->unk08; - actor->world.pos.z += (pos.z * actor->scale.z) * entry->unk08; + SkelAnime_UpdateTranslation(entry->skelAnime, &diff, actor->shape.rot.y); + actor->world.pos.x += diff.x * actor->scale.x * entry->unk08; + actor->world.pos.y += diff.y * actor->scale.y * entry->unk08; + actor->world.pos.z += diff.z * actor->scale.z * entry->unk08; } -void func_80135EE8(GlobalContext* globalCtx, AnimationContext* animationCtx) { +/** + * Performs all requests in the animation queue, then resets the queue flags. + */ +void AnimationContext_Update(GlobalContext* globalCtx, AnimationContext* animationCtx) { AnimationEntry* entry = animationCtx->entries; for (; animationCtx->animationCount != 0; entry++, animationCtx->animationCount--) { - sAnimationLoadDone[entry->type](globalCtx, &entry->types); + sAnimationLoadDone[entry->type](globalCtx, &entry->data); } - D_801F5AB0 = 1; - D_801F5AB4 = 0; + sAnimQueueFlags = 1; + sDisableAnimQueueFlags = 0; } -void SkelAnime_InitLinkAnimetion(GlobalContext* globalCtx, SkelAnime* skelAnime, FlexSkeletonHeader* skeletonHeaderSeg, - LinkAnimationHeader* linkAnimationHeaderSeg, s32 flags, Vec3s* limbDrawTbl, - Vec3s* transitionDrawTbl, s32 limbBufCount) { +/** + * Initializes a skeleton to be used with Link animations to a looping animation, dynamically allocating the frame + * tables if not given. + */ +void SkelAnime_InitLink(GlobalContext* globalCtx, SkelAnime* skelAnime, FlexSkeletonHeader* skeletonHeaderSeg, + LinkAnimationHeader* animation, s32 flags, Vec3s* jointTable, Vec3s* morphTable, + s32 limbBufCount) { FlexSkeletonHeader* skeletonHeader; - s32 headerCount; + s32 headerJointCount; s32 limbCount; - u32 allocSize; + size_t allocSize; skeletonHeader = Lib_SegmentedToVirtual(skeletonHeaderSeg); - headerCount = skeletonHeader->sh.limbCount; + headerJointCount = skeletonHeader->sh.limbCount; skelAnime->initFlags = flags; - limbCount = (flags & 2) ? headerCount : 1; + limbCount = (flags & 2) ? headerJointCount : 1; if (flags & 1) { - limbCount += headerCount; + limbCount += headerJointCount; } if (flags & 4) { - limbCount += headerCount; + limbCount += headerJointCount; } skelAnime->limbCount = limbCount; skelAnime->dListCount = skeletonHeader->dListCount; - skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->sh.skeletonSeg); + skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->sh.segment); allocSize = sizeof(Vec3s) * limbCount; if (flags & 8) { allocSize += 2; } - if (limbDrawTbl == NULL) { - skelAnime->limbDrawTbl = zelda_malloc(allocSize); - skelAnime->transitionDrawTbl = zelda_malloc(allocSize); + if (jointTable == NULL) { + skelAnime->jointTable = ZeldaArena_Malloc(allocSize); + skelAnime->morphTable = ZeldaArena_Malloc(allocSize); } else { - skelAnime->limbDrawTbl = (Vec3s*)ALIGN16((u32)limbDrawTbl); - skelAnime->transitionDrawTbl = (Vec3s*)ALIGN16((u32)transitionDrawTbl); + skelAnime->jointTable = (Vec3s*)ALIGN16((u32)jointTable); + skelAnime->morphTable = (Vec3s*)ALIGN16((u32)morphTable); } - SkelAnime_ChangeLinkAnim(globalCtx, skelAnime, linkAnimationHeaderSeg, 1.0f, 0.0f, 0.0f, 0, 0.0f); + LinkAnimation_Change(globalCtx, skelAnime, animation, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, 0.0f); } -void func_801360A8(SkelAnime* skelAnime) { - if (skelAnime->mode < 2) { - skelAnime->animUpdate = func_80136288; +/** + * Sets the update function of a SkelAnime that uses Link animations based on its mode + */ +void LinkAnimation_SetUpdateFunction(SkelAnime* skelAnime) { + if (skelAnime->mode <= ANIMMODE_LOOP_INTERP) { + skelAnime->update = LinkAnimation_Loop; } else { - skelAnime->animUpdate = func_8013631C; + skelAnime->update = LinkAnimation_Once; } - skelAnime->transCurrentFrame = 0.0f; + skelAnime->morphWeight = 0.0f; } -s32 func_801360E0(GlobalContext* globalCtx, SkelAnime* skelAnime) { - return skelAnime->animUpdate(globalCtx, skelAnime); +/** + * Advances the current Link animation and updates all frame tables. If the animation plays once, returns true when it + * finishes. + */ +s32 LinkAnimation_Update(GlobalContext* globalCtx, SkelAnime* skelAnime) { + return skelAnime->update(globalCtx, skelAnime); } -s32 func_80136104(GlobalContext* globalCtx, SkelAnime* skelAnime) { - f32 prevUnk28 = skelAnime->transCurrentFrame; +/** + * Requests an interpolation between the pose in jointTable to the one in morphTable, advancing the morph but not the + * animation frame + */ +s32 LinkAnimation_Morph(GlobalContext* globalCtx, SkelAnime* skelAnime) { + f32 prevMorphWeight = skelAnime->morphWeight; f32 updateRate = (s32)globalCtx->state.framerateDivisor * 0.5f; - skelAnime->transCurrentFrame -= skelAnime->transitionStep * updateRate; - if (skelAnime->transCurrentFrame <= 0.0f) { - func_801360A8(skelAnime); + skelAnime->morphWeight -= skelAnime->morphRate * updateRate; + if (skelAnime->morphWeight <= 0.0f) { + LinkAnimation_SetUpdateFunction(skelAnime); } - SkelAnime_LoadAnimationType2(globalCtx, skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->transitionDrawTbl, - 1.0f - (skelAnime->transCurrentFrame / prevUnk28)); + AnimationContext_SetInterp(globalCtx, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable, + 1.0f - (skelAnime->morphWeight / prevMorphWeight)); return 0; } -void func_801361BC(GlobalContext* globalCtx, SkelAnime* skelAnime) { - SkelAnime_LoadLinkAnimetion(globalCtx, skelAnime->linkAnimetionSeg, skelAnime->animCurrentFrame, - skelAnime->limbCount, skelAnime->limbDrawTbl); - if (skelAnime->transCurrentFrame != 0) { +/** + * Requests a load of the next frame of a Link animation, advances the morph, and requests an interpolation between + * jointTable and morphTable + */ +void LinkAnimation_AnimateFrame(GlobalContext* globalCtx, SkelAnime* skelAnime) { + AnimationContext_SetLoadFrame(globalCtx, skelAnime->animation, skelAnime->curFrame, skelAnime->limbCount, + skelAnime->jointTable); + if (skelAnime->morphWeight != 0) { f32 updateRate = (s32)globalCtx->state.framerateDivisor * 0.5f; - skelAnime->transCurrentFrame -= skelAnime->transitionStep * updateRate; - if (skelAnime->transCurrentFrame <= 0.0f) { - skelAnime->transCurrentFrame = 0.0f; + skelAnime->morphWeight -= skelAnime->morphRate * updateRate; + if (skelAnime->morphWeight <= 0.0f) { + skelAnime->morphWeight = 0.0f; } else { - SkelAnime_LoadAnimationType2(globalCtx, skelAnime->limbCount, skelAnime->limbDrawTbl, - skelAnime->transitionDrawTbl, skelAnime->transCurrentFrame); + AnimationContext_SetInterp(globalCtx, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable, + skelAnime->morphWeight); } } } -s32 func_80136288(GlobalContext* globalCtx, SkelAnime* skelAnime) { +/** + * Advances a Link animation that loops over its full length + */ +s32 LinkAnimation_Loop(GlobalContext* globalCtx, SkelAnime* skelAnime) { f32 updateRate = (s32)globalCtx->state.framerateDivisor * 0.5f; - skelAnime->animCurrentFrame += skelAnime->animPlaybackSpeed * updateRate; - if (skelAnime->animCurrentFrame < 0.0f) { - skelAnime->animCurrentFrame += skelAnime->totalFrames; - } else if (skelAnime->totalFrames <= skelAnime->animCurrentFrame) { - skelAnime->animCurrentFrame -= skelAnime->totalFrames; + skelAnime->curFrame += skelAnime->playSpeed * updateRate; + if (skelAnime->curFrame < 0.0f) { + skelAnime->curFrame += skelAnime->animLength; + } else if (skelAnime->animLength <= skelAnime->curFrame) { + skelAnime->curFrame -= skelAnime->animLength; } - func_801361BC(globalCtx, skelAnime); + LinkAnimation_AnimateFrame(globalCtx, skelAnime); return 0; } -s32 func_8013631C(GlobalContext* globalCtx, SkelAnime* skelAnime) { +/** + * Advances a Link animation that stops at endFrame and returns true when it is reached. + */ +s32 LinkAnimation_Once(GlobalContext* globalCtx, SkelAnime* skelAnime) { f32 updateRate = (s32)globalCtx->state.framerateDivisor * 0.5f; - if (skelAnime->animCurrentFrame == skelAnime->animFrameCount) { - func_801361BC(globalCtx, skelAnime); + if (skelAnime->curFrame == skelAnime->endFrame) { + LinkAnimation_AnimateFrame(globalCtx, skelAnime); return 1; } - skelAnime->animCurrentFrame += skelAnime->animPlaybackSpeed * updateRate; + skelAnime->curFrame += skelAnime->playSpeed * updateRate; - if (((skelAnime->animCurrentFrame - skelAnime->animFrameCount) * skelAnime->animPlaybackSpeed) > 0.0f) { - skelAnime->animCurrentFrame = skelAnime->animFrameCount; + if (((skelAnime->curFrame - skelAnime->endFrame) * skelAnime->playSpeed) > 0.0f) { + skelAnime->curFrame = skelAnime->endFrame; } else { - if (skelAnime->animCurrentFrame < 0.0f) { - skelAnime->animCurrentFrame += skelAnime->totalFrames; - } else if (skelAnime->totalFrames <= skelAnime->animCurrentFrame) { - skelAnime->animCurrentFrame -= skelAnime->totalFrames; + if (skelAnime->curFrame < 0.0f) { + skelAnime->curFrame += skelAnime->animLength; + } else if (skelAnime->animLength <= skelAnime->curFrame) { + skelAnime->curFrame -= skelAnime->animLength; } } - func_801361BC(globalCtx, skelAnime); + LinkAnimation_AnimateFrame(globalCtx, skelAnime); return 0; } -void SkelAnime_SetTransition(GlobalContext* globalCtx, SkelAnime* skelAnime, f32 transitionRate) { - skelAnime->transCurrentFrame = 1.0f; - skelAnime->transitionStep = 1.0f / transitionRate; +/** + * Sets a new morph and resets the morph weight for the current animation. + */ +void Animation_SetMorph(GlobalContext* globalCtx, SkelAnime* skelAnime, f32 morphFrames) { + skelAnime->morphWeight = 1.0f; + skelAnime->morphRate = 1.0f / morphFrames; } -void SkelAnime_ChangeLinkAnim(GlobalContext* globalCtx, SkelAnime* skelAnime, - LinkAnimationHeader* linkAnimationHeaderSeg, f32 playbackSpeed, f32 frame, f32 frameCount, - u8 animationMode, f32 transitionRate) { - skelAnime->mode = animationMode; - if ((transitionRate != 0.0f) && - ((linkAnimationHeaderSeg != skelAnime->linkAnimetionSeg) || (frame != skelAnime->animCurrentFrame))) { - if (transitionRate < 0) { - func_801360A8(skelAnime); - SkelAnime_CopyVec3s(skelAnime, skelAnime->transitionDrawTbl, skelAnime->limbDrawTbl); - transitionRate = -transitionRate; +/** + * General way to set a new Link animation, allowing choice of playback speed, start frame, end frame, play mode, and + * number of transition frames. Positive morph frames morph from the current pose to the start pose of the new + * animation, then start the new animation. Negative morph frames start the new animation immediately, modified by the + * pose immediately before the animation change. + */ +void LinkAnimation_Change(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* animation, f32 playSpeed, + f32 startFrame, f32 endFrame, u8 mode, f32 morphFrames) { + skelAnime->mode = mode; + if ((morphFrames != 0.0f) && ((animation != skelAnime->animation) || (startFrame != skelAnime->curFrame))) { + if (morphFrames < 0) { + LinkAnimation_SetUpdateFunction(skelAnime); + SkelAnime_CopyFrameTable(skelAnime, skelAnime->morphTable, skelAnime->jointTable); + morphFrames = -morphFrames; } else { - skelAnime->animUpdate = func_80136104; - SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimationHeaderSeg, (s32)frame, skelAnime->limbCount, - skelAnime->transitionDrawTbl); + skelAnime->update = LinkAnimation_Morph; + AnimationContext_SetLoadFrame(globalCtx, animation, (s32)startFrame, skelAnime->limbCount, + skelAnime->morphTable); } - skelAnime->transCurrentFrame = 1.0f; - skelAnime->transitionStep = 1.0f / transitionRate; + skelAnime->morphWeight = 1.0f; + skelAnime->morphRate = 1.0f / morphFrames; } else { - func_801360A8(skelAnime); - SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimationHeaderSeg, (s32)frame, skelAnime->limbCount, - skelAnime->limbDrawTbl); - skelAnime->transCurrentFrame = 0.0f; + LinkAnimation_SetUpdateFunction(skelAnime); + AnimationContext_SetLoadFrame(globalCtx, animation, (s32)startFrame, skelAnime->limbCount, + skelAnime->jointTable); + skelAnime->morphWeight = 0.0f; } - skelAnime->linkAnimetionSeg = linkAnimationHeaderSeg; - skelAnime->animCurrentFrame = 0.0f; - skelAnime->initialFrame = frame; - skelAnime->animCurrentFrame = frame; - skelAnime->animFrameCount = frameCount; - skelAnime->totalFrames = SkelAnime_GetTotalFrames(&linkAnimationHeaderSeg->common); - skelAnime->animPlaybackSpeed = playbackSpeed; + skelAnime->animation = animation; + skelAnime->curFrame = 0.0f; + skelAnime->startFrame = startFrame; + skelAnime->curFrame = startFrame; + skelAnime->endFrame = endFrame; + skelAnime->animLength = Animation_GetLength(animation); + skelAnime->playSpeed = playSpeed; } -void SkelAnime_ChangeLinkAnimDefaultStop(GlobalContext* globalCtx, SkelAnime* skelAnime, - LinkAnimationHeader* linkAnimationHeaderSeg) { - SkelAnime_ChangeLinkAnim(globalCtx, skelAnime, linkAnimationHeaderSeg, 1.0f, 0.0f, - SkelAnime_GetFrameCount(&linkAnimationHeaderSeg->common), 2, 0.0f); +/** + * Immediately changes to a Link animation that plays once at the default speed. + */ +void LinkAnimation_PlayOnce(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* animation) { + LinkAnimation_Change(globalCtx, skelAnime, animation, 1.0f, 0.0f, Animation_GetLastFrame(&animation->common), + ANIMMODE_ONCE, 0.0f); } -void SkelAnime_ChangeLinkAnimPlaybackStop(GlobalContext* globalCtx, SkelAnime* skelAnime, - LinkAnimationHeader* linkAnimationHeaderSeg, f32 playbackSpeed) { - SkelAnime_ChangeLinkAnim(globalCtx, skelAnime, linkAnimationHeaderSeg, playbackSpeed, 0.0f, - SkelAnime_GetFrameCount(&linkAnimationHeaderSeg->common), 2, 0.0f); +/** + * Immediately changes to a Link animation that plays once at the specified speed. + */ +void LinkAnimation_PlayOnceSetSpeed(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* animation, + f32 playSpeed) { + LinkAnimation_Change(globalCtx, skelAnime, animation, playSpeed, 0.0f, Animation_GetLastFrame(&animation->common), + ANIMMODE_ONCE, 0.0f); } -void SkelAnime_ChangeLinkAnimDefaultRepeat(GlobalContext* globalCtx, SkelAnime* skelAnime, - LinkAnimationHeader* linkAnimationHeaderSeg) { - SkelAnime_ChangeLinkAnim(globalCtx, skelAnime, linkAnimationHeaderSeg, 1.0f, 0.0f, - SkelAnime_GetFrameCount(&linkAnimationHeaderSeg->common), 0, 0.0f); +/** + * Immediately changes to a Link animation that loops at the default speed. + */ +void LinkAnimation_PlayLoop(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* animation) { + LinkAnimation_Change(globalCtx, skelAnime, animation, 1.0f, 0.0f, Animation_GetLastFrame(&animation->common), + ANIMMODE_LOOP, 0.0f); } -void SkelAnime_ChangeLinkAnimPlaybackRepeat(GlobalContext* globalCtx, SkelAnime* skelAnime, - LinkAnimationHeader* linkAnimationHeaderSeg, f32 playbackSpeed) { - SkelAnime_ChangeLinkAnim(globalCtx, skelAnime, linkAnimationHeaderSeg, playbackSpeed, 0.0f, - SkelAnime_GetFrameCount(&linkAnimationHeaderSeg->common), 0, 0.0f); +/** + * Immediately changes to a Link animation that loops at the specified speed. + */ +void LinkAnimation_PlayLoopSetSpeed(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* animation, + f32 playSpeed) { + LinkAnimation_Change(globalCtx, skelAnime, animation, playSpeed, 0.0f, Animation_GetLastFrame(&animation->common), + ANIMMODE_LOOP, 0.0f); } -void func_8013670C(GlobalContext* globalCtx, SkelAnime* skelAnime) { - SkelAnime_LoadAnimationType1(globalCtx, skelAnime->limbCount, skelAnime->transitionDrawTbl, skelAnime->limbDrawTbl); +/** + * Requests copying jointTable to morphTable + */ +void LinkAnimation_CopyJointToMorph(GlobalContext* globalCtx, SkelAnime* skelAnime) { + AnimationContext_SetCopyAll(globalCtx, skelAnime->limbCount, skelAnime->morphTable, skelAnime->jointTable); } -void func_8013673C(GlobalContext* globalCtx, SkelAnime* skelAnime) { - SkelAnime_LoadAnimationType1(globalCtx, skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->transitionDrawTbl); +/** + * Requests copying morphTable to jointTable + */ +void LinkAnimation_CopyMorphToJoint(GlobalContext* globalCtx, SkelAnime* skelAnime) { + AnimationContext_SetCopyAll(globalCtx, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable); } -void func_8013676C(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* linkAnimationHeaderSeg, - f32 frame) { - SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimationHeaderSeg, (s32)frame, skelAnime->limbCount, - skelAnime->transitionDrawTbl); +/** + * Requests loading frame data from the Link animation into morphTable + */ +void LinkAnimation_LoadToMorph(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* animation, + f32 frame) { + AnimationContext_SetLoadFrame(globalCtx, animation, (s32)frame, skelAnime->limbCount, skelAnime->morphTable); } -void func_801367B0(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* linkAnimationHeaderSeg, - f32 frame) { - SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimationHeaderSeg, (s32)frame, skelAnime->limbCount, - skelAnime->limbDrawTbl); +/** + * Requests loading frame data from the Link animation into jointTable + */ +void LinkAnimation_LoadToJoint(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* animation, + f32 frame) { + AnimationContext_SetLoadFrame(globalCtx, animation, (s32)frame, skelAnime->limbCount, skelAnime->jointTable); } -void func_801367F4(GlobalContext* globalCtx, SkelAnime* skelAnime, f32 frame) { - SkelAnime_LoadAnimationType2(globalCtx, skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->transitionDrawTbl, - frame); +/** + * Requests interpolating between jointTable and morphTable, placing the result in jointTable + */ +void LinkAnimation_InterpJointMorph(GlobalContext* globalCtx, SkelAnime* skelAnime, f32 weight) { + AnimationContext_SetInterp(globalCtx, skelAnime->limbCount, skelAnime->jointTable, skelAnime->morphTable, weight); } -void func_8013682C(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* linkAnimationHeaderSeg, - f32 transitionFrame, LinkAnimationHeader* LinkAnimationHeaderSeg2, f32 frame, f32 transitionRate, - Vec3s* limbDrawTbl) { - Vec3s* alignedLimbDrawTbl; - SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimationHeaderSeg, (s32)transitionFrame, skelAnime->limbCount, - skelAnime->limbDrawTbl); +/** + * Requests loading frame data from the Link animations and blending them, placing the result in jointTable + */ +void LinkAnimation_BlendToJoint(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* animation1, + f32 frame1, LinkAnimationHeader* animation2, f32 frame2, f32 blendWeight, + Vec3s* blendTable) { + Vec3s* alignedBlendTable; + + AnimationContext_SetLoadFrame(globalCtx, animation1, (s32)frame1, skelAnime->limbCount, skelAnime->jointTable); - alignedLimbDrawTbl = (Vec3s*)ALIGN16((u32)limbDrawTbl); + alignedBlendTable = (Vec3s*)ALIGN16((u32)blendTable); - SkelAnime_LoadLinkAnimetion(globalCtx, LinkAnimationHeaderSeg2, (s32)frame, skelAnime->limbCount, - alignedLimbDrawTbl); - SkelAnime_LoadAnimationType2(globalCtx, skelAnime->limbCount, skelAnime->limbDrawTbl, alignedLimbDrawTbl, - transitionRate); + AnimationContext_SetLoadFrame(globalCtx, animation2, (s32)frame2, skelAnime->limbCount, alignedBlendTable); + AnimationContext_SetInterp(globalCtx, skelAnime->limbCount, skelAnime->jointTable, alignedBlendTable, blendWeight); } -void func_801368CC(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* linkAnimationHeaderSeg, - f32 transitionFrame, LinkAnimationHeader* LinkAnimationHeaderSeg2, f32 frame, f32 transitionRate, - Vec3s* limbDrawTbl) { - Vec3s* alignedLimbDrawTbl; +/** + * Requests loading frame data from the Link animations and blending them, placing the result in morphTable + */ +void LinkAnimation_BlendToMorph(GlobalContext* globalCtx, SkelAnime* skelAnime, LinkAnimationHeader* animation1, + f32 frame1, LinkAnimationHeader* animation2, f32 frame2, f32 blendWeight, + Vec3s* blendTable) { + Vec3s* alignedBlendTable; - SkelAnime_LoadLinkAnimetion(globalCtx, linkAnimationHeaderSeg, (s32)transitionFrame, skelAnime->limbCount, - skelAnime->transitionDrawTbl); + AnimationContext_SetLoadFrame(globalCtx, animation1, (s32)frame1, skelAnime->limbCount, skelAnime->morphTable); - alignedLimbDrawTbl = (Vec3s*)ALIGN16((u32)limbDrawTbl); + alignedBlendTable = (Vec3s*)ALIGN16((u32)blendTable); - SkelAnime_LoadLinkAnimetion(globalCtx, LinkAnimationHeaderSeg2, (s32)frame, skelAnime->limbCount, - alignedLimbDrawTbl); - SkelAnime_LoadAnimationType2(globalCtx, skelAnime->limbCount, skelAnime->transitionDrawTbl, alignedLimbDrawTbl, - transitionRate); + AnimationContext_SetLoadFrame(globalCtx, animation2, (s32)frame2, skelAnime->limbCount, alignedBlendTable); + AnimationContext_SetInterp(globalCtx, skelAnime->limbCount, skelAnime->morphTable, alignedBlendTable, blendWeight); } -void SkelAnime_SetModeStop(SkelAnime* skelAnime) { - skelAnime->mode = 2; - func_801360A8(skelAnime); +/** + * Changes a looping animation to one that stops at the end. + */ +void LinkAnimation_EndLoop(SkelAnime* skelAnime) { + skelAnime->mode = ANIMMODE_ONCE; + LinkAnimation_SetUpdateFunction(skelAnime); } -s32 func_80136990(SkelAnime* skelAnime, f32 arg1, f32 updateRate) { +/** + * Checks if the current frame is after frame and the previous frame was before it. + */ +s32 Animation_OnFrameImpl(SkelAnime* skelAnime, f32 frame, f32 updateRate) { f32 updateSpeed; - f32 temp_f12; + f32 curFrameDiff; f32 nextFrame; - updateSpeed = skelAnime->animPlaybackSpeed * updateRate; - nextFrame = skelAnime->animCurrentFrame - updateSpeed; + updateSpeed = skelAnime->playSpeed * updateRate; + nextFrame = skelAnime->curFrame - updateSpeed; if (nextFrame < 0.0f) { - nextFrame += skelAnime->totalFrames; - } else if (skelAnime->totalFrames <= nextFrame) { - nextFrame -= skelAnime->totalFrames; + nextFrame += skelAnime->animLength; + } else if (skelAnime->animLength <= nextFrame) { + nextFrame -= skelAnime->animLength; } - if ((arg1 == 0.0f) && (updateSpeed > 0.0f)) { - arg1 = skelAnime->totalFrames; + if ((frame == 0.0f) && (updateSpeed > 0.0f)) { + frame = skelAnime->animLength; } - temp_f12 = (nextFrame + updateSpeed) - arg1; - if ((0.0f <= (temp_f12 * updateSpeed)) && (((temp_f12 - updateSpeed) * updateSpeed) < 0.0f)) { - return 1; + curFrameDiff = (nextFrame + updateSpeed) - frame; + if ((0.0f <= (curFrameDiff * updateSpeed)) && (((curFrameDiff - updateSpeed) * updateSpeed) < 0.0f)) { + return true; } - return 0; + return false; } -s32 func_80136A48(SkelAnime* skelAnime, f32 arg1) { +/** + * Checks if the current Link animation has reached the specified frame + */ +s32 LinkAnimation_OnFrame(SkelAnime* skelAnime, f32 frame) { f32 updateRate = gFramerateDivisorHalf; - return func_80136990(skelAnime, arg1, updateRate); + return Animation_OnFrameImpl(skelAnime, frame, updateRate); } +/** + * Initializes a normal skeleton to a looping animation, dynamically allocating the frame tables if not provided. + */ void SkelAnime_Init(GlobalContext* globalCtx, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg, - AnimationHeader* animationSeg, Vec3s* limbDrawTbl, Vec3s* transitionDrawTable, s32 limbCount) { + AnimationHeader* animation, Vec3s* jointTable, Vec3s* morphTable, s32 limbCount) { SkeletonHeader* skeletonHeader; skeletonHeader = Lib_SegmentedToVirtual(skeletonHeaderSeg); skelAnime->limbCount = skeletonHeader->limbCount + 1; - skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->skeletonSeg); - if (limbDrawTbl == NULL) { - skelAnime->limbDrawTbl = zelda_malloc(sizeof(*skelAnime->limbDrawTbl) * skelAnime->limbCount); - skelAnime->transitionDrawTbl = zelda_malloc(sizeof(*skelAnime->transitionDrawTbl) * skelAnime->limbCount); + skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->segment); + if (jointTable == NULL) { + skelAnime->jointTable = ZeldaArena_Malloc(sizeof(*skelAnime->jointTable) * skelAnime->limbCount); + skelAnime->morphTable = ZeldaArena_Malloc(sizeof(*skelAnime->morphTable) * skelAnime->limbCount); } else { - skelAnime->limbDrawTbl = limbDrawTbl; - skelAnime->transitionDrawTbl = transitionDrawTable; + skelAnime->jointTable = jointTable; + skelAnime->morphTable = morphTable; } - if (animationSeg != NULL) { - SkelAnime_ChangeAnimDefaultRepeat(skelAnime, animationSeg); + if (animation != NULL) { + Animation_PlayLoop(skelAnime, animation); } } -void SkelAnime_InitSV(GlobalContext* globalCtx, SkelAnime* skelAnime, FlexSkeletonHeader* skeletonHeaderSeg, - AnimationHeader* animationSeg, Vec3s* limbDrawTbl, Vec3s* transitionDrawTable, s32 limbCount) { +/** + * Initializes a flex skeleton to a looping animation, dynamically allocating the frame tables if not given. + */ +void SkelAnime_InitFlex(GlobalContext* globalCtx, SkelAnime* skelAnime, FlexSkeletonHeader* skeletonHeaderSeg, + AnimationHeader* animation, Vec3s* jointTable, Vec3s* morphTable, s32 limbCount) { FlexSkeletonHeader* skeletonHeader; skeletonHeader = Lib_SegmentedToVirtual(skeletonHeaderSeg); skelAnime->limbCount = skeletonHeader->sh.limbCount + 1; skelAnime->dListCount = skeletonHeader->dListCount; - skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->sh.skeletonSeg); + skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->sh.segment); - if (limbDrawTbl == NULL) { - skelAnime->limbDrawTbl = zelda_malloc(sizeof(*skelAnime->limbDrawTbl) * skelAnime->limbCount); + if (jointTable == NULL) { + skelAnime->jointTable = ZeldaArena_Malloc(sizeof(*skelAnime->jointTable) * skelAnime->limbCount); - skelAnime->transitionDrawTbl = zelda_malloc(sizeof(*skelAnime->transitionDrawTbl) * skelAnime->limbCount); + skelAnime->morphTable = ZeldaArena_Malloc(sizeof(*skelAnime->morphTable) * skelAnime->limbCount); } else { - skelAnime->limbDrawTbl = limbDrawTbl; - skelAnime->transitionDrawTbl = transitionDrawTable; + skelAnime->jointTable = jointTable; + skelAnime->morphTable = morphTable; } - if (animationSeg != NULL) { - SkelAnime_ChangeAnimDefaultRepeat(skelAnime, animationSeg); + if (animation != NULL) { + Animation_PlayLoop(skelAnime, animation); } } +/** + * Initializes a skeleton with SkinLimbs to a looping animation, dynamically allocating the frame tables. + */ void SkelAnime_InitSkin(GlobalContext* globalCtx, SkelAnime* skelAnime, SkeletonHeader* skeletonHeaderSeg, - AnimationHeader* animationSeg) { + AnimationHeader* animation) { SkeletonHeader* skeletonHeader; skeletonHeader = Lib_SegmentedToVirtual(skeletonHeaderSeg); skelAnime->limbCount = skeletonHeader->limbCount + 1; - skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->skeletonSeg); - skelAnime->limbDrawTbl = zelda_malloc(sizeof(*skelAnime->limbDrawTbl) * skelAnime->limbCount); - skelAnime->transitionDrawTbl = zelda_malloc(sizeof(*skelAnime->transitionDrawTbl) * skelAnime->limbCount); + skelAnime->skeleton = Lib_SegmentedToVirtual(skeletonHeader->segment); + skelAnime->jointTable = ZeldaArena_Malloc(sizeof(*skelAnime->jointTable) * skelAnime->limbCount); + skelAnime->morphTable = ZeldaArena_Malloc(sizeof(*skelAnime->morphTable) * skelAnime->limbCount); // Debug prints here, required to match. if (1) {}; - if (animationSeg != NULL) { - SkelAnime_ChangeAnimDefaultRepeat(skelAnime, animationSeg); + if (animation != NULL) { + Animation_PlayLoop(skelAnime, animation); } } -void func_80136C84(SkelAnime* skelAnime) { - if (skelAnime->mode < 2) { - skelAnime->animUpdate = func_8013702C; - } else if (skelAnime->mode < 4) { - skelAnime->animUpdate = func_8013713C; +/** + * Sets the SkelAnime's update function based on its current mode. + */ +void SkelAnime_SetUpdate(SkelAnime* skelAnime) { + if (skelAnime->mode <= ANIMMODE_LOOP_INTERP) { + skelAnime->update = SkelAnime_LoopFull; + } else if (skelAnime->mode <= ANIMMODE_ONCE_INTERP) { + skelAnime->update = SkelAnime_Once; } else { - skelAnime->animUpdate = func_801370B0; + skelAnime->update = SkelAnime_LoopPartial; } } -s32 SkelAnime_FrameUpdateMatrix(SkelAnime* skelAnime) { - return skelAnime->animUpdate(skelAnime); +/** + * Advances the current animation and updates all frame tables. If the animation plays once, returns true when it + * finishes. + */ +s32 SkelAnime_Update(SkelAnime* skelAnime) { + return skelAnime->update(skelAnime); } -s32 func_80136CF4(SkelAnime* skelAnime) { - f32 prevUnk28 = skelAnime->transCurrentFrame; +/** + * Morphs from the pose in jointTable to the one in morphTable, advancing the morph but not the animation frame + */ +s32 SkelAnime_Morph(SkelAnime* skelAnime) { + f32 prevMorphWeight = skelAnime->morphWeight; f32 updateRate = gFramerateDivisorThird; - skelAnime->transCurrentFrame -= skelAnime->transitionStep * updateRate; - if (skelAnime->transCurrentFrame <= 0.0f) { - func_80136C84(skelAnime); - skelAnime->transCurrentFrame = 0.0f; + skelAnime->morphWeight -= skelAnime->morphRate * updateRate; + if (skelAnime->morphWeight <= 0.0f) { + SkelAnime_SetUpdate(skelAnime); + skelAnime->morphWeight = 0.0f; } - SkelAnime_InterpolateVec3s(skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->limbDrawTbl, - skelAnime->transitionDrawTbl, 1.0f - (skelAnime->transCurrentFrame / prevUnk28)); + SkelAnime_InterpFrameTable(skelAnime->limbCount, skelAnime->jointTable, skelAnime->jointTable, + skelAnime->morphTable, 1.0f - (skelAnime->morphWeight / prevMorphWeight)); return 0; } -s32 func_80136D98(SkelAnime* skelAnime) { - s16 temp_a2 = (s16)(skelAnime->transCurrentFrame * 16384.0f); - s16 temp_a1; - f32 sp28; - f32 phi_f2; +/** + * Performs a tapered morph from the pose in jointTable to the one in morphTable, advancing the morph but not the + * animation frame + */ +s32 SkelAnime_MorphTaper(SkelAnime* skelAnime) { + s16 prevPhase = skelAnime->morphWeight * 0x4000; + s16 curPhase; + f32 prevWeight; + f32 curWeight; f32 updateRate = gFramerateDivisorThird; - skelAnime->transCurrentFrame -= skelAnime->transitionStep * updateRate; - if (skelAnime->transCurrentFrame <= 0.0f) { - func_80136C84(skelAnime); - skelAnime->transCurrentFrame = 0.0f; + skelAnime->morphWeight -= skelAnime->morphRate * updateRate; + if (skelAnime->morphWeight <= 0.0f) { + SkelAnime_SetUpdate(skelAnime); + skelAnime->morphWeight = 0.0f; } - temp_a1 = (s16)(skelAnime->transCurrentFrame * 16384.0f); - if (skelAnime->unk03 < 0) { - sp28 = 1.0f - Math_CosS(temp_a2); - phi_f2 = 1.0f - Math_CosS(temp_a1); + curPhase = skelAnime->morphWeight * 0x4000; + if (skelAnime->taper < 0) { + prevWeight = 1.0f - Math_CosS(prevPhase); + curWeight = 1.0f - Math_CosS(curPhase); } else { - sp28 = Math_SinS(temp_a2); - phi_f2 = Math_SinS(temp_a1); + prevWeight = Math_SinS(prevPhase); + curWeight = Math_SinS(curPhase); } - if (phi_f2 != 0.0f) { - phi_f2 /= sp28; + if (curWeight != 0.0f) { + curWeight /= prevWeight; } else { - phi_f2 = 0.0f; + curWeight = 0.0f; } - SkelAnime_InterpolateVec3s(skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->limbDrawTbl, - skelAnime->transitionDrawTbl, 1.0f - phi_f2); + SkelAnime_InterpFrameTable(skelAnime->limbCount, skelAnime->jointTable, skelAnime->jointTable, + skelAnime->morphTable, 1.0f - curWeight); return 0; } -void func_80136F04(SkelAnime* skelAnime) { - s32 t; - s32 pad[2]; - Vec3s sp38[98]; - f32 temp_f10; - f32 temp_f2; - - SkelAnime_AnimateFrame(skelAnime->animCurrentSeg, skelAnime->animCurrentFrame, skelAnime->limbCount, - skelAnime->limbDrawTbl); - if (skelAnime->mode & 0x1) { - t = (s32)skelAnime->animCurrentFrame; - temp_f10 = t; - temp_f2 = skelAnime->animCurrentFrame - temp_f10; - t++; - if (t >= (s32)skelAnime->totalFrames) { - t = 0; +/** + * Gets frame data for the current frame as modified by morphTable and advances the morph + */ +void SkelAnime_AnimateFrame(SkelAnime* skelAnime) { + Vec3s nextjointTable[100]; + + SkelAnime_GetFrameData(skelAnime->animation, skelAnime->curFrame, skelAnime->limbCount, skelAnime->jointTable); + if (skelAnime->mode & ANIM_INTERP) { + s32 frame = skelAnime->curFrame; + f32 partialFrame = skelAnime->curFrame - frame; + + if (++frame >= (s32)skelAnime->animLength) { + frame = 0; } - SkelAnime_AnimateFrame(skelAnime->animCurrentSeg, t, skelAnime->limbCount, sp38); - SkelAnime_InterpolateVec3s(skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->limbDrawTbl, sp38, temp_f2); + SkelAnime_GetFrameData(skelAnime->animation, frame, skelAnime->limbCount, nextjointTable); + SkelAnime_InterpFrameTable(skelAnime->limbCount, skelAnime->jointTable, skelAnime->jointTable, nextjointTable, + partialFrame); } - if (skelAnime->transCurrentFrame != 0) { + if (skelAnime->morphWeight != 0) { f32 updateRate = gFramerateDivisorThird; - skelAnime->transCurrentFrame -= skelAnime->transitionStep * updateRate; - if (skelAnime->transCurrentFrame <= 0.0f) { - skelAnime->transCurrentFrame = 0.0f; - return; + + skelAnime->morphWeight -= skelAnime->morphRate * updateRate; + if (skelAnime->morphWeight <= 0.0f) { + skelAnime->morphWeight = 0.0f; + } else { + SkelAnime_InterpFrameTable(skelAnime->limbCount, skelAnime->jointTable, skelAnime->jointTable, + skelAnime->morphTable, skelAnime->morphWeight); } - SkelAnime_InterpolateVec3s(skelAnime->limbCount, skelAnime->limbDrawTbl, skelAnime->limbDrawTbl, - skelAnime->transitionDrawTbl, skelAnime->transCurrentFrame); } } - -s32 func_8013702C(SkelAnime* skelAnime) { +/** + * Advances an animation that loops over its full length and updates the frame tables + */ +s32 SkelAnime_LoopFull(SkelAnime* skelAnime) { f32 updateRate = gFramerateDivisorThird; - skelAnime->animCurrentFrame += skelAnime->animPlaybackSpeed * updateRate; - if (skelAnime->animCurrentFrame < 0.0f) { - skelAnime->animCurrentFrame += skelAnime->totalFrames; - } else if (skelAnime->totalFrames <= skelAnime->animCurrentFrame) { - skelAnime->animCurrentFrame -= skelAnime->totalFrames; + skelAnime->curFrame += skelAnime->playSpeed * updateRate; + if (skelAnime->curFrame < 0.0f) { + skelAnime->curFrame += skelAnime->animLength; + } else if (skelAnime->animLength <= skelAnime->curFrame) { + skelAnime->curFrame -= skelAnime->animLength; } - func_80136F04(skelAnime); + SkelAnime_AnimateFrame(skelAnime); return 0; } -s32 func_801370B0(SkelAnime* skelAnime) { +/** + * Advances an animation that loops over part of its length and updates the frame tables + */ +s32 SkelAnime_LoopPartial(SkelAnime* skelAnime) { f32 updateRate = gFramerateDivisorThird; - skelAnime->animCurrentFrame += skelAnime->animPlaybackSpeed * updateRate; - if (skelAnime->animCurrentFrame < skelAnime->initialFrame) { - skelAnime->animCurrentFrame = - (skelAnime->animCurrentFrame - skelAnime->initialFrame) + skelAnime->animFrameCount; - } else if (skelAnime->animFrameCount <= skelAnime->animCurrentFrame) { - skelAnime->animCurrentFrame = - (skelAnime->animCurrentFrame - skelAnime->animFrameCount) + skelAnime->initialFrame; + skelAnime->curFrame += skelAnime->playSpeed * updateRate; + if (skelAnime->curFrame < skelAnime->startFrame) { + skelAnime->curFrame = (skelAnime->curFrame - skelAnime->startFrame) + skelAnime->endFrame; + } else if (skelAnime->endFrame <= skelAnime->curFrame) { + skelAnime->curFrame = (skelAnime->curFrame - skelAnime->endFrame) + skelAnime->startFrame; } - func_80136F04(skelAnime); + SkelAnime_AnimateFrame(skelAnime); return 0; } -s32 func_8013713C(SkelAnime* skelAnime) { +/** + * Advances an animation that stops at endFrame and returns true when it is reached. + */ +s32 SkelAnime_Once(SkelAnime* skelAnime) { f32 updateRate = gFramerateDivisorThird; - if (skelAnime->animCurrentFrame == skelAnime->animFrameCount) { - SkelAnime_AnimateFrame(skelAnime->animCurrentSeg, (s32)skelAnime->animCurrentFrame, skelAnime->limbCount, - skelAnime->limbDrawTbl); - func_80136F04(skelAnime); + if (skelAnime->curFrame == skelAnime->endFrame) { + SkelAnime_GetFrameData(skelAnime->animation, skelAnime->curFrame, skelAnime->limbCount, skelAnime->jointTable); + SkelAnime_AnimateFrame(skelAnime); return 1; } - skelAnime->animCurrentFrame += skelAnime->animPlaybackSpeed * updateRate; - if (((skelAnime->animCurrentFrame - skelAnime->animFrameCount) * skelAnime->animPlaybackSpeed) > 0.0f) { - skelAnime->animCurrentFrame = skelAnime->animFrameCount; + skelAnime->curFrame += skelAnime->playSpeed * updateRate; + if (((skelAnime->curFrame - skelAnime->endFrame) * skelAnime->playSpeed) > 0.0f) { + skelAnime->curFrame = skelAnime->endFrame; } else { - if (skelAnime->animCurrentFrame < 0.0f) { - skelAnime->animCurrentFrame += skelAnime->totalFrames; + if (skelAnime->curFrame < 0.0f) { + skelAnime->curFrame += skelAnime->animLength; } else { - if (skelAnime->totalFrames <= skelAnime->animCurrentFrame) { - skelAnime->animCurrentFrame -= skelAnime->totalFrames; + if (skelAnime->animLength <= skelAnime->curFrame) { + skelAnime->curFrame -= skelAnime->animLength; } } } - func_80136F04(skelAnime); + SkelAnime_AnimateFrame(skelAnime); return 0; } -void SkelAnime_ChangeAnimImpl(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 playbackSpeed, f32 frame, - f32 frameCount, u8 animationType, f32 transitionRate, s8 unk2) { - skelAnime->mode = animationType; - if ((transitionRate != 0.0f) && - ((animationSeg != skelAnime->animCurrentSeg) || (frame != skelAnime->animCurrentFrame))) { - if (transitionRate < 0) { - func_80136C84(skelAnime); - SkelAnime_CopyVec3s(skelAnime, skelAnime->transitionDrawTbl, skelAnime->limbDrawTbl); - transitionRate = -transitionRate; +/** + * Fully general way to set a new animation, allowing choice of playback speed, start frame, end frame, play mode, + * number of transition frames, and tapering of the transition. Positive morph frames morph from the current pose to the + * start pose of the new animation, then start the new animation. Negative morph frames start the new animation + * immediately, modified by the pose immediately before the animation change. + */ +void Animation_ChangeImpl(SkelAnime* skelAnime, AnimationHeader* animation, f32 playSpeed, f32 startFrame, f32 endFrame, + u8 mode, f32 morphFrames, s8 taper) { + skelAnime->mode = mode; + if ((morphFrames != 0.0f) && ((animation != skelAnime->animation) || (startFrame != skelAnime->curFrame))) { + if (morphFrames < 0) { + SkelAnime_SetUpdate(skelAnime); + SkelAnime_CopyFrameTable(skelAnime, skelAnime->morphTable, skelAnime->jointTable); + morphFrames = -morphFrames; } else { - if (unk2 != 0) { - skelAnime->animUpdate = func_80136D98; - skelAnime->unk03 = unk2; + if (taper != ANIMTAPER_NONE) { + skelAnime->update = SkelAnime_MorphTaper; + skelAnime->taper = taper; } else { - skelAnime->animUpdate = func_80136CF4; + skelAnime->update = SkelAnime_Morph; } - SkelAnime_AnimateFrame(animationSeg, frame, skelAnime->limbCount, skelAnime->transitionDrawTbl); + SkelAnime_GetFrameData(animation, startFrame, skelAnime->limbCount, skelAnime->morphTable); } - skelAnime->transCurrentFrame = 1.0f; - skelAnime->transitionStep = 1.0f / transitionRate; + skelAnime->morphWeight = 1.0f; + skelAnime->morphRate = 1.0f / morphFrames; } else { - func_80136C84(skelAnime); - SkelAnime_AnimateFrame(animationSeg, frame, skelAnime->limbCount, skelAnime->limbDrawTbl); - skelAnime->transCurrentFrame = 0.0f; + SkelAnime_SetUpdate(skelAnime); + SkelAnime_GetFrameData(animation, startFrame, skelAnime->limbCount, skelAnime->jointTable); + skelAnime->morphWeight = 0.0f; } - skelAnime->animCurrentSeg = animationSeg; - skelAnime->initialFrame = frame; - skelAnime->animFrameCount = frameCount; - skelAnime->totalFrames = SkelAnime_GetTotalFrames(&animationSeg->common); - if (skelAnime->mode >= 4) { - skelAnime->animCurrentFrame = 0.0f; + skelAnime->animation = animation; + skelAnime->startFrame = startFrame; + skelAnime->endFrame = endFrame; + skelAnime->animLength = Animation_GetLength(&animation->common); + if (skelAnime->mode >= ANIMMODE_LOOP_PARTIAL) { + skelAnime->curFrame = 0.0f; } else { - skelAnime->animCurrentFrame = frame; - if (skelAnime->mode < 2) { - skelAnime->animFrameCount = skelAnime->totalFrames - 1.0f; + skelAnime->curFrame = startFrame; + if (skelAnime->mode <= ANIMMODE_LOOP_INTERP) { + skelAnime->endFrame = skelAnime->animLength - 1.0f; } } - skelAnime->animPlaybackSpeed = playbackSpeed; + skelAnime->playSpeed = playSpeed; } -void SkelAnime_ChangeAnim(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 playbackSpeed, f32 frame, - f32 frameCount, u8 mode, f32 transitionRate) { - SkelAnime_ChangeAnimImpl(skelAnime, animationSeg, playbackSpeed, frame, frameCount, mode, transitionRate, 0); +/** + * General way to set a new animation, allowing choice of playback speed, start frame, end frame, play mode, and number + * of transition frames. Positive morph frames morph from the current pose to the start pose of the new animation, then + * start the new animation. Negative morph frames start the new animation immediately, modified by the pose immediately + * before the animation change. + */ +void Animation_Change(SkelAnime* skelAnime, AnimationHeader* animation, f32 playSpeed, f32 startFrame, f32 endFrame, + u8 mode, f32 morphFrames) { + Animation_ChangeImpl(skelAnime, animation, playSpeed, startFrame, endFrame, mode, morphFrames, ANIMTAPER_NONE); } -void SkelAnime_ChangeAnimDefaultStop(SkelAnime* skelAnime, AnimationHeader* animationSeg) { - SkelAnime_ChangeAnim(skelAnime, animationSeg, 1.0f, 0.0f, SkelAnime_GetFrameCount(&animationSeg->common), 2, 0.0f); +/** + * Immediately changes to an animation that plays once at the default speed. + */ +void Animation_PlayOnce(SkelAnime* skelAnime, AnimationHeader* animation) { + Animation_Change(skelAnime, animation, 1.0f, 0.0f, Animation_GetLastFrame(&animation->common), ANIMMODE_ONCE, 0.0f); } -void SkelAnime_ChangeAnimTransitionStop(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 transitionRate) { - SkelAnime_ChangeAnim(skelAnime, animationSeg, 1.0f, 0, SkelAnime_GetFrameCount(&animationSeg->common), 2, - transitionRate); +/** + * Smoothly transitions to an animation that plays once at the default speed. + * Positive morph frames morph from the current pose to the start pose of the new animation, then start the new + * animation. Negative morph frames start the new animation immediately, modified by the pose immediately before the + * animation change. + */ +void Animation_MorphToPlayOnce(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 morphFrames) { + Animation_Change(skelAnime, animationSeg, 1.0f, 0, Animation_GetLastFrame(&animationSeg->common), ANIMMODE_ONCE, + morphFrames); } -void SkelAnime_ChangeAnimPlaybackStop(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 playbackSpeed) { - SkelAnime_ChangeAnim(skelAnime, animationSeg, playbackSpeed, 0.0f, SkelAnime_GetFrameCount(&animationSeg->common), - 2, 0.0f); +/** + * Immediately changes to an animation that plays once at the specified speed. + */ +void Animation_PlayOnceSetSpeed(SkelAnime* skelAnime, AnimationHeader* animation, f32 playSpeed) { + Animation_Change(skelAnime, animation, playSpeed, 0.0f, Animation_GetLastFrame(&animation->common), ANIMMODE_ONCE, + 0.0f); } -void SkelAnime_ChangeAnimDefaultRepeat(SkelAnime* skelAnime, AnimationHeader* animationSeg) { - SkelAnime_ChangeAnim(skelAnime, animationSeg, 1.0f, 0.0f, SkelAnime_GetFrameCount(&animationSeg->common), 0, 0.0f); +/** + * Immediately changes to an animation that loops at the default. + */ +void Animation_PlayLoop(SkelAnime* skelAnime, AnimationHeader* animation) { + Animation_Change(skelAnime, animation, 1.0f, 0.0f, Animation_GetLastFrame(&animation->common), ANIMMODE_LOOP, 0.0f); } -void SkelAnime_ChangeAnimTransitionRepeat(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 transitionRate) { - SkelAnime_ChangeAnim(skelAnime, animationSeg, 1.0f, 0.0f, 0.0f, 0, transitionRate); +/** + * Smoothly transitions to a looping animation, specifying the number of frames for the transition. + * Positive morph frames morph from the current pose to the start pose of the new animation, then start the new + * animation. Negative morph frames start the new animation immediately, modified by the pose immediately before the + * animation change. + */ +void Animation_MorphToLoop(SkelAnime* skelAnime, AnimationHeader* animation, f32 morphFrames) { + Animation_Change(skelAnime, animation, 1.0f, 0.0f, 0.0f, ANIMMODE_LOOP, morphFrames); } -void SkelAnime_ChangeAnimPlaybackRepeat(SkelAnime* skelAnime, AnimationHeader* animationSeg, f32 playbackSpeed) { - SkelAnime_ChangeAnim(skelAnime, animationSeg, playbackSpeed, 0.0f, SkelAnime_GetFrameCount(&animationSeg->common), - 0, 0.0f); +/** + * Immediately changes to an animation that loops at the specified speed. + */ +void Animation_PlayLoopSetSpeed(SkelAnime* skelAnime, AnimationHeader* animation, f32 playbackSpeed) { + Animation_Change(skelAnime, animation, playbackSpeed, 0.0f, Animation_GetLastFrame(&animation->common), + ANIMMODE_LOOP, 0.0f); } -void SkelAnime_AnimSetStop(SkelAnime* skelAnime) { - skelAnime->mode = 2; - skelAnime->animFrameCount = skelAnime->totalFrames; - func_80136C84(skelAnime); +/** + * Changes a looping animation to one that stops at the end. Unused + */ +void Animation_EndLoop(SkelAnime* skelAnime) { + skelAnime->mode = ANIMMODE_ONCE; + skelAnime->endFrame = skelAnime->animLength; + SkelAnime_SetUpdate(skelAnime); } -void SkelAnime_AnimReverse(SkelAnime* skelAnime) { - f32 initialFrame = skelAnime->initialFrame; +/** + * Reverses the current animation. + */ +void Animation_Reverse(SkelAnime* skelAnime) { + f32 startFrame = skelAnime->startFrame; - skelAnime->initialFrame = skelAnime->animFrameCount; - skelAnime->animPlaybackSpeed = -skelAnime->animPlaybackSpeed; - skelAnime->animFrameCount = initialFrame; + skelAnime->startFrame = skelAnime->endFrame; + skelAnime->playSpeed = -skelAnime->playSpeed; + skelAnime->endFrame = startFrame; } -void func_80137674(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src, u8* index) { +/** + * Copies the src frame table to the dst frame table if copyFlag for that limb is true. + */ +void SkelAnime_CopyFrameTableTrue(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src, u8* copyFlag) { s32 i; for (i = 0; i < skelAnime->limbCount; i++, dst++, src++) { - if (*index++) { + if (*copyFlag++) { *dst = *src; } } } -void func_801376DC(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src, u8* arg3) { +/** + * Copies the src frame table to the dst frame table if copyFlag for that limb is false. + */ +void SkelAnime_CopyFrameTableFalse(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src, u8* copyFlag) { s32 i; for (i = 0; i < skelAnime->limbCount; i++, dst++, src++) { - if (*arg3++ < 1U) { + if (!*copyFlag++) { *dst = *src; } } } -/* - * Moves `pos` backwards on the xz plane from `angle` +/** + * Updates translation of the root limb and calculates `pos`, the difference between + * the old and new positions of the root limb as rotated by `angle`. Used to allow + * animations to change an actor's position. */ -void func_80137748(SkelAnime* skelAnime, Vec3f* pos, s16 angle) { +void SkelAnime_UpdateTranslation(SkelAnime* skelAnime, Vec3f* diff, s16 angle) { f32 x; f32 z; f32 sin; f32 cos; - if (skelAnime->flags & 0x10) { - pos->z = 0.0f; - pos->x = 0.0f; + if (skelAnime->moveFlags & ANIM_FLAG_NOMOVE) { + diff->z = 0.0f; + diff->x = 0.0f; } else { // `angle` rotation around y axis. - x = skelAnime->limbDrawTbl->x - skelAnime->prevFramePos.x; - z = skelAnime->limbDrawTbl->z - skelAnime->prevFramePos.z; + x = skelAnime->jointTable->x - skelAnime->prevTransl.x; + z = skelAnime->jointTable->z - skelAnime->prevTransl.z; sin = Math_SinS(angle); cos = Math_CosS(angle); - pos->x = x * cos + z * sin; - pos->z = z * cos - x * sin; + diff->x = x * cos + z * sin; + diff->z = z * cos - x * sin; } - skelAnime->prevFramePos.x = skelAnime->limbDrawTbl->x; - skelAnime->limbDrawTbl->x = skelAnime->unk3E.x; - skelAnime->prevFramePos.z = skelAnime->limbDrawTbl->z; - skelAnime->limbDrawTbl->z = skelAnime->unk3E.z; - if (skelAnime->flags & ANIM_FLAG_UPDATEXZ) { - if (skelAnime->flags & ANIM_FLAG_UPDATEY) { - pos->y = 0.0f; + skelAnime->prevTransl.x = skelAnime->jointTable->x; + skelAnime->jointTable->x = skelAnime->baseTransl.x; + skelAnime->prevTransl.z = skelAnime->jointTable->z; + skelAnime->jointTable->z = skelAnime->baseTransl.z; + if (skelAnime->moveFlags & ANIM_FLAG_UPDATEY) { + if (skelAnime->moveFlags & ANIM_FLAG_NOMOVE) { + diff->y = 0.0f; } else { - pos->y = skelAnime->limbDrawTbl->y - skelAnime->prevFramePos.y; + diff->y = skelAnime->jointTable->y - skelAnime->prevTransl.y; } - skelAnime->prevFramePos.y = skelAnime->limbDrawTbl->y; - skelAnime->limbDrawTbl->y = skelAnime->unk3E.y; + skelAnime->prevTransl.y = skelAnime->jointTable->y; + skelAnime->jointTable->y = skelAnime->baseTransl.y; } else { - pos->y = 0.0f; - skelAnime->prevFramePos.y = skelAnime->limbDrawTbl->y; + diff->y = 0.0f; + skelAnime->prevTransl.y = skelAnime->jointTable->y; } - skelAnime->flags &= ~ANIM_FLAG_UPDATEY; + skelAnime->moveFlags &= ~ANIM_FLAG_NOMOVE; } -s32 func_801378B8(SkelAnime* skelAnime, f32 arg1) { - return func_80136990(skelAnime, arg1, 1.0f); +/** + * Checks if the current animation is at the specified frame + */ +s32 Animation_OnFrame(SkelAnime* skelAnime, f32 frame) { + return Animation_OnFrameImpl(skelAnime, frame, 1.0f); } +/** + * Frees the frame tables for a skelAnime with dynamically allocated tables. + */ void SkelAnime_Free(SkelAnime* skelAnime, GlobalContext* globalCtx) { - if (skelAnime->limbDrawTbl != NULL) { - zelda_free(skelAnime->limbDrawTbl); + if (skelAnime->jointTable != NULL) { + ZeldaArena_Free(skelAnime->jointTable); } - if (skelAnime->transitionDrawTbl != NULL) { - zelda_free(skelAnime->transitionDrawTbl); + if (skelAnime->morphTable != NULL) { + ZeldaArena_Free(skelAnime->morphTable); } } -void SkelAnime_CopyVec3s(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src) { +/** + * Copies the src frame table to the dst frame table. + */ +void SkelAnime_CopyFrameTable(SkelAnime* skelAnime, Vec3s* dst, Vec3s* src) { bcopy(src, dst, sizeof(Vec3s) * skelAnime->limbCount); } diff --git a/src/code/z_view.c b/src/code/z_view.c index 034f045b1..c325fd563 100644 --- a/src/code/z_view.c +++ b/src/code/z_view.c @@ -237,7 +237,7 @@ s32 View_SetQuake(View* view, Vec3f rot, Vec3f scale, f32 speed) { return 1; } -s32 View_StepQuake(View* view, RSPMatrix* matrix) { +s32 View_StepQuake(View* view, Mtx* matrix) { MtxF mf; if (view->quakeSpeed == 0.0f) { @@ -256,16 +256,16 @@ s32 View_StepQuake(View* view, RSPMatrix* matrix) { view->currQuakeScale.z += ((view->quakeScale.z - view->currQuakeScale.z) * view->quakeSpeed); } - SysMatrix_FromRSPMatrix(matrix, &mf); - SysMatrix_SetCurrentState(&mf); - SysMatrix_RotateStateAroundXAxis(view->currQuakeRot.x); - SysMatrix_InsertYRotation_f(view->currQuakeRot.y, 1); - SysMatrix_InsertZRotation_f(view->currQuakeRot.z, 1); - Matrix_Scale(view->currQuakeScale.x, view->currQuakeScale.y, view->currQuakeScale.z, 1); - SysMatrix_InsertZRotation_f(-view->currQuakeRot.z, 1); - SysMatrix_InsertYRotation_f(-view->currQuakeRot.y, 1); - SysMatrix_RotateStateAroundXAxis(-view->currQuakeRot.x); - SysMatrix_GetStateAsRSPMatrix(matrix); + Matrix_FromRSPMatrix(matrix, &mf); + Matrix_SetCurrentState(&mf); + Matrix_RotateStateAroundXAxis(view->currQuakeRot.x); + Matrix_InsertYRotation_f(view->currQuakeRot.y, 1); + Matrix_InsertZRotation_f(view->currQuakeRot.z, 1); + Matrix_Scale(view->currQuakeScale.x, view->currQuakeScale.y, view->currQuakeScale.z, MTXMODE_APPLY); + Matrix_InsertZRotation_f(-view->currQuakeRot.z, 1); + Matrix_InsertYRotation_f(-view->currQuakeRot.y, 1); + Matrix_RotateStateAroundXAxis(-view->currQuakeRot.x); + Matrix_ToMtx(matrix); return 1; } @@ -310,7 +310,7 @@ s32 View_RenderToPerspectiveMatrix(View* view) { guPerspective(projection, &view->normal, view->fovy, aspect, view->zNear, view->zFar, view->scale); view->projection = *projection; //! @bug: This cast of `projection` is invalid - View_StepQuake(view, (RSPMatrix*)projection); + View_StepQuake(view, (Mtx*)projection); gSPPerspNormalize(POLY_OPA_DISP++, view->normal); gSPMatrix(POLY_OPA_DISP++, projection, G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_PROJECTION); diff --git a/src/code/z_vr_box.c b/src/code/z_vr_box.c index 1fca4801d..9e949beac 100644 --- a/src/code/z_vr_box.c +++ b/src/code/z_vr_box.c @@ -35,9 +35,9 @@ void func_80143148(SkyboxContext* skyboxCtx, s32 arg1) { } } -void func_801431E8(GameState* gamestate, SkyboxContext* skyboxCtx, s16 skyType) { - GlobalContext* globalCtx = (GlobalContext*)gamestate; - u32 size; +void func_801431E8(GameState* gameState, SkyboxContext* skyboxCtx, s16 skyType) { + GlobalContext* globalCtx = (GlobalContext*)gameState; + size_t size; void* offset; s32 pad; @@ -82,7 +82,7 @@ void func_801431E8(GameState* gamestate, SkyboxContext* skyboxCtx, s16 skyType) } void func_80143324(GlobalContext* globalCtx, SkyboxContext* skyboxCtx, s16 skyType) { - u32 size; + size_t size; if (1) {} @@ -133,22 +133,22 @@ void func_80143324(GlobalContext* globalCtx, SkyboxContext* skyboxCtx, s16 skyTy } } -void func_801434E4(GameState* gamestate, SkyboxContext* skyboxCtx, s16 skyType) { +void func_801434E4(GameState* gameState, SkyboxContext* skyboxCtx, s16 skyType) { skyboxCtx->skyboxShouldDraw = 0; skyboxCtx->rotX = skyboxCtx->rotY = skyboxCtx->rotZ = 0.0f; - func_801431E8(gamestate, skyboxCtx, skyType); + func_801431E8(gameState, skyboxCtx, skyType); if (skyType != 0) { - skyboxCtx->unk17C = THA_AllocEndAlign16(&gamestate->heap, 0x3840); + skyboxCtx->unk17C = THA_AllocEndAlign16(&gameState->heap, 0x3840); if (skyType == 5) { // Allocate enough space for the vertices for a 6 sided skybox (cube) - skyboxCtx->roomVtx = THA_AllocEndAlign16(&gamestate->heap, sizeof(Vtx) * 32 * 6); + skyboxCtx->roomVtx = THA_AllocEndAlign16(&gameState->heap, sizeof(Vtx) * 32 * 6); func_80143148(skyboxCtx, 6); } else { // Allocate enough space for the vertices for a 5 sided skybox (bottom is missing) - skyboxCtx->roomVtx = THA_AllocEndAlign16(&gamestate->heap, sizeof(Vtx) * 32 * 5); + skyboxCtx->roomVtx = THA_AllocEndAlign16(&gameState->heap, sizeof(Vtx) * 32 * 5); func_80143148(skyboxCtx, 5); } } |
