Merge remote-tracking branch 'upstream/main' into EnGs_Doc

This commit is contained in:
blackgamma7 2024-06-19 20:41:28 -04:00
commit bc3faed1e4
61 changed files with 913 additions and 1107 deletions

View File

@ -133,7 +133,7 @@ OBJCOPY := $(MIPS_BINUTILS_PREFIX)objcopy
OBJDUMP := $(MIPS_BINUTILS_PREFIX)objdump
NM := $(MIPS_BINUTILS_PREFIX)nm
N64_EMULATOR ?=
N64_EMULATOR ?=
INC := -Iinclude -Iinclude/libc -Isrc -I$(BUILD_DIR) -I. -I$(EXTRACTED_DIR)
@ -243,7 +243,7 @@ $(BUILD_DIR)/src/boot/stackcheck.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/__osMalloc.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/code_800FC620.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/code_800FCE80.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/fp_math.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/rand.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/gfxprint.o: OPTFLAGS := -O2
$(BUILD_DIR)/src/code/jpegutils.o: OPTFLAGS := -O2

17
include/fp_math.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef FP_MATH_H
#define FP_MATH_H
#include "ultra64.h"
f32 Math_FTanF(f32 angle);
f32 Math_FFloorF(f32 x);
f32 Math_FCeilF(f32 x);
f32 Math_FRoundF(f32 x);
f32 Math_FNearbyIntF(f32 x);
f32 Math_FTruncF(f32 x);
f32 Math_FAtanF(f32 x);
f32 Math_FAtan2F(f32 y, f32 x);
f32 Math_FAsinF(f32 x);
f32 Math_FAcosF(f32 x);
#endif

View File

@ -4,23 +4,6 @@
#include "z64.h"
#include "macros.h"
f32 fabsf(f32 f);
#ifdef __sgi
#pragma intrinsic(fabsf)
#else
#define fabsf(f) __builtin_fabsf((f32)(f))
#endif
f32 sqrtf(f32 f);
#ifdef __sgi
#pragma intrinsic(sqrtf)
#endif
f64 sqrt(f64 f);
#ifdef __sgi
#pragma intrinsic(sqrt)
#endif
void cleararena(void);
void bootproc(void);
void Main_ThreadEntry(void* arg);
@ -839,41 +822,6 @@ s32 Environment_IsForcedSequenceDisabled(void);
void Environment_PlayStormNatureAmbience(PlayState* play);
void Environment_StopStormNatureAmbience(PlayState* play);
void Environment_WarpSongLeave(PlayState* play);
void Lib_MemSet(u8* dest, size_t len, u8 val);
f32 Math_CosS(s16 angle);
f32 Math_SinS(s16 angle);
s32 Math_ScaledStepToS(s16* pValue, s16 target, s16 step);
s32 Math_StepToS(s16* pValue, s16 target, s16 step);
s32 Math_StepToF(f32* pValue, f32 target, f32 step);
s32 Math_StepUntilAngleS(s16* pValue, s16 limit, s16 step);
s32 Math_StepUntilS(s16* pValue, s16 limit, s16 step);
s32 Math_StepToAngleS(s16* pValue, s16 target, s16 step);
s32 Math_StepUntilF(f32* pValue, f32 limit, f32 step);
s32 Math_AsymStepToF(f32* pValue, f32 target, f32 incrStep, f32 decrStep);
void Lib_GetControlStickData(f32* outMagnitude, s16* outAngle, Input* input);
s16 Rand_S16Offset(s16 base, s16 range);
void Math_Vec3f_Copy(Vec3f* dest, Vec3f* src);
void Math_Vec3s_ToVec3f(Vec3f* dest, Vec3s* src);
void Math_Vec3f_Sum(Vec3f* a, Vec3f* b, Vec3f* dest);
void Math_Vec3f_Diff(Vec3f* a, Vec3f* b, Vec3f* dest);
void Math_Vec3s_DiffToVec3f(Vec3f* dest, Vec3s* a, Vec3s* b);
void Math_Vec3f_Scale(Vec3f* vec, f32 scaleF);
f32 Math_Vec3f_DistXYZ(Vec3f* a, Vec3f* b);
f32 Math_Vec3f_DistXYZAndStoreDiff(Vec3f* a, Vec3f* b, Vec3f* dest);
f32 Math_Vec3f_DistXZ(Vec3f* a, Vec3f* b);
s16 Math_Vec3f_Yaw(Vec3f* origin, Vec3f* point);
s16 Math_Vec3f_Pitch(Vec3f* a, Vec3f* b);
void Actor_ProcessInitChain(Actor* actor, InitChainEntry* ichain);
f32 Math_SmoothStepToF(f32* pValue, f32 target, f32 fraction, f32 step, f32 minStep);
void Math_ApproachF(f32* pValue, f32 target, f32 fraction, f32 step);
void Math_ApproachZeroF(f32* pValue, f32 fraction, f32 step);
f32 Math_SmoothStepToDegF(f32* pValue, f32 target, f32 fraction, f32 step, f32 minStep);
s16 Math_SmoothStepToS(s16* pValue, s16 target, s16 scale, s16 step, s16 minStep);
void Math_ApproachS(s16* pValue, s16 target, s16 scale, s16 step);
void Color_RGBA8_Copy(Color_RGBA8* dst, Color_RGBA8* src);
void Sfx_PlaySfxCentered(u16 sfxId);
void Sfx_PlaySfxCentered2(u16 sfxId);
void Sfx_PlaySfxAtPos(Vec3f* projectedPos, u16 sfxId);
void Health_InitMeter(PlayState* play);
void Health_UpdateMeter(PlayState* play);
void Health_DrawMeter(PlayState* play);
@ -1346,80 +1294,9 @@ void Main(void* arg);
void SysCfb_Init(s32 n64dd);
void* SysCfb_GetFbPtr(s32 idx);
void* SysCfb_GetFbEnd(void);
f32 Math_FactorialF(f32 n);
f32 Math_Factorial(s32 n);
f32 Math_PowF(f32 base, s32 exp);
f32 Math_SinF(f32 angle);
f32 Math_CosF(f32 angle);
s32 Math3D_PlaneVsLineSegClosestPoint(f32 planeAA, f32 planeAB, f32 planeAC, f32 planeADist, f32 planeBA, f32 planeBB,
f32 planeBC, f32 planeBDist, Vec3f* linePointA, Vec3f* linePointB,
Vec3f* closestPoint);
void Math3D_LineClosestToPoint(InfiniteLine* line, Vec3f* pos, Vec3f* closestPoint);
s32 Math3D_PlaneVsPlaneVsLineClosestPoint(f32 planeAA, f32 planeAB, f32 planeAC, f32 planeADist, f32 planeBA,
f32 planeBB, f32 planeBC, f32 planeBDist, Vec3f* point, Vec3f* closestPoint);
void Math3D_LineSplitRatio(Vec3f* v0, Vec3f* v1, f32 ratio, Vec3f* ret);
f32 Math3D_Cos(Vec3f* a, Vec3f* b);
s32 Math3D_CosOut(Vec3f* a, Vec3f* b, f32* dst);
void Math3D_Vec3fReflect(Vec3f* vec, Vec3f* normal, Vec3f* reflVec);
s32 Math3D_PointInSquare2D(f32 upperLeftX, f32 lowerRightX, f32 upperLeftY, f32 lowerRightY, f32 x, f32 y);
f32 Math3D_Dist1DSq(f32 a, f32 b);
f32 Math3D_Dist2DSq(f32 x0, f32 y0, f32 x1, f32 y1);
f32 Math3D_Vec3fMagnitudeSq(Vec3f* vec);
f32 Math3D_Vec3fMagnitude(Vec3f* vec);
f32 Math3D_Vec3fDistSq(Vec3f* a, Vec3f* b);
void Math3D_Vec3f_Cross(Vec3f* a, Vec3f* b, Vec3f* ret);
void Math3D_SurfaceNorm(Vec3f* va, Vec3f* vb, Vec3f* vc, Vec3f* normal);
f32 Math3D_Vec3f_DistXYZ(Vec3f* a, Vec3f* b);
s32 Math3D_PointRelativeToCubeFaces(Vec3f* point, Vec3f* min, Vec3f* max);
s32 Math3D_PointRelativeToCubeEdges(Vec3f* point, Vec3f* min, Vec3f* max);
s32 Math3D_PointRelativeToCubeVertices(Vec3f* point, Vec3f* min, Vec3f* max);
s32 Math3D_LineVsCube(Vec3f* min, Vec3f* max, Vec3f* a, Vec3f* b);
void Math3D_RotateXZPlane(Vec3f* pointOnPlane, s16 angle, f32* a, f32* c, f32* d);
void Math3D_DefPlane(Vec3f* va, Vec3f* vb, Vec3f* vc, f32* nx, f32* ny, f32* nz, f32* originDist);
f32 Math3D_UDistPlaneToPos(f32 nx, f32 ny, f32 nz, f32 originDist, Vec3f* p);
f32 Math3D_DistPlaneToPos(f32 nx, f32 ny, f32 nz, f32 originDist, Vec3f* p);
s32 Math3D_TriChkPointParaYSlopedY(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 z, f32 x);
s32 Math3D_TriChkPointParaYIntersectDist(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 z,
f32 x, f32* yIntersect, f32 chkDist);
s32 Math3D_TriChkPointParaYIntersectInsideTri(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist,
f32 z, f32 x, f32* yIntersect, f32 chkDist);
s32 Math3D_TriChkLineSegParaYIntersect(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 z,
f32 x, f32* yIntersect, f32 y0, f32 y1);
s32 Math3D_TriChkPointParaYDist(Vec3f* v0, Vec3f* v1, Vec3f* v2, Plane* plane, f32 z, f32 x, f32 chkDist);
s32 Math3D_TriChkPointParaXIntersect(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 y,
f32 z, f32* xIntersect);
s32 Math3D_TriChkLineSegParaXIntersect(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 y,
f32 z, f32* xIntersect, f32 x0, f32 x1);
s32 Math3D_TriChkPointParaXDist(Vec3f* v0, Vec3f* v1, Vec3f* v2, Plane* plane, f32 y, f32 z, f32 chkDist);
s32 Math3D_TriChkPointParaZIntersect(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 x,
f32 y, f32* zIntersect);
s32 Math3D_TriChkLineSegParaZIntersect(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 x,
f32 y, f32* zIntersect, f32 z0, f32 z1);
s32 Math3D_TriChkLineSegParaZDist(Vec3f* v0, Vec3f* v1, Vec3f* v2, Plane* plane, f32 x, f32 y, f32 chkDist);
s32 Math3D_LineSegVsPlane(f32 nx, f32 ny, f32 nz, f32 originDist, Vec3f* linePointA, Vec3f* linePointB,
Vec3f* intersect, s32 fromFront);
void Math3D_TriNorm(TriNorm* tri, Vec3f* va, Vec3f* vb, Vec3f* vc);
s32 Math3D_PointDistSqToLine2D(f32 x0, f32 y0, f32 x1, f32 y1, f32 x2, f32 y2, f32* lineLenSq);
s32 Math3D_LineVsSph(Sphere16* sphere, Linef* line);
s32 Math3D_TriVsSphIntersect(Sphere16* sphere, TriNorm* tri, Vec3f* intersectPoint);
s32 Math3D_CylVsLineSeg(Cylinder16* cyl, Vec3f* linePointA, Vec3f* linePointB, Vec3f* intersectA, Vec3f* intersectB);
s32 Math3D_CylVsTri(Cylinder16* cyl, TriNorm* tri);
s32 Math3D_CylTriVsIntersect(Cylinder16* cyl, TriNorm* tri, Vec3f* intersect);
s32 Math3D_SphVsSph(Sphere16* sphereA, Sphere16* sphereB);
s32 Math3D_SphVsSphOverlap(Sphere16* sphereA, Sphere16* sphereB, f32* overlapSize);
s32 Math3D_SphVsSphOverlapCenterDist(Sphere16* sphereA, Sphere16* sphereB, f32* overlapSize, f32* centerDist);
s32 Math3D_SphVsCylOverlap(Sphere16* sph, Cylinder16* cyl, f32* overlapSize);
s32 Math3D_SphVsCylOverlapCenterDist(Sphere16* sph, Cylinder16* cyl, f32* overlapSize, f32* centerDist);
s32 Math3D_CylVsCylOverlap(Cylinder16* ca, Cylinder16* cb, f32* overlapSize);
s32 Math3D_CylVsCylOverlapCenterDist(Cylinder16* ca, Cylinder16* cb, f32* overlapSize, f32* centerDist);
s32 Math3D_TriVsTriIntersect(TriNorm* ta, TriNorm* tb, Vec3f* intersect);
s32 Math3D_XZInSphere(Sphere16* sphere, f32 x, f32 z);
s32 Math3D_XYInSphere(Sphere16* sphere, f32 x, f32 y);
s32 Math3D_YZInSphere(Sphere16* sphere, f32 y, f32 z);
void Math3D_DrawSphere(PlayState* play, Sphere16* sph);
void Math3D_DrawCylinder(PlayState* play, Cylinder16* cyl);
s16 Math_Atan2S(f32 x, f32 y);
f32 Math_Atan2F(f32 x, f32 y);
void Matrix_Init(GameState* gameState);
void Matrix_Push(void);
void Matrix_Pop(void);
@ -1681,24 +1558,7 @@ void Audio_Init(void);
void Audio_InitSound(void);
void func_800F7170(void);
void func_800F71BC(s32 arg0);
void Audio_SetSfxBanksMute(u16 muteMask);
void Audio_QueueSeqCmdMute(u8 channelIndex);
void Audio_ClearBGMMute(u8 channelIndex);
void Audio_PlaySfxGeneral(u16 sfxId, Vec3f* pos, u8 token, f32* freqScale, f32* vol, s8* reverbAdd);
void Audio_ProcessSfxRequest(void);
void Audio_ChooseActiveSfx(u8 bankId);
void Audio_PlayActiveSfx(u8 bankId);
void Audio_StopSfxByBank(u8 bankId);
void func_800F8884(u8 bankId, Vec3f* pos);
void Audio_StopSfxByPosAndBank(u8 bankId, Vec3f* pos);
void Audio_StopSfxByPos(Vec3f* pos);
void Audio_StopSfxByPosAndId(Vec3f* pos, u16 sfxId);
void Audio_StopSfxByTokenAndId(u8 token, u16 sfxId);
void Audio_StopSfxById(u32 sfxId);
void Audio_ProcessSfxRequests(void);
void func_800F8F88(void);
u8 Audio_IsSfxPlaying(u32 sfxId);
void Audio_ResetSfx(void);
void Audio_StartSequence(u8 seqPlayerIndex, u8 seqId, u8 seqArgs, u16 fadeInDuration);
void Audio_StopSequence(u8 seqPlayerIndex, u16 fadeOutDuration);
void Audio_QueueSeqCmd(u32 cmd);
@ -1748,20 +1608,7 @@ s8 PadUtils_GetRelX(Input* input);
s8 PadUtils_GetRelY(Input* input);
void PadUtils_UpdateRelXY(Input* input);
s32 PadSetup_Init(OSMesgQueue* mq, u8* outMask, OSContStatus* status);
f32 Math_FTanF(f32 angle);
f32 Math_FFloorF(f32 x);
f32 Math_FCeilF(f32 x);
f32 Math_FRoundF(f32 x);
f32 Math_FNearbyIntF(f32 x);
f32 Math_FTruncF(f32 x);
f32 Math_FAtanF(f32 x);
f32 Math_FAtan2F(f32 y, f32 x);
f32 Math_FAsinF(f32 x);
f32 Math_FAcosF(f32 x);
f32 ceilf(f32 x);
f32 truncf(f32 x);
f32 roundf(f32 x);
f32 nearbyintf(f32 x);
void* SystemArena_Malloc(u32 size);
void* SystemArena_MallocR(u32 size);
void* SystemArena_Realloc(void* ptr, u32 newSize);
@ -1779,14 +1626,7 @@ void* SystemArena_ReallocDebug(void* ptr, u32 newSize, const char* file, int lin
void SystemArena_FreeDebug(void* ptr, const char* file, int line);
void SystemArena_Display(void);
#endif
u32 Rand_Next(void);
void Rand_Seed(u32 seed);
f32 Rand_ZeroOne(void);
f32 Rand_Centered(void);
void Rand_Seed_Variable(u32* rndNum, u32 seed);
u32 Rand_Next_Variable(u32* rndNum);
f32 Rand_ZeroOne_Variable(u32* rndNum);
f32 Rand_Centered_Variable(u32* rndNum);
void __osMallocInit(Arena* arena, void* start, u32 size);
void __osMallocAddBlock(Arena* arena, void* start, s32 size);
void __osMallocCleanup(Arena* arena);
@ -1825,8 +1665,6 @@ s32 JpegDecoder_ParseNextSymbol(JpegHuffmanTable* hTable, s16* outCoeff, s8* out
u16 JpegDecoder_ReadBits(u8 len);
s32 osPfsFreeBlocks(OSPfs* pfs, s32* leftoverBytes);
void guScale(Mtx* m, f32 x, f32 y, f32 z);
f32 sinf(f32 angle);
s16 sins(u16 angle);
OSTask* _VirtualToPhysicalTask(OSTask* intp);
void osSpTaskLoad(OSTask* intp);
void osSpTaskStartGo(OSTask* tp);
@ -1890,8 +1728,6 @@ s32 osPfsDeleteFile(OSPfs* pfs, u16 companyCode, u32 gameCode, u8* gameName, u8*
s32 __osPfsReleasePages(OSPfs* pfs, __OSInode* inode, u8 initialPage, u8 bank, __OSInodeUnit* finalPage);
void guOrthoF(f32[4][4], f32, f32, f32, f32, f32, f32, f32);
void guOrtho(Mtx*, f32, f32, f32, f32, f32, f32, f32);
f32 cosf(f32 angle);
s16 coss(u16 angle);
void osViSetEvent(OSMesgQueue* mq, OSMesg msg, u32 retraceCount);
s32 osPfsIsPlug(OSMesgQueue* mq, u8* pattern);
void __osPfsRequestData(u8 cmd);

View File

@ -1,7 +1,9 @@
#ifndef ICHAIN_H
#define ICHAIN_H
#include "libc/stddef.h"
#include "ultra64.h"
struct Actor;
typedef struct {
u32 cont: 1;
@ -55,4 +57,6 @@ typedef enum {
#define ICHAIN_CONTINUE 1
#define ICHAIN_STOP 0
void Actor_ProcessInitChain(struct Actor* actor, InitChainEntry* ichain);
#endif

View File

@ -34,6 +34,23 @@ double round(double);
long lroundf(float);
long lround(double);
f32 fabsf(f32 f);
#ifdef __sgi
#pragma intrinsic(fabsf)
#else
#define fabsf(f) __builtin_fabsf((f32)(f))
#endif
f32 sqrtf(f32 f);
#ifdef __sgi
#pragma intrinsic(sqrtf)
#endif
f64 sqrt(f64 f);
#ifdef __sgi
#pragma intrinsic(sqrt)
#endif
extern float qNaN0x3FFFFF;
extern float qNaN0x10000;
extern float sNaN0x3FFFFF;

View File

@ -14,7 +14,6 @@
#define VIRTUAL_TO_PHYSICAL(addr) (uintptr_t)((u8*)(addr) - 0x80000000)
#define SEGMENTED_TO_VIRTUAL(addr) PHYSICAL_TO_VIRTUAL(gSegments[SEGMENT_NUMBER(addr)] + SEGMENT_OFFSET(addr))
#define SQ(x) ((x)*(x))
#define ABS(x) ((x) >= 0 ? (x) : -(x))
#define DECR(x) ((x) == 0 ? 0 : --(x))
#define CLAMP(x, min, max) ((x) < (min) ? (min) : (x) > (max) ? (max) : (x))

15
include/rand.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef RAND_H
#define RAND_H
#include "ultra64.h"
u32 Rand_Next(void);
void Rand_Seed(u32 seed);
f32 Rand_ZeroOne(void);
f32 Rand_Centered(void);
void Rand_Seed_Variable(u32* rndNum, u32 seed);
u32 Rand_Next_Variable(u32* rndNum);
f32 Rand_ZeroOne_Variable(u32* rndNum);
f32 Rand_Centered_Variable(u32* rndNum);
#endif

View File

@ -109,6 +109,7 @@
#define R_C_UP_ICON_Y YREG(89)
#define R_EPONAS_SONG_PLAYED DREG(53)
#define R_MAGIC_FILL_COLOR(i) ZREG(0 + (i))
#define R_PAUSE_PAGE_SWITCH_FRAME_ADVANCE_ON ZREG(13)
#define R_C_BTN_COLOR(i) ZREG(39 + (i))
#define R_B_BTN_COLOR(i) ZREG(43 + (i))
#define R_START_LABEL_DD(i) ZREG(48 + (i))
@ -352,4 +353,15 @@ typedef enum {
#define R_VI_CUR_ADDI_SCAN_LINES HREG(83)
#define R_VI_CUR_Y_SCALE_MODE HREG(84)
typedef struct {
/* 0x00 */ s32 regPage; // 0: no page selected (reg editor is not active); 1: first page; `REG_PAGES`: last page
/* 0x04 */ s32 regGroup; // Indexed from 0 to `REG_GROUPS`-1. Each group has its own character to identify it.
/* 0x08 */ s32 regCur; // Selected reg, indexed from 0 as the page start
/* 0x0C */ s32 dPadInputPrev;
/* 0x10 */ s32 inputRepeatTimer;
/* 0x14 */ s16 data[REG_GROUPS * REGS_PER_GROUP]; // Accessed through *REG macros, see regs.h
} RegEditor; // size = 0x15D4
extern RegEditor* gRegEditor;
#endif

View File

@ -125,4 +125,27 @@ typedef struct {
#define SFX_DIST_SCALING 10.0f
#endif
void Audio_SetSfxBanksMute(u16 muteMask);
void Audio_QueueSeqCmdMute(u8 channelIndex);
void Audio_ClearBGMMute(u8 channelIndex);
void Audio_PlaySfxGeneral(u16 sfxId, Vec3f* pos, u8 token, f32* freqScale, f32* vol, s8* reverbAdd);
void Audio_ProcessSfxRequest(void);
void Audio_ChooseActiveSfx(u8 bankId);
void Audio_PlayActiveSfx(u8 bankId);
void Audio_StopSfxByBank(u8 bankId);
void func_800F8884(u8 bankId, Vec3f* pos);
void Audio_StopSfxByPosAndBank(u8 bankId, Vec3f* pos);
void Audio_StopSfxByPos(Vec3f* pos);
void Audio_StopSfxByPosAndId(Vec3f* pos, u16 sfxId);
void Audio_StopSfxByTokenAndId(u8 token, u16 sfxId);
void Audio_StopSfxById(u32 sfxId);
void Audio_ProcessSfxRequests(void);
void func_800F8F88(void);
u8 Audio_IsSfxPlaying(u32 sfxId);
void Audio_ResetSfx(void);
extern Vec3f gSfxDefaultPos;
extern f32 gSfxDefaultFreqAndVolScale;
extern s8 gSfxDefaultReverb;
#endif

14
include/sys_math.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef SYS_MATH_H
#define SYS_MATH_H
#include "ultra64.h"
f32 Math_FactorialF(f32 n);
f32 Math_Factorial(s32 n);
f32 Math_PowF(f32 base, s32 exp);
f32 Math_SinF(f32 angle);
f32 Math_CosF(f32 angle);
s16 Math_Atan2S(f32 x, f32 y);
f32 Math_Atan2F(f32 x, f32 y);
#endif

73
include/sys_math3d.h Normal file
View File

@ -0,0 +1,73 @@
#ifndef SYS_MATH3D_H
#define SYS_MATH3D_H
#include "ultra64.h"
#include "z64math.h"
s32 Math3D_PlaneVsLineSegClosestPoint(f32 planeAA, f32 planeAB, f32 planeAC, f32 planeADist, f32 planeBA, f32 planeBB,
f32 planeBC, f32 planeBDist, Vec3f* linePointA, Vec3f* linePointB,
Vec3f* closestPoint);
void Math3D_LineClosestToPoint(InfiniteLine* line, Vec3f* pos, Vec3f* closestPoint);
s32 Math3D_PlaneVsPlaneVsLineClosestPoint(f32 planeAA, f32 planeAB, f32 planeAC, f32 planeADist, f32 planeBA,
f32 planeBB, f32 planeBC, f32 planeBDist, Vec3f* point, Vec3f* closestPoint);
void Math3D_LineSplitRatio(Vec3f* v0, Vec3f* v1, f32 ratio, Vec3f* ret);
f32 Math3D_Cos(Vec3f* a, Vec3f* b);
s32 Math3D_CosOut(Vec3f* a, Vec3f* b, f32* dst);
void Math3D_Vec3fReflect(Vec3f* vec, Vec3f* normal, Vec3f* reflVec);
s32 Math3D_PointInSquare2D(f32 upperLeftX, f32 lowerRightX, f32 upperLeftY, f32 lowerRightY, f32 x, f32 y);
f32 Math3D_Dist1DSq(f32 a, f32 b);
f32 Math3D_Dist2DSq(f32 x0, f32 y0, f32 x1, f32 y1);
f32 Math3D_Vec3fMagnitudeSq(Vec3f* vec);
f32 Math3D_Vec3fMagnitude(Vec3f* vec);
f32 Math3D_Vec3fDistSq(Vec3f* a, Vec3f* b);
void Math3D_Vec3f_Cross(Vec3f* a, Vec3f* b, Vec3f* ret);
void Math3D_SurfaceNorm(Vec3f* va, Vec3f* vb, Vec3f* vc, Vec3f* normal);
f32 Math3D_Vec3f_DistXYZ(Vec3f* a, Vec3f* b);
s32 Math3D_PointRelativeToCubeFaces(Vec3f* point, Vec3f* min, Vec3f* max);
s32 Math3D_PointRelativeToCubeEdges(Vec3f* point, Vec3f* min, Vec3f* max);
s32 Math3D_PointRelativeToCubeVertices(Vec3f* point, Vec3f* min, Vec3f* max);
s32 Math3D_LineVsCube(Vec3f* min, Vec3f* max, Vec3f* a, Vec3f* b);
void Math3D_RotateXZPlane(Vec3f* pointOnPlane, s16 angle, f32* a, f32* c, f32* d);
void Math3D_DefPlane(Vec3f* va, Vec3f* vb, Vec3f* vc, f32* nx, f32* ny, f32* nz, f32* originDist);
f32 Math3D_UDistPlaneToPos(f32 nx, f32 ny, f32 nz, f32 originDist, Vec3f* p);
f32 Math3D_DistPlaneToPos(f32 nx, f32 ny, f32 nz, f32 originDist, Vec3f* p);
s32 Math3D_TriChkPointParaYSlopedY(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 z, f32 x);
s32 Math3D_TriChkPointParaYIntersectDist(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 z,
f32 x, f32* yIntersect, f32 chkDist);
s32 Math3D_TriChkPointParaYIntersectInsideTri(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist,
f32 z, f32 x, f32* yIntersect, f32 chkDist);
s32 Math3D_TriChkLineSegParaYIntersect(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 z,
f32 x, f32* yIntersect, f32 y0, f32 y1);
s32 Math3D_TriChkPointParaYDist(Vec3f* v0, Vec3f* v1, Vec3f* v2, Plane* plane, f32 z, f32 x, f32 chkDist);
s32 Math3D_TriChkPointParaXIntersect(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 y,
f32 z, f32* xIntersect);
s32 Math3D_TriChkLineSegParaXIntersect(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 y,
f32 z, f32* xIntersect, f32 x0, f32 x1);
s32 Math3D_TriChkPointParaXDist(Vec3f* v0, Vec3f* v1, Vec3f* v2, Plane* plane, f32 y, f32 z, f32 chkDist);
s32 Math3D_TriChkPointParaZIntersect(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 x,
f32 y, f32* zIntersect);
s32 Math3D_TriChkLineSegParaZIntersect(Vec3f* v0, Vec3f* v1, Vec3f* v2, f32 nx, f32 ny, f32 nz, f32 originDist, f32 x,
f32 y, f32* zIntersect, f32 z0, f32 z1);
s32 Math3D_TriChkLineSegParaZDist(Vec3f* v0, Vec3f* v1, Vec3f* v2, Plane* plane, f32 x, f32 y, f32 chkDist);
s32 Math3D_LineSegVsPlane(f32 nx, f32 ny, f32 nz, f32 originDist, Vec3f* linePointA, Vec3f* linePointB,
Vec3f* intersect, s32 fromFront);
void Math3D_TriNorm(TriNorm* tri, Vec3f* va, Vec3f* vb, Vec3f* vc);
s32 Math3D_PointDistSqToLine2D(f32 x0, f32 y0, f32 x1, f32 y1, f32 x2, f32 y2, f32* lineLenSq);
s32 Math3D_LineVsSph(Sphere16* sphere, Linef* line);
s32 Math3D_TriVsSphIntersect(Sphere16* sphere, TriNorm* tri, Vec3f* intersectPoint);
s32 Math3D_CylVsLineSeg(Cylinder16* cyl, Vec3f* linePointA, Vec3f* linePointB, Vec3f* intersectA, Vec3f* intersectB);
s32 Math3D_CylVsTri(Cylinder16* cyl, TriNorm* tri);
s32 Math3D_CylTriVsIntersect(Cylinder16* cyl, TriNorm* tri, Vec3f* intersect);
s32 Math3D_SphVsSph(Sphere16* sphereA, Sphere16* sphereB);
s32 Math3D_SphVsSphOverlap(Sphere16* sphereA, Sphere16* sphereB, f32* overlapSize);
s32 Math3D_SphVsSphOverlapCenterDist(Sphere16* sphereA, Sphere16* sphereB, f32* overlapSize, f32* centerDist);
s32 Math3D_SphVsCylOverlap(Sphere16* sph, Cylinder16* cyl, f32* overlapSize);
s32 Math3D_SphVsCylOverlapCenterDist(Sphere16* sph, Cylinder16* cyl, f32* overlapSize, f32* centerDist);
s32 Math3D_CylVsCylOverlap(Cylinder16* ca, Cylinder16* cb, f32* overlapSize);
s32 Math3D_CylVsCylOverlapCenterDist(Cylinder16* ca, Cylinder16* cb, f32* overlapSize, f32* centerDist);
s32 Math3D_TriVsTriIntersect(TriNorm* ta, TriNorm* tb, Vec3f* intersect);
s32 Math3D_XZInSphere(Sphere16* sphere, f32 x, f32 z);
s32 Math3D_XYInSphere(Sphere16* sphere, f32 x, f32 y);
s32 Math3D_YZInSphere(Sphere16* sphere, f32 y, f32 z);
#endif

View File

@ -21,6 +21,12 @@ typedef union {
f32 f;
} fu;
f32 sinf(f32 angle);
s16 sins(u16 angle);
f32 cosf(f32 angle);
s16 coss(u16 angle);
extern f32 __libm_qnan_f;
#endif

View File

@ -172,7 +172,6 @@ extern u8 gSequenceTable[];
extern u8 gSampleBankTable[];
extern SaveContext gSaveContext;
extern RegEditor* gRegEditor;
extern u8 gUseCutsceneCam;
extern u16 D_8015FCCC;

View File

@ -44,6 +44,7 @@
#include "sfx.h"
#include "color.h"
#include "gfxprint.h"
#include "z_lib.h"
#include "ichain.h"
#include "regs.h"
#include "irqmgr.h"
@ -58,6 +59,10 @@
#include "gfx.h"
#include "jpeg.h"
#include "prerender.h"
#include "rand.h"
#include "sys_math.h"
#include "sys_math3d.h"
#include "fp_math.h"
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
@ -99,15 +104,6 @@
// NOTE: Once we start supporting other builds, this can be changed with an ifdef
#define REGION_NATIVE REGION_EU
typedef struct {
/* 0x00 */ s32 regPage; // 0: no page selected (reg editor is not active); 1: first page; `REG_PAGES`: last page
/* 0x04 */ s32 regGroup; // Indexed from 0 to `REG_GROUPS`-1. Each group has its own character to identify it.
/* 0x08 */ s32 regCur; // Selected reg, indexed from 0 as the page start
/* 0x0C */ s32 dPadInputPrev;
/* 0x10 */ s32 inputRepeatTimer;
/* 0x14 */ s16 data[REG_GROUPS * REGS_PER_GROUP]; // Accessed through *REG macros, see regs.h
} RegEditor; // size = 0x15D4
typedef struct {
/* 0x00 */ u8 seqId;
/* 0x01 */ u8 natureAmbienceId;
@ -225,8 +221,8 @@ typedef struct {
} GameOverContext; // size = 0x2
typedef enum {
/* 0 */ LENS_MODE_HIDE_ACTORS, // lens actors are visible by default, and hidden by using lens (for example, fake walls)
/* 1 */ LENS_MODE_SHOW_ACTORS // lens actors are invisible by default, and shown by using lens (for example, invisible enemies)
/* 0 */ LENS_MODE_SHOW_ACTORS, // lens actors are invisible by default, and shown by using lens (for example, invisible enemies)
/* 1 */ LENS_MODE_HIDE_ACTORS // lens actors are visible by default, and hidden by using lens (for example, fake walls)
} LensMode;
typedef enum {
@ -396,7 +392,7 @@ typedef struct PlayState {
/* 0x10760 */ PauseContext pauseCtx;
/* 0x10A20 */ GameOverContext gameOverCtx;
/* 0x10A24 */ EnvironmentContext envCtx;
/* 0x10B20 */ AnimationContext animationCtx;
/* 0x10B20 */ AnimTaskQueue animTaskQueue;
/* 0x117A4 */ ObjectContext objectCtx;
/* 0x11CBC */ RoomContext roomCtx;
/* 0x11D34 */ TransitionActorContext transiActorCtx;

130
include/z64animation.h Executable file → Normal file
View File

@ -91,7 +91,7 @@ typedef enum {
#define ANIM_FLAG_0 (1 << 0) // (no effect outside of player) Related to scaling an animation from/to child/adult
#define ANIM_FLAG_UPDATE_Y (1 << 1)
#define ANIM_FLAG_PLAYER_2 (1 << 2) // (player-only) Related to scaling an animation from/to child/adult
#define ANIM_FLAG_PLAYER_SETMOVE (1 << 3) // (player-only) Call AnimationContext_SetMoveActor
#define ANIM_FLAG_PLAYER_SETMOVE (1 << 3) // (player-only) Call AnimTaskQueue_AddActorMove
#define ANIM_FLAG_NO_MOVE (1 << 4)
#define ANIM_FLAG_PLAYER_7 (1 << 7) // (player-only)
@ -239,95 +239,95 @@ s16 Animation_GetLength(void* animation);
s16 Animation_GetLastFrame(void* animation);
/*
* Animation requests
* Animation Task Queue
*/
typedef enum {
/* 0 */ ANIMENTRY_LOADFRAME,
/* 1 */ ANIMENTRY_COPYALL,
/* 2 */ ANIMENTRY_INTERP,
/* 3 */ ANIMENTRY_COPYTRUE,
/* 4 */ ANIMENTRY_COPYFALSE,
/* 5 */ ANIMENTRY_MOVEACTOR
} AnimationType;
/* 0 */ ANIMTASK_LOAD_PLAYER_FRAME,
/* 1 */ ANIMTASK_COPY,
/* 2 */ ANIMTASK_INTERP,
/* 3 */ ANIMTASK_COPY_USING_MAP,
/* 4 */ ANIMTASK_COPY_USING_MAP_INVERTED,
/* 5 */ ANIMTASK_ACTOR_MOVE
} AnimTaskType;
typedef struct {
/* 0x000 */ DmaRequest req;
/* 0x020 */ OSMesgQueue msgQueue;
/* 0x038 */ OSMesg msg;
} AnimEntryLoadFrame; // size = 0x3C
/* 0x00 */ DmaRequest req;
/* 0x20 */ OSMesgQueue msgQueue;
/* 0x38 */ OSMesg msg;
} AnimTaskLoadPlayerFrame; // size = 0x3C
typedef struct {
/* 0x000 */ u8 queueFlag;
/* 0x001 */ u8 vecCount;
/* 0x004 */ Vec3s* dst;
/* 0x008 */ Vec3s* src;
} AnimEntryCopyAll; // size = 0xC
/* 0x00 */ u8 group;
/* 0x01 */ u8 vecCount;
/* 0x04 */ Vec3s* dest;
/* 0x08 */ Vec3s* src;
} AnimTaskCopy; // size = 0xC
typedef struct {
/* 0x000 */ u8 queueFlag;
/* 0x001 */ u8 vecCount;
/* 0x004 */ Vec3s* base;
/* 0x008 */ Vec3s* mod;
/* 0x00C */ f32 weight;
} AnimEntryInterp; // size = 0x10
/* 0x00 */ u8 group;
/* 0x01 */ u8 vecCount;
/* 0x04 */ Vec3s* base;
/* 0x08 */ Vec3s* mod;
/* 0x0C */ f32 weight;
} AnimTaskInterp; // size = 0x10
typedef struct {
/* 0x000 */ u8 queueFlag;
/* 0x001 */ u8 vecCount;
/* 0x004 */ Vec3s* dst;
/* 0x008 */ Vec3s* src;
/* 0x00C */ u8* copyFlag;
} AnimEntryCopyTrue; // size = 0x10
/* 0x00 */ u8 group;
/* 0x01 */ u8 vecCount;
/* 0x04 */ Vec3s* dest;
/* 0x08 */ Vec3s* src;
/* 0x0C */ u8* limbCopyMap;
} AnimTaskCopyUsingMap; // size = 0x10
typedef struct {
/* 0x000 */ u8 queueFlag;
/* 0x001 */ u8 vecCount;
/* 0x004 */ Vec3s* dst;
/* 0x008 */ Vec3s* src;
/* 0x00C */ u8* copyFlag;
} AnimEntryCopyFalse; // size = 0x10
/* 0x00 */ u8 group;
/* 0x01 */ u8 vecCount;
/* 0x04 */ Vec3s* dest;
/* 0x08 */ Vec3s* src;
/* 0x0C */ u8* limbCopyMap;
} AnimTaskCopyUsingMapInverted; // size = 0x10
typedef struct {
/* 0x000 */ struct Actor* actor;
/* 0x004 */ struct SkelAnime* skelAnime;
/* 0x008 */ f32 diffScaleY;
} AnimEntryMoveActor; // size = 0xC
/* 0x00 */ struct Actor* actor;
/* 0x04 */ struct SkelAnime* skelAnime;
/* 0x08 */ f32 diffScaleY;
} AnimTaskActorMove; // size = 0xC
typedef union {
AnimEntryLoadFrame load;
AnimEntryCopyAll copy;
AnimEntryInterp interp;
AnimEntryCopyTrue copy1;
AnimEntryCopyFalse copy0;
AnimEntryMoveActor move;
} AnimationEntryData; // size = 0x3C
AnimTaskLoadPlayerFrame loadPlayerFrame;
AnimTaskCopy copy;
AnimTaskInterp interp;
AnimTaskCopyUsingMap copyUsingMap;
AnimTaskCopyUsingMapInverted copyUsingMapInverted;
AnimTaskActorMove actorMove;
} AnimTaskData; // size = 0x3C
typedef struct {
/* 0x00 */ u8 type;
/* 0x04 */ AnimationEntryData data;
} AnimationEntry; // size = 0x40
/* 0x04 */ AnimTaskData data;
} AnimTask; // size = 0x40
#define ANIMATION_ENTRY_MAX 50
#define ANIM_TASK_QUEUE_MAX 50
typedef struct AnimationContext {
s16 animationCount;
AnimationEntry entries[ANIMATION_ENTRY_MAX];
} AnimationContext; // size = 0xC84
typedef struct AnimTaskQueue {
s16 count;
AnimTask tasks[ANIM_TASK_QUEUE_MAX];
} AnimTaskQueue; // size = 0xC84
void AnimationContext_SetLoadFrame(struct PlayState* play, LinkAnimationHeader* animation, s32 frame, s32 limbCount,
Vec3s* frameTable);
void AnimationContext_SetCopyAll(struct PlayState* play, s32 vecCount, Vec3s* dst, Vec3s* src);
void AnimationContext_SetCopyTrue(struct PlayState* play, s32 vecCount, Vec3s* dst, Vec3s* src, u8* copyFlag);
void AnimationContext_SetCopyFalse(struct PlayState* play, s32 vecCount, Vec3s* dst, Vec3s* src, u8* copyFlag);
void AnimationContext_SetInterp(struct PlayState* play, s32 vecCount, Vec3s* base, Vec3s* mod, f32 weight);
void AnimationContext_SetMoveActor(struct PlayState* play, struct Actor* actor, SkelAnime* skelAnime, f32 moveDiffScaleY);
void AnimTaskQueue_AddLoadPlayerFrame(struct PlayState* play, LinkAnimationHeader* animation, s32 frame, s32 limbCount,
Vec3s* frameTable);
void AnimTaskQueue_AddCopy(struct PlayState* play, s32 vecCount, Vec3s* dest, Vec3s* src);
void AnimTaskQueue_AddInterp(struct PlayState* play, s32 vecCount, Vec3s* base, Vec3s* mod, f32 weight);
void AnimTaskQueue_AddCopyUsingMap(struct PlayState* play, s32 vecCount, Vec3s* dest, Vec3s* src, u8* limbCopyMap);
void AnimTaskQueue_AddCopyUsingMapInverted(struct PlayState* play, s32 vecCount, Vec3s* dest, Vec3s* src, u8* limbCopyMap);
void AnimTaskQueue_AddActorMove(struct PlayState* play, struct Actor* actor, SkelAnime* skelAnime, f32 moveDiffScaleY);
void AnimationContext_SetNextQueue(struct PlayState* play);
void AnimationContext_DisableQueue(struct PlayState* play);
void AnimTaskQueue_SetNextGroup(struct PlayState* play);
void AnimTaskQueue_DisableTransformTasksForGroup(struct PlayState* play);
void AnimationContext_Reset(AnimationContext* animationCtx);
void AnimationContext_Update(struct PlayState* play, AnimationContext* animationCtx);
void AnimTaskQueue_Reset(AnimTaskQueue* animTaskQueue);
void AnimTaskQueue_Update(struct PlayState* play, AnimTaskQueue* animTaskQueue);
/*
* Link animations

View File

@ -6,10 +6,6 @@
#include "z64math.h"
#include "z64save.h"
// these two angle conversion macros are slightly inaccurate
#define CAM_DEG_TO_BINANG(degrees) (s16)TRUNCF_BINANG((degrees) * 182.04167f + .5f)
#define CAM_BINANG_TO_DEG(binang) ((f32)(binang) * (360.0001525f / 65535.0f))
#define CAM_STAT_CUT 0
#define CAM_STAT_WAIT 1
#define CAM_STAT_UNK3 3

View File

@ -2,7 +2,9 @@
#define Z64MATH_H
#include "ultra64.h"
#include "math.h"
#define SQ(x) ((x)*(x))
#define VEC_SET(V,X,Y,Z) (V).x=(X);(V).y=(Y);(V).z=(Z)
typedef struct {
@ -116,6 +118,11 @@ typedef VecSphGeo VecGeo;
#define BINANG_TO_RAD_ALT(binang) (((f32)(binang) / (f32)0x8000) * M_PI)
#define BINANG_TO_RAD_ALT2(binang) (((f32)(binang) * M_PI) / 0x8000)
// Angle conversion macros (Camera)
// these two angle conversion macros are slightly inaccurate
#define CAM_DEG_TO_BINANG(degrees) (s16)TRUNCF_BINANG((degrees) * 182.04167f + .5f)
#define CAM_BINANG_TO_DEG(binang) ((f32)(binang) * (360.0001525f / 65535.0f))
// Vector macros
#define SQXZ(vec) ((vec).x * (vec).x + (vec).z * (vec).z)
#define DOTXZ(vec1, vec2) ((vec1).x * (vec2).x + (vec1).z * (vec2).z)

View File

@ -20,6 +20,33 @@ typedef enum {
/* 0x04 */ PAUSE_WORLD_MAP
} PauseMenuPage;
// The XZ coordinates in which direction each pause page is at
// e.g. the item page is in the -z direction
/*
* < item >
*
* ^ ^
* x
* equip o--> map
* |
* v z v v
*
* < quest >
*/
#define PAUSE_ITEM_X (0)
#define PAUSE_ITEM_Z (-1)
#define PAUSE_MAP_X (1)
#define PAUSE_MAP_Z (0)
#define PAUSE_QUEST_X (0)
#define PAUSE_QUEST_Z (1)
#define PAUSE_EQUIP_X (-1)
#define PAUSE_EQUIP_Z (0)
// The pause camera looks at x=0,z=0,
// with the eye being PAUSE_EYE_DIST away in the direction opposite to the active page,
// which results in the camera being pointed (through x=0,z=0) towards the active page.
#define PAUSE_EYE_DIST (64.0f)
#define PAUSE_EQUIP_PLAYER_WIDTH 64
#define PAUSE_EQUIP_PLAYER_HEIGHT 112
@ -58,7 +85,7 @@ typedef enum {
// Sub-states of PAUSE_STATE_MAIN
typedef enum {
/* 0 */ PAUSE_MAIN_STATE_IDLE,
/* 1 */ PAUSE_MAIN_STATE_1,
/* 1 */ PAUSE_MAIN_STATE_SWITCHING_PAGE,
/* 2 */ PAUSE_MAIN_STATE_2,
/* 3 */ PAUSE_MAIN_STATE_3,
/* 4 */ PAUSE_MAIN_STATE_4,
@ -98,9 +125,9 @@ typedef struct {
/* 0x01D6 */ u16 debugState;
/* 0x01D8 */ Vec3f eye;
/* 0x01E4 */ u16 mainState;
/* 0x01E6 */ u16 mode;
/* 0x01E6 */ u16 nextPageMode; // During a page switch, indicates the page before switching and the direction to scroll in. Value is `(2 * prev pageIndex) + (scroll left ? 1 : 0)`
/* 0x01E8 */ u16 pageIndex; // "kscp_pos"
/* 0x01EA */ u16 unk_1EA;
/* 0x01EA */ u16 pageSwitchTimer;
/* 0x01EC */ u16 unk_1EC;
/* 0x01F0 */ f32 unk_1F0;
/* 0x01F4 */ f32 unk_1F4;

44
include/z_lib.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef Z_LIB_H
#define Z_LIB_H
#include "libc/stddef.h"
#include "padmgr.h"
#include "z64math.h"
#include "color.h"
void Lib_MemSet(u8* dest, size_t len, u8 val);
f32 Math_CosS(s16 angle);
f32 Math_SinS(s16 angle);
s32 Math_ScaledStepToS(s16* pValue, s16 target, s16 step);
s32 Math_StepToS(s16* pValue, s16 target, s16 step);
s32 Math_StepToF(f32* pValue, f32 target, f32 step);
s32 Math_StepUntilAngleS(s16* pValue, s16 limit, s16 step);
s32 Math_StepUntilS(s16* pValue, s16 limit, s16 step);
s32 Math_StepToAngleS(s16* pValue, s16 target, s16 step);
s32 Math_StepUntilF(f32* pValue, f32 limit, f32 step);
s32 Math_AsymStepToF(f32* pValue, f32 target, f32 incrStep, f32 decrStep);
void Lib_GetControlStickData(f32* outMagnitude, s16* outAngle, Input* input);
s16 Rand_S16Offset(s16 base, s16 range);
void Math_Vec3f_Copy(Vec3f* dest, Vec3f* src);
void Math_Vec3s_ToVec3f(Vec3f* dest, Vec3s* src);
void Math_Vec3f_Sum(Vec3f* a, Vec3f* b, Vec3f* dest);
void Math_Vec3f_Diff(Vec3f* a, Vec3f* b, Vec3f* dest);
void Math_Vec3s_DiffToVec3f(Vec3f* dest, Vec3s* a, Vec3s* b);
void Math_Vec3f_Scale(Vec3f* vec, f32 scaleF);
f32 Math_Vec3f_DistXYZ(Vec3f* a, Vec3f* b);
f32 Math_Vec3f_DistXYZAndStoreDiff(Vec3f* a, Vec3f* b, Vec3f* dest);
f32 Math_Vec3f_DistXZ(Vec3f* a, Vec3f* b);
s16 Math_Vec3f_Yaw(Vec3f* origin, Vec3f* point);
s16 Math_Vec3f_Pitch(Vec3f* a, Vec3f* b);
f32 Math_SmoothStepToF(f32* pValue, f32 target, f32 fraction, f32 step, f32 minStep);
void Math_ApproachF(f32* pValue, f32 target, f32 fraction, f32 step);
void Math_ApproachZeroF(f32* pValue, f32 fraction, f32 step);
f32 Math_SmoothStepToDegF(f32* pValue, f32 target, f32 fraction, f32 step, f32 minStep);
s16 Math_SmoothStepToS(s16* pValue, s16 target, s16 scale, s16 step, s16 minStep);
void Math_ApproachS(s16* pValue, s16 target, s16 scale, s16 step);
void Color_RGBA8_Copy(Color_RGBA8* dst, Color_RGBA8* src);
void Sfx_PlaySfxCentered(u16 sfxId);
void Sfx_PlaySfxCentered2(u16 sfxId);
void Sfx_PlaySfxAtPos(Vec3f* projectedPos, u16 sfxId);
#endif

13
spec
View File

@ -437,6 +437,9 @@ beginseg
include "$(BUILD_DIR)/src/code/sys_cfb.o"
include "$(BUILD_DIR)/src/code/sys_math.o"
include "$(BUILD_DIR)/src/code/sys_math3d.o"
#if OOT_DEBUG
include "$(BUILD_DIR)/src/code/sys_math3d_draw.o"
#endif
include "$(BUILD_DIR)/src/code/sys_math_atan.o"
include "$(BUILD_DIR)/src/code/sys_matrix.o"
include "$(BUILD_DIR)/src/code/sys_ucode.o"
@ -484,7 +487,7 @@ beginseg
include "$(BUILD_DIR)/src/code/code_800FC620.o"
include "$(BUILD_DIR)/src/code/padutils.o"
include "$(BUILD_DIR)/src/code/padsetup.o"
include "$(BUILD_DIR)/src/code/code_800FCE80.o"
include "$(BUILD_DIR)/src/code/fp_math.o"
include "$(BUILD_DIR)/src/code/fp.o"
include "$(BUILD_DIR)/src/code/system_malloc.o"
include "$(BUILD_DIR)/src/code/rand.o"
@ -597,8 +600,12 @@ beginseg
include "$(BUILD_DIR)/src/code/fmodf.o"
include "$(BUILD_DIR)/src/code/__osMemset.o"
include "$(BUILD_DIR)/src/code/__osMemmove.o"
include_data_with_rodata "$(BUILD_DIR)/src/code/z_message_PAL.o"
include "$(BUILD_DIR)/src/code/z_game_over.o"
// For some reason, the data sections of these files are placed here near the
// rodata sections of the other files
include_data_only_within_rodata "$(BUILD_DIR)/src/code/z_message_PAL.o"
include_data_only_within_rodata "$(BUILD_DIR)/src/code/z_game_over.o"
include_no_data "$(BUILD_DIR)/src/code/z_message_PAL.o"
include_no_data "$(BUILD_DIR)/src/code/z_game_over.o"
include "$(BUILD_DIR)/src/code/z_construct.o"
include "$(BUILD_DIR)/data/audio_tables.rodata.o"
include "$(BUILD_DIR)/data/rsp.text.o"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,12 +1,58 @@
#include "global.h"
s16 sKaleidoSetupKscpPos0[] = { PAUSE_QUEST, PAUSE_EQUIP, PAUSE_ITEM, PAUSE_MAP };
f32 sKaleidoSetupEyeX0[] = { 0.0f, 64.0f, 0.0f, -64.0f };
f32 sKaleidoSetupEyeZ0[] = { -64.0f, 0.0f, 64.0f, 0.0f };
/*
* The following three arrays are effectively unused.
* They are partly equivalent to the `sKaleidoSetupRightPage*` arrays below,
* but make each page correspond to the opposite page instead of the page to the right.
*/
s16 sKaleidoSetupKscpPos1[] = { PAUSE_MAP, PAUSE_QUEST, PAUSE_EQUIP, PAUSE_ITEM };
f32 sKaleidoSetupEyeX1[] = { -64.0f, 0.0f, 64.0f, 0.0f };
f32 sKaleidoSetupEyeZ1[] = { 0.0f, -64.0f, 0.0f, 64.0f };
s16 sKaleidoSetupUnusedPageIndex[] = {
PAUSE_QUEST, // PAUSE_ITEM
PAUSE_EQUIP, // PAUSE_MAP
PAUSE_ITEM, // PAUSE_QUEST
PAUSE_MAP, // PAUSE_EQUIP
};
f32 sKaleidoSetupUnusedEyeX[] = {
PAUSE_EYE_DIST * -PAUSE_QUEST_X, // PAUSE_ITEM
PAUSE_EYE_DIST * -PAUSE_EQUIP_X, // PAUSE_MAP
PAUSE_EYE_DIST * -PAUSE_ITEM_X, // PAUSE_QUEST
PAUSE_EYE_DIST * -PAUSE_MAP_X, // PAUSE_EQUIP
};
f32 sKaleidoSetupUnusedEyeZ[] = {
PAUSE_EYE_DIST * -PAUSE_QUEST_Z, // PAUSE_ITEM
PAUSE_EYE_DIST * -PAUSE_EQUIP_Z, // PAUSE_MAP
PAUSE_EYE_DIST * -PAUSE_ITEM_Z, // PAUSE_QUEST
PAUSE_EYE_DIST * -PAUSE_MAP_Z, // PAUSE_EQUIP
};
/*
* The following three arrays are used when opening the pause menu to set up a page switch such that scrolling left
* brings to the initial page.
* For example to open the menu on page PAUSE_ITEM, the menu would open on PAUSE_MAP and scroll left to PAUSE_ITEM.
*/
s16 sKaleidoSetupRightPageIndex[] = {
PAUSE_MAP, // PAUSE_ITEM
PAUSE_QUEST, // PAUSE_MAP
PAUSE_EQUIP, // PAUSE_QUEST
PAUSE_ITEM, // PAUSE_EQUIP
};
f32 sKaleidoSetupRightPageEyeX[] = {
PAUSE_EYE_DIST * -PAUSE_MAP_X, // PAUSE_ITEM
PAUSE_EYE_DIST * -PAUSE_QUEST_X, // PAUSE_MAP
PAUSE_EYE_DIST * -PAUSE_EQUIP_X, // PAUSE_QUEST
PAUSE_EYE_DIST * -PAUSE_ITEM_X, // PAUSE_EQUIP
};
f32 sKaleidoSetupRightPageEyeZ[] = {
PAUSE_EYE_DIST * -PAUSE_MAP_Z, // PAUSE_ITEM
PAUSE_EYE_DIST * -PAUSE_QUEST_Z, // PAUSE_MAP
PAUSE_EYE_DIST * -PAUSE_EQUIP_Z, // PAUSE_QUEST
PAUSE_EYE_DIST * -PAUSE_ITEM_Z, // PAUSE_EQUIP
};
void KaleidoSetup_Update(PlayState* play) {
PauseContext* pauseCtx = &play->pauseCtx;
@ -30,24 +76,33 @@ void KaleidoSetup_Update(PlayState* play) {
WREG(16) = -175;
WREG(17) = 155;
pauseCtx->unk_1EA = 0;
pauseCtx->mainState = PAUSE_MAIN_STATE_1;
pauseCtx->pageSwitchTimer = 0;
if (ZREG(48) == 0) {
pauseCtx->eye.x = sKaleidoSetupEyeX0[pauseCtx->pageIndex];
pauseCtx->eye.z = sKaleidoSetupEyeZ0[pauseCtx->pageIndex];
pauseCtx->pageIndex = sKaleidoSetupKscpPos0[pauseCtx->pageIndex];
// Setting mainState here is irrelevant, mainState is only used under PAUSE_STATE_MAIN,
// which isn't involved in the initial pause menu opening page scrolling animation.
// mainState is also overwritten later before being used.
pauseCtx->mainState = PAUSE_MAIN_STATE_SWITCHING_PAGE;
//! @bug REG collision
if (R_START_LABEL_DD(0) == 0) {
// Never reached, unused, and the data would be wrong anyway
// (scrolling left from this would not bring to the initial page)
pauseCtx->eye.x = sKaleidoSetupUnusedEyeX[pauseCtx->pageIndex];
pauseCtx->eye.z = sKaleidoSetupUnusedEyeZ[pauseCtx->pageIndex];
pauseCtx->pageIndex = sKaleidoSetupUnusedPageIndex[pauseCtx->pageIndex];
} else {
pauseCtx->eye.x = sKaleidoSetupEyeX1[pauseCtx->pageIndex];
pauseCtx->eye.z = sKaleidoSetupEyeZ1[pauseCtx->pageIndex];
pauseCtx->pageIndex = sKaleidoSetupKscpPos1[pauseCtx->pageIndex];
// Set eye position and pageIndex such that scrolling left brings to the desired page
pauseCtx->eye.x = sKaleidoSetupRightPageEyeX[pauseCtx->pageIndex];
pauseCtx->eye.z = sKaleidoSetupRightPageEyeZ[pauseCtx->pageIndex];
pauseCtx->pageIndex = sKaleidoSetupRightPageIndex[pauseCtx->pageIndex];
}
pauseCtx->mode = (u16)(pauseCtx->pageIndex * 2) + 1;
// Set next page mode to scroll left
pauseCtx->nextPageMode = (u16)(pauseCtx->pageIndex * 2) + 1;
pauseCtx->state = PAUSE_STATE_WAIT_LETTERBOX;
PRINTF("=%d eye.x=%f, eye.z=%f kscp_pos=%d\n", pauseCtx->mode, pauseCtx->eye.x, pauseCtx->eye.z,
pauseCtx->pageIndex);
PRINTF("=%d eye.x=%f, eye.z=%f kscp_pos=%d\n", pauseCtx->nextPageMode, pauseCtx->eye.x,
pauseCtx->eye.z, pauseCtx->pageIndex);
}
if (pauseCtx->state == PAUSE_STATE_WAIT_LETTERBOX) {
@ -77,7 +132,7 @@ void KaleidoSetup_Init(PlayState* play) {
pauseCtx->alpha = 0;
// mainState = PAUSE_MAIN_STATE_IDLE , pageIndex = PAUSE_ITEM
pauseCtx->unk_1EA = pauseCtx->mainState = pauseCtx->mode = pauseCtx->pageIndex = 0;
pauseCtx->pageSwitchTimer = pauseCtx->mainState = pauseCtx->nextPageMode = pauseCtx->pageIndex = 0;
pauseCtx->unk_204 = -314.0f;

View File

@ -215,7 +215,7 @@ s16 sSunDepthTestY;
// These variables could be moved farther down in the file to reduce the amount
// of block number padding here, but currently this causes BSS ordering issues
// for debug.
#pragma increment_block_number 230
#pragma increment_block_number 227
LightNode* sNGameOverLightNode;
LightInfo sNGameOverLightInfo;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,4 @@
#include "global.h"
#include "ultra64.h"
/**
* @param angle binang

View File

@ -89,7 +89,7 @@ void func_8087DB24(BgHakaMegane* this, PlayState* play) {
this->dyna.actor.objectSlot = this->requiredObjectSlot;
this->dyna.actor.draw = BgHakaMegane_Draw;
Actor_SetObjectDependency(play, &this->dyna.actor);
if (play->roomCtx.curRoom.lensMode != LENS_MODE_HIDE_ACTORS) {
if (play->roomCtx.curRoom.lensMode != LENS_MODE_SHOW_ACTORS) {
CollisionHeader* colHeader;
CollisionHeader* collision;

View File

@ -177,19 +177,19 @@ void DemoEc_UpdateBgFlags(DemoEc* this, PlayState* play) {
void func_8096D594(DemoEc* this, PlayState* play) {
this->skelAnime.moveFlags |= ANIM_FLAG_0 | ANIM_FLAG_UPDATE_Y;
AnimationContext_SetMoveActor(play, &this->actor, &this->skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, 1.0f);
}
void func_8096D5D4(DemoEc* this, PlayState* play) {
this->skelAnime.baseTransl = this->skelAnime.jointTable[0];
this->skelAnime.prevTransl = this->skelAnime.jointTable[0];
this->skelAnime.moveFlags |= ANIM_FLAG_0 | ANIM_FLAG_UPDATE_Y;
AnimationContext_SetMoveActor(play, &this->actor, &this->skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, 1.0f);
}
void func_8096D64C(DemoEc* this, PlayState* play) {
this->skelAnime.moveFlags |= ANIM_FLAG_0 | ANIM_FLAG_UPDATE_Y;
AnimationContext_SetMoveActor(play, &this->actor, &this->skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, 1.0f);
}
void DemoEc_UpdateEyes(DemoEc* this) {

View File

@ -55,7 +55,7 @@ s32 DemoIk_CheckForCue(PlayState* play, u16 cueId, s32 cueChannel) {
void DemoIk_SetMove(DemoIk* this, PlayState* play) {
this->skelAnime.moveFlags |= ANIM_FLAG_0;
AnimationContext_SetMoveActor(play, &this->actor, &this->skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, 1.0f);
}
void DemoIk_EndMove(DemoIk* this) {

View File

@ -338,7 +338,7 @@ void func_80A795C8(EnIn* this, PlayState* play) {
void func_80A79690(SkelAnime* skelAnime, EnIn* this, PlayState* play) {
if (skelAnime->baseTransl.y < skelAnime->jointTable[0].y) {
skelAnime->moveFlags |= ANIM_FLAG_0 | ANIM_FLAG_UPDATE_Y;
AnimationContext_SetMoveActor(play, &this->actor, skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, skelAnime, 1.0f);
}
}

View File

@ -757,7 +757,7 @@ void EnNb_InitDemo6KInConfrontation(EnNb* this, PlayState* play) {
void func_80AB2688(EnNb* this, PlayState* play) {
this->skelAnime.moveFlags |= ANIM_FLAG_0;
AnimationContext_SetMoveActor(play, &this->actor, &this->skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, 1.0f);
}
void func_80AB26C8(EnNb* this) {

View File

@ -392,7 +392,7 @@ s32 EnRu1_UpdateSkelAnime(EnRu1* this) {
void func_80AEB364(EnRu1* this, PlayState* play) {
this->skelAnime.moveFlags |= ANIM_FLAG_0;
AnimationContext_SetMoveActor(play, &this->actor, &this->skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, 1.0f);
}
void func_80AEB3A4(EnRu1* this, PlayState* play) {
@ -463,7 +463,7 @@ void func_80AEB6E0(EnRu1* this, PlayState* play) {
if (skelAnime->baseTransl.y < skelAnime->jointTable[0].y) {
skelAnime->moveFlags |= ANIM_FLAG_0 | ANIM_FLAG_UPDATE_Y;
AnimationContext_SetMoveActor(play, &this->actor, skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, skelAnime, 1.0f);
}
}
@ -474,7 +474,7 @@ void func_80AEB738(EnRu1* this, PlayState* play) {
skelAnime->prevTransl = skelAnime->jointTable[0];
if (skelAnime->baseTransl.y < skelAnime->jointTable[0].y) {
skelAnime->moveFlags |= ANIM_FLAG_0 | ANIM_FLAG_UPDATE_Y;
AnimationContext_SetMoveActor(play, &this->actor, skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, skelAnime, 1.0f);
}
}

View File

@ -61,7 +61,7 @@ void func_80862FA8(EnTest* this, PlayState* play);
s32 EnTest_ReactToProjectile(PlayState* play, EnTest* this);
static u8 sJointCopyFlags[] = {
static u8 sUpperBodyLimbCopyMap[] = {
false, // STALFOS_LIMB_NONE
false, // STALFOS_LIMB_ROOT
false, // STALFOS_LIMB_UPPERBODY_ROOT
@ -1742,15 +1742,15 @@ void EnTest_Update(Actor* thisx, PlayState* play) {
case 1:
Animation_Change(&this->upperSkelanime, &gStalfosBlockWithShieldAnim, 2.0f, 0.0f,
Animation_GetLastFrame(&gStalfosBlockWithShieldAnim), 2, 2.0f);
AnimationContext_SetCopyTrue(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelanime.jointTable, sJointCopyFlags);
AnimTaskQueue_AddCopyUsingMap(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelanime.jointTable, sUpperBodyLimbCopyMap);
this->unk_7DE++;
break;
case 2:
SkelAnime_Update(&this->upperSkelanime);
SkelAnime_CopyFrameTableTrue(&this->skelAnime, this->skelAnime.jointTable,
this->upperSkelanime.jointTable, sJointCopyFlags);
this->upperSkelanime.jointTable, sUpperBodyLimbCopyMap);
break;
case 3:
@ -1769,7 +1769,7 @@ void EnTest_Update(Actor* thisx, PlayState* play) {
this->upperSkelanime.jointTable, this->skelAnime.jointTable,
1.0f - (this->upperSkelanime.morphWeight / oldWeight));
SkelAnime_CopyFrameTableTrue(&this->skelAnime, this->skelAnime.jointTable,
this->upperSkelanime.jointTable, sJointCopyFlags);
this->upperSkelanime.jointTable, sUpperBodyLimbCopyMap);
break;
}

View File

@ -255,20 +255,20 @@ void func_80B3C8CC(EnXc* this, PlayState* play) {
if (skelAnime->jointTable[0].y >= skelAnime->baseTransl.y) {
skelAnime->moveFlags |= ANIM_FLAG_0 | ANIM_FLAG_UPDATE_Y;
AnimationContext_SetMoveActor(play, &this->actor, skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, skelAnime, 1.0f);
}
}
void func_80B3C924(EnXc* this, PlayState* play) {
this->skelAnime.moveFlags |= ANIM_FLAG_0 | ANIM_FLAG_UPDATE_Y;
AnimationContext_SetMoveActor(play, &this->actor, &this->skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, 1.0f);
}
void func_80B3C964(EnXc* this, PlayState* play) {
this->skelAnime.baseTransl = this->skelAnime.jointTable[0];
this->skelAnime.prevTransl = this->skelAnime.jointTable[0];
this->skelAnime.moveFlags |= ANIM_FLAG_0 | ANIM_FLAG_UPDATE_Y;
AnimationContext_SetMoveActor(play, &this->actor, &this->skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, 1.0f);
}
void func_80B3C9DC(EnXc* this) {

View File

@ -346,7 +346,7 @@ void func_80B4B834(CsCmdActorCue* cue, Vec3f* dest) {
void func_80B4B874(EnZl1* this, PlayState* play) {
this->skelAnime.moveFlags |= ANIM_FLAG_0;
AnimationContext_SetMoveActor(play, &this->actor, &this->skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, 1.0f);
}
void func_80B4B8B4(EnZl1* this, PlayState* play) {

View File

@ -299,7 +299,7 @@ void EnZl4_UpdateFace(EnZl4* this) {
void EnZl4_SetMove(EnZl4* this, PlayState* play) {
this->skelAnime.moveFlags |= ANIM_FLAG_0;
AnimationContext_SetMoveActor(play, &this->actor, &this->skelAnime, 1.0f);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime, 1.0f);
}
void func_80B5BB78(EnZl4* this, PlayState* play) {

View File

@ -11,7 +11,7 @@
#include "terminal.h"
// For retail BSS ordering, the block number of sStreamSfxProjectedPos must be 0.
#pragma increment_block_number 198
#pragma increment_block_number 193
#define FLAGS ACTOR_FLAG_4

View File

@ -1989,7 +1989,7 @@ void Player_AnimReplaceApplyFlags(PlayState* play, Player* this, s32 flags) {
this->skelAnime.moveFlags = flags & 0xFF;
Player_ZeroSpeedXZ(this);
AnimationContext_DisableQueue(play);
AnimTaskQueue_DisableTransformTasksForGroup(play);
}
void Player_AnimReplacePlayOnceSetSpeed(PlayState* play, Player* this, LinkAnimationHeader* anim, s32 flags,
@ -3071,8 +3071,8 @@ s32 func_808358F0(Player* this, PlayState* play) {
if ((func_808334E4(this) == animSeg) || (func_80833528(this) == animSeg) || (func_808335B0(this) == animSeg) ||
(func_808335F4(this) == animSeg)) {
AnimationContext_SetCopyAll(play, this->skelAnime.limbCount, this->upperSkelAnime.jointTable,
this->skelAnime.jointTable);
AnimTaskQueue_AddCopy(play, this->skelAnime.limbCount, this->upperSkelAnime.jointTable,
this->skelAnime.jointTable);
} else {
LinkAnimation_Update(play, &this->upperSkelAnime);
}
@ -3425,22 +3425,22 @@ s32 Player_UpdateUpperBody(Player* this, PlayState* play) {
// The functionality contained within this block of code is never used in practice
// because `upperAnimInterpWeight` is always 0.
if ((func_80833350(this) == 0) || (this->speedXZ != 0.0f)) {
AnimationContext_SetCopyFalse(play, this->skelAnime.limbCount, this->upperSkelAnime.jointTable,
this->skelAnime.jointTable, sUpperBodyLimbCopyMap);
AnimTaskQueue_AddCopyUsingMapInverted(play, this->skelAnime.limbCount, this->upperSkelAnime.jointTable,
this->skelAnime.jointTable, sUpperBodyLimbCopyMap);
}
Math_StepToF(&this->upperAnimInterpWeight, 0.0f, 0.25f);
AnimationContext_SetInterp(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelAnime.jointTable, 1.0f - this->upperAnimInterpWeight);
AnimTaskQueue_AddInterp(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelAnime.jointTable, 1.0f - this->upperAnimInterpWeight);
} else if ((func_80833350(this) == 0) || (this->speedXZ != 0.0f)) {
// Only copy the upper body animation to the upper body limbs in the main skeleton.
// Doing so allows the main skeleton to play its own animation for the lower body limbs.
AnimationContext_SetCopyTrue(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelAnime.jointTable, sUpperBodyLimbCopyMap);
AnimTaskQueue_AddCopyUsingMap(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelAnime.jointTable, sUpperBodyLimbCopyMap);
} else {
// Copy all of the upper body animation into the whole main skeleton.
// The upper body has full control of all limbs.
AnimationContext_SetCopyAll(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelAnime.jointTable);
AnimTaskQueue_AddCopy(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelAnime.jointTable);
}
return true;
@ -4650,7 +4650,7 @@ s32 Player_ActionChange_12(Player* this, PlayState* play) {
this->actor.bgCheckFlags |= BGCHECKFLAG_GROUND;
LinkAnimation_PlayOnceSetSpeed(play, &this->skelAnime, anim, 1.3f);
AnimationContext_DisableQueue(play);
AnimTaskQueue_DisableTransformTasksForGroup(play);
this->actor.shape.rot.y = this->yaw = this->actor.wallYaw + 0x8000;
@ -8105,10 +8105,10 @@ void Player_Action_80841BA8(Player* this, PlayState* play) {
LinkAnimation_Update(play, &this->skelAnime);
if (Player_HoldsTwoHandedWeapon(this)) {
AnimationContext_SetLoadFrame(play, func_80833338(this), 0, this->skelAnime.limbCount,
this->skelAnime.morphTable);
AnimationContext_SetCopyTrue(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->skelAnime.morphTable, sUpperBodyLimbCopyMap);
AnimTaskQueue_AddLoadPlayerFrame(play, func_80833338(this), 0, this->skelAnime.limbCount,
this->skelAnime.morphTable);
AnimTaskQueue_AddCopyUsingMap(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->skelAnime.morphTable, sUpperBodyLimbCopyMap);
}
Player_GetMovementSpeedAndYaw(this, &speedTarget, &yawTarget, SPEED_MODE_CURVED, play);
@ -9033,7 +9033,7 @@ void Player_Action_8084411C(Player* this, PlayState* play) {
} else if ((this->ledgeClimbType >= PLAYER_LEDGE_CLIMB_2) && (this->yDistToLedge < 150.0f) &&
(((this->actor.world.pos.y - this->actor.floorHeight) + this->yDistToLedge) >
(70.0f * this->ageProperties->unk_08))) {
AnimationContext_DisableQueue(play);
AnimTaskQueue_DisableTransformTasksForGroup(play);
if (this->stateFlags1 & PLAYER_STATE1_2) {
func_80832698(this, NA_SE_VO_LI_HOOKSHOT_HANG);
} else {
@ -11345,9 +11345,9 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) {
Player_UpdateCamAndSeqModes(play, this);
if (this->skelAnime.moveFlags & ANIM_FLAG_PLAYER_SETMOVE) {
AnimationContext_SetMoveActor(
play, &this->actor, &this->skelAnime,
(this->skelAnime.moveFlags & ANIM_FLAG_PLAYER_2) ? 1.0f : this->ageProperties->unk_08);
AnimTaskQueue_AddActorMove(play, &this->actor, &this->skelAnime,
(this->skelAnime.moveFlags & ANIM_FLAG_PLAYER_2) ? 1.0f
: this->ageProperties->unk_08);
}
Player_UpdateShapeYaw(this, play);
@ -11417,8 +11417,10 @@ void Player_UpdateCommon(Player* this, PlayState* play, Input* input) {
}
}
}
AnimationContext_SetNextQueue(play);
// Because Player updates early relative to most actors, his animation tasks will belong to group 0.
// Task group 1 is set here at the end of Player's update, meaning tasks that get added by other
// actors will be in a different group.
AnimTaskQueue_SetNextGroup(play);
}
Math_Vec3f_Copy(&this->actor.home.pos, &this->actor.world.pos);
@ -12635,8 +12637,7 @@ void Player_Action_8084CC98(Player* this, PlayState* play) {
LinkAnimation_AnimateFrame(play, &this->skelAnime);
}
AnimationContext_SetCopyAll(play, this->skelAnime.limbCount, this->skelAnime.morphTable,
this->skelAnime.jointTable);
AnimTaskQueue_AddCopy(play, this->skelAnime.limbCount, this->skelAnime.morphTable, this->skelAnime.jointTable);
if ((play->csCtx.state != CS_STATE_IDLE) || (this->csAction != PLAYER_CSACTION_NONE)) {
if (this->csAction == PLAYER_CSACTION_7) {
@ -12674,16 +12675,16 @@ void Player_Action_8084CC98(Player* this, PlayState* play) {
func_80832698(this, NA_SE_VO_LI_LASH);
}
AnimationContext_SetCopyAll(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelAnime.jointTable);
AnimTaskQueue_AddCopy(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelAnime.jointTable);
} else {
if (LinkAnimation_OnFrame(&this->upperSkelAnime, 10.0f)) {
Player_PlaySfx(this, NA_SE_IT_LASH);
func_80832698(this, NA_SE_VO_LI_LASH);
}
AnimationContext_SetCopyTrue(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelAnime.jointTable, sUpperBodyLimbCopyMap);
AnimTaskQueue_AddCopyUsingMap(play, this->skelAnime.limbCount, this->skelAnime.jointTable,
this->upperSkelAnime.jointTable, sUpperBodyLimbCopyMap);
}
} else {
LinkAnimationHeader* anim = NULL;

View File

@ -135,12 +135,45 @@ s16 D_8082AB2C[] = {
24, 72, 13, 22, 19, 20, 19, 27, 14, 26, 22, 21, 49, 32, 45, 60, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 16, 32, 8,
};
static u8 D_8082AB6C[][5] = {
/**
* Contains the status of buttons for each page.
*
* Indexed by `pageIndex + pt` values,
* where pageIndex is from the `PauseMenuPage` enum
* and pt is 0 or 2 (respectively `PAGE_SWITCH_PT_LEFT` and `PAGE_SWITCH_PT_RIGHT`).
*
* `PauseMenuPage` enum values are ordered clockwise, starting at PAUSE_ITEM. That means adding 1 to a page index
* produces (modulo 4) the index of the page to the right, and similar with subtracting 1 for the left page.
* The indexing of this array relies on this property, but without modulo operations. Instead, the data for the first
* and last pages (PAUSE_ITEM, PAUSE_EQUIP) is duplicated.
*
* For example when scrolling left from the quest page PAUSE_QUEST (so, to PAUSE_MAP),
* the index is `PAUSE_QUEST + PAGE_SWITCH_PT_LEFT` and the data is button status for the map page.
*/
static u8 gPageSwitchNextButtonStatus[][5] = {
// PAUSE_ITEM + PAGE_SWITCH_PT_LEFT
//
// -> PAUSE_EQUIP
{ BTN_ENABLED, BTN_DISABLED, BTN_DISABLED, BTN_DISABLED, BTN_ENABLED },
// PAUSE_MAP + PAGE_SWITCH_PT_LEFT
//
// -> PAUSE_ITEM
{ BTN_ENABLED, BTN_ENABLED, BTN_ENABLED, BTN_ENABLED, BTN_DISABLED },
// PAUSE_QUEST + PAGE_SWITCH_PT_LEFT
// PAUSE_ITEM + PAGE_SWITCH_PT_RIGHT
// -> PAUSE_MAP
{ BTN_ENABLED, BTN_DISABLED, BTN_DISABLED, BTN_DISABLED, BTN_DISABLED },
// PAUSE_EQUIP + PAGE_SWITCH_PT_LEFT
// PAUSE_MAP + PAGE_SWITCH_PT_RIGHT
// -> PAUSE_QUEST
{ BTN_ENABLED, BTN_DISABLED, BTN_DISABLED, BTN_DISABLED, BTN_ENABLED },
//
// PAUSE_QUEST + PAGE_SWITCH_PT_RIGHT
// -> PAUSE_EQUIP
{ BTN_ENABLED, BTN_DISABLED, BTN_DISABLED, BTN_DISABLED, BTN_ENABLED },
//
// PAUSE_EQUIP + PAGE_SWITCH_PT_RIGHT
// -> PAUSE_ITEM
{ BTN_ENABLED, BTN_ENABLED, BTN_ENABLED, BTN_ENABLED, BTN_DISABLED },
};
@ -155,16 +188,49 @@ static s16 D_8082ABA4 = 0;
static s16 sInDungeonScene = false;
static f32 D_8082ABAC[] = {
-4.0f, 4.0f, 4.0f, 4.0f, 4.0f, -4.0f, -4.0f, -4.0f,
/*
* The following three `sPageSwitch*` arrays are indexed by nextPageMode values,
* which encode the page to switch from and the scroll direction.
*
* sPageSwitchEyeDx/Dz describe how to move the camera eye so that the pages appear scrolling and the next active page
* is switched into view.
*
* sPageSwitchNextPageIndex contains the page a nextPageMode leads to once scrolling is done.
*/
#define PAGE_SWITCH_NSTEPS 16
static f32 sPageSwitchEyeDx[] = {
-PAUSE_EYE_DIST * (PAUSE_MAP_X - PAUSE_ITEM_X) / PAGE_SWITCH_NSTEPS, // PAUSE_ITEM right
-PAUSE_EYE_DIST*(PAUSE_EQUIP_X - PAUSE_ITEM_X) / PAGE_SWITCH_NSTEPS, // PAUSE_ITEM left
-PAUSE_EYE_DIST*(PAUSE_QUEST_X - PAUSE_MAP_X) / PAGE_SWITCH_NSTEPS, // PAUSE_MAP right
-PAUSE_EYE_DIST*(PAUSE_ITEM_X - PAUSE_MAP_X) / PAGE_SWITCH_NSTEPS, // PAUSE_MAP left
-PAUSE_EYE_DIST*(PAUSE_EQUIP_X - PAUSE_QUEST_X) / PAGE_SWITCH_NSTEPS, // PAUSE_QUEST right
-PAUSE_EYE_DIST*(PAUSE_MAP_X - PAUSE_QUEST_X) / PAGE_SWITCH_NSTEPS, // PAUSE_QUEST left
-PAUSE_EYE_DIST*(PAUSE_ITEM_X - PAUSE_EQUIP_X) / PAGE_SWITCH_NSTEPS, // PAUSE_EQUIP right
-PAUSE_EYE_DIST*(PAUSE_QUEST_X - PAUSE_EQUIP_X) / PAGE_SWITCH_NSTEPS, // PAUSE_EQUIP left
};
static f32 D_8082ABCC[] = {
-4.0f, -4.0f, -4.0f, 4.0f, 4.0f, 4.0f, 4.0f, -4.0f,
static f32 sPageSwitchEyeDz[] = {
-PAUSE_EYE_DIST * (PAUSE_MAP_Z - PAUSE_ITEM_Z) / PAGE_SWITCH_NSTEPS, // PAUSE_ITEM right
-PAUSE_EYE_DIST*(PAUSE_EQUIP_Z - PAUSE_ITEM_Z) / PAGE_SWITCH_NSTEPS, // PAUSE_ITEM left
-PAUSE_EYE_DIST*(PAUSE_QUEST_Z - PAUSE_MAP_Z) / PAGE_SWITCH_NSTEPS, // PAUSE_MAP right
-PAUSE_EYE_DIST*(PAUSE_ITEM_Z - PAUSE_MAP_Z) / PAGE_SWITCH_NSTEPS, // PAUSE_MAP left
-PAUSE_EYE_DIST*(PAUSE_EQUIP_Z - PAUSE_QUEST_Z) / PAGE_SWITCH_NSTEPS, // PAUSE_QUEST right
-PAUSE_EYE_DIST*(PAUSE_MAP_Z - PAUSE_QUEST_Z) / PAGE_SWITCH_NSTEPS, // PAUSE_QUEST left
-PAUSE_EYE_DIST*(PAUSE_ITEM_Z - PAUSE_EQUIP_Z) / PAGE_SWITCH_NSTEPS, // PAUSE_EQUIP right
-PAUSE_EYE_DIST*(PAUSE_QUEST_Z - PAUSE_EQUIP_Z) / PAGE_SWITCH_NSTEPS, // PAUSE_EQUIP left
};
static u16 D_8082ABEC[] = {
PAUSE_MAP, PAUSE_EQUIP, PAUSE_QUEST, PAUSE_ITEM, PAUSE_EQUIP, PAUSE_MAP, PAUSE_ITEM, PAUSE_QUEST,
static u16 sPageSwitchNextPageIndex[] = {
PAUSE_MAP, // PAUSE_ITEM right
PAUSE_EQUIP, // PAUSE_ITEM left
PAUSE_QUEST, // PAUSE_MAP right
PAUSE_ITEM, // PAUSE_MAP left
PAUSE_EQUIP, // PAUSE_QUEST right
PAUSE_MAP, // PAUSE_QUEST left
PAUSE_ITEM, // PAUSE_EQUIP right
PAUSE_QUEST, // PAUSE_EQUIP left
};
u8 gSlotAgeReqs[] = {
@ -489,26 +555,29 @@ void KaleidoScope_SetDefaultCursor(PlayState* play) {
}
}
void KaleidoScope_SwitchPage(PauseContext* pauseCtx, u8 pt) {
pauseCtx->mainState = PAUSE_MAIN_STATE_1;
pauseCtx->unk_1EA = 0;
#define PAGE_SWITCH_PT_LEFT 0
#define PAGE_SWITCH_PT_RIGHT 2
if (!pt) {
pauseCtx->mode = pauseCtx->pageIndex * 2 + 1;
void KaleidoScope_SetupPageSwitch(PauseContext* pauseCtx, u8 pt) {
pauseCtx->mainState = PAUSE_MAIN_STATE_SWITCHING_PAGE;
pauseCtx->pageSwitchTimer = 0;
if (!pt) { // PAGE_SWITCH_PT_LEFT
pauseCtx->nextPageMode = pauseCtx->pageIndex * 2 + 1;
Audio_PlaySfxGeneral(NA_SE_SY_WIN_SCROLL_LEFT, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
pauseCtx->cursorSpecialPos = PAUSE_CURSOR_PAGE_RIGHT;
} else {
pauseCtx->mode = pauseCtx->pageIndex * 2;
} else { // PAGE_SWITCH_PT_RIGHT
pauseCtx->nextPageMode = pauseCtx->pageIndex * 2;
Audio_PlaySfxGeneral(NA_SE_SY_WIN_SCROLL_RIGHT, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
pauseCtx->cursorSpecialPos = PAUSE_CURSOR_PAGE_LEFT;
}
gSaveContext.buttonStatus[1] = D_8082AB6C[pauseCtx->pageIndex + pt][1];
gSaveContext.buttonStatus[2] = D_8082AB6C[pauseCtx->pageIndex + pt][2];
gSaveContext.buttonStatus[3] = D_8082AB6C[pauseCtx->pageIndex + pt][3];
gSaveContext.buttonStatus[4] = D_8082AB6C[pauseCtx->pageIndex + pt][4];
gSaveContext.buttonStatus[1] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex + pt][1];
gSaveContext.buttonStatus[2] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex + pt][2];
gSaveContext.buttonStatus[3] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex + pt][3];
gSaveContext.buttonStatus[4] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex + pt][4];
PRINTF("kscope->kscp_pos+pt = %d\n", pauseCtx->pageIndex + pt);
@ -525,12 +594,12 @@ void KaleidoScope_HandlePageToggles(PauseContext* pauseCtx, Input* input) {
}
if (CHECK_BTN_ALL(input->press.button, BTN_R)) {
KaleidoScope_SwitchPage(pauseCtx, 2);
KaleidoScope_SetupPageSwitch(pauseCtx, PAGE_SWITCH_PT_RIGHT);
return;
}
if (CHECK_BTN_ALL(input->press.button, BTN_Z)) {
KaleidoScope_SwitchPage(pauseCtx, 0);
KaleidoScope_SetupPageSwitch(pauseCtx, PAGE_SWITCH_PT_LEFT);
return;
}
@ -538,7 +607,7 @@ void KaleidoScope_HandlePageToggles(PauseContext* pauseCtx, Input* input) {
if (pauseCtx->stickAdjX < -30) {
pauseCtx->pageSwitchInputTimer++;
if ((pauseCtx->pageSwitchInputTimer >= 10) || (pauseCtx->pageSwitchInputTimer == 0)) {
KaleidoScope_SwitchPage(pauseCtx, 0);
KaleidoScope_SetupPageSwitch(pauseCtx, PAGE_SWITCH_PT_LEFT);
}
} else {
pauseCtx->pageSwitchInputTimer = -1;
@ -547,7 +616,7 @@ void KaleidoScope_HandlePageToggles(PauseContext* pauseCtx, Input* input) {
if (pauseCtx->stickAdjX > 30) {
pauseCtx->pageSwitchInputTimer++;
if ((pauseCtx->pageSwitchInputTimer >= 10) || (pauseCtx->pageSwitchInputTimer == 0)) {
KaleidoScope_SwitchPage(pauseCtx, 2);
KaleidoScope_SetupPageSwitch(pauseCtx, PAGE_SWITCH_PT_RIGHT);
}
} else {
pauseCtx->pageSwitchInputTimer = -1;
@ -1533,21 +1602,21 @@ void KaleidoScope_UpdateNamePanel(PlayState* play) {
}
}
void func_808237B4(PlayState* play, Input* input) {
void KaleidoScope_UpdatePageSwitch(PlayState* play, Input* input) {
PauseContext* pauseCtx = &play->pauseCtx;
s32 cond = false;
s32 mode;
s32 frameAdvanceFreeze = false;
s32 nextPageMode;
if (ZREG(13) && !CHECK_BTN_ALL(input->press.button, BTN_L)) {
cond = true;
if (R_PAUSE_PAGE_SWITCH_FRAME_ADVANCE_ON && !CHECK_BTN_ALL(input->press.button, BTN_L)) {
frameAdvanceFreeze = true;
}
if (!cond) {
mode = pauseCtx->mode;
pauseCtx->eye.x += D_8082ABAC[mode];
pauseCtx->eye.z += D_8082ABCC[mode];
if (!frameAdvanceFreeze) {
nextPageMode = pauseCtx->nextPageMode;
pauseCtx->eye.x += sPageSwitchEyeDx[nextPageMode];
pauseCtx->eye.z += sPageSwitchEyeDz[nextPageMode];
if (pauseCtx->unk_1EA < 32) {
if (pauseCtx->pageSwitchTimer < ((4 * PAGE_SWITCH_NSTEPS) / 2)) {
WREG(16) -= WREG(25) / WREG(6);
WREG(17) -= WREG(26) / WREG(6);
} else {
@ -1555,11 +1624,11 @@ void func_808237B4(PlayState* play, Input* input) {
WREG(17) += WREG(26) / WREG(6);
}
pauseCtx->unk_1EA += 4;
pauseCtx->pageSwitchTimer += 4;
if (pauseCtx->unk_1EA == 64) {
pauseCtx->unk_1EA = 0;
pauseCtx->pageIndex = D_8082ABEC[pauseCtx->mode];
if (pauseCtx->pageSwitchTimer == (4 * PAGE_SWITCH_NSTEPS)) {
pauseCtx->pageSwitchTimer = 0;
pauseCtx->pageIndex = sPageSwitchNextPageIndex[pauseCtx->nextPageMode];
pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE;
}
}
@ -2471,28 +2540,32 @@ void KaleidoScope_GrayOutTextureRGBA32(u32* texture, u16 pixelCount) {
void KaleidoScope_UpdateOpening(PlayState* play) {
PauseContext* pauseCtx = &play->pauseCtx;
pauseCtx->eye.x += D_8082ABAC[pauseCtx->mode] * ZREG(46);
pauseCtx->eye.z += D_8082ABCC[pauseCtx->mode] * ZREG(46);
pauseCtx->unk_1EA += 4 * ZREG(46);
pauseCtx->eye.x += sPageSwitchEyeDx[pauseCtx->nextPageMode] * ZREG(46);
pauseCtx->eye.z += sPageSwitchEyeDz[pauseCtx->nextPageMode] * ZREG(46);
pauseCtx->pageSwitchTimer += 4 * ZREG(46);
if (pauseCtx->unk_1EA == (64 * ZREG(47))) {
if (pauseCtx->pageSwitchTimer == (4 * PAGE_SWITCH_NSTEPS * ZREG(47))) {
// Finished opening
func_80084BF4(play, 1);
gSaveContext.buttonStatus[0] = D_8082AB6C[pauseCtx->pageIndex][0];
gSaveContext.buttonStatus[1] = D_8082AB6C[pauseCtx->pageIndex][1];
gSaveContext.buttonStatus[2] = D_8082AB6C[pauseCtx->pageIndex][2];
gSaveContext.buttonStatus[3] = D_8082AB6C[pauseCtx->pageIndex][3];
gSaveContext.buttonStatus[4] = D_8082AB6C[pauseCtx->pageIndex][4];
pauseCtx->pageIndex = D_8082ABEC[pauseCtx->mode];
gSaveContext.buttonStatus[0] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex][0];
gSaveContext.buttonStatus[1] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex][1];
gSaveContext.buttonStatus[2] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex][2];
gSaveContext.buttonStatus[3] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex][3];
gSaveContext.buttonStatus[4] = gPageSwitchNextButtonStatus[pauseCtx->pageIndex][4];
pauseCtx->pageIndex = sPageSwitchNextPageIndex[pauseCtx->nextPageMode];
pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE;
pauseCtx->state++; // PAUSE_STATE_MAIN
pauseCtx->alpha = 255;
Interface_LoadActionLabelB(play, DO_ACTION_SAVE);
} else if (pauseCtx->unk_1EA == 64) {
} else if (pauseCtx->pageSwitchTimer == (4 * PAGE_SWITCH_NSTEPS * 1)) {
// `ZREG(47)` is always 1 so this normally never happens
pauseCtx->pageIndex = D_8082ABEC[pauseCtx->mode];
pauseCtx->mode = (u16)(pauseCtx->pageIndex * 2) + 1;
pauseCtx->pageIndex = sPageSwitchNextPageIndex[pauseCtx->nextPageMode];
pauseCtx->nextPageMode = (u16)(pauseCtx->pageIndex * 2) + 1;
}
}
@ -3071,7 +3144,7 @@ void KaleidoScope_Update(PlayState* play) {
WREG(2) = -6240;
func_800F64E0(0);
} else if (CHECK_BTN_ALL(input->press.button, BTN_B)) {
pauseCtx->mode = 0;
pauseCtx->nextPageMode = 0;
pauseCtx->promptChoice = 0;
Audio_PlaySfxGeneral(NA_SE_SY_DECIDE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
@ -3085,8 +3158,8 @@ void KaleidoScope_Update(PlayState* play) {
}
break;
case PAUSE_MAIN_STATE_1:
func_808237B4(play, play->state.input);
case PAUSE_MAIN_STATE_SWITCHING_PAGE:
KaleidoScope_UpdatePageSwitch(play, play->state.input);
break;
case PAUSE_MAIN_STATE_2:
@ -3118,7 +3191,7 @@ void KaleidoScope_Update(PlayState* play) {
} else if (CHECK_BTN_ALL(input->press.button, BTN_B)) {
AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_OFF);
pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE;
pauseCtx->mode = 0;
pauseCtx->nextPageMode = 0;
pauseCtx->promptChoice = 0;
Audio_PlaySfxGeneral(NA_SE_SY_DECIDE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);
@ -3168,7 +3241,7 @@ void KaleidoScope_Update(PlayState* play) {
} else if (CHECK_BTN_ALL(input->press.button, BTN_B)) {
AudioOcarina_SetInstrument(OCARINA_INSTRUMENT_OFF);
pauseCtx->mainState = PAUSE_MAIN_STATE_IDLE;
pauseCtx->mode = 0;
pauseCtx->nextPageMode = 0;
pauseCtx->promptChoice = 0;
Audio_PlaySfxGeneral(NA_SE_SY_DECIDE, &gSfxDefaultPos, 4, &gSfxDefaultFreqAndVolScale,
&gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb);

View File

@ -1,5 +1,5 @@
CFLAGS := -Wall -Wextra -pedantic -std=c99 -g -O2
PROGRAMS := elf2rom makeromfs mkdmadata mkldscript reloc_prereq vtxdis yaz0
PROGRAMS := elf2rom makeromfs mkdmadata mkldscript reloc_prereq vtxdis
ifeq ($(shell command -v clang >/dev/null 2>&1; echo $$?),0)
CC := clang
@ -36,7 +36,6 @@ mkdmadata_SOURCES := mkdmadata.c spec.c util.c
mkldscript_SOURCES := mkldscript.c spec.c util.c
reloc_prereq_SOURCES := reloc_prereq.c spec.c util.c
vtxdis_SOURCES := vtxdis.c
yaz0_SOURCES := yaz0tool.c yaz0.c util.c
define COMPILE =

View File

@ -131,6 +131,7 @@ def main():
if not (
mapfile_segment.name.startswith("..boot")
or mapfile_segment.name.startswith("..code")
or mapfile_segment.name.startswith("..buffers")
or mapfile_segment.name.startswith("..ovl_")
):
continue
@ -152,13 +153,15 @@ def main():
base_value = read_u32(base, file.vrom + reloc.offset_32)
build_value = read_u32(build, file.vrom + reloc.offset_32)
elif reloc.offset_hi16 is not None and reloc.offset_lo16 is not None:
if read_u16(base, file.vrom + reloc.offset_hi16) != read_u16(
build, file.vrom + reloc.offset_hi16
) or read_u16(base, file.vrom + reloc.offset_hi16) != read_u16(
build, file.vrom + reloc.offset_hi16
if (
read_u16(base, file.vrom + reloc.offset_hi16)
!= read_u16(build, file.vrom + reloc.offset_hi16)
) or (
read_u16(base, file.vrom + reloc.offset_lo16)
!= read_u16(build, file.vrom + reloc.offset_lo16)
):
print(
f"Error: Reference to {reloc.name} in {file.filepath} is in a shifted portion of the ROM.\n"
f"Error: Reference to {reloc.name} in {file.filepath} is in a shifted (or non-matching even ignoring relocs) portion of the ROM.\n"
"Please ensure that the only differences between the baserom and the current build are due to data ordering.",
file=sys.stderr,
)
@ -186,7 +189,9 @@ def main():
for mapfile_segment in source_code_segments:
for file in mapfile_segment:
pointers_in_section = [
p for p in pointers if file.vram <= p.build_value < file.vram + file.size
p
for p in pointers
if file.vram <= p.build_value < file.vram + file.size
]
if not pointers_in_section:
continue

View File

@ -42,10 +42,6 @@ static void write_ld_script(FILE *fout)
// initialized data (.text, .data, .rodata, .sdata)
// Increment the start of the section
//if (seg->fields & (1 << STMT_increment))
//fprintf(fout, " . += 0x%08X;\n", seg->increment);
fprintf(fout, " _%sSegmentRomStartTemp = _RomSize;\n"
" _%sSegmentRomStart = _%sSegmentRomStartTemp;\n"
" ..%s ", seg->name, seg->name, seg->name, seg->name);
@ -68,10 +64,13 @@ static void write_ld_script(FILE *fout)
for (j = 0; j < seg->includesCount; j++)
{
fprintf(fout, " %s (.text)\n", seg->includes[j].fpath);
if (seg->includes[j].linkerPadding != 0)
fprintf(fout, " . += 0x%X;\n", seg->includes[j].linkerPadding);
fprintf(fout, " . = ALIGN(0x10);\n");
if (!seg->includes[j].dataOnlyWithinRodata)
{
fprintf(fout, " %s (.text)\n", seg->includes[j].fpath);
if (seg->includes[j].linkerPadding != 0)
fprintf(fout, " . += 0x%X;\n", seg->includes[j].linkerPadding);
fprintf(fout, " . = ALIGN(0x10);\n");
}
}
fprintf(fout, " _%sSegmentTextEnd = .;\n", seg->name);
@ -82,20 +81,11 @@ static void write_ld_script(FILE *fout)
for (j = 0; j < seg->includesCount; j++)
{
if (!seg->includes[j].dataWithRodata)
if (!seg->includes[j].dataOnlyWithinRodata && !seg->includes[j].noData)
fprintf(fout, " %s (.data)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
}
/*
for (j = 0; j < seg->includesCount; j++)
fprintf(fout, " %s (.rodata)\n", seg->includes[j].fpath);
for (j = 0; j < seg->includesCount; j++)
fprintf(fout, " %s (.sdata)\n", seg->includes[j].fpath);
*/
//fprintf(fout, " . = ALIGN(0x10);\n");
fprintf(fout, " _%sSegmentDataEnd = .;\n", seg->name);
fprintf(fout, " _%sSegmentDataSize = ABSOLUTE( _%sSegmentDataEnd - _%sSegmentDataStart );\n", seg->name, seg->name, seg->name);
@ -104,7 +94,7 @@ static void write_ld_script(FILE *fout)
for (j = 0; j < seg->includesCount; j++)
{
if (seg->includes[j].dataWithRodata)
if (seg->includes[j].dataOnlyWithinRodata)
fprintf(fout, " %s (.data)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
@ -116,11 +106,12 @@ static void write_ld_script(FILE *fout)
// the beginning of the entire rodata area in order to remain consistent.
// Inconsistencies will lead to various .rodata reloc crashes as a result of
// either missing relocs or wrong relocs.
fprintf(fout, " %s (.rodata)\n"
" %s (.rodata.str*)\n"
" %s (.rodata.cst*)\n"
" . = ALIGN(0x10);\n",
seg->includes[j].fpath, seg->includes[j].fpath, seg->includes[j].fpath);
if (!seg->includes[j].dataOnlyWithinRodata)
fprintf(fout, " %s (.rodata)\n"
" %s (.rodata.str*)\n"
" %s (.rodata.cst*)\n"
" . = ALIGN(0x10);\n",
seg->includes[j].fpath, seg->includes[j].fpath, seg->includes[j].fpath);
}
fprintf(fout, " _%sSegmentRoDataEnd = .;\n", seg->name);
@ -130,15 +121,17 @@ static void write_ld_script(FILE *fout)
fprintf(fout, " _%sSegmentSDataStart = .;\n", seg->name);
for (j = 0; j < seg->includesCount; j++)
fprintf(fout, " %s (.sdata)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
if (!seg->includes[j].dataOnlyWithinRodata)
fprintf(fout, " %s (.sdata)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
fprintf(fout, " _%sSegmentSDataEnd = .;\n", seg->name);
fprintf(fout, " _%sSegmentOvlStart = .;\n", seg->name);
for (j = 0; j < seg->includesCount; j++)
fprintf(fout, " %s (.ovl)\n", seg->includes[j].fpath);
if (!seg->includes[j].dataOnlyWithinRodata)
fprintf(fout, " %s (.ovl)\n", seg->includes[j].fpath);
fprintf(fout, " _%sSegmentOvlEnd = .;\n", seg->name);
@ -166,20 +159,24 @@ static void write_ld_script(FILE *fout)
seg->name, seg->name, seg->name, seg->name);
for (j = 0; j < seg->includesCount; j++)
fprintf(fout, " %s (.sbss)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
if (!seg->includes[j].dataOnlyWithinRodata)
fprintf(fout, " %s (.sbss)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
for (j = 0; j < seg->includesCount; j++)
fprintf(fout, " %s (.scommon)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
if (!seg->includes[j].dataOnlyWithinRodata)
fprintf(fout, " %s (.scommon)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
for (j = 0; j < seg->includesCount; j++)
fprintf(fout, " %s (.bss)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
if (!seg->includes[j].dataOnlyWithinRodata)
fprintf(fout, " %s (.bss)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
for (j = 0; j < seg->includesCount; j++)
fprintf(fout, " %s (COMMON)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
if (!seg->includes[j].dataOnlyWithinRodata)
fprintf(fout, " %s (COMMON)\n"
" . = ALIGN(0x10);\n", seg->includes[j].fpath);
fprintf(fout, " . = ALIGN(0x10);\n"
" _%sSegmentBssEnd = .;\n"
@ -187,25 +184,6 @@ static void write_ld_script(FILE *fout)
" }\n"
" _%sSegmentBssSize = ABSOLUTE( _%sSegmentBssEnd - _%sSegmentBssStart );\n\n",
seg->name, seg->name, seg->name, seg->name, seg->name);
// Increment the end of the segment
//if (seg->fields & (1 << STMT_increment))
//fprintf(fout, " . += 0x%08X;\n", seg->increment);
//fprintf(fout, " ..%s.ovl ADDR(..%s) + SIZEOF(..%s) :\n"
// /*" ..%s.bss :\n"*/
// " {\n",
// seg->name, seg->name, seg->name);
//fprintf(fout, " _%sSegmentOvlStart = .;\n", seg->name);
//for (j = 0; j < seg->includesCount; j++)
// fprintf(fout, " %s (.ovl)\n", seg->includes[j].fpath);
////fprintf(fout, " . = ALIGN(0x10);\n");
//fprintf(fout, " _%sSegmentOvlEnd = .;\n", seg->name);
//fprintf(fout, "\n }\n");
}
fputs(" _RomEnd = _RomSize;\n\n", fout);

View File

@ -136,7 +136,8 @@ static const char *const stmtNames[] =
[STMT_entry] = "entry",
[STMT_flags] = "flags",
[STMT_include] = "include",
[STMT_include_data_with_rodata] = "include_data_with_rodata",
[STMT_include_data_only_within_rodata] = "include_data_only_within_rodata",
[STMT_include_no_data] = "include_no_data",
[STMT_name] = "name",
[STMT_number] = "number",
[STMT_romalign] = "romalign",
@ -158,7 +159,8 @@ STMTId get_stmt_id_by_stmt_name(const char *stmtName, int lineNum) {
bool parse_segment_statement(struct Segment *currSeg, STMTId stmt, char* args, int lineNum) {
// ensure no duplicates (except for 'include' or 'pad_text')
if (stmt != STMT_include && stmt != STMT_include_data_with_rodata && stmt != STMT_pad_text &&
if (stmt != STMT_include && stmt != STMT_include_data_only_within_rodata &&
stmt != STMT_include_no_data && stmt != STMT_pad_text &&
(currSeg->fields & (1 << stmt)))
util_fatal_error("line %i: duplicate '%s' statement", lineNum, stmtNames[stmt]);
@ -211,7 +213,8 @@ bool parse_segment_statement(struct Segment *currSeg, STMTId stmt, char* args, i
util_fatal_error("line %i: alignment is not a power of two", lineNum);
break;
case STMT_include:
case STMT_include_data_with_rodata:
case STMT_include_data_only_within_rodata:
case STMT_include_no_data:
currSeg->includesCount++;
currSeg->includes = realloc(currSeg->includes, currSeg->includesCount * sizeof(*currSeg->includes));
@ -219,7 +222,8 @@ bool parse_segment_statement(struct Segment *currSeg, STMTId stmt, char* args, i
util_fatal_error("line %i: invalid filename", lineNum);
currSeg->includes[currSeg->includesCount - 1].linkerPadding = 0;
currSeg->includes[currSeg->includesCount - 1].dataWithRodata = (stmt == STMT_include_data_with_rodata);
currSeg->includes[currSeg->includesCount - 1].dataOnlyWithinRodata = (stmt == STMT_include_data_only_within_rodata);
currSeg->includes[currSeg->includesCount - 1].noData = (stmt == STMT_include_no_data);
break;
case STMT_increment:
if (!parse_number(args, &currSeg->increment))

View File

@ -14,7 +14,8 @@ typedef enum {
STMT_entry,
STMT_flags,
STMT_include,
STMT_include_data_with_rodata,
STMT_include_data_only_within_rodata,
STMT_include_no_data,
STMT_name,
STMT_number,
STMT_romalign,
@ -34,7 +35,8 @@ enum {
struct Include {
char* fpath;
int linkerPadding;
uint8_t dataWithRodata;
bool dataOnlyWithinRodata;
bool noData;
};
typedef struct Segment {

View File

@ -1,238 +0,0 @@
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "yaz0.h"
// decoder implementation by thakis of http://www.amnoid.de
// src points to the yaz0 source data (to the "real" source data, not at the header!)
// dst points to a buffer uncompressedSize bytes large (you get uncompressedSize from
// the second 4 bytes in the Yaz0 header).
void yaz0_decode(uint8_t* src, uint8_t* dst, int uncompressedSize)
{
int srcPlace = 0, dstPlace = 0; // current read/write positions
unsigned int validBitCount = 0; // number of valid bits left in "code" byte
uint8_t currCodeByte;
while (dstPlace < uncompressedSize)
{
// read new "code" byte if the current one is used up
if (validBitCount == 0)
{
currCodeByte = src[srcPlace];
++srcPlace;
validBitCount = 8;
}
if ((currCodeByte & 0x80) != 0)
{
// straight copy
dst[dstPlace] = src[srcPlace];
dstPlace++;
srcPlace++;
}
else
{
// RLE part
uint8_t byte1 = src[srcPlace];
uint8_t byte2 = src[srcPlace + 1];
srcPlace += 2;
unsigned int dist = ((byte1 & 0xF) << 8) | byte2;
unsigned int copySource = dstPlace - (dist + 1);
unsigned int numBytes = byte1 >> 4;
if (numBytes == 0)
{
numBytes = src[srcPlace] + 0x12;
srcPlace++;
}
else
{
numBytes += 2;
}
// copy run
for (unsigned int i = 0; i < numBytes; ++i)
{
dst[dstPlace] = dst[copySource];
copySource++;
dstPlace++;
}
}
// use next bit from "code" byte
currCodeByte <<= 1;
validBitCount -= 1;
}
}
// encoder implementation by shevious, with bug fixes by notwa
typedef uint32_t uint32_t;
typedef uint8_t uint8_t;
#define MAX_RUNLEN (0xFF + 0x12)
// simple and straight encoding scheme for Yaz0
static uint32_t simpleEnc(uint8_t *src, int size, int pos, uint32_t *pMatchPos)
{
int numBytes = 1;
int matchPos = 0;
int startPos = pos - 0x1000;
int end = size - pos;
if (startPos < 0)
startPos = 0;
// maximum runlength for 3 byte encoding
if (end > MAX_RUNLEN)
end = MAX_RUNLEN;
for (int i = startPos; i < pos; i++)
{
int j;
for (j = 0; j < end; j++)
{
if (src[i + j] != src[j + pos])
break;
}
if (j > numBytes)
{
numBytes = j;
matchPos = i;
}
}
*pMatchPos = matchPos;
if (numBytes == 2)
numBytes = 1;
return numBytes;
}
// a lookahead encoding scheme for ngc Yaz0
static uint32_t nintendoEnc(uint8_t *src, int size, int pos, uint32_t *pMatchPos)
{
uint32_t numBytes = 1;
static uint32_t numBytes1;
static uint32_t matchPos;
static int prevFlag = 0;
// if prevFlag is set, it means that the previous position
// was determined by look-ahead try.
// so just use it. this is not the best optimization,
// but nintendo's choice for speed.
if (prevFlag == 1)
{
*pMatchPos = matchPos;
prevFlag = 0;
return numBytes1;
}
prevFlag = 0;
numBytes = simpleEnc(src, size, pos, &matchPos);
*pMatchPos = matchPos;
// if this position is RLE encoded, then compare to copying 1 byte and next position(pos+1) encoding
if (numBytes >= 3)
{
numBytes1 = simpleEnc(src, size, pos + 1, &matchPos);
// if the next position encoding is +2 longer than current position, choose it.
// this does not guarantee the best optimization, but fairly good optimization with speed.
if (numBytes1 >= numBytes + 2)
{
numBytes = 1;
prevFlag = 1;
}
}
return numBytes;
}
int yaz0_encode(uint8_t *src, uint8_t *dst, int srcSize)
{
int srcPos = 0;
int dstPos = 0;
int bufPos = 0;
uint8_t buf[24]; // 8 codes * 3 bytes maximum
uint32_t validBitCount = 0; // number of valid bits left in "code" byte
uint8_t currCodeByte = 0; // a bitfield, set bits meaning copy, unset meaning RLE
while (srcPos < srcSize)
{
uint32_t numBytes;
uint32_t matchPos;
numBytes = nintendoEnc(src, srcSize, srcPos, &matchPos);
if (numBytes < 3)
{
// straight copy
buf[bufPos] = src[srcPos];
bufPos++;
srcPos++;
//set flag for straight copy
currCodeByte |= (0x80 >> validBitCount);
}
else
{
//RLE part
uint32_t dist = srcPos - matchPos - 1;
uint8_t byte1, byte2, byte3;
if (numBytes >= 0x12) // 3 byte encoding
{
byte1 = 0 | (dist >> 8);
byte2 = dist & 0xFF;
buf[bufPos++] = byte1;
buf[bufPos++] = byte2;
// maximum runlength for 3 byte encoding
if (numBytes > MAX_RUNLEN)
numBytes = MAX_RUNLEN;
byte3 = numBytes - 0x12;
buf[bufPos++] = byte3;
}
else // 2 byte encoding
{
byte1 = ((numBytes - 2) << 4) | (dist >> 8);
byte2 = dist & 0xFF;
buf[bufPos++] = byte1;
buf[bufPos++] = byte2;
}
srcPos += numBytes;
}
validBitCount++;
// write eight codes
if (validBitCount == 8)
{
dst[dstPos++] = currCodeByte;
for (int j = 0; j < bufPos; j++)
dst[dstPos++] = buf[j];
currCodeByte = 0;
validBitCount = 0;
bufPos = 0;
}
}
if (validBitCount > 0)
{
dst[dstPos++] = currCodeByte;
for (int j = 0; j < bufPos; j++)
dst[dstPos++] = buf[j];
currCodeByte = 0;
validBitCount = 0;
bufPos = 0;
}
return dstPos;
}

View File

@ -1,10 +0,0 @@
#ifndef _YAZ0_H_
#define _YAZ0_H_
int yaz0_encode2(uint8_t *src, uint8_t *dest, int uncompressedSize);
void yaz0_decode(uint8_t* src, uint8_t* dst, int uncompressedSize);
int yaz0_encode(uint8_t *src, uint8_t *dest, int srcSize);
#endif // _YAZ0_H_

View File

@ -1,201 +0,0 @@
#ifdef __linux__
#define _POSIX_C_SOURCE 199309L
#endif
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "yaz0.h"
#include "util.h"
// TODO: Windows support
static unsigned long int get_time_milliseconds(void)
{
#ifdef __linux__
struct timespec tspec;
clock_gettime(CLOCK_MONOTONIC, &tspec);
return (tspec.tv_sec * 1000) + tspec.tv_nsec / 1000000;
#else
// dummy
return 0;
#endif
}
static void print_report(unsigned long int time, size_t compSize, size_t uncompSize)
{
unsigned int minutes = time / (1000 * 60);
float seconds = (float)(time % (1000 * 60)) / 1000;
printf("compression ratio: %.2fKiB / %.2fKiB (%.2f%%)\n"
"time: %um %.3fs\n",
(float)compSize / 1024, (float)uncompSize / 1024,
(float)compSize * 100 / (float)uncompSize,
minutes, seconds);
}
static void compress_file(const char *inputFileName, const char *outputFileName, bool verbose)
{
size_t uncompSize;
uint8_t *input = util_read_whole_file(inputFileName, &uncompSize);
uint8_t *output = malloc(uncompSize * 2); // TODO: figure out how much space we need
unsigned long int time;
if (verbose)
{
printf("decompressing %s\n", inputFileName);
time = get_time_milliseconds();
}
// compress data
size_t compSize = yaz0_encode(input, output, uncompSize);
if (verbose)
time = get_time_milliseconds() - time;
// make Yaz0 header
uint8_t header[16] = {0};
header[0] = 'Y';
header[1] = 'a';
header[2] = 'z';
header[3] = '0';
util_write_uint32_be(header + 4, uncompSize);
// write output file
FILE *outFile = fopen(outputFileName, "wb");
if (outFile == NULL)
util_fatal_error("failed to open file '%s' for writing", outputFileName);
fwrite(header, sizeof(header), 1, outFile);
fwrite(output, compSize, 1, outFile);
fclose(outFile);
free(input);
free(output);
if (verbose)
print_report(time, compSize, uncompSize);
}
static void decompress_file(const char *inputFileName, const char *outputFileName, bool verbose)
{
size_t compSize;
uint8_t *input = util_read_whole_file(inputFileName, &compSize);
size_t uncompSize;
uint8_t *output;
unsigned long int time = 0;
// read header
if (input[0] != 'Y' || input[1] != 'a' || input[2] != 'z' || input[3] != '0')
util_fatal_error("file '%s' does not have a valid Yaz0 header", inputFileName);
uncompSize = util_read_uint32_be(input + 4);
// decompress data
output = malloc(uncompSize);
if (verbose)
{
printf("decompressing %s\n", inputFileName);
time = get_time_milliseconds();
}
yaz0_decode(input + 16, output, uncompSize);
if (verbose)
time = get_time_milliseconds() - time;
// write output file
FILE *outFile = fopen(outputFileName, "wb");
fwrite(output, uncompSize, 1, outFile);
fclose(outFile);
free(input);
free(output);
if (verbose)
print_report(time, compSize, uncompSize);
}
static void usage(const char *execName)
{
printf("Yaz0 compressor/decompressor\n"
"usage: %s [-d] [-h] [-v] INPUT_FILE OUTPUT_FILE\n"
"compresses INPUT_FILE using Yaz0 encoding and writes output to OUTPUT_FILE\n"
"Available options:\n"
"-d: decompresses INPUT_FILE, a Yaz0 compressed file, and writes decompressed\n"
" output to OUTPUT_FILE\n"
"-v: prints verbose output (compression ratio and time)\n"
"-h: shows this help message\n",
execName);
}
int main(int argc, char **argv)
{
int i;
const char *inputFileName = NULL;
const char *outputFileName = NULL;
bool decompress = false;
bool verbose = false;
// parse arguments
for (i = 1; i < argc; i++)
{
char *arg = argv[i];
if (arg[0] == '-')
{
if (strcmp(arg, "-d") == 0)
decompress = true;
else if (strcmp(arg, "-v") == 0)
verbose = true;
else if (strcmp(arg, "-h") == 0)
{
usage(argv[0]);
return 0;
}
else
{
printf("unknown option %s\n", arg);
usage(argv[0]);
return 1;
}
}
else
{
if (inputFileName == NULL)
inputFileName = arg;
else if (outputFileName == NULL)
outputFileName = arg;
else
{
puts("too many files specified");
usage(argv[0]);
return 1;
}
}
}
if (inputFileName == NULL)
{
puts("no input file specified");
usage(argv[0]);
return 1;
}
if (outputFileName == NULL)
{
puts("no output file specified");
usage(argv[0]);
return 1;
}
if (decompress)
decompress_file(inputFileName, outputFileName, verbose);
else
compress_file(inputFileName, outputFileName, verbose);
return 0;
}