diff --git a/README.md b/README.md index 6d6ba19b..81866958 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ All versions are supported, and the US 1.0 version (SHA1 = 0cb115d8716dbbc2922fd As of June 11, 2025, this is our current score: -    Decomp progress: 90.89% +    Decomp progress: 90.87% -    Documentation progress: 59.17% +    Documentation progress: 59.40% --- @@ -121,11 +121,11 @@ As of June 11, 2025, this is our current score: ``` ==================================================================== ADVENTURE ONE (ASM -> C Decompilation) - -------------- 90.89% Complete (91.67% NON_MATCHING) --------------- + -------------- 90.87% Complete (91.65% NON_MATCHING) --------------- # Decompiled functions: 1913 - # GLOBAL_ASM remaining: 38 + # GLOBAL_ASM remaining: 37 # NON_MATCHING functions: 4 - # NON_EQUIVALENT WIP functions: 19 + # NON_EQUIVALENT WIP functions: 29 --------------------------- Game Status ---------------------------- Balloons: 42/47, Keys: 4/4, Trophies: 4/5 T.T. Amulets: 4/4, Wizpig Amulets: 4/4 @@ -133,14 +133,14 @@ As of June 11, 2025, this is our current score: We are racing in Star City. (Lap 3/3) ==================================================================== ADVENTURE TWO (Cleanup & Documentation) - ------------------------- 59.17% Complete -------------------------- - # Documented functions: 1206 - # Undocumented remaining: 447 + ------------------------- 59.40% Complete -------------------------- + # Documented functions: 1208 + # Undocumented remaining: 445 --------------------------- Game Status ---------------------------- Balloons: 29/47, Keys: 3/4, Trophies: 2/5 T.T. Amulets: 3/4, Wizpig Amulets: 2/4 -------------------------------------------------------------------- - We are collecting silver coins in Treasure Caves. (0/8 silver coins) + We are collecting silver coins in Treasure Caves. (1/8 silver coins) ==================================================================== ``` diff --git a/include/f3ddkr.h b/include/f3ddkr.h index 7527dbba..ffcc3c02 100644 --- a/include/f3ddkr.h +++ b/include/f3ddkr.h @@ -6,6 +6,44 @@ // This file is an extension of PR/gbi.h +/** + * This section explains how billboarding works from a 3D geometry perspective. + * Several modifications were made to the RSP to implement billboarding: + * + * 1) For the gSPVertexDKR command, the last parameter is either 0 or 1 (G_VTX_APPEND): + * - If 0: Vertices are always written to the beginning of RSP's internal vertex array, and their count is stored. + * - If 1: Vertices are appended after those written with flag 0. + * + * 2) The commands gDkrEnableBillboard and gDkrDisableBillboard control billboarding: + * - When gDkrEnableBillboard is active, vertices processed by gSPVertexDKR have their coordinates added to + * the coordinates of vertex 0 in RSP's vertex array. + * - This addition occurs after MVP matrix transformation but before perspective division (normalization of (x,y,z,w) to (x/w,y/w,z/w,1)). + * + * Implementation Steps: + * 1) First, push an anchor vertex using gSPVertexDKR. This vertex should have a standard MVP matrix applied + * (with normal perspective and camera setup like other 3D objects). Inside RSP, this vertex gets transformed + * to clip coordinates (x,y,z,w). Note: with standard perspective, w represents the vertex's distance from the camera. + * + * 2) Create a billboard matrix (simplest case: identity matrix) and store it in slot G_MTX_DKR_INDEX_2. + * More complex versions can tilt the sprite or scale it along two axes. This matrix will be used for subsequent + * billboard vertices (without camera or projection transformations). + * + * 3) Enable billboarding with gDkrEnableBillboard. All subsequent billboard vertices will be added to the anchor vertex. + * + * 4) Push billboard vertices using gSPVertexDKR and render primitives with gSPPolygon. These vertices use sprite-space coordinates. + * Example: For a 32×64 sprite, vertices would be (0,0,0), (32,0,0), (32,64,0), (0,64,0). + * + * How Coordinate Addition Works (Perspective Explanation): + * Let the anchor vertex have coordinates (x,y,z,w) and our sprite be 32×64 as above. After normalization: + * anchor becomes (x/w,y/w,z/w,1). A billboard vertex would have (x+32,y,z,w) → ((x+32)/w,y/w,z/w,1). + * + * Screen-space implications (assuming 320px viewport width): + * The sprite's on-screen width becomes (32/w)*160 pixels. Since w equals distance from camera, sprites + * farther away appear smaller (creating perspective). However, additional scaling is needed because + * without accounting for field of view and aspect ratio, a 32×64 sprite wouldn't match the size of + * a 32×64 3D object at the same location. + */ + // Color combiner values. // cycle 1 modes @@ -112,6 +150,7 @@ #define G_MTX_DKR_INDEX_2 2 #define G_MW_BILLBOARD 0x02 //0x01 = billboarding enabled, 0x00 = disabled #define G_MW_MVPMATRIX 0x0A //Specifies the index of the mvp matrix. +#define G_VTX_APPEND 1 #define gDkrEnableBillboard(pkt) \ gMoveWd(pkt, G_MW_BILLBOARD, 0, 1) diff --git a/include/structs.h b/include/structs.h index 68ac4d0a..9c4ade54 100644 --- a/include/structs.h +++ b/include/structs.h @@ -112,8 +112,8 @@ typedef struct TextureHeader { // 6 = IA4 // 7 = CI4 (16 colors) // 8 = CI8 (64 colors) - /* 0x03 */ s8 unk3; - /* 0x04 */ s8 unk4; + /* 0x03 */ s8 posX; // X coordinate of the texture in the sprite's 2D space + /* 0x04 */ s8 posY; // Y coordinate of the texture in the sprite's 2D space /* 0x05 */ u8 numberOfInstances; // Always 1 in the ROM. /* 0x06 */ s16 flags; // 0x04 = Interlaced texture @@ -151,19 +151,21 @@ typedef struct ShadowHeapProperties { s16 vtxCount; // Offset from the center of the screen. } ShadowHeapProperties; +typedef struct SpriteAsset { + /* 0x00 */ s16 baseTextureId; + /* 0x02 */ s16 numberOfFrames; // 1 means static texture + /* 0x04 */ Vec2s anchor; // 2D coordinates on the sprite used as the anchor point for positioning in 3D space + /* 0x08 */ s32 unused_field; + /* 0x0C */ u8 frameTexOffsets[1]; // actual size is numberOfFrames + 1 +} SpriteAsset; + typedef struct Sprite { - /* 0x00 */ s16 baseTextureId; - /* 0x02 */ s16 numberOfFrames; // 1 means static texture - /* 0x04 */ s16 numberOfInstances; - /* 0x06 */ s16 drawFlags; - union { - /* 0x08 */ TextureHeader **frames; - /* 0x08 */ Gfx *gfx[1]; - }; - union { - /* 0x0C */ u8 val[1]; // Actual size varies. - /* 0x0C */ u8 *ptr[1]; // Display list? - } unkC; + /* 0x00 */ s16 numberOfFrames; // 1 means static texture + /* 0x02 */ s16 numberOfTextures; + /* 0x04 */ s16 numberOfInstances; + /* 0x06 */ s16 drawFlags; + /* 0x08 */ TextureHeader **textures; + /* 0x0C */ Gfx *frames[1]; // Actual size varies. } Sprite; /* Size: 0x20 bytes */ diff --git a/src/audio_spatial.c b/src/audio_spatial.c index 8b2739c8..a06ff6c7 100644 --- a/src/audio_spatial.c +++ b/src/audio_spatial.c @@ -194,7 +194,7 @@ void audspat_update_all(Object **objList, s32 numObjects, s32 updateRate) { jingleVolume = 0; viewportLayout = cam_get_viewport_layout(); numCameras = cam_set_layout(viewportLayout); - cameras = get_cutscene_camera_segment(); + cameras = cam_get_cameras(); // Update audio points for (i = 0; i < gNumAudioPoints; i++) { diff --git a/src/camera.c b/src/camera.c index 16b7a1f2..15e5bbc1 100644 --- a/src/camera.c +++ b/src/camera.c @@ -10,6 +10,8 @@ #include "PRinternal/piint.h" #include "PRinternal/viint.h" +#define CAMERA_MODEL_STACK_SIZE 5 + /************ .data ************/ s8 gAntiPiracyViewport = FALSE; @@ -80,7 +82,7 @@ s32 gNumCameras; UNUSED s32 D_80120CEC; ObjectTransform gCameraTransform; s32 gMtxOriginID; -s32 gSpriteAnimOff; +s32 gSpriteAnimMode; f32 gCurCamFOV; s8 gCutsceneCameraActive; s8 gAdjustViewportHeight; @@ -88,21 +90,21 @@ s32 gNoCamShake; s32 gModelMatrixStackPos; s32 gCameraMatrixPos; UNUSED s32 D_80120D24; -f32 gModelMatrixViewX[6]; -f32 gModelMatrixViewY[6]; -f32 gModelMatrixViewZ[5]; +f32 gCameraRelPosStackX[CAMERA_MODEL_STACK_SIZE + 1]; +f32 gCameraRelPosStackY[CAMERA_MODEL_STACK_SIZE + 1]; +f32 gCameraRelPosStackZ[CAMERA_MODEL_STACK_SIZE]; u16 perspNorm; -MtxF *gModelMatrixF[6]; -Mtx *gModelMatrix[6]; -f32 D_80120DA0[5 * 16]; +MtxF *gModelMatrixF[CAMERA_MODEL_STACK_SIZE + 1]; +Mtx *gModelMatrix[CAMERA_MODEL_STACK_SIZE + 1]; +f32 D_80120DA0[CAMERA_MODEL_STACK_SIZE * 16]; MtxF gPerspectiveMatrixF; +MtxF gViewProjMatrixF; MtxF gViewMatrixF; -MtxF gCameraMatrixF; -MtxF gProjectionMatrixF; -Mtx gProjectionMatrix; -UNUSED Mtx gUnusedProjectionMatrix; // Copied to the same way as gProjectionMatrix, but not actually used. +MtxF gInverseViewMatrixF; +Mtx gPerspectiveMatrix; +UNUSED Mtx gInverseViewMatrix; MtxF gCurrentModelMatrixF; -MtxF gCurrentModelMatrixS; +MtxF gCurrentMVPMatrixF; /******************************/ @@ -130,7 +132,7 @@ void cam_init(void) { gModelMatrixStackPos = 0; gCameraMatrixPos = 0; gViewportLayout = 0; - gSpriteAnimOff = FALSE; + gSpriteAnimMode = SPRITE_ANIM_NORMALIZED; gNoCamShake = FALSE; gAdjustViewportHeight = FALSE; gAntiPiracyViewport = FALSE; @@ -144,7 +146,7 @@ void cam_init(void) { guPerspectiveF(gPerspectiveMatrixF, &perspNorm, CAMERA_DEFAULT_FOV, CAMERA_ASPECT, CAMERA_NEAR, CAMERA_FAR, CAMERA_SCALE); - mtxf_to_mtx(&gPerspectiveMatrixF, &gProjectionMatrix); + mtxf_to_mtx(&gPerspectiveMatrixF, &gPerspectiveMatrix); gCurCamFOV = CAMERA_DEFAULT_FOV; } @@ -196,7 +198,7 @@ void cam_set_fov(f32 camFieldOfView) { gCurCamFOV = camFieldOfView; guPerspectiveF(gPerspectiveMatrixF, &perspNorm, camFieldOfView, CAMERA_ASPECT, CAMERA_NEAR, CAMERA_FAR, CAMERA_SCALE); - mtxf_to_mtx(&gPerspectiveMatrixF, &gProjectionMatrix); + mtxf_to_mtx(&gPerspectiveMatrixF, &gPerspectiveMatrix); } } @@ -206,14 +208,14 @@ void cam_set_fov(f32 camFieldOfView) { UNUSED void cam_reset_fov(void) { guPerspectiveF(gPerspectiveMatrixF, &perspNorm, CAMERA_DEFAULT_FOV, CAMERA_ASPECT, CAMERA_NEAR, CAMERA_FAR, CAMERA_SCALE); - mtxf_to_mtx(&gPerspectiveMatrixF, &gProjectionMatrix); + mtxf_to_mtx(&gPerspectiveMatrixF, &gPerspectiveMatrix); } /** * Return the current fixed point model matrix. */ UNUSED MtxF *mtx_get_modelmtx_s16(void) { - return &gCurrentModelMatrixS; + return &gCurrentMVPMatrixF; } /** @@ -643,7 +645,7 @@ void viewport_main(Gfx **dlist, Mtx **mats) { gScreenViewports[gActiveCameraID].scissorY2); viewport_rsp_set(dlist, 0, 0, 0, 0); gActiveCameraID = tempCameraID; - if (mats != 0) { + if (mats != NULL) { func_80067D3C(dlist, mats); } gActiveCameraID = originalCameraID; @@ -863,11 +865,11 @@ void viewport_scissor(Gfx **dList) { // Official Name: camGetPlayerProjMtx / camSetProjMtx - ?? void func_80067D3C(Gfx **dList, UNUSED Mtx **mtx) { - s32 camID; + s32 originalCamID; gSPPerspNormalize((*dList)++, perspNorm); - camID = gActiveCameraID; + originalCamID = gActiveCameraID; if (gCutsceneCameraActive) { gActiveCameraID += 4; } @@ -884,8 +886,8 @@ void func_80067D3C(Gfx **dList, UNUSED Mtx **mtx) { } gCameraTransform.z_position = -gCameras[gActiveCameraID].trans.z_position; - mtxf_from_inverse_transform(&gCameraMatrixF, &gCameraTransform); - mtxf_mul(&gCameraMatrixF, &gPerspectiveMatrixF, &gViewMatrixF); + mtxf_from_inverse_transform(&gViewMatrixF, &gCameraTransform); + mtxf_mul(&gViewMatrixF, &gPerspectiveMatrixF, &gViewProjMatrixF); gCameraTransform.rotation.y_rotation = -0x8000 - gCameras[gActiveCameraID].trans.rotation.y_rotation; gCameraTransform.rotation.x_rotation = @@ -899,10 +901,10 @@ void func_80067D3C(Gfx **dList, UNUSED Mtx **mtx) { } gCameraTransform.z_position = gCameras[gActiveCameraID].trans.z_position; - mtxf_from_transform(&gProjectionMatrixF, &gCameraTransform); - mtxf_to_mtx(&gProjectionMatrixF, &gUnusedProjectionMatrix); + mtxf_from_transform(&gInverseViewMatrixF, &gCameraTransform); + mtxf_to_mtx(&gInverseViewMatrixF, &gInverseViewMatrix); - gActiveCameraID = camID; + gActiveCameraID = originalCamID; } /** @@ -942,7 +944,7 @@ void mtx_ortho(Gfx **dList, Mtx **mtx) { // clang-format off // Required to be one line, but the "\" fixes that. for (j = 0; j < 4; j++) { \ - gViewMatrixF[i][j] = gOrthoMatrixF[i][j]; + gViewProjMatrixF[i][j] = gOrthoMatrixF[i][j]; } // clang-format on } @@ -955,9 +957,9 @@ void mtx_ortho(Gfx **dList, Mtx **mtx) { */ void mtx_perspective(Gfx **dList, Mtx **mtx) { mtxf_from_inverse_transform(&gCurrentModelMatrixF, &D_800DD288); - mtxf_mul(&gCurrentModelMatrixF, &gPerspectiveMatrixF, &gViewMatrixF); + mtxf_mul(&gCurrentModelMatrixF, &gPerspectiveMatrixF, &gViewProjMatrixF); mtxf_from_inverse_transform(gModelMatrixF[0], &D_800DD2A0); - mtxf_mul(gModelMatrixF[0], &gViewMatrixF, &gCurrentModelMatrixF); + mtxf_mul(gModelMatrixF[0], &gViewProjMatrixF, &gCurrentModelMatrixF); mtxf_to_mtx(&gCurrentModelMatrixF, *mtx); gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL((*mtx)++), G_MTX_DKR_INDEX_0); gModelMatrixStackPos = 0; @@ -1019,37 +1021,45 @@ UNUSED const char D_800E6F44[] = "cameraPushSprMtx: model stack overflow!!\n"; */ void mtx_world_origin(Gfx **dList, Mtx **mtx) { mtxf_from_translation(gModelMatrixF[gModelMatrixStackPos], 0.0f, 0.0f, 0.0f); - mtxf_mul(gModelMatrixF[gModelMatrixStackPos], &gViewMatrixF, &gCurrentModelMatrixF); + mtxf_mul(gModelMatrixF[gModelMatrixStackPos], &gViewProjMatrixF, &gCurrentModelMatrixF); mtxf_to_mtx(&gCurrentModelMatrixF, *mtx); gModelMatrix[gModelMatrixStackPos] = *mtx; gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL((*mtx)++), gMtxOriginID); } /** - * If set to true, disables animated sprite frames. - * Used when the sprite frame is already established before calling to draw. + * Sets the sprite animation mode. + * This determines how the animation frame is interpreted: either as a frame index, + * or as a normalized progress value from 0 to 255. */ -void sprite_anim_off(s32 setting) { - gSpriteAnimOff = setting; +void cam_set_sprite_anim_mode(s32 setting) { + gSpriteAnimMode = setting; } /** - * Calculates angle from object to camera, then renders the sprite as a billboard, facing the camera. + * Renders a sprite in 3D space as a billboard. + * + * If the sprite represents a vehicle part (e.g., wheel, propeller, fan), + * the function calculates the appropriate animation frame based on the object's + * orientation relative to the camera, ensuring the sprite correctly matches + * the viewing angle. It also orients the sprite properly in 3D space with tilt. + * + * For regular sprites, it sets up a standard billboard that always faces the camera. */ -s32 render_sprite_billboard(Gfx **dList, Mtx **mtx, Vertex **vertexList, Object *obj, Sprite *arg4, s32 flags) { +s32 render_sprite_billboard(Gfx **dList, Mtx **mtx, Vertex **vtx, Object *obj, Sprite *sprite, s32 flags) { f32 diffX; f32 diffY; Vertex *v; f32 lateralDist; f32 sineY; f32 cosY; - f32 sp44; + f32 temp; f32 diffZ; s32 tanX; s32 tanY; - s32 angleDiff; + s32 tiltAngle; s32 result; - s32 textureFrame; + s32 frameID; if (obj == NULL) { stubbed_printf("\nCam do 2D sprite called with NULL pointer!"); @@ -1057,40 +1067,59 @@ s32 render_sprite_billboard(Gfx **dList, Mtx **mtx, Vertex **vertexList, Object result = TRUE; if (flags & RENDER_VEHICLE_PART) { - diffX = gModelMatrixViewX[gCameraMatrixPos] - obj->segment.trans.x_position; - diffY = gModelMatrixViewY[gCameraMatrixPos] - obj->segment.trans.y_position; - diffZ = gModelMatrixViewZ[gCameraMatrixPos] - obj->segment.trans.z_position; + // Vehicle parts like wheels, propellers, and fans are implemented as sprites, + // each with 16 frames representing different orientations. + // This requires calculating the correct frame based on the relative orientation + // between the object and the camera, as well as properly orienting the sprite in 3D space. + + // Calculate camera position relative to the object's position + diffX = gCameraRelPosStackX[gCameraMatrixPos] - obj->segment.trans.x_position; + diffY = gCameraRelPosStackY[gCameraMatrixPos] - obj->segment.trans.y_position; + diffZ = gCameraRelPosStackZ[gCameraMatrixPos] - obj->segment.trans.z_position; + + // Rotate camera coordinates by the object's yaw rotation + // to get the camera orientation relative to the vehicle, + // e.g., to determine if we view the wheel from the side. sineY = sins_f(obj->segment.trans.rotation.y_rotation); cosY = coss_f(obj->segment.trans.rotation.y_rotation); - sp44 = (diffX * cosY) + (diffZ * sineY); + + temp = (diffX * cosY) + (diffZ * sineY); diffZ = (diffZ * cosY) - (diffX * sineY); - tanY = arctan2_f(sp44, sqrtf((diffY * diffY) + (diffZ * diffZ))); - tanX = -sins_s16(arctan2_f(sp44, diffZ)) >> 8; + diffX = temp; + + // Calculate the angle between the camera direction and the vertical plane of the vehicle + tanY = arctan2_f(diffX, sqrtf((diffY * diffY) + (diffZ * diffZ))); + + tanX = -sins_s16(arctan2_f(diffX, diffZ)) >> 8; if (diffZ < 0.0f) { diffZ = -diffZ; tanX = 1 - tanX; tanY = -tanY; } - angleDiff = arctan2_f(diffY, diffZ); - if (angleDiff > 0x8000) { - angleDiff -= 0x10000; + + tiltAngle = arctan2_f(diffY, diffZ); + if (tiltAngle > 0x8000) { + tiltAngle -= 0x10000; } - angleDiff = (angleDiff * tanX) >> 8; - textureFrame = (tanY >> 7) & 0xFF; - if (textureFrame > 127) { + tiltAngle = (tiltAngle * tanX) >> 8; + frameID = (tanY >> 7) & 0xFF; + if (frameID > 127) { stubbed_printf("CamDo2DSprite FrameNo Overflow !!!\n"); - textureFrame = 255 - textureFrame; - angleDiff += 0x8000; + frameID = 255 - frameID; + tiltAngle += 0x8000; result = FALSE; } - textureFrame *= 2; - diffX = gModelMatrixViewX[gCameraMatrixPos] - obj->segment.trans.x_position; - diffY = gModelMatrixViewY[gCameraMatrixPos] - obj->segment.trans.y_position; - diffZ = gModelMatrixViewZ[gCameraMatrixPos] - obj->segment.trans.z_position; + frameID *= 2; + + // Construct the model matrix for the sprite, + // orienting it perpendicular to the camera and applying the calculated tilt angle. + diffX = gCameraRelPosStackX[gCameraMatrixPos] - obj->segment.trans.x_position; + diffY = gCameraRelPosStackY[gCameraMatrixPos] - obj->segment.trans.y_position; + diffZ = gCameraRelPosStackZ[gCameraMatrixPos] - obj->segment.trans.z_position; lateralDist = sqrtf((diffX * diffX) + (diffZ * diffZ)); gCameraTransform.rotation.y_rotation = arctan2_f(diffX, diffZ); gCameraTransform.rotation.x_rotation = -arctan2_f(diffY, lateralDist); - gCameraTransform.rotation.z_rotation = angleDiff; + gCameraTransform.rotation.z_rotation = tiltAngle; gCameraTransform.scale = obj->segment.trans.scale; gCameraTransform.x_position = obj->segment.trans.x_position; gCameraTransform.y_position = obj->segment.trans.y_position; @@ -1098,13 +1127,18 @@ s32 render_sprite_billboard(Gfx **dList, Mtx **mtx, Vertex **vertexList, Object mtxf_from_transform(&gCurrentModelMatrixF, &gCameraTransform); gModelMatrixStackPos++; mtxf_mul(&gCurrentModelMatrixF, gModelMatrixF[gModelMatrixStackPos - 1], gModelMatrixF[gModelMatrixStackPos]); - mtxf_mul(gModelMatrixF[gModelMatrixStackPos], &gViewMatrixF, &gCurrentModelMatrixF); + mtxf_mul(gModelMatrixF[gModelMatrixStackPos], &gViewProjMatrixF, &gCurrentModelMatrixF); mtxf_to_mtx(&gCurrentModelMatrixF, *mtx); gModelMatrix[gModelMatrixStackPos] = *mtx; gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL((*mtx)++), G_MTX_DKR_INDEX_2); + // Push an empty vertex because sprite vertices are hardcoded to start from index 1, + // and billboard mode is not enabled for vehicle parts. gSPVertexDKR((*dList)++, OS_K0_TO_PHYSICAL(&gVehiclePartVertex), 1, 0); } else { - v = *vertexList; + // For non-vehicle parts, set up a standard billboard. + + // Push the anchor vertex at the object's position + v = *vtx; v->x = obj->segment.trans.x_position; v->y = obj->segment.trans.y_position; v->z = obj->segment.trans.z_position; @@ -1112,43 +1146,61 @@ s32 render_sprite_billboard(Gfx **dList, Mtx **mtx, Vertex **vertexList, Object v->g = 255; v->b = 255; v->a = 255; - gSPVertexDKR((*dList)++, OS_K0_TO_PHYSICAL(*vertexList), 1, 0); - (*vertexList)++; + gSPVertexDKR((*dList)++, OS_K0_TO_PHYSICAL(*vtx), 1, 0); + (*vtx)++; + + // Create a billboard matrix that compensates for camera tilt, + // so the sprite tilts consistently with other objects relative to the camera. + // Aspect ratio compensation is applied to maintain proper sprite proportions on screen. if (!gCutsceneCameraActive) { - angleDiff = gCameras[gActiveCameraID].trans.rotation.z_rotation + obj->segment.trans.rotation.z_rotation; + tiltAngle = gCameras[gActiveCameraID].trans.rotation.z_rotation + obj->segment.trans.rotation.z_rotation; } else { - angleDiff = + tiltAngle = gCameras[gActiveCameraID + 4].trans.rotation.z_rotation + obj->segment.trans.rotation.z_rotation; } - textureFrame = obj->segment.animFrame; + frameID = obj->segment.animFrame; gModelMatrixStackPos++; - mtxf_billboard(gModelMatrixF[gModelMatrixStackPos], angleDiff, obj->segment.trans.scale, gVideoAspectRatio); + mtxf_billboard(gModelMatrixF[gModelMatrixStackPos], tiltAngle, obj->segment.trans.scale, gVideoAspectRatio); mtxf_to_mtx(gModelMatrixF[gModelMatrixStackPos], *mtx); gModelMatrix[gModelMatrixStackPos] = *mtx; gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL((*mtx)++), G_MTX_DKR_INDEX_2); + // Enable billboard mode; subsequent vertices will be rendered relative to the anchor point gDkrEnableBillboard((*dList)++); } - if (gSpriteAnimOff == FALSE) { - textureFrame = ((textureFrame & 0xFF) * arg4->baseTextureId) >> 8; + // Calculate the correct animation frame based on the current animation mode. + if (gSpriteAnimMode == SPRITE_ANIM_NORMALIZED) { + frameID = ((frameID & 0xFF) * sprite->numberOfFrames) >> 8; } + + // The RENDER_ANTI_ALIASING flag shares the same value as RENDER_VEHICLE_PART, + // so we must clear RENDER_VEHICLE_PART from flags to avoid conflicts. + // Anti-aliasing is automatically enabled for semi-transparent sprites. flags &= ~RENDER_VEHICLE_PART; if (flags & RENDER_SEMI_TRANSPARENT) { flags |= RENDER_ANTI_ALIASING; } - material_load_simple(dList, arg4->drawFlags | (flags & (RENDER_FOG_ACTIVE | RENDER_SEMI_TRANSPARENT | - RENDER_Z_COMPARE | RENDER_ANTI_ALIASING))); + + // Load material and set render flags including fog, transparency, z-compare, and anti-aliasing + material_load_simple(dList, sprite->drawFlags | (flags & (RENDER_FOG_ACTIVE | RENDER_SEMI_TRANSPARENT | + RENDER_Z_COMPARE | RENDER_ANTI_ALIASING))); + if (!(flags & RENDER_Z_UPDATE)) { gDPSetPrimColor((*dList)++, 0, 0, 255, 255, 255, 255); } - gSPDisplayList((*dList)++, arg4->gfx[textureFrame + 1]); + gSPDisplayList((*dList)++, sprite->frames[frameID]); + + // Pop the model matrix stack and select the appropriate matrix index for rendering gModelMatrixStackPos--; if (gModelMatrixStackPos == 0) { - textureFrame = G_MTX_DKR_INDEX_0; + frameID = G_MTX_DKR_INDEX_0; } else { - textureFrame = G_MTX_DKR_INDEX_1; + frameID = G_MTX_DKR_INDEX_1; } - gSPSelectMatrixDKR((*dList)++, textureFrame); + gSPSelectMatrixDKR((*dList)++, frameID); + + // Disable billboard mode gDkrDisableBillboard((*dList)++); + return result; } @@ -1161,61 +1213,65 @@ void render_ortho_triangle_image(Gfx **dList, Mtx **mtx, Vertex **vtx, ObjectSeg UNUSED s32 pad; f32 scale; s32 index; - Vertex *temp_v1; + Vertex *vertex; MtxF aspectMtxF; MtxF scaleMtxF; - if (sprite != NULL) { - temp_v1 = *vtx; - temp_v1->x = segment->trans.x_position; - temp_v1->y = segment->trans.y_position; - temp_v1->z = segment->trans.z_position; - temp_v1->r = 255; // These don't actually do anything since vertex colours are disabled anyway. - temp_v1->g = 255; - temp_v1->b = 255; - temp_v1->a = 255; - gSPVertexDKR((*dList)++, OS_K0_TO_PHYSICAL(*vtx), 1, 0); - (*vtx)++; // Can't be done in the macro? - index = segment->animFrame; - gModelMatrixStackPos++; - gCameraTransform.rotation.y_rotation = -segment->trans.rotation.y_rotation; - gCameraTransform.rotation.x_rotation = -segment->trans.rotation.x_rotation; - gCameraTransform.rotation.z_rotation = - gCameras[gActiveCameraID].trans.rotation.z_rotation + segment->trans.rotation.z_rotation; - gCameraTransform.x_position = 0.0f; - gCameraTransform.y_position = 0.0f; - gCameraTransform.z_position = 0.0f; - if (gAdjustViewportHeight) { - scale = segment->trans.scale; - mtxf_from_scale(&scaleMtxF, scale, scale, 1.0f); - mtxf_billboard(&aspectMtxF, 0, 1.0f, gVideoAspectRatio); - mtxf_mul(&aspectMtxF, &scaleMtxF, &gCurrentModelMatrixF); - } else { - scale = segment->trans.scale; - mtxf_from_scale(&gCurrentModelMatrixF, scale, scale, 1.0f); - } - mtxf_from_inverse_transform(&aspectMtxF, &gCameraTransform); - mtxf_mul(&gCurrentModelMatrixF, &aspectMtxF, gModelMatrixF[gModelMatrixStackPos]); - mtxf_to_mtx(gModelMatrixF[gModelMatrixStackPos], *mtx); - gModelMatrix[gModelMatrixStackPos] = *mtx; - gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL((*mtx)++), G_MTX_DKR_INDEX_2); - gDkrEnableBillboard((*dList)++); - if (gSpriteAnimOff == FALSE) { - index = (((u8) index) * sprite->baseTextureId) >> 8; - } - material_load_simple(dList, sprite->drawFlags | flags); - if (index >= sprite->baseTextureId) { - index = sprite->baseTextureId - 1; - } - gSPDisplayList((*dList)++, sprite->unkC.ptr[index]); - if (--gModelMatrixStackPos == 0) { - index = G_MTX_DKR_INDEX_0; - } else { - index = G_MTX_DKR_INDEX_1; - } - gSPSelectMatrixDKR((*dList)++, index); - gDkrDisableBillboard((*dList)++); + if (sprite == NULL) { + return; } + + vertex = *vtx; + vertex->x = segment->trans.x_position; + vertex->y = segment->trans.y_position; + vertex->z = segment->trans.z_position; + vertex->r = 255; // These don't actually do anything since vertex colours are disabled anyway. + vertex->g = 255; + vertex->b = 255; + vertex->a = 255; + + gSPVertexDKR((*dList)++, OS_K0_TO_PHYSICAL(*vtx), 1, 0); + (*vtx)++; // Can't be done in the macro? + index = segment->animFrame; + + gModelMatrixStackPos++; + gCameraTransform.rotation.y_rotation = -segment->trans.rotation.y_rotation; + gCameraTransform.rotation.x_rotation = -segment->trans.rotation.x_rotation; + gCameraTransform.rotation.z_rotation = + gCameras[gActiveCameraID].trans.rotation.z_rotation + segment->trans.rotation.z_rotation; + gCameraTransform.x_position = 0.0f; + gCameraTransform.y_position = 0.0f; + gCameraTransform.z_position = 0.0f; + if (gAdjustViewportHeight) { + scale = segment->trans.scale; + mtxf_from_scale(&scaleMtxF, scale, scale, 1.0f); + mtxf_billboard(&aspectMtxF, 0, 1.0f, gVideoAspectRatio); + mtxf_mul(&aspectMtxF, &scaleMtxF, &gCurrentModelMatrixF); + } else { + scale = segment->trans.scale; + mtxf_from_scale(&gCurrentModelMatrixF, scale, scale, 1.0f); + } + mtxf_from_inverse_transform(&aspectMtxF, &gCameraTransform); + mtxf_mul(&gCurrentModelMatrixF, &aspectMtxF, gModelMatrixF[gModelMatrixStackPos]); + mtxf_to_mtx(gModelMatrixF[gModelMatrixStackPos], *mtx); + gModelMatrix[gModelMatrixStackPos] = *mtx; + gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL((*mtx)++), G_MTX_DKR_INDEX_2); + gDkrEnableBillboard((*dList)++); + if (gSpriteAnimMode == SPRITE_ANIM_NORMALIZED) { + index = (((u8) index) * sprite->numberOfFrames) >> 8; + } + material_load_simple(dList, sprite->drawFlags | flags); + if (index >= sprite->numberOfFrames) { + index = sprite->numberOfFrames - 1; + } + gSPDisplayList((*dList)++, sprite->frames[index]); + if (--gModelMatrixStackPos == 0) { + index = G_MTX_DKR_INDEX_0; + } else { + index = G_MTX_DKR_INDEX_1; + } + gSPSelectMatrixDKR((*dList)++, index); + gDkrDisableBillboard((*dList)++); } /** @@ -1317,49 +1373,69 @@ void mtx_shear_push(Gfx **dList, Mtx **mtx, Object *obj, Object *objBase, f32 sh (arg2_zPos * (cossf_x_arg3 * cossf_y_arg3)) + arg3_zPos; matrix_mult[3][3] = 1.0f; - mtxf_mul(&matrix_mult, &gViewMatrixF, &gCurrentModelMatrixS); - mtxf_to_mtx(&gCurrentModelMatrixS, *mtx); + mtxf_mul(&matrix_mult, &gViewProjMatrixF, &gCurrentMVPMatrixF); + mtxf_to_mtx(&gCurrentMVPMatrixF, *mtx); gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL((*mtx)++), G_MTX_DKR_INDEX_1); } /** - * Generate a model view matrix, convert to fixed point, then push it to the RSP. + * Pushes a model matrix onto the model matrix stack, generates an MVP matrix from it, and uploads it to the RSP. + * Also computes the camera's position relative to the new model (at the top of the stack), + * and pushes it onto the camera-relative position stack. + * This relative camera position can later be used for sprite positioning. + * * Official Name: camPushModelMtx */ s32 mtx_cam_push(Gfx **dList, Mtx **mtx, ObjectTransform *trans, f32 scaleY, f32 offsetY) { - f32 tempX; - f32 tempY; - f32 tempZ; + f32 camRelX, camRelY, camRelZ; s32 index; f32 scaleFactor; + // Generate model transformation matrix from input transform mtxf_from_transform(&gCurrentModelMatrixF, trans); + + // Apply optional Y-axis translation if (offsetY != 0.0f) { mtxf_translate_y(&gCurrentModelMatrixF, offsetY); } + + // Apply optional Y-axis scaling if (scaleY != 1.0f) { mtxf_scale_y(&gCurrentModelMatrixF, scaleY); } + + // Multiply model matrix with parent matrix (top of the model stack) mtxf_mul(&gCurrentModelMatrixF, gModelMatrixF[gModelMatrixStackPos], gModelMatrixF[gModelMatrixStackPos + 1]); - mtxf_mul(gModelMatrixF[gModelMatrixStackPos + 1], &gViewMatrixF, &gCurrentModelMatrixS); - mtxf_to_mtx(&gCurrentModelMatrixS, *mtx); + + // Compute the model-view-projection matrix + mtxf_mul(gModelMatrixF[gModelMatrixStackPos + 1], &gViewProjMatrixF, &gCurrentMVPMatrixF); + + // Convert the MVP matrix to fixed-point format and upload to RSP + mtxf_to_mtx(&gCurrentMVPMatrixF, *mtx); gModelMatrixStackPos++; - gModelMatrix[0, gModelMatrixStackPos] = *mtx; // Should be [gModelMatrixStackPos] - if (gModelMatrixStackPos >= ARRAY_COUNT(gModelMatrix)) { + gModelMatrix[gModelMatrixStackPos] = *mtx; + + if (gModelMatrixStackPos > CAMERA_MODEL_STACK_SIZE) { stubbed_printf("cameraPushModelMtx: model stack overflow!!\n"); } - if (1) {} - if (1) {}; // Fakematch + gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL((*mtx)++), G_MTX_DKR_INDEX_1); - mtxf_transform_point(gModelMatrixF[gModelMatrixStackPos], 0.0f, 0.0f, 0.0f, &tempX, &tempY, &tempZ); + + // Compute world-space position of the model's origin (0, 0, 0) + mtxf_transform_point(gModelMatrixF[gModelMatrixStackPos], 0.0f, 0.0f, 0.0f, &camRelX, &camRelY, &camRelZ); + index = gActiveCameraID; - // Use cutscene cam as a base if applicable. if (gCutsceneCameraActive) { + // Use cutscene camera if active index += 4; } - tempX = gCameras[index].trans.x_position - tempX; - tempY = gCameras[index].trans.y_position - tempY; - tempZ = gCameras[index].trans.z_position - tempZ; + + // Compute camera position relative to the model's origin in world space + camRelX = gCameras[index].trans.x_position - camRelX; + camRelY = gCameras[index].trans.y_position - camRelY; + camRelZ = gCameras[index].trans.z_position - camRelZ; + + // Convert camera position from world space to the model's local coordinate space gCameraTransform.rotation.y_rotation = -trans->rotation.y_rotation; gCameraTransform.rotation.x_rotation = -trans->rotation.x_rotation; gCameraTransform.rotation.z_rotation = -trans->rotation.z_rotation; @@ -1367,21 +1443,28 @@ s32 mtx_cam_push(Gfx **dList, Mtx **mtx, ObjectTransform *trans, f32 scaleY, f32 gCameraTransform.y_position = 0.0f; gCameraTransform.z_position = 0.0f; gCameraTransform.scale = 1.0f; + mtxf_from_inverse_transform(&gCurrentModelMatrixF, &gCameraTransform); - mtxf_transform_point(&gCurrentModelMatrixF, tempX, tempY, tempZ, &tempX, &tempY, &tempZ); + mtxf_transform_point(&gCurrentModelMatrixF, camRelX, camRelY, camRelZ, &camRelX, &camRelY, &camRelZ); + + // Adjust for model scale scaleFactor = 1.0f / trans->scale; - tempX *= scaleFactor; - tempY *= scaleFactor; - tempZ *= scaleFactor; + camRelX *= scaleFactor; + camRelY *= scaleFactor; + camRelZ *= scaleFactor; + + // Push camera position relative to the current model onto the stack gCameraMatrixPos++; - index = gCameraMatrixPos; - gModelMatrixViewX[index] = tempX; - gModelMatrixViewY[index] = tempY; - gModelMatrixViewZ[index] = tempZ; - if (0) { + gCameraRelPosStackX[gCameraMatrixPos] = camRelX; + gCameraRelPosStackY[gCameraMatrixPos] = camRelY; + gCameraRelPosStackZ[gCameraMatrixPos] = camRelZ; + + if (gCameraMatrixPos > CAMERA_MODEL_STACK_SIZE) { stubbed_printf("camPushModelMtx: bsp stack overflow!!\n"); } + #ifdef AVOID_UB + // Likely void in original code, but returns 0 to match waves_render. return 0; #endif } @@ -1425,7 +1508,7 @@ void mtx_head_push(Gfx **dList, Mtx **mtx, Object_68 *objGfx, s16 headAngle) { (-offsetZ * (sins_headAngle * sins_unk1C)) + offsetY; headMtxF[3][2] = (-offsetX * -sins_headAngle) + (-offsetZ * coss_headAngle) + offsetZ; headMtxF[3][3] = 1.0f; - mtxf_mul(&headMtxF, &gCurrentModelMatrixS, &rotationMtxF); + mtxf_mul(&headMtxF, &gCurrentMVPMatrixF, &rotationMtxF); mtxf_to_mtx(&rotationMtxF, *mtx); gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL((*mtx)++), G_MTX_DKR_INDEX_2); gSPSelectMatrixDKR((*dList)++, G_MTX_DKR_INDEX_1); @@ -1435,9 +1518,9 @@ void mtx_head_push(Gfx **dList, Mtx **mtx, Object_68 *objGfx, s16 headAngle) { * Writes the model matrix vector to the arguments. */ UNUSED void get_modelmatrix_vector(f32 *x, f32 *y, f32 *z) { - *x = gModelMatrixViewX[gCameraMatrixPos]; - *y = gModelMatrixViewY[gCameraMatrixPos]; - *z = gModelMatrixViewZ[gCameraMatrixPos]; + *x = gCameraRelPosStackX[gCameraMatrixPos]; + *y = gCameraRelPosStackY[gCameraMatrixPos]; + *z = gCameraRelPosStackZ[gCameraMatrixPos]; } /** @@ -1445,18 +1528,18 @@ UNUSED void get_modelmatrix_vector(f32 *x, f32 *y, f32 *z) { * If the stack pos is less than zero, set the RSP stack pos to 0. */ void mtx_pop(Gfx **dList) { + s32 temp; + gCameraMatrixPos--; gModelMatrixStackPos--; - { - s32 temp = gCameraMatrixPos; - if ((temp && temp) != 0) {} - if (temp > ARRAY_COUNT(gModelMatrixViewX)) { - stubbed_printf("camPopModelMtx: model stack negative overflow!!\n"); - // TODO: get the condition matching for this one too. - stubbed_printf("camPopModelMtx: bsp stack negative overflow!!\n"); - } - } // Fakematch + if (gModelMatrixStackPos < 0) { + stubbed_printf("camPopModelMtx: model stack negative overflow!!\n"); + } + + if ((temp = gCameraMatrixPos < 0)) { // temp required to match + stubbed_printf("camPopModelMtx: bsp stack negative overflow!!\n"); + } if (gModelMatrixStackPos > 0) { gSPMatrixDKR((*dList)++, OS_K0_TO_PHYSICAL(gModelMatrix[gModelMatrixStackPos]), G_MTX_DKR_INDEX_1); @@ -1502,14 +1585,14 @@ UNUSED void cam_rotate(s32 angleX, s32 angleY, s32 angleZ) { } /** - * Returns the segment data of the active camera, but won't apply the offset for cutscenes. + * Returns the active camera, but won't apply the offset for cutscenes. */ Camera *cam_get_active_camera_no_cutscenes(void) { return &gCameras[gActiveCameraID]; } /** - * Returns the segment data of the active camera. + * Returns the active camera. */ Camera *cam_get_active_camera(void) { if (gCutsceneCameraActive) { @@ -1522,32 +1605,32 @@ Camera *cam_get_active_camera(void) { * Returns the segment data of the active cutscene camera. * If no cutscene is active, return player 1's camera. */ -Camera *get_cutscene_camera_segment(void) { +Camera *cam_get_cameras(void) { if (gCutsceneCameraActive) { return &gCameras[4]; } - return &gCameras[PLAYER_ONE]; + return &gCameras[0]; } /** * Return the current floating point projection matrix. */ MtxF *get_projection_matrix_f32(void) { - return &gProjectionMatrixF; + return &gInverseViewMatrixF; } /** * Return the current fixed point projection matrix. */ Mtx *get_projection_matrix_s16(void) { - return &gProjectionMatrix; + return &gPerspectiveMatrix; } /** * Return the current camera matrix. */ MtxF *get_camera_matrix(void) { - return &gCameraMatrixF; + return &gViewMatrixF; } /** @@ -1556,7 +1639,7 @@ MtxF *get_camera_matrix(void) { f32 get_distance_to_camera(f32 x, f32 y, f32 z) { f32 ox, oy, oz; - mtxf_transform_point(&gCameraMatrixF, x, y, z, &ox, &oy, &oz); + mtxf_transform_point(&gViewMatrixF, x, y, z, &ox, &oy, &oz); return oz; } diff --git a/src/camera.h b/src/camera.h index a52ae012..1741f83e 100644 --- a/src/camera.h +++ b/src/camera.h @@ -37,6 +37,11 @@ #define VIEWPORT_AUTO 0x8000 +enum SpriteAnimMode { + SPRITE_ANIM_NORMALIZED, // animFrame is a normalized value from 0 to 255 mapped across frames + SPRITE_ANIM_FRAME_INDEX // animFrame is treated as the exact frame ID (e.g., 0, 1, 2...) +}; + enum ViewportCount { VIEWPORT_LAYOUT_1_PLAYER, VIEWPORT_LAYOUT_2_PLAYERS, @@ -124,10 +129,10 @@ void mtx_perspective(Gfx **dList, Mtx **mtx); void viewport_rsp_set(Gfx **dList, s32 halfWidth, s32 halfHeight, s32 centerX, s32 centerY); void viewport_reset(Gfx **dList); void mtx_world_origin(Gfx **dList, Mtx **mtx); -void sprite_anim_off(s32 setting); +void cam_set_sprite_anim_mode(s32 setting); Camera *cam_get_active_camera_no_cutscenes(void); Camera *cam_get_active_camera(void); -Camera *get_cutscene_camera_segment(void); +Camera *cam_get_cameras(void); MtxF *get_projection_matrix_f32(void); Mtx *get_projection_matrix_s16(void); MtxF *get_camera_matrix(void); diff --git a/src/game_ui.c b/src/game_ui.c index 3bd3d684..6dcfd226 100644 --- a/src/game_ui.c +++ b/src/game_ui.c @@ -804,9 +804,9 @@ void hud_render_player(Gfx **dList, Mtx **mtx, Vertex **vertexList, Object *obj, hud_main_time_trial(countdown, obj, updateRate); } else { if (cutscene_id() == 10) { - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); hud_balloons(racer); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } else { switch (get_current_level_race_type()) { case RACETYPE_DEFAULT: @@ -836,7 +836,7 @@ void hud_render_player(Gfx **dList, Mtx **mtx, Vertex **vertexList, Object *obj, } } if (racer->raceFinished == TRUE) { - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); if (is_in_time_trial()) { hud_time_trial_finish(racer, updateRate); } else if (cam_get_viewport_layout() == VIEWPORT_LAYOUT_1_PLAYER && racer->finishPosition == 1) { @@ -852,7 +852,7 @@ void hud_render_player(Gfx **dList, Mtx **mtx, Vertex **vertexList, Object *obj, block_95: hud_race_finish_multiplayer(racer, updateRate); } - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } gMinimapFade = FALSE; sprite_opaque(TRUE); @@ -949,7 +949,7 @@ void hud_audio_update(s32 updateRate) { void hud_main_race(s32 countdown, Object *obj, s32 updateRate) { Object_Racer *racer = &obj->unk64->racer; - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); hud_course_arrows(racer, updateRate); hud_wrong_way(racer, updateRate); hud_race_start(countdown, updateRate); @@ -968,7 +968,7 @@ void hud_main_race(s32 countdown, Object *obj, s32 updateRate) { } hud_weapon(obj, updateRate); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } /** @@ -1080,7 +1080,7 @@ void hud_main_treasure(s32 countdown, Object *obj, s32 updateRate) { racer = &obj->unk64->racer; racers = get_racer_objects(&numRacers); - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); hud_race_start(countdown, updateRate); switch (gNumActivePlayers) { case 1: @@ -1107,7 +1107,7 @@ void hud_main_treasure(s32 countdown, Object *obj, s32 updateRate) { rendermode_reset(&gHudDL); hud_bananas(racer, updateRate); hud_weapon(obj, updateRate); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } /** @@ -1116,7 +1116,7 @@ void hud_main_treasure(s32 countdown, Object *obj, s32 updateRate) { void hud_main_eggs(s32 countdown, Object *obj, s32 updateRate) { Object_Racer *racer = &obj->unk64->racer; if (racer->raceFinished == FALSE) { - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); hud_race_start(countdown, updateRate); hud_weapon(obj, updateRate); if ((127 - (updateRate * 2)) >= gCurrentHud->entry[HUD_EGG_CHALLENGE_ICON].challengeEggs.alphaTimer) { @@ -1129,7 +1129,7 @@ void hud_main_eggs(s32 countdown, Object *obj, s32 updateRate) { if (gNumActivePlayers != 2) { hud_draw_eggs(obj, updateRate); } - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } } @@ -1167,7 +1167,7 @@ void hud_draw_eggs(Object *racerObj, s32 updateRate) { racer = &racers[0]->unk64->racer; } if (numRacers == MAXCONTROLLERS) { - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); portraitX = gCurrentHud->entry[HUD_CHALLENGE_PORTRAIT].pos.x; portraitY = gCurrentHud->entry[HUD_CHALLENGE_PORTRAIT].pos.y; diffX = (gCurrentHud->entry[HUD_EGG_CHALLENGE_ICON].pos.x - portraitX); @@ -1196,7 +1196,7 @@ void hud_draw_eggs(Object *racerObj, s32 updateRate) { gCurrentHud->entry[HUD_EGG_CHALLENGE_ICON].pos.x = portraitX + diffX; gCurrentHud->entry[HUD_CHALLENGE_PORTRAIT].pos.y = portraitY; gCurrentHud->entry[HUD_EGG_CHALLENGE_ICON].pos.y = portraitY + diffY; - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } } @@ -1253,7 +1253,7 @@ void hud_main_battle(s32 countdown, Object *obj, s32 updateRate) { racer = &obj->unk64->racer; if (gNumActivePlayers != 1 || racer->raceFinished == FALSE) { - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); hud_race_start(countdown, updateRate); hud_weapon(obj, updateRate); racerObjs = get_racer_objects(&numRacers); @@ -1277,7 +1277,7 @@ void hud_main_battle(s32 countdown, Object *obj, s32 updateRate) { hud_bananas(racer, updateRate); break; } - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } } @@ -1302,7 +1302,7 @@ void func_800A1E48(Object *racerObj, s32 updateRate) { racer = &racers[PLAYER_ONE]->unk64->racer; } - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); if (numRacers == 4) { offsetX = 0; offsetY = 0; @@ -1350,7 +1350,7 @@ void func_800A1E48(Object *racerObj, s32 updateRate) { gCurrentHud->entry[HUD_BATTLE_BANANA_COUNT_2].pos.y += tempY; } - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } /** @@ -1397,7 +1397,7 @@ void hud_main_boss(s32 countdown, Object *obj, s32 updateRate) { LevelHeader *level; Object_Racer *racer = &obj->unk64->racer; - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); hud_wrong_way(racer, updateRate); hud_race_start(countdown, updateRate); hud_race_time(racer, updateRate); @@ -1410,7 +1410,7 @@ void hud_main_boss(s32 countdown, Object *obj, s32 updateRate) { hud_speedometre(obj, updateRate); hud_race_position(racer, updateRate); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } /** @@ -1419,14 +1419,14 @@ void hud_main_boss(s32 countdown, Object *obj, s32 updateRate) { void hud_main_taj(s32 countdown, Object *obj, s32 updateRate) { Object_Racer *racer = &obj->unk64->racer; - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); hud_wrong_way(racer, updateRate); hud_lap_count(racer, updateRate); hud_race_position(racer, updateRate); hud_race_time(racer, updateRate); hud_race_start(countdown, updateRate); hud_speedometre(obj, updateRate); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } /** @@ -1439,7 +1439,7 @@ void hud_main_hub(Object *obj, s32 updateRate) { if (cam_get_viewport_layout() == PLAYER_ONE) { racer = &obj->unk64->racer; - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); hud_balloons(racer); hud_speedometre(obj, updateRate); if (is_in_two_player_adventure()) { @@ -1447,7 +1447,7 @@ void hud_main_hub(Object *obj, s32 updateRate) { portrait->spriteID = (get_settings()->racers[1].character + HUD_SPRITE_PORTRAIT); hud_element_render(&gHudDL, &gHudMtx, &gHudVtx, portrait); } - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } } @@ -1576,7 +1576,7 @@ void hud_main_time_trial(s32 arg0, Object *playerRacerObj, s32 updateRate) { } obj68->animUpdateTimer = 0; - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); hud_course_arrows(curRacer, updateRate); if (curRacer->raceFinished == FALSE) { spB8 = gCurrentHud->entry[HUD_LAP_TIME_TEXT].pos.y; @@ -1761,7 +1761,7 @@ void hud_main_time_trial(s32 arg0, Object *playerRacerObj, s32 updateRate) { set_kerning(FALSE); } - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } void hud_stopwatch_face(u8 arg0, u8 arg1, u8 animID, u8 arg3, u8 arg4) { @@ -2019,13 +2019,13 @@ void hud_bananas(Object_Racer *racer, s32 updateRate) { } } else { gCurrentHud->entry[HUD_BANANA_COUNT_ICON_SPIN].spriteOffset = prevSprite + 128; - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); sprite_opaque(TRUE); enable_pal_viewport_height_adjust(TRUE); hud_element_render(&gHudDL, &gHudMtx, &gHudVtx, &gCurrentHud->entry[HUD_BANANA_COUNT_ICON_SPIN]); sprite_opaque(FALSE); enable_pal_viewport_height_adjust(FALSE); - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); gCurrentHud->entry[HUD_BANANA_COUNT_ICON_SPIN].spriteOffset -= 128; } temp_lo = bananas / 10; @@ -3435,11 +3435,11 @@ void hud_render_general(Gfx **dList, Mtx **mtx, Vertex **vtx, s32 updateRate) { } else if (gHudLevelHeader->race_type == RACETYPE_CHALLENGE_BATTLE) { // Show life counter and icons in 2 player. if (gNumActivePlayers == 2 && gHudToggleSettings[gHUDNumPlayers] == 0) { - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); sprite_opaque(FALSE); mtx_ortho(&gHudDL, &gHudMtx); func_800A1E48(0, updateRate); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); rendermode_reset(&gHudDL); sprite_opaque(TRUE); } else { @@ -3457,7 +3457,7 @@ void hud_render_general(Gfx **dList, Mtx **mtx, Vertex **vtx, s32 updateRate) { spE0 = gCurrentHud->entry[HUD_CHALLENGE_PORTRAIT].pos.y; sprite_opaque(FALSE); mtx_ortho(&gHudDL, &gHudMtx); - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); gCurrentHud->entry[HUD_CHALLENGE_PORTRAIT].pos.x = 225.0f; if (osTvType == OS_TV_TYPE_PAL) { gCurrentHud->entry[HUD_CHALLENGE_PORTRAIT].pos.y = 181.5f; @@ -3514,7 +3514,7 @@ void hud_render_general(Gfx **dList, Mtx **mtx, Vertex **vtx, s32 updateRate) { gCurrentHud->entry[HUD_CHALLENGE_PORTRAIT].pos.y = spE0; sprite_opaque(TRUE); rendermode_reset(&gHudDL); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } } } @@ -3606,7 +3606,7 @@ void hud_render_general(Gfx **dList, Mtx **mtx, Vertex **vtx, s32 updateRate) { return; } someObjSeg = cam_get_active_camera(); - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); minimap = (Sprite *) lvlMdl->minimapSpriteIndex; switch (gHUDNumPlayers) { case TWO_PLAYERS: @@ -3761,7 +3761,7 @@ void hud_render_general(Gfx **dList, Mtx **mtx, Vertex **vtx, s32 updateRate) { } } gDPPipeSync(gHudDL++); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); sprite_opaque(TRUE); *dList = gHudDL; *mtx = gHudMtx; diff --git a/src/menu.c b/src/menu.c index 1a4fc253..54ba6326 100644 --- a/src/menu.c +++ b/src/menu.c @@ -2692,7 +2692,7 @@ void menu_timestamp_render(s32 frameCount, s32 xPos, s32 yPos, u8 red, u8 green, xOffset3 = 5; } get_timestamp_from_frames(frameCount, &minutes, &seconds, &hundredths); - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); sprite_opaque(FALSE); gMenuImages[imageIndex].spriteOffset = minutes / 10; @@ -2732,7 +2732,7 @@ void menu_timestamp_render(s32 frameCount, s32 xPos, s32 yPos, u8 red, u8 green, gMenuImages[imageIndex].trans.x_position = xPos; menu_element_render(imageIndex); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); sprite_opaque(TRUE); sMenuGuiColourR = 255; sMenuGuiColourG = 255; @@ -2786,7 +2786,7 @@ void menu_number_render(s32 number, s32 x, s32 y, s32 r, s32 g, s32 b, s32 a, UN sMenuGuiColourB = b; sMenuGuiOpacity = a; sprite_opaque(0); - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); if (powerOfTen && number) {} // Fakematch gMenuImages[0].trans.y_position = y; for (i = 0; i < strLen; i++) { @@ -2796,7 +2796,7 @@ void menu_number_render(s32 number, s32 x, s32 y, s32 r, s32 g, s32 b, s32 a, UN x += 12; } sprite_opaque(1); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); sMenuGuiColourR = 255; sMenuGuiColourG = 255; sMenuGuiColourB = 255; @@ -2976,7 +2976,7 @@ void draw_menu_elements(s32 state, MenuElement *elems, f32 scale) { shouldResetRenderSettings = FALSE; rendermode_reset(&sMenuCurrDisplayList); } - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); sprite_opaque(FALSE); gMenuImages[elems->t.assetID].trans.x_position = xPos - SCREEN_WIDTH_HALF; gMenuImages[elems->t.assetID].trans.y_position = @@ -2992,7 +2992,7 @@ void draw_menu_elements(s32 state, MenuElement *elems, f32 scale) { sMenuGuiColourBlendFactor = elems->filterBlendFactor; sMenuGuiOpacity = elems->opacity; menu_element_render(elems->t.assetID); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); sprite_opaque(TRUE); break; case 6: @@ -3377,7 +3377,7 @@ void render_title_screen(UNUSED s32 updateRate, f32 updateRateF) { mtx_ortho(&sMenuCurrDisplayList, &sMenuCurrHudMat); scale = (f32) gTitleRevealTimer * (1.0f / 32.0f); sMenuGuiOpacity = (gTitleRevealTimer * 8) - 1; - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); if (scale != 1.0f) { texrect_draw_scaled(&sMenuCurrDisplayList, sGameTitleTileOffsets, SCREEN_WIDTH_FLOAT_HALF, 52.0f, scale, scale, COLOUR_RGBA32(255, 255, 255, 254), TEXRECT_POINT); @@ -4294,7 +4294,7 @@ void savemenu_render_element(SaveFileData *file, s32 x, s32 y) { } else { i = 120; } - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); offsetY = (i - y); gMenuImages[2].trans.y_position = offsetY - 49; gMenuImages[spriteID].trans.y_position = offsetY - 24; @@ -4308,7 +4308,7 @@ void savemenu_render_element(SaveFileData *file, s32 x, s32 y) { sprite_opaque(1); gMenuImages[spriteID].trans.x_position = x - (128 - SAVE_MENU_SPRITE_OFFSET); menu_element_render(spriteID); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } if (drawTexture != NULL) { texrect_draw(&sMenuCurrDisplayList, drawTexture, x + (60 + SAVE_MENU_TEXT_OFFSET_1), y + 6, 255, 255, 255, 255); @@ -7609,14 +7609,14 @@ void fileselect_render(UNUSED s32 updateRate) { } fileselect_render_element(var_s2, gFileSelectButtons[i].x + gFileSelectElementPos[2], gFileSelectButtons[i].y + gFileSelectElementPos[3], 0, 0, 0, 128); - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); gMenuImages->spriteOffset = gSavefileInfo[i].balloonCount / 10; fileselect_render_element(0, gFileSelectButtons[i].x + gFileSelectElementPos[6] - 6, gFileSelectButtons[i].y + gFileSelectElementPos[7], 0, 0, 0, 128); gMenuImages->spriteOffset = gSavefileInfo[i].balloonCount % 10; fileselect_render_element(0, gFileSelectButtons[i].x + gFileSelectElementPos[6] + 6, gFileSelectButtons[i].y + gFileSelectElementPos[7], 0, 0, 0, 128); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); sMenuGuiColourG = 64; sMenuGuiColourB = 64; fileselect_render_element(10, gFileSelectButtons[i].x + gFileSelectElementPos[8], @@ -9365,7 +9365,7 @@ void trackmenu_setup_render(UNUSED s32 updateRate) { (gTwoPlayerRacerCountMenu.textPos[0] + gTwoPlayerRacerCountMenu.x) - 1, (gTwoPlayerRacerCountMenu.textPos[1] + gTwoPlayerRacerCountMenu.y + regionOffset) - 1, gMenuText[ASSET_MENU_TEXT_NUMBEROFRACERS], ALIGN_MIDDLE_CENTER); - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); sprite_opaque(FALSE); for (temp2 = 0; temp2 < 3; temp2++) { @@ -9389,7 +9389,7 @@ void trackmenu_setup_render(UNUSED s32 updateRate) { sMenuGuiColourB = 255; } sprite_opaque(TRUE); - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } } } @@ -11298,7 +11298,7 @@ void results_render(UNUSED s32 updateRate, f32 opacity) { draw_text(&sMenuCurrDisplayList, time - 34, y2 + offsetY + 2, gRacePlacementsArray[spA0], ALIGN_MIDDLE_CENTER); #endif rendermode_reset(&sMenuCurrDisplayList); - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); sprite_opaque(FALSE); sMenuGuiColourR = 255; sMenuGuiColourG = 255 - 64 * spA0; @@ -11342,7 +11342,7 @@ void results_render(UNUSED s32 updateRate, f32 opacity) { menu_element_render(0); } y2 += 17; - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); sprite_opaque(TRUE); sMenuGuiColourG = 255; sMenuGuiColourBlendFactor = 0; @@ -14579,7 +14579,7 @@ void dialogue_tt_gamestatus(void) { return; } settings = get_settings(); - sprite_anim_off(TRUE); + cam_set_sprite_anim_mode(SPRITE_ANIM_FRAME_INDEX); if (osTvType == OS_TV_TYPE_PAL) { y = 10; } else { @@ -14657,7 +14657,7 @@ void dialogue_tt_gamestatus(void) { } menu_element_render(14); } - sprite_anim_off(FALSE); + cam_set_sprite_anim_mode(SPRITE_ANIM_NORMALIZED); } /** diff --git a/src/object_functions.c b/src/object_functions.c index f4ae83cb..81e11c18 100644 --- a/src/object_functions.c +++ b/src/object_functions.c @@ -3044,7 +3044,7 @@ void obj_loop_parkwarden(Object *obj, s32 updateRate) { if (var_f2 < 1000.0f) { var_f2 = 1000.0f - var_f2; sp3C = (127.0f * var_f2) / 1000.0f; - temp_v0_22 = get_cutscene_camera_segment(); + temp_v0_22 = cam_get_cameras(); xPosDiff = obj->segment.trans.x_position - temp_v0_22->trans.x_position; zPosDiff = obj->segment.trans.z_position - temp_v0_22->trans.z_position; arctan = audspat_calculate_spatial_pan(xPosDiff, zPosDiff, temp_v0_22->trans.rotation.y_rotation); diff --git a/src/objects.c b/src/objects.c index dc003ae4..38feddbe 100644 --- a/src/objects.c +++ b/src/objects.c @@ -1104,7 +1104,7 @@ void func_8000CC7C(Vehicle vehicle, u32 arg1, s32 arg2) { } cutsceneID = -1; if (is_time_trial_enabled() && raceType == RACETYPE_DEFAULT) { - cutsceneCameraSegment = get_cutscene_camera_segment(); + cutsceneCameraSegment = cam_get_cameras(); cutsceneID = (u8) cutsceneCameraSegment->zoom; cutsceneCameraSegment->zoom = 1; } diff --git a/src/particles.c b/src/particles.c index aea6c843..b609be5b 100644 --- a/src/particles.c +++ b/src/particles.c @@ -1555,7 +1555,7 @@ Particle *create_general_particle(Object *obj, ParticleEmitter *emitter) { if (particle->kind == PARTICLE_KIND_SPRITE) { particle->sprite = (Sprite *) tex_load_sprite(descriptor->textureID, 0); if (particle->sprite != NULL) { - if (particle->sprite->frames[0]->flags & 4) { + if (particle->sprite->textures[0]->flags & 4) { if (particle->descFlags & PARTICLE_DESC_FLAG_1000) { particle->trans.flags |= OBJ_FLAGS_UNK_0100; } else { @@ -1563,7 +1563,7 @@ Particle *create_general_particle(Object *obj, ParticleEmitter *emitter) { } } if (behaviour->flags & PARTICLE_RANDOM_TEXTURE_FRAME) { - particle->textureFrame = rand_range(0, particle->sprite->baseTextureId - 1) << 8; + particle->textureFrame = rand_range(0, particle->sprite->numberOfFrames - 1) << 8; if ((particle->descFlags & (PARTICLE_TEXTURE_ANIM_FORWARD_ENABLED | PARTICLE_TEXTURE_ANIM_BACKWARD_ENABLED)) == PARTICLE_TEXTURE_ANIM_BACKWARD_ENABLED) { @@ -1572,7 +1572,7 @@ Particle *create_general_particle(Object *obj, ParticleEmitter *emitter) { } else if ((particle->descFlags & (PARTICLE_TEXTURE_ANIM_FORWARD_ENABLED | PARTICLE_TEXTURE_ANIM_BACKWARD_ENABLED)) == PARTICLE_TEXTURE_ANIM_BACKWARD_ENABLED) { - particle->textureFrame = (particle->sprite->baseTextureId << 8) - 1; + particle->textureFrame = (particle->sprite->numberOfFrames << 8) - 1; } else { particle->textureFrame = 0; } @@ -2173,7 +2173,7 @@ void update_particle_texture_frame(Particle *particle) { keepGoing = -1; i = 0; // required to match - textureCount = particle->kind == PARTICLE_KIND_SPRITE ? particle->sprite->baseTextureId * 256 + textureCount = particle->kind == PARTICLE_KIND_SPRITE ? particle->sprite->numberOfFrames * 256 : particle->model->texture->numOfTextures; forwardEnabled = particle->descFlags & PARTICLE_TEXTURE_ANIM_FORWARD_ENABLED; @@ -2406,7 +2406,7 @@ void render_particle(Particle *particle, Gfx **dList, Mtx **mtx, Vertex **vtx, s if (particle->kind == PARTICLE_KIND_SPRITE) { temp = particle->textureFrame; particle->textureFrame >>= 8; - particle->textureFrame = (particle->textureFrame * 255) / (particle->sprite->baseTextureId); + particle->textureFrame = (particle->textureFrame * 255) / (particle->sprite->numberOfFrames); render_sprite_billboard(dList, mtx, vtx, (Object *) particle, particle->sprite, renderFlags); particle->textureFrame = temp; } else { diff --git a/src/textures_sprites.c b/src/textures_sprites.c index 321c1e11..cd8a7b0a 100644 --- a/src/textures_sprites.c +++ b/src/textures_sprites.c @@ -7,8 +7,9 @@ #include "game_ui.h" #define MAX_NUM_TEXTURES 700 -#define TEX_SPRITE_COUNT 50 +#define MAX_NUM_SPRITES 100 #define TEX_PALLETE_COUNT 20 +#define MAX_SPRITE_ASSET_SIZE 512 #define MAX_TEX_PALETTE_SIZE 640 #define TEXTURE_GFX_SIZE (12 * sizeof(Gfx)) #define PALETTE_GFX_SIZE (6 * sizeof(Gfx)) @@ -366,13 +367,13 @@ s32 *gSpriteOffsetTable; s32 *gSpriteCache; -Sprite *gCurrentSprite; +SpriteAsset *gCurrentSpriteAsset; s32 gSpriteTableSize; s32 gSpriteCacheCount; s32 D_8012635C; // Set but never used -Vertex *D_80126360; -Gfx *D_80126364; -Triangle *D_80126368; +Vertex *gSpriteVertices; +Gfx *gSpriteDLists; +Triangle *gSpriteTriangles; TempTexHeader *gTempTextureHeader; u8 *D_80126370; @@ -404,8 +405,8 @@ void tex_init_textures(void) { for (i = 0; gTextureAssetTable[TEX_TABLE_3D][i] != -1; i++) {} gTextureTableSize[TEX_TABLE_3D] = --i; - gSpriteCache = mempool_alloc_safe(sizeof(Sprite) * TEX_SPRITE_COUNT, COLOUR_TAG_MAGENTA); - gCurrentSprite = mempool_alloc_safe(sizeof(Sprite) * 32, COLOUR_TAG_MAGENTA); + gSpriteCache = mempool_alloc_safe(8 * MAX_NUM_SPRITES, COLOUR_TAG_MAGENTA); + gCurrentSpriteAsset = mempool_alloc_safe(MAX_SPRITE_ASSET_SIZE, COLOUR_TAG_MAGENTA); gSpriteCacheCount = 0; gSpriteOffsetTable = (s32 *) load_asset_section_from_rom(ASSET_SPRITES_TABLE); gSpriteTableSize = 0; @@ -936,17 +937,22 @@ void material_load_simple(Gfx **dList, s32 flags) { } } +/** + * Loads a sprite from its asset, allocates memory for vertices, triangles, and display lists, + * and initializes the display list for each texture and frame. + * If the sprite is already cached, returns it from the cache. + */ Sprite *tex_load_sprite(s32 spriteID, s32 arg1) { Sprite *refSprite; - Sprite *newSprite; - s32 cacheNum; Sprite *sprite; + s32 cacheNum; + SpriteAsset *spriteAsset; TextureHeader *tex; s32 i; s32 size; s8 allocFailed; s8 cacheFull; - s16 frameCount; + s16 numTextures; s32 allocSize; D_8012635C = arg1; @@ -965,7 +971,7 @@ Sprite *tex_load_sprite(s32 spriteID, s32 arg1) { cacheNum = -1; for (i = 0; i < gSpriteCacheCount; i++) { // @fake - if (newSprite) {} + if (sprite) {} if (gSpriteCache[ASSETCACHE_ID(i)] == -1) { cacheNum = i; } @@ -978,20 +984,19 @@ Sprite *tex_load_sprite(s32 spriteID, s32 arg1) { } size = gSpriteOffsetTable[spriteID]; - sprite = gCurrentSprite; - load_asset_to_address(12, (u32) sprite, size, gSpriteOffsetTable[spriteID + 1] - size); + spriteAsset = gCurrentSpriteAsset; + load_asset_to_address(ASSET_SPRITES, (u32) spriteAsset, size, gSpriteOffsetTable[spriteID + 1] - size); - frameCount = sprite->unkC.val[sprite->numberOfFrames]; - size = frameCount * 4; - allocSize = size * sizeof(Vertex); - allocSize += size << 3; - allocSize += sprite->numberOfFrames * sizeof(Gfx); - allocSize += frameCount << 4 << 1; - allocSize += size; + numTextures = spriteAsset->frameTexOffsets[spriteAsset->numberOfFrames]; + allocSize = numTextures * 4 * sizeof(Vertex); + allocSize += (numTextures * 4) << 3; + allocSize += spriteAsset->numberOfFrames * sizeof(Gfx); + allocSize += numTextures << 4 << 1; + allocSize += numTextures * 4; allocSize += (s32) align16((u8 *) 0x10); - allocSize += (s32) align16((u8 *) (sprite->numberOfFrames * 4)); - newSprite = (Sprite *) mempool_alloc(allocSize, COLOUR_TAG_MAGENTA); - if (newSprite == NULL) { + allocSize += (s32) align16((u8 *) (spriteAsset->numberOfFrames * 4)); + sprite = (Sprite *) mempool_alloc(allocSize, COLOUR_TAG_MAGENTA); + if (sprite == NULL) { if (cacheFull) { gSpriteCacheCount--; } @@ -999,18 +1004,19 @@ Sprite *tex_load_sprite(s32 spriteID, s32 arg1) { return NULL; } - D_80126368 = (Triangle *) ((s32) newSprite + (s32) align16((u8 *) sizeof(Sprite)) + - (s32) align16((u8 *) (sprite->numberOfFrames * 4))); - D_80126364 = (Gfx *) (&((u8 *) D_80126368)[frameCount << 5]); // `<< 5` is `sizeof(Triangle) * 2` - D_80126360 = (Vertex *) ((Gfx *) (((s32) & ((u8 *) D_80126364)[frameCount << 5]) + (sprite->numberOfFrames << 3))); - newSprite->gfx[0] = (Gfx *) &((u8 *) D_80126360)[frameCount * sizeof(Vertex) * 4]; + gSpriteTriangles = (Triangle *) ((s32) sprite + (s32) align16((u8 *) sizeof(Sprite)) + + (s32) align16((u8 *) (spriteAsset->numberOfFrames * 4))); + gSpriteDLists = (Gfx *) ((s32) gSpriteTriangles + numTextures * 0x20); // 0x20 = sizeof(Triangle) * 2 + gSpriteVertices = (Vertex *) ((s32) gSpriteDLists + numTextures * 0x20 + + spriteAsset->numberOfFrames * sizeof(Gfx)); // 0x20 = sizeof(Gfx) * 4 + sprite->textures = (TextureHeader **) ((s32) gSpriteVertices + numTextures * sizeof(Vertex) * 4); allocFailed = FALSE; - for (i = 0; i < frameCount; i++) { + for (i = 0; i < numTextures; i++) { gTexColourTag = COLOUR_TAG_LIME; - tex = load_texture(sprite->baseTextureId + i); - newSprite->frames[i] = tex; - if (newSprite->frames[i] == NULL) { + tex = load_texture(spriteAsset->baseTextureId + i); + sprite->textures[i] = tex; + if (sprite->textures[i] == NULL) { allocFailed = TRUE; } @@ -1020,8 +1026,8 @@ Sprite *tex_load_sprite(s32 spriteID, s32 arg1) { gFirstTexIsLoaded = FALSE; if (allocFailed) { - for (i = 0; i < frameCount; i++) { - tex = (TextureHeader *) newSprite->frames[i]; + for (i = 0; i < numTextures; i++) { + tex = (TextureHeader *) sprite->textures[i]; if (tex != NULL) { tex_free(tex); } @@ -1029,25 +1035,25 @@ Sprite *tex_load_sprite(s32 spriteID, s32 arg1) { if (cacheFull) { gSpriteCacheCount--; } - mempool_free(newSprite); + mempool_free(sprite); return NULL; } - newSprite->numberOfFrames = frameCount; - newSprite->baseTextureId = sprite->numberOfFrames; - for (i = 0; i < sprite->numberOfFrames; i++) { - newSprite->unkC.ptr[i] = (u8 *) D_80126364; - func_8007CDC0(sprite, newSprite, i); + sprite->numberOfTextures = numTextures; + sprite->numberOfFrames = spriteAsset->numberOfFrames; + for (i = 0; i < spriteAsset->numberOfFrames; i++) { + sprite->frames[i] = gSpriteDLists; + sprite_init_frame(spriteAsset, sprite, i); } - if (gSpriteCacheCount >= 100) { + if (gSpriteCacheCount >= MAX_NUM_SPRITES) { return NULL; } gSpriteCache[ASSETCACHE_ID(cacheNum)] = spriteID; - gSpriteCache[ASSETCACHE_PTR(cacheNum)] = (s32) newSprite; - newSprite->numberOfInstances = 1; - return newSprite; + gSpriteCache[ASSETCACHE_PTR(cacheNum)] = (s32) sprite; + sprite->numberOfInstances = 1; + return sprite; } /** @@ -1101,26 +1107,26 @@ s32 tex_asset_size(s32 id) { } UNUSED u8 func_8007C660(s32 texID) { - Sprite *temp_s1; + SpriteAsset *spriteAsset; s32 j; s32 i; - s32 temp_v1; + s32 numTextures; if (texID & ASSET_MASK_TEX3D) { return 0; } - if (D_80126370 == 0) { + if (D_80126370 == NULL) { D_80126370 = (u8 *) mempool_alloc_safe(gTextureTableSize[TEX_TABLE_2D], COLOUR_TAG_MAGENTA); for (i = 0; i < gTextureTableSize[TEX_TABLE_2D]; i++) { - D_80126370[i] = 0; + D_80126370[i] = FALSE; } for (i = 0; i < gSpriteTableSize; i++) { - temp_s1 = gCurrentSprite; - load_asset_to_address(ASSET_SPRITES, (u32) temp_s1, gSpriteOffsetTable[i], + spriteAsset = gCurrentSpriteAsset; + load_asset_to_address(ASSET_SPRITES, (u32) spriteAsset, gSpriteOffsetTable[i], gSpriteOffsetTable[i + 1] - gSpriteOffsetTable[i]); - temp_v1 = temp_s1->unkC.val[temp_s1->numberOfFrames]; - for (j = 0; j < temp_v1; j++) { - D_80126370[temp_s1->baseTextureId + j] = 1; + numTextures = spriteAsset->frameTexOffsets[spriteAsset->numberOfFrames]; + for (j = 0; j < numTextures; j++) { + D_80126370[spriteAsset->baseTextureId + j] = TRUE; } } } @@ -1149,11 +1155,11 @@ UNUSED s32 sprite_cache_asset_id(s32 cacheID) { return gSpriteCache[ASSETCACHE_ID(cacheID)]; } -s32 load_sprite_info(s32 spriteIndex, s32 *numOfInstancesOut, s32 *unkOut, s32 *numFramesOut, s32 *formatOut, +s32 load_sprite_info(s32 spriteIndex, s32 *anchorXOut, s32 *anchorYOut, s32 *numFramesOut, s32 *formatOut, s32 *sizeOut) { TextureHeader *tex; s32 i; - Sprite *new_var2; + SpriteAsset *spriteAsset; s32 j; s32 start; s32 size; @@ -1161,36 +1167,36 @@ s32 load_sprite_info(s32 spriteIndex, s32 *numOfInstancesOut, s32 *unkOut, s32 * if ((spriteIndex < 0) || (spriteIndex >= gSpriteTableSize)) { textureCouldNotBeLoaded: - *numOfInstancesOut = 0; - *unkOut = 0; + *anchorXOut = 0; + *anchorYOut = 0; *numFramesOut = 0; return 0; } start = gSpriteOffsetTable[spriteIndex]; size = gSpriteOffsetTable[spriteIndex + 1] - start; - new_var2 = gCurrentSprite; + spriteAsset = gCurrentSpriteAsset; new_var = size; - load_asset_to_address(ASSET_SPRITES, (u32) new_var2, start, new_var); - tex = load_texture(new_var2->unkC.val[0] + new_var2->baseTextureId); + load_asset_to_address(ASSET_SPRITES, (u32) spriteAsset, start, new_var); + tex = load_texture(spriteAsset->frameTexOffsets[0] + spriteAsset->baseTextureId); if (tex != NULL) { *formatOut = TEX_FORMAT(tex->format); tex_free(tex); *sizeOut = 0; - for (i = 0; i < new_var2->numberOfFrames; i++) { - for (j = new_var2->unkC.val[i]; j < (s32) new_var2->unkC.val[i + 1]; j++) { - *sizeOut += tex_asset_size(new_var2->baseTextureId + j); + for (i = 0; i < spriteAsset->numberOfFrames; i++) { + for (j = spriteAsset->frameTexOffsets[i]; j < (s32) spriteAsset->frameTexOffsets[i + 1]; j++) { + *sizeOut += tex_asset_size(spriteAsset->baseTextureId + j); } } - *numFramesOut = new_var2->numberOfFrames; - *numOfInstancesOut = new_var2->numberOfInstances; - *unkOut = new_var2->drawFlags; + *numFramesOut = spriteAsset->numberOfFrames; + *anchorXOut = spriteAsset->anchor.x; + *anchorYOut = spriteAsset->anchor.y; return 1; } goto textureCouldNotBeLoaded; } void func_8007CA68(s32 arg0, s32 arg1, s32 *arg2, s32 *arg3, s32 *arg4) { - Sprite *sprite; + SpriteAsset *spriteAsset; TextureHeader *tex; s32 temp_a0; s32 temp_v1; @@ -1212,38 +1218,38 @@ void func_8007CA68(s32 arg0, s32 arg1, s32 *arg2, s32 *arg3, s32 *arg4) { // Must be on the same line. (maybe a macro?) // clang-format off - sprite = gCurrentSprite; \ - load_asset_to_address(12, (u32)sprite, temp_a2, gSpriteOffsetTable[arg0 + 1] - temp_a2); + spriteAsset = gCurrentSpriteAsset; \ + load_asset_to_address(ASSET_SPRITES, (u32)spriteAsset, temp_a2, gSpriteOffsetTable[arg0 + 1] - temp_a2); // clang-format on - if (sprite->numberOfFrames < arg1) { + if (spriteAsset->numberOfFrames < arg1) { failedExit: *arg2 = 0; *arg3 = 0; *arg4 = 0; return; } - tex = load_texture(sprite->unkC.val[arg1] + sprite->baseTextureId); + tex = load_texture(spriteAsset->frameTexOffsets[arg1] + spriteAsset->baseTextureId); if (tex == NULL) { goto failedExit; } - *arg4 = tex_asset_size(sprite->unkC.val[arg1] + sprite->baseTextureId); - var_s3 = tex->unk3 - sprite->numberOfInstances; - var_s4 = sprite->drawFlags - tex->unk4; + *arg4 = tex_asset_size(spriteAsset->frameTexOffsets[arg1] + spriteAsset->baseTextureId); + var_s3 = tex->posX - spriteAsset->anchor.x; + var_s4 = spriteAsset->anchor.y - tex->posY; temp_a1 = tex->width; temp_a2 = tex->height; var_s5 = var_s3 + temp_a1; var_s6 = var_s4 - temp_a2; tex_free(tex); - for (var_s1 = sprite->unkC.val[arg1] + 1; var_s1 < sprite->unkC.val[arg1 + 1]; var_s1++) { - tex = load_texture(sprite->baseTextureId + var_s1); + for (var_s1 = spriteAsset->frameTexOffsets[arg1] + 1; var_s1 < spriteAsset->frameTexOffsets[arg1 + 1]; var_s1++) { + tex = load_texture(spriteAsset->baseTextureId + var_s1); if (tex == NULL) { goto failedExit; } - *arg4 += tex_asset_size(sprite->baseTextureId + var_s1); - temp_v1 = tex->unk3 - sprite->numberOfInstances; - temp_a0 = sprite->drawFlags - tex->unk4; + *arg4 += tex_asset_size(spriteAsset->baseTextureId + var_s1); + temp_v1 = tex->posX - spriteAsset->anchor.x; + temp_a0 = spriteAsset->anchor.y - tex->posY; temp_a1 = tex->width; temp_a2 = tex->height; if (temp_v1 < var_s3) { @@ -1278,8 +1284,8 @@ void sprite_free(Sprite *sprite) { if (sprite->numberOfInstances <= 0) { for (i = 0; i < gSpriteCacheCount; i++) { if (sprite == (Sprite *) gSpriteCache[ASSETCACHE_PTR(i)]) { - for (frame = 0; frame < sprite->numberOfFrames; frame++) { - tex_free(sprite->frames[frame]); + for (frame = 0; frame < sprite->numberOfTextures; frame++) { + tex_free(sprite->textures[frame]); } mempool_free(sprite); gSpriteCache[ASSETCACHE_ID(i)] = -1; @@ -1291,120 +1297,149 @@ void sprite_free(Sprite *sprite) { } } -void func_8007CDC0(Sprite *sprite1, Sprite *sprite2, s32 arg2) { +/** + * Creates a display list that renders the specified sprite frame. + * A frame may consist of multiple tiles. + * For correct rendering, billboard mode must be enabled in the RSP beforehand, + * and the anchor vertex must already be pushed. + */ +void sprite_init_frame(SpriteAsset *spriteAsset, Sprite *sprite, s32 frameId) { UNUSED s32 pad[2]; - s32 spriteCount; - s32 spriteDrawFlags; - s32 xTemp; - s32 yTemp; + s32 anchorX; + s32 anchorY; + s32 tileOffsetX; + s32 tileOffsetY; s32 left; - s32 var_t5; + s32 numQuads; s32 curVertIndex; - s32 j; + s32 tileEnd; s32 texWidth; s32 texHeight; - s32 i; - Vertex *vertices; + s32 tileIndex; + Vertex *vertex; Vertex *curVerts; - Triangle *triangles; + Triangle *triangle; Gfx *dlptr; TextureHeader *tex; - spriteCount = sprite1->numberOfInstances; - spriteDrawFlags = sprite1->drawFlags; - i = sprite1->unkC.val[arg2]; - j = sprite1->unkC.val[arg2 + 1]; - dlptr = D_80126364; - vertices = D_80126360; - triangles = D_80126368; - if (i < j) { - tex = sprite2->frames[i]; - sprite2->drawFlags = ((tex->flags & 0xFFFF) & 0x3B); + anchorX = spriteAsset->anchor.x; + anchorY = spriteAsset->anchor.y; + tileIndex = spriteAsset->frameTexOffsets[frameId]; + tileEnd = spriteAsset->frameTexOffsets[frameId + 1]; + dlptr = gSpriteDLists; + vertex = gSpriteVertices; + triangle = gSpriteTriangles; + + // Extract draw flags from the first tile's texture + if (tileIndex < tileEnd) { + tex = sprite->textures[tileIndex]; + sprite->drawFlags = ((tex->flags & 0xFFFF) & (RENDER_ANTI_ALIASING | RENDER_Z_COMPARE | RENDER_FOG_ACTIVE | + RENDER_CUTOUT | RENDER_COLOUR_INDEX)); } + curVertIndex = 0; - var_t5 = 0; - while (i < j) { - curVerts = vertices; - tex = sprite2->frames[i]; + numQuads = 0; + while (tileIndex < tileEnd) { + curVerts = vertex; + tex = sprite->textures[tileIndex]; + texWidth = tex->width; texHeight = tex->height; - xTemp = tex->unk3 - spriteCount; - yTemp = spriteDrawFlags - tex->unk4; - vertices->x = xTemp; - vertices->y = yTemp - 1; - vertices->z = 0; - vertices->r = 255; - vertices->g = 255; - vertices->b = 255; - vertices->a = 255; - vertices++; - vertices->x = xTemp + texWidth - 1; - vertices->y = yTemp - 1; - vertices->z = 0; - vertices->r = 255; - vertices->g = 255; - vertices->b = 255; - vertices->a = 255; - vertices++; - vertices->x = xTemp + texWidth - 1; - vertices->y = yTemp - texHeight; - vertices->z = 0; - vertices->r = 255; - vertices->g = 255; - vertices->b = 255; - vertices->a = 255; - vertices++; - vertices->x = xTemp; - vertices->y = yTemp - texHeight; - vertices->z = 0; - vertices->r = 255; - vertices->g = 255; - vertices->b = 255; - vertices->a = 255; - vertices++; + // Calculate tile position relative to the sprite's anchor point + // Positive tileOffsetY means up + tileOffsetX = tex->posX - anchorX; + tileOffsetY = anchorY - tex->posY; + + vertex->x = tileOffsetX; + vertex->y = tileOffsetY - 1; + vertex->z = 0; + vertex->r = 255; + vertex->g = 255; + vertex->b = 255; + vertex->a = 255; + vertex++; + + vertex->x = tileOffsetX + texWidth - 1; + vertex->y = tileOffsetY - 1; + vertex->z = 0; + vertex->r = 255; + vertex->g = 255; + vertex->b = 255; + vertex->a = 255; + vertex++; + + vertex->x = tileOffsetX + texWidth - 1; + vertex->y = tileOffsetY - texHeight; + vertex->z = 0; + vertex->r = 255; + vertex->g = 255; + vertex->b = 255; + vertex->a = 255; + vertex++; + + vertex->x = tileOffsetX; + vertex->y = tileOffsetY - texHeight; + vertex->z = 0; + vertex->r = 255; + vertex->g = 255; + vertex->b = 255; + vertex->a = 255; + vertex++; + + // Upload display list commands for the current tile gDkrDmaDisplayList(dlptr++, OS_K0_TO_PHYSICAL(tex->cmd), tex->numberOfCommands); - if (var_t5 == 0) { - left = j - i; - if (left >= 6) { + + // Upload up to 20 vertices to the RSP at once (5 quads max) + // G_VTX_APPEND is required for billboard rendering + if (numQuads == 0) { + left = tileEnd - tileIndex; + if (left > 5) { left = 5; } - gSPVertexDKR(dlptr++, OS_K0_TO_PHYSICAL(curVerts), (left * 4), 1); + gSPVertexDKR(dlptr++, OS_K0_TO_PHYSICAL(curVerts), (left * 4), G_VTX_APPEND); } - gSPPolygon(dlptr++, OS_K0_TO_PHYSICAL(triangles), 2, 1); - triangles[0].flags = 0x40; - triangles[0].vi0 = curVertIndex + 3; - triangles[0].vi1 = curVertIndex + 2; - triangles[0].vi2 = curVertIndex + 1; - triangles[0].uv0.u = (texWidth - 1) << 5; - triangles[0].uv0.v = (texHeight - 1) << 5; - triangles[0].uv1.u = (texWidth - 1) << 5; - triangles[0].uv1.v = 0; - triangles[0].uv2.u = 1; - triangles[0].uv2.v = 0; - triangles[1].flags = 0x40; - triangles[1].vi0 = curVertIndex + 4; - triangles[1].vi1 = curVertIndex + 3; - triangles[1].vi2 = curVertIndex + 1; - triangles[1].uv0.u = 1; - triangles[1].uv0.v = (texHeight - 1) << 5; - triangles[1].uv1.u = (texWidth - 1) << 5; - triangles[1].uv1.v = (texHeight - 1) << 5; - triangles[1].uv2.u = 1; - triangles[1].uv2.v = 0; - triangles += 2; + + // vertex index 0 is reserved for the billboard anchor vertex, already loaded into RSP + gSPPolygon(dlptr++, OS_K0_TO_PHYSICAL(triangle), 2, TRIN_ENABLE_TEXTURE); + triangle->flags = BACKFACE_DRAW; + triangle->vi0 = curVertIndex + 3; + triangle->vi1 = curVertIndex + 2; + triangle->vi2 = curVertIndex + 1; + triangle->uv0.u = (texWidth - 1) << 5; + triangle->uv0.v = (texHeight - 1) << 5; + triangle->uv1.u = (texWidth - 1) << 5; + triangle->uv1.v = 0; + triangle->uv2.u = 1; + triangle->uv2.v = 0; + triangle++; + + triangle->flags = BACKFACE_DRAW; + triangle->vi0 = curVertIndex + 4; + triangle->vi1 = curVertIndex + 3; + triangle->vi2 = curVertIndex + 1; + triangle->uv0.u = 1; + triangle->uv0.v = (texHeight - 1) << 5; + triangle->uv1.u = (texWidth - 1) << 5; + triangle->uv1.v = (texHeight - 1) << 5; + triangle->uv2.u = 1; + triangle->uv2.v = 0; + triangle++; + curVertIndex += 4; - var_t5 += 1; - i += 1; - if (var_t5 >= 5) { - var_t5 = 0; + + numQuads++; + tileIndex++; + if (numQuads >= 5) { + numQuads = 0; curVertIndex = 0; } } + gDPPipeSync(dlptr++); gSPEndDisplayList(dlptr++); - D_80126364 = dlptr; - D_80126360 = vertices; - D_80126368 = triangles; + gSpriteDLists = dlptr; + gSpriteVertices = vertex; + gSpriteTriangles = triangle; } /** diff --git a/src/textures_sprites.h b/src/textures_sprites.h index 79116d2b..53b7a3d4 100644 --- a/src/textures_sprites.h +++ b/src/textures_sprites.h @@ -170,7 +170,7 @@ TextureHeader *set_animated_texture_header(TextureHeader *texHead, s32 offset); TextureHeader *load_texture(s32 arg0); s32 tex_asset_size(s32 id); s32 tex_cache_asset_id(s32 cacheID); -s32 load_sprite_info(s32 spriteIndex, s32 *numOfInstancesOut, s32 *unkOut, s32 *numFramesOut, s32 *formatOut, +s32 load_sprite_info(s32 spriteIndex, s32 *anchorXOut, s32 *anchorYOut, s32 *numFramesOut, s32 *formatOut, s32 *sizeOut); void gfx_init_basic_xlu(Gfx **dList, u32 index, u32 primitiveColor, u32 environmentColor); void func_8007CA68(s32 arg0, s32 arg1, s32 *arg2, s32 *arg3, s32 *arg4); @@ -179,6 +179,6 @@ void tex_init_textures(void); void material_set_blinking_lights(Gfx **dList, TextureHeader *texture_list, u32 flags, s32 texture_index); void material_init(TextureHeader *tex, Gfx *_dList); -void func_8007CDC0(Sprite *sprite1, Sprite *sprite2, s32 arg2); +void sprite_init_frame(SpriteAsset *sprite1, Sprite *sprite2, s32 arg2); #endif diff --git a/src/tracks.c b/src/tracks.c index cc2a9842..12b26505 100644 --- a/src/tracks.c +++ b/src/tracks.c @@ -4443,7 +4443,7 @@ void obj_loop_fogchanger(Object *obj) { camera = NULL; if (check_if_showing_cutscene_camera()) { - camera = get_cutscene_camera_segment(); + camera = cam_get_cameras(); views = cam_get_viewport_layout() + 1; } else { racers = get_racer_objects(&views); diff --git a/ver/symbols/symbol_addrs.jpn.v79.txt b/ver/symbols/symbol_addrs.jpn.v79.txt index 92462c7d..5b74c013 100644 --- a/ver/symbols/symbol_addrs.jpn.v79.txt +++ b/ver/symbols/symbol_addrs.jpn.v79.txt @@ -913,7 +913,7 @@ mtx_perspective = 0x8006814C; viewport_rsp_set = 0x80068228; viewport_reset = 0x8006837C; mtx_world_origin = 0x800684D8; -sprite_anim_off = 0x800685D8; +cam_set_sprite_anim_mode = 0x800685D8; render_sprite_billboard = 0x800685E4; render_ortho_triangle_image = 0x80068CC4; mtx_shear_push = 0x80069078; @@ -926,7 +926,7 @@ cam_move_dir = 0x80069C40; cam_rotate = 0x80069D84; cam_get_active_camera_no_cutscenes = 0x80069DCC; cam_get_active_camera = 0x80069DF0; -get_cutscene_camera_segment = 0x80069E4C; +cam_get_cameras = 0x80069E4C; get_projection_matrix_f32 = 0x80069E74; get_projection_matrix_s16 = 0x80069E80; get_camera_matrix = 0x80069E8C; @@ -1292,7 +1292,7 @@ sprite_cache_asset_id = 0x8007CBB0; load_sprite_info = 0x8007CBF0; func_8007CA68 = 0x8007CD78; sprite_free = 0x8007CFC0; -func_8007CDC0 = 0x8007D0D0; +sprite_init_frame = 0x8007D0D0; material_init = 0x8007D404; tex_palette_id = 0x8007F274; tex_animate_texture = 0x8007F290; @@ -3943,7 +3943,7 @@ gNumCameras = 0x80122758; D_80120CEC = 0x8012275C; gCameraTransform = 0x80122760; gMtxOriginID = 0x80122778; -gSpriteAnimOff = 0x8012277C; +gSpriteAnimMode = 0x8012277C; gCurCamFOV = 0x80122780; gCutsceneCameraActive = 0x80122784; gAdjustViewportHeight = 0x80122785; @@ -3951,21 +3951,21 @@ gNoCamShake = 0x80122788; gModelMatrixStackPos = 0x8012278C; gCameraMatrixPos = 0x80122790; D_80120D24 = 0x80122794; -gModelMatrixViewX = 0x80122798; -gModelMatrixViewY = 0x801227B0; -gModelMatrixViewZ = 0x801227C8; +gCameraRelPosStackX = 0x80122798; +gCameraRelPosStackY = 0x801227B0; +gCameraRelPosStackZ = 0x801227C8; perspNorm = 0x801227DC; gModelMatrixF = 0x801227E0; gModelMatrix = 0x801227F8; D_80120DA0 = 0x80122810; gPerspectiveMatrixF = 0x80122950; -gViewMatrixF = 0x80122990; -gCameraMatrixF = 0x801229D0; -gProjectionMatrixF = 0x80122A10; -gProjectionMatrix = 0x80122A50; -gUnusedProjectionMatrix = 0x80122A90; +gViewProjMatrixF = 0x80122990; +gViewMatrixF = 0x801229D0; +gInverseViewMatrixF = 0x80122A10; +gPerspectiveMatrix = 0x80122A50; +gInverseViewMatrix = 0x80122A90; gCurrentModelMatrixF = 0x80122AD0; -gCurrentModelMatrixS = 0x80122B10; +gCurrentMVPMatrixF = 0x80122B10; // controller .bss sSIMesgQueue = 0x80122B50; @@ -4140,13 +4140,13 @@ gCiPalettesSize = 0x80127DD0; gFirstTexIsLoaded = 0x80127DD4; gSpriteOffsetTable = 0x80127DD8; gSpriteCache = 0x80127DDC; -gCurrentSprite = 0x80127DE0; +gCurrentSpriteAsset = 0x80127DE0; gSpriteTableSize = 0x80127DE4; gSpriteCacheCount = 0x80127DE8; D_8012635C = 0x80127DEC; -D_80126360 = 0x80127DF0; -D_80126364 = 0x80127DF4; -D_80126368 = 0x80127DF8; +gSpriteVertices = 0x80127DF0; +gSpriteDLists = 0x80127DF4; +gSpriteTriangles = 0x80127DF8; gTempTextureHeader = 0x80127DFC; D_80126370 = 0x80127E00; gCurrentRenderFlags = 0x80127E04; diff --git a/ver/symbols/symbol_addrs.pal.v77.txt b/ver/symbols/symbol_addrs.pal.v77.txt index 8e08937c..e3c3ae53 100644 --- a/ver/symbols/symbol_addrs.pal.v77.txt +++ b/ver/symbols/symbol_addrs.pal.v77.txt @@ -911,7 +911,7 @@ mtx_perspective = 0x8006807C; viewport_rsp_set = 0x80068158; viewport_reset = 0x800682AC; mtx_world_origin = 0x80068408; -sprite_anim_off = 0x80068508; +cam_set_sprite_anim_mode = 0x80068508; render_sprite_billboard = 0x80068514; render_ortho_triangle_image = 0x80068BF4; mtx_shear_push = 0x80068FA8; @@ -924,7 +924,7 @@ cam_move_dir = 0x80069B70; cam_rotate = 0x80069CB4; cam_get_active_camera_no_cutscenes = 0x80069CFC; cam_get_active_camera = 0x80069D20; -get_cutscene_camera_segment = 0x80069D7C; +cam_get_cameras = 0x80069D7C; get_projection_matrix_f32 = 0x80069DA4; get_projection_matrix_s16 = 0x80069DB0; get_camera_matrix = 0x80069DBC; @@ -1288,7 +1288,7 @@ sprite_cache_asset_id = 0x8007C8A0; load_sprite_info = 0x8007C8E0; func_8007CA68 = 0x8007CA68; sprite_free = 0x8007CCB0; -func_8007CDC0 = 0x8007CDC0; +sprite_init_frame = 0x8007CDC0; material_init = 0x8007D0F4; tex_palette_id = 0x8007EF64; tex_animate_texture = 0x8007EF80; @@ -3653,7 +3653,7 @@ gNumCameras = 0x80120D78; D_80120CEC = 0x80120D7C; gCameraTransform = 0x80120D80; gMtxOriginID = 0x80120D98; -gSpriteAnimOff = 0x80120D9C; +gSpriteAnimMode = 0x80120D9C; gCurCamFOV = 0x80120DA0; gCutsceneCameraActive = 0x80120DA4; gAdjustViewportHeight = 0x80120DA5; @@ -3661,21 +3661,21 @@ gNoCamShake = 0x80120DA8; gModelMatrixStackPos = 0x80120DAC; gCameraMatrixPos = 0x80120DB0; D_80120D24 = 0x80120DB4; -gModelMatrixViewX = 0x80120DB8; -gModelMatrixViewY = 0x80120DD0; -gModelMatrixViewZ = 0x80120DE8; +gCameraRelPosStackX = 0x80120DB8; +gCameraRelPosStackY = 0x80120DD0; +gCameraRelPosStackZ = 0x80120DE8; perspNorm = 0x80120DFC; gModelMatrixF = 0x80120E00; gModelMatrix = 0x80120E18; D_80120DA0 = 0x80120E30; gPerspectiveMatrixF = 0x80120F70; -gViewMatrixF = 0x80120FB0; -gCameraMatrixF = 0x80120FF0; -gProjectionMatrixF = 0x80121030; -gProjectionMatrix = 0x80121070; -gUnusedProjectionMatrix = 0x801210B0; +gViewProjMatrixF = 0x80120FB0; +gViewMatrixF = 0x80120FF0; +gInverseViewMatrixF = 0x80121030; +gPerspectiveMatrix = 0x80121070; +gInverseViewMatrix = 0x801210B0; gCurrentModelMatrixF = 0x801210F0; -gCurrentModelMatrixS = 0x80121130; +gCurrentMVPMatrixF = 0x80121130; sSIMesgQueue = 0x80121170; sSIMesgBuf = 0x80121188; gSIMesg = 0x8012118C; @@ -3826,13 +3826,13 @@ gCiPalettesSize = 0x801263D0; gFirstTexIsLoaded = 0x801263D4; gSpriteOffsetTable = 0x801263D8; gSpriteCache = 0x801263DC; -gCurrentSprite = 0x801263E0; +gCurrentSpriteAsset = 0x801263E0; gSpriteTableSize = 0x801263E4; gSpriteCacheCount = 0x801263E8; D_8012635C = 0x801263EC; -D_80126360 = 0x801263F0; -D_80126364 = 0x801263F4; -D_80126368 = 0x801263F8; +gSpriteVertices = 0x801263F0; +gSpriteDLists = 0x801263F4; +gSpriteTriangles = 0x801263F8; gTempTextureHeader = 0x801263FC; D_80126370 = 0x80126400; gCurrentRenderFlags = 0x80126404; diff --git a/ver/symbols/symbol_addrs.pal.v80.txt b/ver/symbols/symbol_addrs.pal.v80.txt index b2b69a12..38654da7 100644 --- a/ver/symbols/symbol_addrs.pal.v80.txt +++ b/ver/symbols/symbol_addrs.pal.v80.txt @@ -857,7 +857,7 @@ mtx_perspective = 0x800682BC; viewport_rsp_set = 0x80068398; viewport_reset = 0x800684EC; mtx_world_origin = 0x80068648; -sprite_anim_off = 0x80068748; +cam_set_sprite_anim_mode = 0x80068748; render_sprite_billboard = 0x80068754; render_ortho_triangle_image = 0x80068E34; mtx_shear_push = 0x800691E8; @@ -870,7 +870,7 @@ cam_move_dir = 0x80069DB0; cam_rotate = 0x80069EF4; cam_get_active_camera_no_cutscenes = 0x80069F3C; cam_get_active_camera = 0x80069F60; -get_cutscene_camera_segment = 0x80069FBC; +cam_get_cameras = 0x80069FBC; get_projection_matrix_f32 = 0x80069FE4; get_projection_matrix_s16 = 0x80069FF0; get_camera_matrix = 0x80069FFC; @@ -1211,7 +1211,7 @@ sprite_cache_asset_id = 0x8007CCF0; load_sprite_info = 0x8007CD30; func_8007CA68 = 0x8007CEB8; sprite_free = 0x8007D100; -func_8007CDC0 = 0x8007D210; +sprite_init_frame = 0x8007D210; material_init = 0x8007D544; tex_palette_id = 0x8007F3B4; tex_animate_texture = 0x8007F3D0; @@ -3583,7 +3583,7 @@ gNumCameras = 0x801212F8; D_80120CEC = 0x801212FC; gCameraTransform = 0x80121300; gMtxOriginID = 0x80121318; -gSpriteAnimOff = 0x8012131C; +gSpriteAnimMode = 0x8012131C; gCurCamFOV = 0x80121320; gCutsceneCameraActive = 0x80121324; gAdjustViewportHeight = 0x80121325; @@ -3591,21 +3591,21 @@ gNoCamShake = 0x80121328; gModelMatrixStackPos = 0x8012132C; gCameraMatrixPos = 0x80121330; D_80120D24 = 0x80121334; -gModelMatrixViewX = 0x80121338; -gModelMatrixViewY = 0x80121350; -gModelMatrixViewZ = 0x80121368; +gCameraRelPosStackX = 0x80121338; +gCameraRelPosStackY = 0x80121350; +gCameraRelPosStackZ = 0x80121368; perspNorm = 0x8012137C; gModelMatrixF = 0x80121380; gModelMatrix = 0x80121398; D_80120DA0 = 0x801213B0; gPerspectiveMatrixF = 0x801214F0; -gViewMatrixF = 0x80121530; -gCameraMatrixF = 0x80121570; -gProjectionMatrixF = 0x801215B0; -gProjectionMatrix = 0x801215F0; -gUnusedProjectionMatrix = 0x80121630; +gViewProjMatrixF = 0x80121530; +gViewMatrixF = 0x80121570; +gInverseViewMatrixF = 0x801215B0; +gPerspectiveMatrix = 0x801215F0; +gInverseViewMatrix = 0x80121630; gCurrentModelMatrixF = 0x80121670; -gCurrentModelMatrixS = 0x801216B0; +gCurrentMVPMatrixF = 0x801216B0; sSIMesgQueue = 0x801216F0; sSIMesgBuf = 0x80121708; gSIMesg = 0x8012170C; @@ -3758,13 +3758,13 @@ gCiPalettesSize = 0x80126970; gFirstTexIsLoaded = 0x80126974; gSpriteOffsetTable = 0x80126978; gSpriteCache = 0x8012697C; -gCurrentSprite = 0x80126980; +gCurrentSpriteAsset = 0x80126980; gSpriteTableSize = 0x80126984; gSpriteCacheCount = 0x80126988; D_8012635C = 0x8012698C; -D_80126360 = 0x80126990; -D_80126364 = 0x80126994; -D_80126368 = 0x80126998; +gSpriteVertices = 0x80126990; +gSpriteDLists = 0x80126994; +gSpriteTriangles = 0x80126998; gTempTextureHeader = 0x8012699C; D_80126370 = 0x801269A0; gCurrentRenderFlags = 0x801269A4; diff --git a/ver/symbols/symbol_addrs.us.v77.txt b/ver/symbols/symbol_addrs.us.v77.txt index 2d3f73d0..6309d951 100644 --- a/ver/symbols/symbol_addrs.us.v77.txt +++ b/ver/symbols/symbol_addrs.us.v77.txt @@ -911,7 +911,7 @@ mtx_perspective = 0x8006807C; viewport_rsp_set = 0x80068158; viewport_reset = 0x800682AC; mtx_world_origin = 0x80068408; -sprite_anim_off = 0x80068508; +cam_set_sprite_anim_mode = 0x80068508; render_sprite_billboard = 0x80068514; render_ortho_triangle_image = 0x80068BF4; mtx_shear_push = 0x80068FA8; @@ -924,7 +924,7 @@ cam_move_dir = 0x80069B70; cam_rotate = 0x80069CB4; cam_get_active_camera_no_cutscenes = 0x80069CFC; cam_get_active_camera = 0x80069D20; -get_cutscene_camera_segment = 0x80069D7C; +cam_get_cameras = 0x80069D7C; get_projection_matrix_f32 = 0x80069DA4; get_projection_matrix_s16 = 0x80069DB0; get_camera_matrix = 0x80069DBC; @@ -1288,7 +1288,7 @@ sprite_cache_asset_id = 0x8007C8A0; load_sprite_info = 0x8007C8E0; func_8007CA68 = 0x8007CA68; sprite_free = 0x8007CCB0; -func_8007CDC0 = 0x8007CDC0; +sprite_init_frame = 0x8007CDC0; material_init = 0x8007D0F4; tex_palette_id = 0x8007EF64; tex_animate_texture = 0x8007EF80; @@ -4058,7 +4058,7 @@ gNumCameras = 0x80120CE8; D_80120CEC = 0x80120CEC; gCameraTransform = 0x80120CF0; gMtxOriginID = 0x80120D08; -gSpriteAnimOff = 0x80120D0C; +gSpriteAnimMode = 0x80120D0C; gCurCamFOV = 0x80120D10; gCutsceneCameraActive = 0x80120D14; gAdjustViewportHeight = 0x80120D15; @@ -4066,21 +4066,21 @@ gNoCamShake = 0x80120D18; gModelMatrixStackPos = 0x80120D1C; gCameraMatrixPos = 0x80120D20; D_80120D24 = 0x80120D24; -gModelMatrixViewX = 0x80120D28; -gModelMatrixViewY = 0x80120D40; -gModelMatrixViewZ = 0x80120D58; +gCameraRelPosStackX = 0x80120D28; +gCameraRelPosStackY = 0x80120D40; +gCameraRelPosStackZ = 0x80120D58; perspNorm = 0x80120D6C; gModelMatrixF = 0x80120D70; gModelMatrix = 0x80120D88; D_80120DA0 = 0x80120DA0; gPerspectiveMatrixF = 0x80120EE0; -gViewMatrixF = 0x80120F20; -gCameraMatrixF = 0x80120F60; -gProjectionMatrixF = 0x80120FA0; -gProjectionMatrix = 0x80120FE0; -gUnusedProjectionMatrix = 0x80121020; +gViewProjMatrixF = 0x80120F20; +gViewMatrixF = 0x80120F60; +gInverseViewMatrixF = 0x80120FA0; +gPerspectiveMatrix = 0x80120FE0; +gInverseViewMatrix = 0x80121020; gCurrentModelMatrixF = 0x80121060; -gCurrentModelMatrixS = 0x801210A0; +gCurrentMVPMatrixF = 0x801210A0; // controller .bss sSIMesgQueue = 0x801210E0; @@ -4253,13 +4253,13 @@ gCiPalettesSize = 0x80126340; gFirstTexIsLoaded = 0x80126344; gSpriteOffsetTable = 0x80126348; gSpriteCache = 0x8012634C; -gCurrentSprite = 0x80126350; +gCurrentSpriteAsset = 0x80126350; gSpriteTableSize = 0x80126354; gSpriteCacheCount = 0x80126358; D_8012635C = 0x8012635C; -D_80126360 = 0x80126360; -D_80126364 = 0x80126364; -D_80126368 = 0x80126368; +gSpriteVertices = 0x80126360; +gSpriteDLists = 0x80126364; +gSpriteTriangles = 0x80126368; gTempTextureHeader = 0x8012636C; D_80126370 = 0x80126370; gCurrentRenderFlags = 0x80126374; diff --git a/ver/symbols/symbol_addrs.us.v80.txt b/ver/symbols/symbol_addrs.us.v80.txt index 819ba0dc..f66d7093 100644 --- a/ver/symbols/symbol_addrs.us.v80.txt +++ b/ver/symbols/symbol_addrs.us.v80.txt @@ -857,7 +857,7 @@ mtx_perspective = 0x800682BC; viewport_rsp_set = 0x80068398; viewport_reset = 0x800684EC; mtx_world_origin = 0x80068648; -sprite_anim_off = 0x80068748; +cam_set_sprite_anim_mode = 0x80068748; render_sprite_billboard = 0x80068754; render_ortho_triangle_image = 0x80068E34; mtx_shear_push = 0x800691E8; @@ -870,7 +870,7 @@ cam_move_dir = 0x80069DB0; cam_rotate = 0x80069EF4; cam_get_active_camera_no_cutscenes = 0x80069F3C; cam_get_active_camera = 0x80069F60; -get_cutscene_camera_segment = 0x80069FBC; +cam_get_cameras = 0x80069FBC; get_projection_matrix_f32 = 0x80069FE4; get_projection_matrix_s16 = 0x80069FF0; get_camera_matrix = 0x80069FFC; @@ -1211,7 +1211,7 @@ sprite_cache_asset_id = 0x8007CCF0; load_sprite_info = 0x8007CD30; func_8007CA68 = 0x8007CEB8; sprite_free = 0x8007D100; -func_8007CDC0 = 0x8007D210; +sprite_init_frame = 0x8007D210; material_init = 0x8007D544; tex_palette_id = 0x8007F3B4; tex_animate_texture = 0x8007F3D0; @@ -3579,7 +3579,7 @@ gNumCameras = 0x80121268; D_80120CEC = 0x8012126C; gCameraTransform = 0x80121270; gMtxOriginID = 0x80121288; -gSpriteAnimOff = 0x8012128C; +gSpriteAnimMode = 0x8012128C; gCurCamFOV = 0x80121290; gCutsceneCameraActive = 0x80121294; gAdjustViewportHeight = 0x80121295; @@ -3587,21 +3587,21 @@ gNoCamShake = 0x80121298; gModelMatrixStackPos = 0x8012129C; gCameraMatrixPos = 0x801212A0; D_80120D24 = 0x801212A4; -gModelMatrixViewX = 0x801212A8; -gModelMatrixViewY = 0x801212C0; -gModelMatrixViewZ = 0x801212D8; +gCameraRelPosStackX = 0x801212A8; +gCameraRelPosStackY = 0x801212C0; +gCameraRelPosStackZ = 0x801212D8; perspNorm = 0x801212EC; gModelMatrixF = 0x801212F0; gModelMatrix = 0x80121308; D_80120DA0 = 0x80121320; gPerspectiveMatrixF = 0x80121460; -gViewMatrixF = 0x801214A0; -gCameraMatrixF = 0x801214E0; -gProjectionMatrixF = 0x80121520; -gProjectionMatrix = 0x80121560; -gUnusedProjectionMatrix = 0x801215A0; +gViewProjMatrixF = 0x801214A0; +gViewMatrixF = 0x801214E0; +gInverseViewMatrixF = 0x80121520; +gPerspectiveMatrix = 0x80121560; +gInverseViewMatrix = 0x801215A0; gCurrentModelMatrixF = 0x801215E0; -gCurrentModelMatrixS = 0x80121620; +gCurrentMVPMatrixF = 0x80121620; sSIMesgQueue = 0x80121660; sSIMesgBuf = 0x80121678; gSIMesg = 0x8012167C; @@ -3754,13 +3754,13 @@ gCiPalettesSize = 0x801268E0; gFirstTexIsLoaded = 0x801268E4; gSpriteOffsetTable = 0x801268E8; gSpriteCache = 0x801268EC; -gCurrentSprite = 0x801268F0; +gCurrentSpriteAsset = 0x801268F0; gSpriteTableSize = 0x801268F4; gSpriteCacheCount = 0x801268F8; D_8012635C = 0x801268FC; -D_80126360 = 0x80126900; -D_80126364 = 0x80126904; -D_80126368 = 0x80126908; +gSpriteVertices = 0x80126900; +gSpriteDLists = 0x80126904; +gSpriteTriangles = 0x80126908; gTempTextureHeader = 0x8012690C; D_80126370 = 0x80126910; gCurrentRenderFlags = 0x80126914;