Files
Diddy-Kong-Racing/src/camera.c
T

1622 lines
57 KiB
C
Raw Normal View History

/* The comment below is needed for this file to be picked up by generate_ld */
/* RAM_POS: 0x80065EA0 */
#include "camera.h"
#include "audio.h"
#include "objects.h"
#include "game.h"
2023-06-22 15:13:36 -04:00
#include "tracks.h"
2021-09-17 23:52:24 -04:00
#include "video.h"
#include "lib/src/libc/rmonPrintf.h"
2022-10-24 15:37:47 +01:00
#include "math_util.h"
#include "weather.h"
2023-09-29 18:50:06 -04:00
#include "lib/src/os/piint.h"
/************ .rodata ************/
UNUSED const char D_800E6F00[] = "Camera Error: Illegal mode!\n";
/*********************************/
/************ .data ************/
2022-10-24 15:37:47 +01:00
s8 gAntiPiracyViewport = FALSE;
// x1, y1, x2, y2
// posX, posY, width, height
// scissorX1, scissorY1, scissorX2, scissorY2
// flags
2024-01-26 09:12:45 -05:00
#define DEFAULT_VIEWPORT \
0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_WIDTH_HALF, SCREEN_HEIGHT_HALF, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0, \
SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, 0
ScreenViewport gScreenViewports[4] = {
{ DEFAULT_VIEWPORT },
{ DEFAULT_VIEWPORT },
{ DEFAULT_VIEWPORT },
{ DEFAULT_VIEWPORT },
};
2023-01-23 12:54:17 +00:00
u32 gViewportWithBG = FALSE;
2024-01-26 09:12:45 -05:00
Vertex gVehiclePartVertex = { 0, 0, 0, 255, 255, 255, 255 };
2024-01-26 09:12:45 -05:00
// The viewport z-range below is half of the max (511)
#define G_HALFZ (G_MAXZ / 2) /* 9 bits of integer screen-Z precision */
// RSP Viewports
2023-01-23 12:54:17 +00:00
Vp gViewportStack[20] = {
2024-01-26 09:12:45 -05:00
{ { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } }, { { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } },
{ { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } }, { { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } },
{ { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } }, { { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } },
{ { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } }, { { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } },
{ { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } }, { { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } },
{ { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } }, { { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } },
{ { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } }, { { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } },
{ { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } }, { { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } },
{ { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } }, { { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } },
{ { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } }, { { { 0, 0, G_HALFZ, 0 }, { 0, 0, G_HALFZ, 0 } } },
};
2022-03-10 09:01:18 -05:00
ObjectTransform D_800DD288 = {
2021-09-17 09:34:22 -04:00
0, 0, 0, 0, 1.0f, 0.0f, 0.0f, -281.0f,
};
2022-03-10 09:01:18 -05:00
ObjectTransform D_800DD2A0 = {
2021-09-17 09:34:22 -04:00
0, 0, 0, 0, 1.0f, 0.0f, 0.0f, 0.0f,
};
2023-10-06 14:40:45 +01:00
Matrix gOrthoMatrixF = {
{ 1.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 1.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.0f, 160.0f },
};
2024-01-26 09:12:45 -05:00
u8 gCameraZoomLevels[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
/*******************************/
/************ .bss ************/
2023-10-06 14:40:45 +01:00
ObjectSegment gCameraSegment[8];
s32 gNumberOfViewports;
2022-11-20 23:37:50 +00:00
s32 gActiveCameraID;
2023-01-06 19:39:37 +00:00
s32 gViewportCap;
UNUSED s32 D_80120CEC;
2023-01-23 12:54:17 +00:00
ObjectTransform gCameraTransform;
2023-10-06 14:40:45 +01:00
s32 gMatrixType;
s32 gSpriteAnimOff;
f32 gCurCamFOV;
2022-10-24 15:37:47 +01:00
s8 gCutsceneCameraActive;
s8 gAdjustViewportHeight;
s32 D_80120D18;
2023-10-06 14:40:45 +01:00
s32 gModelMatrixStackPos;
s32 gCameraMatrixPos;
2022-10-24 15:37:47 +01:00
UNUSED s32 D_80120D24;
2023-10-06 14:40:45 +01:00
f32 gModelMatrixViewX[6];
f32 gModelMatrixViewY[6];
f32 gModelMatrixViewZ[5];
u16 perspNorm;
2023-10-06 14:40:45 +01:00
Matrix *gModelMatrixF[6];
MatrixS *gModelMatrixS[6];
2022-03-10 09:01:18 -05:00
Matrix D_80120DA0[5];
Matrix gPerspectiveMatrixF;
2023-10-06 14:40:45 +01:00
Matrix gViewMatrixF;
Matrix gCameraMatrixF;
Matrix gProjectionMatrixF;
MatrixS gProjectionMatrixS;
UNUSED MatrixS gUnusedProjectionMatrixS; // Copied to the same way as gProjectionMatrixS, but not actually used.
Matrix gCurrentModelMatrixF;
Matrix gCurrentModelMatrixS;
/******************************/
2023-09-29 18:50:06 -04:00
#ifdef NON_MATCHING
extern s32 D_B0000578;
2023-04-12 07:55:53 -04:00
/**
* Official Name: camInit
2024-01-26 09:12:45 -05:00
*/
void camera_init(void) {
2023-09-29 18:50:06 -04:00
s32 i;
s32 j;
u32 stat;
2024-01-26 09:12:45 -05:00
// This loop is not cooperating.
for (i = 0; i < 5; i++) {
gModelMatrixF[i] = D_80120DA0 + i + i * 0;
}
2023-09-29 18:50:06 -04:00
for (j = 0; j < 8; j++) {
2022-11-20 23:37:50 +00:00
gActiveCameraID = j;
camera_reset(200, 200, 200, 0, 0, 180);
2023-09-29 18:50:06 -04:00
}
2024-01-26 09:12:45 -05:00
gCutsceneCameraActive = FALSE;
2022-11-20 23:37:50 +00:00
gActiveCameraID = 0;
2023-10-06 14:40:45 +01:00
gModelMatrixStackPos = 0;
gCameraMatrixPos = 0;
gNumberOfViewports = 0;
gSpriteAnimOff = FALSE;
D_80120D18 = 0;
2022-10-24 15:37:47 +01:00
gAdjustViewportHeight = 0;
gAntiPiracyViewport = 0;
2024-01-26 09:12:45 -05:00
2023-09-29 18:50:06 -04:00
WAIT_ON_IOBUSY(stat);
2024-01-26 09:12:45 -05:00
// 0xB0000578 is a direct read from the ROM as opposed to RAM
2023-09-29 18:50:06 -04:00
if (((D_B0000578 & 0xFFFF) & 0xFFFF) != 0x8965) {
2022-10-24 15:37:47 +01:00
gAntiPiracyViewport = TRUE;
}
2023-09-29 18:50:06 -04:00
2024-01-26 09:12:45 -05:00
guPerspectiveF(gPerspectiveMatrixF, &perspNorm, CAMERA_DEFAULT_FOV, CAMERA_ASPECT, CAMERA_NEAR, CAMERA_FAR,
CAMERA_SCALE);
f32_matrix_to_s16_matrix(&gPerspectiveMatrixF, &gProjectionMatrixS);
gCurCamFOV = CAMERA_DEFAULT_FOV;
}
#else
GLOBAL_ASM("asm/non_matchings/camera/camera_init.s")
#endif
void func_80066060(s32 cameraID, s32 zoomLevel) {
if (cameraID >= 0 && cameraID < 4) {
gCameraZoomLevels[cameraID] = zoomLevel;
gCameraSegment[cameraID].object.animationID = zoomLevel;
}
}
2022-10-24 15:37:47 +01:00
/**
* Set gAdjustViewportHeight to PAL mode if necessary, if setting is 1.
* Otherwise, set it to 0, regardless of TV type.
2024-01-26 09:12:45 -05:00
*/
2022-10-24 15:37:47 +01:00
void set_viewport_tv_type(s8 setting) {
if (osTvType == TV_TYPE_PAL) {
gAdjustViewportHeight = setting;
}
}
2022-10-24 15:37:47 +01:00
void func_800660C0(void) {
D_80120D18 = 1;
}
2022-10-24 15:37:47 +01:00
void func_800660D0(void) {
D_80120D18 = 0;
}
2021-12-10 19:03:19 +00:00
/**
* Unused function that will return the current camera's FoV.
* Official Name: camGetFOV
2021-12-10 19:03:19 +00:00
*/
UNUSED f32 get_current_camera_fov(void) {
return gCurCamFOV;
}
2021-12-10 19:03:19 +00:00
/**
* Set the FoV of the viewspace, then recalculate the perspective matrix.
* Official Name: camSetFOV
2021-12-10 19:03:19 +00:00
*/
void update_camera_fov(f32 camFieldOfView) {
if (CAMERA_MIN_FOV < camFieldOfView && camFieldOfView < CAMERA_MAX_FOV && camFieldOfView != gCurCamFOV) {
gCurCamFOV = camFieldOfView;
2024-01-26 09:12:45 -05:00
guPerspectiveF(gPerspectiveMatrixF, &perspNorm, camFieldOfView, CAMERA_ASPECT, CAMERA_NEAR, CAMERA_FAR,
CAMERA_SCALE);
2023-10-06 14:40:45 +01:00
f32_matrix_to_s16_matrix(&gPerspectiveMatrixF, &gProjectionMatrixS);
}
}
2021-12-10 19:03:19 +00:00
/**
* Unused function that recalculates the perspective matrix.
*/
UNUSED void calculate_camera_perspective(void) {
2024-01-26 09:12:45 -05:00
guPerspectiveF(gPerspectiveMatrixF, &perspNorm, CAMERA_DEFAULT_FOV, CAMERA_ASPECT, CAMERA_NEAR, CAMERA_FAR,
CAMERA_SCALE);
2023-10-06 14:40:45 +01:00
f32_matrix_to_s16_matrix(&gPerspectiveMatrixF, &gProjectionMatrixS);
}
/**
* Return the current fixed point model matrix.
2024-01-26 09:12:45 -05:00
*/
UNUSED Matrix *matrix_get_model_s16(void) {
return &gCurrentModelMatrixS;
}
2023-01-06 19:39:37 +00:00
/**
* Returns the number of active viewports.
2024-01-26 09:12:45 -05:00
*/
s32 get_viewport_count(void) {
return gNumberOfViewports;
}
2022-12-04 18:43:29 +00:00
/**
* Return the index of the active view.
* 0-3 is players 1-4, and 4-7 is the same, but with 4 added on for cutscenes.
2024-01-26 09:12:45 -05:00
*/
2022-12-04 18:43:29 +00:00
s32 get_current_viewport(void) {
2022-11-20 23:37:50 +00:00
return gActiveCameraID;
}
/**
* Initialises the camera object for the tracks menu.
2024-01-26 09:12:45 -05:00
*/
void camera_init_tracks_menu(Gfx **dList, MatrixS **mtxS) {
2023-01-23 12:54:17 +00:00
ObjectSegment *cam;
s16 angleY;
s16 angleX;
s16 angleZ;
s16 sp24;
2023-01-23 12:54:17 +00:00
f32 posX;
f32 posY;
f32 posZ;
2023-01-06 19:39:37 +00:00
set_active_viewports_and_max(0);
set_active_camera(0);
2023-01-23 12:54:17 +00:00
cam = get_active_camera_segment();
angleY = cam->trans.y_rotation;
angleX = cam->trans.x_rotation;
angleZ = cam->trans.z_rotation;
posX = cam->trans.x_position;
posY = cam->trans.y_position;
posZ = cam->trans.z_position;
2023-05-14 22:48:05 +01:00
sp24 = cam->camera.unk38;
2023-01-23 12:54:17 +00:00
cam->trans.z_rotation = 0;
cam->trans.x_rotation = 0;
cam->trans.y_rotation = -0x8000;
2023-05-14 22:48:05 +01:00
cam->camera.unk38 = 0;
2023-01-23 12:54:17 +00:00
cam->trans.x_position = 0.0f;
cam->trans.y_position = 0.0f;
cam->trans.z_position = 0.0f;
2023-01-06 19:39:37 +00:00
update_envmap_position(0.0f, 0.0f, -1.0f);
func_80066CDC(dList, mtxS);
2023-05-14 22:48:05 +01:00
cam->camera.unk38 = sp24;
2023-01-23 12:54:17 +00:00
cam->trans.y_rotation = angleY;
cam->trans.x_rotation = angleX;
cam->trans.z_rotation = angleZ;
cam->trans.x_position = posX;
cam->trans.y_position = posY;
cam->trans.z_position = posZ;
}
2022-11-20 23:37:50 +00:00
/**
* Compare the coordinates passed through to the active camera and return the distance between them.
2024-01-26 09:12:45 -05:00
*/
2022-11-20 23:37:50 +00:00
f32 get_distance_to_active_camera(f32 xPos, f32 yPos, f32 zPos) {
2022-03-28 08:36:12 -04:00
s32 index;
f32 dx, dz, dy;
2022-11-20 23:37:50 +00:00
index = gActiveCameraID;
2022-10-24 15:37:47 +01:00
if (gCutsceneCameraActive) {
2022-03-28 08:36:12 -04:00
index += 4;
}
2023-10-06 14:40:45 +01:00
dz = zPos - gCameraSegment[index].trans.z_position;
dx = xPos - gCameraSegment[index].trans.x_position;
dy = yPos - gCameraSegment[index].trans.y_position;
2022-03-28 08:36:12 -04:00
return sqrtf((dz * dz) + ((dx * dx) + (dy * dy)));
}
/**
* Sets the position and angle of the active camera.
* Also sets the other properties of the camera to a default.
2024-01-26 09:12:45 -05:00
*/
void camera_reset(s32 xPos, s32 yPos, s32 zPos, s32 angleZ, s32 angleX, s32 angleY) {
gCameraSegment[gActiveCameraID].trans.z_rotation = (s16) (angleZ * 0xB6);
2023-10-06 14:40:45 +01:00
gCameraSegment[gActiveCameraID].trans.x_position = (f32) xPos;
gCameraSegment[gActiveCameraID].trans.y_position = (f32) yPos;
gCameraSegment[gActiveCameraID].trans.z_position = (f32) zPos;
gCameraSegment[gActiveCameraID].trans.x_rotation = (s16) (angleX * 0xB6);
gCameraSegment[gActiveCameraID].camera.unk38 = 0;
2023-10-06 14:40:45 +01:00
gCameraSegment[gActiveCameraID].z_velocity = 0.0f;
gCameraSegment[gActiveCameraID].unk28 = 0.0f;
gCameraSegment[gActiveCameraID].camera.unk2C = 0.0f;
gCameraSegment[gActiveCameraID].camera.distanceToCamera = 0.0f;
gCameraSegment[gActiveCameraID].x_velocity = 160.0f;
gCameraSegment[gActiveCameraID].trans.y_rotation = (s16) (angleY * 0xB6);
gCameraSegment[gActiveCameraID].object.animationID = gCameraZoomLevels[gActiveCameraID];
}
2022-10-24 15:37:47 +01:00
/**
* Write directly to the second set of object stack indeces.
* The first 4 are reserved for the 4 player viewports, so the misc views, used in the title screen
* and course previews instead use the next 4.
2024-01-26 09:12:45 -05:00
*/
2022-10-24 15:37:47 +01:00
void write_to_object_render_stack(s32 stackPos, f32 xPos, f32 yPos, f32 zPos, s16 arg4, s16 arg5, s16 arg6) {
stackPos += 4;
2023-10-06 14:40:45 +01:00
gCameraSegment[stackPos].camera.unk38 = 0;
gCameraSegment[stackPos].trans.x_position = xPos;
gCameraSegment[stackPos].trans.y_position = yPos;
gCameraSegment[stackPos].trans.z_position = zPos;
gCameraSegment[stackPos].trans.y_rotation = arg4;
gCameraSegment[stackPos].trans.x_rotation = arg5;
gCameraSegment[stackPos].trans.z_rotation = arg6;
gCameraSegment[stackPos].object.cameraSegmentID = get_level_segment_index_from_position(xPos, yPos, zPos);
2022-10-24 15:37:47 +01:00
gCutsceneCameraActive = TRUE;
}
2022-10-24 15:37:47 +01:00
/**
* Check if the misc camera view is active.
* Official name: camIsUserView
2024-01-26 09:12:45 -05:00
*/
2022-10-24 15:37:47 +01:00
s8 check_if_showing_cutscene_camera(void) {
return gCutsceneCameraActive;
}
2022-10-24 15:37:47 +01:00
/**
* Disable the cutscene camera, returning it to the conventional mode.
2024-01-26 09:12:45 -05:00
*/
2022-10-24 15:37:47 +01:00
void disable_cutscene_camera(void) {
gCutsceneCameraActive = FALSE;
}
2022-10-24 15:37:47 +01:00
/**
2023-01-06 19:39:37 +00:00
* Sets the cap for the viewports. Usually reflecting how many there are.
2022-10-24 15:37:47 +01:00
* If the number passed is within 1-4, then the stack cap is set to
* how many active viewports there are.
2024-01-26 09:12:45 -05:00
*/
2023-01-06 19:39:37 +00:00
s32 set_active_viewports_and_max(s32 num) {
2022-10-24 15:37:47 +01:00
if (num >= 0 && num < 4) {
gNumberOfViewports = num;
} else {
gNumberOfViewports = 0;
}
switch (gNumberOfViewports) {
case VIEWPORTS_COUNT_1_PLAYER:
2023-01-06 19:39:37 +00:00
gViewportCap = 1;
break;
case VIEWPORTS_COUNT_2_PLAYERS:
2023-01-06 19:39:37 +00:00
gViewportCap = 2;
break;
case VIEWPORTS_COUNT_3_PLAYERS:
2023-01-06 19:39:37 +00:00
gViewportCap = 3;
break;
case VIEWPORTS_COUNT_4_PLAYERS:
2023-01-06 19:39:37 +00:00
gViewportCap = 4;
break;
}
2023-01-06 19:39:37 +00:00
if (gActiveCameraID >= gViewportCap) {
2022-11-20 23:37:50 +00:00
gActiveCameraID = 0;
}
2023-01-06 19:39:37 +00:00
return gViewportCap;
}
2022-10-24 15:37:47 +01:00
/**
2023-01-06 19:39:37 +00:00
* Sets the active viewport ID to the passed number.
2022-10-24 15:37:47 +01:00
* If it's not within 1-4, then it's set to 0.
* Official name: camSetView
2024-01-26 09:12:45 -05:00
*/
2023-01-06 19:39:37 +00:00
void set_active_camera(s32 num) {
2022-10-24 15:37:47 +01:00
if (num >= 0 && num < 4) {
2022-11-20 23:37:50 +00:00
gActiveCameraID = num;
} else {
2024-05-25 20:29:41 +01:00
stubbed_printf("Camera Error: Illegal player no!\n");
2022-11-20 23:37:50 +00:00
gActiveCameraID = 0;
}
}
2023-01-23 12:54:17 +00:00
/**
* Takes the size of each view frame and writes them to the viewport stack, using values compatable with the RSP.
* Only does this if extended backgrounds are enabled.
2024-01-26 09:12:45 -05:00
*/
2023-01-23 12:54:17 +00:00
void copy_viewports_to_stack(void) {
2021-12-10 19:03:19 +00:00
s32 width;
s32 height;
2023-01-23 12:54:17 +00:00
s32 port;
2021-12-10 19:03:19 +00:00
s32 yPos;
s32 xPos;
s32 i;
2023-01-23 12:54:17 +00:00
gViewportWithBG = 1 - gViewportWithBG;
for (i = 0; i < 4; i++) {
2021-12-10 19:03:19 +00:00
if (gScreenViewports[i].flags & VIEWPORT_UNK_04) {
gScreenViewports[i].flags &= ~VIEWPORT_EXTRA_BG;
2021-12-10 19:03:19 +00:00
} else if (gScreenViewports[i].flags & VIEWPORT_UNK_02) {
gScreenViewports[i].flags |= VIEWPORT_EXTRA_BG;
}
2023-01-23 12:54:17 +00:00
gScreenViewports[i].flags &= ~(VIEWPORT_UNK_02 | VIEWPORT_UNK_04);
if (gScreenViewports[i].flags & VIEWPORT_EXTRA_BG) {
2021-12-10 19:03:19 +00:00
if (!(gScreenViewports[i].flags & VIEWPORT_X_CUSTOM)) {
2023-01-23 12:54:17 +00:00
xPos = (((gScreenViewports[i].x2 - gScreenViewports[i].x1) + 1) << 1) + (gScreenViewports[i].x1 * 4);
} else {
2021-12-10 19:03:19 +00:00
xPos = gScreenViewports[i].posX;
xPos *= 4;
}
2021-12-10 19:03:19 +00:00
if (!(gScreenViewports[i].flags & VIEWPORT_Y_CUSTOM)) {
2023-01-23 12:54:17 +00:00
yPos = (((gScreenViewports[i].y2 - gScreenViewports[i].y1 + 1)) << 1) + (gScreenViewports[i].y1 * 4);
} else {
2021-12-10 19:03:19 +00:00
yPos = gScreenViewports[i].posY;
yPos *= 4;
}
2021-12-10 19:03:19 +00:00
if (!(gScreenViewports[i].flags & VIEWPORT_WIDTH_CUSTOM)) {
width = gScreenViewports[i].x2 - gScreenViewports[i].x1;
width += 1;
width *= 2;
} else {
2021-12-10 19:03:19 +00:00
width = gScreenViewports[i].width;
width *= 2;
}
2021-12-10 19:03:19 +00:00
if (!(gScreenViewports[i].flags & VIEWPORT_HEIGHT_CUSTOM)) {
2023-01-23 12:54:17 +00:00
height = (gScreenViewports[i].y2 - gScreenViewports[i].y1) + 1;
2021-12-10 19:03:19 +00:00
height *= 2;
} else {
2021-12-10 19:03:19 +00:00
height = gScreenViewports[i].height;
height *= 2;
}
2023-01-23 12:54:17 +00:00
port = i + (gViewportWithBG * 5);
port += 10;
if (get_filtered_cheats() & CHEAT_MIRRORED_TRACKS) {
2024-01-26 09:12:45 -05:00
if (0) {} // Fakematch
2023-01-23 12:54:17 +00:00
width = -width;
}
2023-01-23 12:54:17 +00:00
gViewportStack[port].vp.vtrans[0] = xPos;
gViewportStack[port].vp.vtrans[1] = yPos;
gViewportStack[port].vp.vscale[0] = width;
gViewportStack[port].vp.vscale[1] = height;
}
}
}
2023-01-28 20:25:21 -05:00
void camEnableUserView(s32 viewPortIndex, s32 arg1) {
if (arg1) {
gScreenViewports[viewPortIndex].flags |= VIEWPORT_EXTRA_BG;
} else {
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].flags |= VIEWPORT_UNK_02;
}
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].flags &= ~VIEWPORT_UNK_04;
}
2023-01-28 20:25:21 -05:00
void camDisableUserView(s32 viewPortIndex, s32 arg1) {
if (arg1) {
gScreenViewports[viewPortIndex].flags &= ~VIEWPORT_EXTRA_BG;
} else {
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].flags |= VIEWPORT_UNK_04;
}
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].flags &= ~VIEWPORT_UNK_02;
}
/**
* Return's the current viewport's flag status for extended backgrounds.
* Required to draw some extra things used in menus.
2024-01-26 09:12:45 -05:00
*/
s32 check_viewport_background_flag(s32 viewPortIndex) {
return gScreenViewports[viewPortIndex].flags & VIEWPORT_EXTRA_BG;
}
2023-01-23 12:54:17 +00:00
/**
* Sets the intended viewport to the size passed through by arguments.
* Official Name: camSetUserView
2024-01-26 09:12:45 -05:00
*/
void viewport_menu_set(s32 viewPortIndex, s32 x1, s32 y1, s32 x2, s32 y2) {
s32 widthAndHeight, width, height;
s32 temp;
2025-02-14 18:40:55 +00:00
widthAndHeight = fb_size();
height = GET_VIDEO_HEIGHT(widthAndHeight) & 0xFFFF;
width = GET_VIDEO_WIDTH(widthAndHeight);
2021-12-10 19:03:19 +00:00
if (x2 < x1) {
temp = x1;
x1 = x2;
x2 = temp;
}
2021-12-10 19:03:19 +00:00
if (y2 < y1) {
temp = y1;
2021-12-10 19:03:19 +00:00
y1 = y2;
y2 = temp;
}
2023-01-23 12:54:17 +00:00
if (x1 >= width || x2 < 0 || y1 >= height || y2 < 0) {
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].scissorX1 = 0;
gScreenViewports[viewPortIndex].scissorY1 = 0;
gScreenViewports[viewPortIndex].scissorX2 = 0;
gScreenViewports[viewPortIndex].scissorY2 = 0;
} else {
if (x1 < 0) {
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].scissorX1 = 0;
} else {
gScreenViewports[viewPortIndex].scissorX1 = x1;
}
2021-12-10 19:03:19 +00:00
if (y1 < 0) {
gScreenViewports[viewPortIndex].scissorY1 = 0;
} else {
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].scissorY1 = y1;
}
if (x2 >= width) {
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].scissorX2 = width - 1;
} else {
gScreenViewports[viewPortIndex].scissorX2 = x2;
}
if (y2 >= height) {
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].scissorY2 = height - 1;
} else {
gScreenViewports[viewPortIndex].scissorY2 = y2;
}
}
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].y1 = y1;
gScreenViewports[viewPortIndex].x1 = x1;
gScreenViewports[viewPortIndex].x2 = x2;
gScreenViewports[viewPortIndex].y2 = y2;
}
2021-12-10 19:03:19 +00:00
/**
* Set the selected viewport's coordinate offsets and view size.
* If you pass VIEWPORT_AUTO through, then the property will be automatically set when the game creates the viewports.
*/
void set_viewport_properties(s32 viewPortIndex, s32 posX, s32 posY, s32 width, s32 height) {
if (posX != VIEWPORT_AUTO) {
gScreenViewports[viewPortIndex].posX = posX;
gScreenViewports[viewPortIndex].flags |= VIEWPORT_X_CUSTOM;
} else {
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].flags &= ~VIEWPORT_X_CUSTOM;
}
2021-12-10 19:03:19 +00:00
if (posY != VIEWPORT_AUTO) {
2024-01-26 09:12:45 -05:00
//!@bug Viewport Y writes to the X value. Luckily, all cases this function is called use VIEWPORT_AUTO,
// so this bug doesn't happen in practice.
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].posX = posY;
gScreenViewports[viewPortIndex].flags |= VIEWPORT_Y_CUSTOM;
} else {
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].flags &= ~VIEWPORT_Y_CUSTOM;
}
2021-12-10 19:03:19 +00:00
if (width != VIEWPORT_AUTO) {
gScreenViewports[viewPortIndex].width = width;
gScreenViewports[viewPortIndex].flags |= VIEWPORT_WIDTH_CUSTOM;
} else {
2021-12-10 19:03:19 +00:00
gScreenViewports[viewPortIndex].flags &= ~VIEWPORT_WIDTH_CUSTOM;
}
2021-12-10 19:03:19 +00:00
if (height != VIEWPORT_AUTO) {
gScreenViewports[viewPortIndex].height = height;
gScreenViewports[viewPortIndex].flags |= VIEWPORT_HEIGHT_CUSTOM;
} else {
gScreenViewports[viewPortIndex].flags &= ~VIEWPORT_HEIGHT_CUSTOM;
}
}
2021-12-10 19:03:19 +00:00
/**
* Sets the passed values to be equal to the selected viewports scissor size, before drawing the background elements.
* Usually, this is the same size as the viewport's size.
2023-01-31 12:02:37 -05:00
* Official name: camGetVisibleUserView
2021-12-10 19:03:19 +00:00
*/
s32 copy_viewport_background_size_to_coords(s32 viewPortIndex, s32 *x1, s32 *y1, s32 *x2, s32 *y2) {
2024-01-26 09:12:45 -05:00
// gDPFillRectangle values
2021-12-10 19:03:19 +00:00
*x1 = gScreenViewports[viewPortIndex].scissorX1;
*x2 = gScreenViewports[viewPortIndex].scissorX2;
*y1 = gScreenViewports[viewPortIndex].scissorY1;
*y2 = gScreenViewports[viewPortIndex].scissorY2;
if ((*x1 | *x2 | *y1 | *y2) == 0) {
return 0;
}
return 1;
}
2021-12-10 19:03:19 +00:00
/**
* Sets the passed values to the coordinate size of the passed viewport.
2023-01-31 12:02:37 -05:00
* Official name: camGetUserView
2021-12-10 19:03:19 +00:00
*/
void copy_viewport_frame_size_to_coords(s32 viewPortIndex, s32 *x1, s32 *y1, s32 *x2, s32 *y2) {
*x1 = gScreenViewports[viewPortIndex].x1;
*y1 = gScreenViewports[viewPortIndex].y1;
*x2 = gScreenViewports[viewPortIndex].x2;
2021-12-10 19:03:19 +00:00
*y2 = gScreenViewports[viewPortIndex].y2;
}
2021-12-10 19:03:19 +00:00
/**
* Unused function that sets the passed values to the framebuffer's size in coordinates.
* Official name: camGetWindowLimits
2021-12-10 19:03:19 +00:00
*/
UNUSED void copy_framebuffer_size_to_coords(s32 *x1, s32 *y1, s32 *x2, s32 *y2) {
2025-02-14 18:40:55 +00:00
u32 widthAndHeight = fb_size();
2021-12-10 19:03:19 +00:00
*x1 = 0;
*y1 = 0;
*x2 = GET_VIDEO_WIDTH(widthAndHeight);
*y2 = GET_VIDEO_HEIGHT(widthAndHeight);
}
#ifdef NON_EQUIVALENT
// viewport_main
2024-01-26 09:12:45 -05:00
// Alternative attempt: https://decomp.me/scratch/rcJYo
2021-07-08 10:59:11 -05:00
// Still a work-in-progress but it doesn't seem to cause any problems,
// which is why it is labeled under NON_EQUIVALENT
2021-07-08 10:59:11 -05:00
#define SCISSOR_INTERLACE G_SC_NON_INTERLACE
void func_80066CDC(Gfx **dlist, MatrixS **mats) {
2023-05-19 13:13:26 -04:00
u32 sp58_y;
u32 sp54_x;
u32 sp50_altPosY;
u32 sp4C_altPosX;
u32 posX;
u32 posY;
2023-05-19 13:13:26 -04:00
u32 x;
u32 y;
u32 videoHeight;
u32 videoWidth;
2021-07-08 10:59:11 -05:00
u32 widthAndHeight;
2023-05-19 13:13:26 -04:00
s32 savedCameraID;
s32 originalCameraID;
s32 tempCameraID;
s32 viewports;
2021-07-08 10:59:11 -05:00
2023-05-19 13:13:26 -04:00
originalCameraID = gActiveCameraID;
savedCameraID = gActiveCameraID;
if (func_8000E184() && gNumberOfViewports == VIEWPORTS_COUNT_1_PLAYER) {
2022-11-20 23:37:50 +00:00
gActiveCameraID = 1;
2023-05-19 13:13:26 -04:00
savedCameraID = 0;
2021-07-08 10:59:11 -05:00
}
2025-02-14 18:40:55 +00:00
widthAndHeight = fb_size();
videoHeight = GET_VIDEO_HEIGHT(widthAndHeight);
videoWidth = GET_VIDEO_WIDTH(widthAndHeight);
2023-05-19 13:13:26 -04:00
if (gScreenViewports[savedCameraID].flags & VIEWPORT_EXTRA_BG) {
tempCameraID = gActiveCameraID;
gActiveCameraID = savedCameraID;
2024-01-26 09:12:45 -05:00
gDPSetScissor((*dlist)++, SCISSOR_INTERLACE, gScreenViewports[gActiveCameraID].scissorX1,
gScreenViewports[gActiveCameraID].scissorY1, gScreenViewports[gActiveCameraID].scissorX2,
gScreenViewports[gActiveCameraID].scissorY2);
viewport_rsp_set(dlist, 0, 0, 0, 0);
2023-05-19 13:13:26 -04:00
gActiveCameraID = tempCameraID;
2022-03-28 08:36:12 -04:00
if (mats != 0) {
func_80067D3C(dlist, mats);
2021-07-08 10:59:11 -05:00
}
2023-05-19 13:13:26 -04:00
gActiveCameraID = originalCameraID;
2021-07-08 10:59:11 -05:00
return;
}
2023-05-19 13:13:26 -04:00
viewports = gNumberOfViewports;
if (viewports == VIEWPORTS_COUNT_3_PLAYERS) {
viewports = VIEWPORTS_COUNT_4_PLAYERS;
2021-07-08 10:59:11 -05:00
}
2023-05-19 13:13:26 -04:00
y = videoHeight >> 1;
x = videoWidth >> 1;
sp54_x = x;
sp58_y = y;
if (osTvType == TV_TYPE_PAL) {
2023-05-19 13:13:26 -04:00
sp58_y = 145;
2021-07-08 10:59:11 -05:00
}
2023-05-19 13:13:26 -04:00
switch (viewports) {
case VIEWPORTS_COUNT_1_PLAYER:
2023-05-19 13:13:26 -04:00
posY = sp58_y;
if (osTvType == TV_TYPE_PAL) {
posY -= 18;
2021-07-08 10:59:11 -05:00
}
gDPSetScissor((*dlist)++, SCISSOR_INTERLACE, 0, 0, videoWidth, videoHeight);
2023-05-19 13:13:26 -04:00
posX = x;
2021-07-08 10:59:11 -05:00
break;
case VIEWPORTS_COUNT_2_PLAYERS:
2022-11-20 23:37:50 +00:00
if (gActiveCameraID == 0) {
posY = videoHeight >> 2;
if (osTvType == TV_TYPE_PAL) {
posY -= 12;
2021-07-08 10:59:11 -05:00
}
2023-05-19 13:13:26 -04:00
gDPSetScissor((*dlist)++, SCISSOR_INTERLACE, 0, 0, videoWidth, (y - (videoHeight >> 7)));
2021-07-08 10:59:11 -05:00
} else {
2023-05-19 13:13:26 -04:00
posY = y;
posY += videoHeight >> 2;
2024-01-26 09:12:45 -05:00
gDPSetScissor((*dlist)++, SCISSOR_INTERLACE, 0, (y + (videoHeight >> 7)), videoWidth,
(videoHeight - (videoHeight >> 7)));
2021-07-08 10:59:11 -05:00
}
2023-05-19 13:13:26 -04:00
posX = x;
2021-07-08 10:59:11 -05:00
break;
case VIEWPORTS_COUNT_3_PLAYERS:
2022-11-20 23:37:50 +00:00
if (gActiveCameraID == 0) {
2023-05-19 13:13:26 -04:00
posY = sp58_y;
posX = videoWidth >> 2;
2023-05-19 13:13:26 -04:00
gDPSetScissor((*dlist)++, SCISSOR_INTERLACE, 0, 0, x - (videoWidth >> 8), videoHeight);
2021-07-08 10:59:11 -05:00
} else {
2023-05-19 13:13:26 -04:00
posY = sp58_y;
2024-01-26 09:12:45 -05:00
// posX = x;
2023-05-19 13:13:26 -04:00
posX = x + (videoWidth >> 2);
2024-01-26 09:12:45 -05:00
gDPSetScissor((*dlist)++, SCISSOR_INTERLACE, x + (videoWidth >> 8), 0, videoWidth - (videoWidth >> 8),
videoHeight);
2021-07-08 10:59:11 -05:00
}
break;
case VIEWPORTS_COUNT_4_PLAYERS:
2023-05-19 13:13:26 -04:00
sp58_y >>= 1;
sp54_x = x >> 1;
posY = 0;
posX = 0;
2022-11-20 23:37:50 +00:00
switch (gActiveCameraID) {
2021-07-08 10:59:11 -05:00
case 0:
2024-01-26 09:12:45 -05:00
// Using posX and posY here is not smart since IDO can't optimize out the zero now.
// Why here of all places did they do this instead of just setting zero like everywhere else?
gDPSetScissor((*dlist)++, SCISSOR_INTERLACE, posX, posY, (x - (videoWidth >> 8)),
(y - (videoHeight >> 7)));
2023-05-19 13:13:26 -04:00
break;
2021-07-08 10:59:11 -05:00
case 1:
2023-05-19 13:13:26 -04:00
posX = x;
2024-01-26 09:12:45 -05:00
gDPSetScissor((*dlist)++, SCISSOR_INTERLACE, (sp54_x + (videoWidth >> 8)), 0,
((sp54_x + sp54_x) - (videoWidth >> 8)), (y - (videoHeight >> 7)));
2021-07-08 10:59:11 -05:00
break;
case 2:
2023-05-19 13:13:26 -04:00
posY = y;
2024-01-26 09:12:45 -05:00
gDPSetScissor((*dlist)++, SCISSOR_INTERLACE, 0, y + (videoHeight >> 7), x - (videoWidth >> 8),
(y + y) - (videoHeight >> 7));
2021-07-08 10:59:11 -05:00
break;
case 3:
2023-05-19 13:13:26 -04:00
posY = y;
posX = x;
2024-01-26 09:12:45 -05:00
gDPSetScissor((*dlist)++, SCISSOR_INTERLACE, (sp54_x + (videoWidth >> 8)), y + (videoHeight >> 7),
(x + x) - (videoWidth >> 8), (y + y) - (videoHeight >> 7));
2021-07-08 10:59:11 -05:00
break;
}
2023-05-19 13:13:26 -04:00
posY += sp58_y;
posX += sp54_x;
if (osTvType == TV_TYPE_PAL) {
2023-05-19 13:13:26 -04:00
if (gActiveCameraID <= VIEWPORTS_COUNT_2_PLAYERS) {
posY -= 20;
2023-05-19 13:13:26 -04:00
} else {
posY -= 6;
2021-07-08 10:59:11 -05:00
}
}
break;
default:
//@bug These values are unset!
posY = sp50_altPosY;
posX = sp4C_altPosX;
2021-07-08 10:59:11 -05:00
break;
}
if (osTvType == TV_TYPE_PAL) {
posX -= 4;
2021-07-08 10:59:11 -05:00
}
viewport_rsp_set(dlist, sp54_x, sp58_y, posX, posY);
if (mats != NULL) {
2022-03-28 08:36:12 -04:00
func_80067D3C(dlist, mats);
2021-07-08 10:59:11 -05:00
}
2023-05-19 13:13:26 -04:00
gActiveCameraID = originalCameraID;
2021-07-08 10:59:11 -05:00
}
#else
GLOBAL_ASM("asm/non_matchings/camera/func_80066CDC.s")
2021-07-08 10:59:11 -05:00
#endif
/**
* Takes the size of the screen as depicted by the active menu viewport, then sets the RDP scissor to match it.
* Official Name: camSetScissor
2024-01-26 09:12:45 -05:00
*/
void viewport_scissor(Gfx **dlist) {
s32 size;
s32 lrx;
s32 lry;
s32 ulx;
s32 uly;
s32 numViewports;
s32 temp;
s32 temp2;
s32 temp3;
s32 temp4;
s32 width;
s32 height;
2025-02-14 18:40:55 +00:00
size = fb_size();
height = (u16) GET_VIDEO_HEIGHT(size);
width = (u16) size;
numViewports = gNumberOfViewports;
if (numViewports != 0) {
if (numViewports == VIEWPORTS_COUNT_3_PLAYERS) {
numViewports = VIEWPORTS_COUNT_4_PLAYERS;
}
lrx = ulx = 0;
lry = uly = 0;
2024-01-26 09:12:45 -05:00
// clang-format off
lrx += width;\
lry += height;
2024-01-26 09:12:45 -05:00
// clang-format on
temp = lry >> 7;
temp2 = lrx >> 8;
temp4 = lrx >> 1;
temp3 = lry >> 1;
switch (numViewports) {
case 1:
2024-01-26 09:12:45 -05:00
switch (gActiveCameraID) {
case 0:
lry = temp3 - temp;
break;
default:
uly = temp3 + temp;
lry -= temp;
break;
}
break;
case 2:
2024-01-26 09:12:45 -05:00
switch (gActiveCameraID) {
case 0:
lrx = temp4 - temp2;
break;
default:
ulx = temp4 + temp2;
lrx -= temp2;
break;
}
break;
case 3:
2024-01-26 09:12:45 -05:00
// clang-format off
switch (gActiveCameraID) {
case 0:
lrx = temp4 - temp2;\
lry = temp3 - temp;
break;
case 1:
ulx = temp4 + temp2;
lrx -= temp2;
lry = temp3 - temp;
break;
case 2:
uly = temp3 + temp;
lrx = temp4 - temp2;\
lry -= temp;
break;
case 3:
ulx = temp4 + temp2;\
uly = temp3 + temp;
lrx -= temp2;\
lry -= temp;
break;
}
// clang-format on
break;
}
gDPSetScissor((*dlist)++, 0, ulx, uly, lrx, lry);
return;
}
gDPSetScissor((*dlist)++, 0, 0, 0, width, height);
}
2022-03-28 08:36:12 -04:00
2024-01-26 09:12:45 -05:00
// Official Name: camGetPlayerProjMtx / camSetProjMtx - ??
void func_80067D3C(Gfx **dlist, UNUSED MatrixS **mats) {
2022-03-28 08:36:12 -04:00
s32 temp;
gSPPerspNormalize((*dlist)++, perspNorm);
2022-03-28 08:36:12 -04:00
2022-11-20 23:37:50 +00:00
temp = gActiveCameraID;
2022-10-24 15:37:47 +01:00
if (gCutsceneCameraActive) {
2022-11-20 23:37:50 +00:00
gActiveCameraID += 4;
2022-03-28 08:36:12 -04:00
}
2023-10-06 14:40:45 +01:00
gCameraTransform.y_rotation = 0x8000 + gCameraSegment[gActiveCameraID].trans.y_rotation;
2024-01-26 09:12:45 -05:00
gCameraTransform.x_rotation =
gCameraSegment[gActiveCameraID].trans.x_rotation + gCameraSegment[gActiveCameraID].camera.unk38;
2023-10-06 14:40:45 +01:00
gCameraTransform.z_rotation = gCameraSegment[gActiveCameraID].trans.z_rotation;
2022-03-28 08:36:12 -04:00
2023-10-06 14:40:45 +01:00
gCameraTransform.x_position = -gCameraSegment[gActiveCameraID].trans.x_position;
gCameraTransform.y_position = -gCameraSegment[gActiveCameraID].trans.y_position;
2022-03-28 08:36:12 -04:00
if (D_80120D18 != 0) {
2023-10-06 14:40:45 +01:00
gCameraTransform.y_position -= gCameraSegment[gActiveCameraID].camera.distanceToCamera;
2022-03-28 08:36:12 -04:00
}
2023-10-06 14:40:45 +01:00
gCameraTransform.z_position = -gCameraSegment[gActiveCameraID].trans.z_position;
2022-03-28 08:36:12 -04:00
2023-10-06 14:40:45 +01:00
object_transform_to_matrix_2(gCameraMatrixF, &gCameraTransform);
f32_matrix_mult(&gCameraMatrixF, &gPerspectiveMatrixF, &gViewMatrixF);
2022-03-28 08:36:12 -04:00
2023-10-06 14:40:45 +01:00
gCameraTransform.y_rotation = -0x8000 - gCameraSegment[gActiveCameraID].trans.y_rotation;
2024-01-26 09:12:45 -05:00
gCameraTransform.x_rotation =
-(gCameraSegment[gActiveCameraID].trans.x_rotation + gCameraSegment[gActiveCameraID].camera.unk38);
2023-10-06 14:40:45 +01:00
gCameraTransform.z_rotation = -gCameraSegment[gActiveCameraID].trans.z_rotation;
2023-01-23 12:54:17 +00:00
gCameraTransform.scale = 1.0f;
2023-10-06 14:40:45 +01:00
gCameraTransform.x_position = gCameraSegment[gActiveCameraID].trans.x_position;
gCameraTransform.y_position = gCameraSegment[gActiveCameraID].trans.y_position;
2022-03-28 08:36:12 -04:00
if (D_80120D18 != 0) {
2023-10-06 14:40:45 +01:00
gCameraTransform.y_position += gCameraSegment[gActiveCameraID].camera.distanceToCamera;
2022-03-28 08:36:12 -04:00
}
2023-10-06 14:40:45 +01:00
gCameraTransform.z_position = gCameraSegment[gActiveCameraID].trans.z_position;
2022-03-28 08:36:12 -04:00
2023-10-06 14:40:45 +01:00
object_transform_to_matrix(gProjectionMatrixF, &gCameraTransform);
f32_matrix_to_s16_matrix(&gProjectionMatrixF, &gUnusedProjectionMatrixS);
2022-03-28 08:36:12 -04:00
2022-11-20 23:37:50 +00:00
gActiveCameraID = temp;
2022-03-28 08:36:12 -04:00
}
/**
* Sets the Y value of the Y axis in the matrix to the passed value.
* This is used to vertically scale ortho geometry to look identical across NTSC and PAL systems.
* Official Name: camOrthoYAspect
*/
void set_ortho_matrix_height(f32 value) {
2023-10-06 14:40:45 +01:00
gOrthoMatrixF[1][1] = value;
}
2022-12-18 12:39:40 +00:00
/**
* Sets the current matrix to represent an orthogonal view.
* Used for drawing triangles on screen as HUD.
* Official Name: camStandardOrtho
2024-01-26 09:12:45 -05:00
*/
2022-12-18 12:39:40 +00:00
void set_ortho_matrix_view(Gfx **dlist, MatrixS **mtx) {
2021-09-17 23:52:24 -04:00
u32 widthAndHeight;
s32 width, height;
s32 i, j;
2025-02-14 18:40:55 +00:00
widthAndHeight = fb_size();
height = GET_VIDEO_HEIGHT(widthAndHeight);
width = GET_VIDEO_WIDTH(widthAndHeight);
2023-10-06 14:40:45 +01:00
f32_matrix_to_s16_matrix(&gOrthoMatrixF, *mtx);
gModelMatrixS[0] = *mtx;
2023-01-23 12:54:17 +00:00
gViewportStack[gActiveCameraID + 5].vp.vscale[0] = width * 2;
gViewportStack[gActiveCameraID + 5].vp.vscale[1] = width * 2;
gViewportStack[gActiveCameraID + 5].vp.vtrans[0] = width * 2;
gViewportStack[gActiveCameraID + 5].vp.vtrans[1] = height * 2;
gSPViewport((*dlist)++, OS_K0_TO_PHYSICAL(&gViewportStack[gActiveCameraID + 5]));
gSPMatrix((*dlist)++, OS_PHYSICAL_TO_K0((*mtx)++), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_MODELVIEW);
2023-10-06 14:40:45 +01:00
gModelMatrixStackPos = 0;
gMatrixType = G_MTX_DKR_INDEX_0;
for (i = 0; i < 4; i++) {
2024-01-26 09:12:45 -05:00
// clang-format off
// Required to be one line, but the "\" fixes that.
for (j = 0; j < 4; j++) { \
2023-10-06 14:40:45 +01:00
gViewMatrixF[i][j] = gOrthoMatrixF[i][j];
}
2024-01-26 09:12:45 -05:00
// clang-format on
}
}
2024-01-26 09:12:45 -05:00
// Official Name: camStandardPersp?
void func_8006807C(Gfx **dlist, MatrixS **mtx) {
2023-10-06 14:40:45 +01:00
object_transform_to_matrix_2(gCurrentModelMatrixF, &D_800DD288);
f32_matrix_mult(&gCurrentModelMatrixF, &gPerspectiveMatrixF, &gViewMatrixF);
2024-01-26 09:12:45 -05:00
object_transform_to_matrix_2((float(*)[4]) gModelMatrixF[0], &D_800DD2A0);
2023-10-06 14:40:45 +01:00
f32_matrix_mult(gModelMatrixF[0], &gViewMatrixF, &gCurrentModelMatrixF);
f32_matrix_to_s16_matrix(&gCurrentModelMatrixF, *mtx);
gSPMatrix((*dlist)++, OS_PHYSICAL_TO_K0((*mtx)++), G_MTX_NOPUSH | G_MTX_MUL | G_MTX_MODELVIEW);
2023-10-06 14:40:45 +01:00
gModelMatrixStackPos = 0;
gMatrixType = G_MTX_DKR_INDEX_0;
}
/**
* Sets the RSP viewport onscreen to the given properties.
* Viewports have a centre position and a scale factor, rather than a standard four corners.
* Official Name: camSetViewport
2024-01-26 09:12:45 -05:00
*/
void viewport_rsp_set(Gfx **dlist, s32 width, s32 height, s32 posX, s32 posY) {
2021-12-10 19:03:19 +00:00
s32 tempWidth = (get_filtered_cheats() & CHEAT_MIRRORED_TRACKS) ? -width : width;
2024-05-03 17:24:00 +01:00
#ifdef ANTI_TAMPER
2022-10-24 15:37:47 +01:00
// Antipiracy measure. Flips the screen upside down.
if (gAntiPiracyViewport) {
2021-12-10 19:03:19 +00:00
height = -height;
tempWidth = -width;
}
2024-05-03 17:24:00 +01:00
#endif
if (!(gScreenViewports[gActiveCameraID].flags & VIEWPORT_EXTRA_BG)) {
2023-01-23 12:54:17 +00:00
gViewportStack[gActiveCameraID].vp.vtrans[0] = posX * 4;
gViewportStack[gActiveCameraID].vp.vtrans[1] = posY * 4;
gViewportStack[gActiveCameraID].vp.vscale[0] = tempWidth * 4;
gViewportStack[gActiveCameraID].vp.vscale[1] = height * 4;
gSPViewport((*dlist)++, OS_PHYSICAL_TO_K0(&gViewportStack[gActiveCameraID]));
} else {
2023-01-23 12:54:17 +00:00
gSPViewport((*dlist)++, OS_PHYSICAL_TO_K0(&gViewportStack[gActiveCameraID + 10 + (gViewportWithBG * 5)]));
}
}
/**
* Resets the viewport back to default.
* If in the track menu, or post-race, set it to a small screen view instead.
* Official Name: camResetView?
2024-01-26 09:12:45 -05:00
*/
void viewport_reset(Gfx **dlist) {
u32 widthAndHeight, width, height;
2022-11-20 23:37:50 +00:00
gActiveCameraID = 4;
2025-02-14 18:40:55 +00:00
widthAndHeight = fb_size();
height = GET_VIDEO_HEIGHT(widthAndHeight);
width = GET_VIDEO_WIDTH(widthAndHeight);
if (!(gScreenViewports[gActiveCameraID].flags & VIEWPORT_EXTRA_BG)) {
2021-10-27 17:17:08 -04:00
gDPSetScissor((*dlist)++, G_SC_NON_INTERLACE, 0, 0, width - 1, height - 1);
viewport_rsp_set(dlist, width >> 1, height >> 1, width >> 1, height >> 1);
} else {
viewport_scissor(dlist);
viewport_rsp_set(dlist, 0, 0, 0, 0);
}
2022-11-20 23:37:50 +00:00
gActiveCameraID = 0;
}
2024-05-25 20:29:41 +01:00
UNUSED const char D_800E6F34[] = "cameraPushSprMtx: model stack overflow!!\n";
/**
* Sets the matrix position to the world origin (0, 0, 0)
* Used when the next thing rendered relies on there not being any matrix offset.
* Official Name: camOffsetZero?
2024-01-26 09:12:45 -05:00
*/
void matrix_world_origin(Gfx **dlist, MatrixS **mtx) {
2023-10-06 14:40:45 +01:00
f32_matrix_from_position(gModelMatrixF[gModelMatrixStackPos], 0.0f, 0.0f, 0.0f);
f32_matrix_mult(gModelMatrixF[gModelMatrixStackPos], &gViewMatrixF, &gCurrentModelMatrixF);
f32_matrix_to_s16_matrix(&gCurrentModelMatrixF, *mtx);
gModelMatrixS[gModelMatrixStackPos] = *mtx;
gSPMatrix((*dlist)++, OS_PHYSICAL_TO_K0((*mtx)++), gMatrixType << 6);
}
/**
* If set to true, disables animated sprite frames.
* Used when the sprite frame is already established before calling to draw.
*/
void sprite_anim_off(s32 setting) {
gSpriteAnimOff = setting;
}
/**
* Calculates angle from object to camera, then renders the sprite as a billboard, facing the camera.
*/
2024-01-26 09:12:45 -05:00
s32 render_sprite_billboard(Gfx **dlist, MatrixS **mtx, Vertex **vertexList, Object *obj, unk80068514_arg4 *arg4,
s32 flags) {
2023-10-06 14:40:45 +01:00
f32 diffX;
f32 diffY;
Vertex *v;
2023-10-06 14:40:45 +01:00
f32 lateralDist;
f32 sineY;
f32 cosY;
f32 sp44;
2023-10-06 14:40:45 +01:00
f32 diffZ;
s32 tanX;
s32 tanY;
s32 angleDiff;
s32 result;
2023-10-06 14:40:45 +01:00
s32 textureFrame;
2024-05-25 20:29:41 +01:00
if (obj == NULL) {
stubbed_printf("\nCam do 2D sprite called with NULL pointer!");
}
result = TRUE;
if (flags & RENDER_VEHICLE_PART) {
2023-10-06 14:40:45 +01:00
diffX = gModelMatrixViewX[gCameraMatrixPos] - obj->segment.trans.x_position;
diffY = gModelMatrixViewY[gCameraMatrixPos] - obj->segment.trans.y_position;
diffZ = gModelMatrixViewZ[gCameraMatrixPos] - obj->segment.trans.z_position;
sineY = sins_f(obj->segment.trans.y_rotation);
cosY = coss_f(obj->segment.trans.y_rotation);
sp44 = (diffX * cosY) + (diffZ * sineY);
diffZ = (diffZ * cosY) - (diffX * sineY);
tanY = arctan2_f(sp44, sqrtf((diffY * diffY) + (diffZ * diffZ)));
tanX = -sins(arctan2_f(sp44, diffZ)) >> 8;
if (diffZ < 0.0f) {
diffZ = -diffZ;
tanX = 1 - tanX;
tanY = -tanY;
}
2023-10-06 14:40:45 +01:00
angleDiff = arctan2_f(diffY, diffZ);
if (angleDiff > 0x8000) {
angleDiff -= 0x10000;
}
2023-10-06 14:40:45 +01:00
angleDiff = (angleDiff * tanX) >> 8;
textureFrame = (tanY >> 7) & 0xFF;
if (textureFrame > 127) {
2024-05-25 20:29:41 +01:00
stubbed_printf("CamDo2DSprite FrameNo Overflow !!!\n");
2023-10-06 14:40:45 +01:00
textureFrame = 255 - textureFrame;
angleDiff += 0x8000;
result = FALSE;
}
2023-10-06 14:40:45 +01:00
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;
lateralDist = sqrtf((diffX * diffX) + (diffZ * diffZ));
gCameraTransform.y_rotation = arctan2_f(diffX, diffZ);
gCameraTransform.x_rotation = -arctan2_f(diffY, lateralDist);
gCameraTransform.z_rotation = angleDiff;
2023-01-23 12:54:17 +00:00
gCameraTransform.scale = obj->segment.trans.scale;
gCameraTransform.x_position = obj->segment.trans.x_position;
gCameraTransform.y_position = obj->segment.trans.y_position;
gCameraTransform.z_position = obj->segment.trans.z_position;
2023-10-06 14:40:45 +01:00
object_transform_to_matrix(gCurrentModelMatrixF, &gCameraTransform);
gModelMatrixStackPos++;
2024-01-26 09:12:45 -05:00
f32_matrix_mult(&gCurrentModelMatrixF, gModelMatrixF[gModelMatrixStackPos - 1],
gModelMatrixF[gModelMatrixStackPos]);
2023-10-06 14:40:45 +01:00
f32_matrix_mult(gModelMatrixF[gModelMatrixStackPos], &gViewMatrixF, &gCurrentModelMatrixF);
f32_matrix_to_s16_matrix(&gCurrentModelMatrixF, *mtx);
gModelMatrixS[gModelMatrixStackPos] = *mtx;
gSPMatrix((*dlist)++, OS_PHYSICAL_TO_K0((*mtx)++), G_MTX_DKR_INDEX_2);
gSPVertexDKR((*dlist)++, OS_K0_TO_PHYSICAL(&gVehiclePartVertex), 1, 0);
} else {
v = *vertexList;
v->x = obj->segment.trans.x_position;
v->y = obj->segment.trans.y_position;
v->z = obj->segment.trans.z_position;
v->r = 255; // These don't actually do anything since vertex colours are disabled anyway.
v->g = 255;
v->b = 255;
v->a = 255;
gSPVertexDKR((*dlist)++, OS_PHYSICAL_TO_K0(*vertexList), 1, 0);
(*vertexList)++;
if (gCutsceneCameraActive == 0) {
2023-10-06 14:40:45 +01:00
angleDiff = gCameraSegment[gActiveCameraID].trans.z_rotation + obj->segment.trans.z_rotation;
} else {
2023-10-06 14:40:45 +01:00
angleDiff = gCameraSegment[gActiveCameraID + 4].trans.z_rotation + obj->segment.trans.z_rotation;
}
2023-10-06 14:40:45 +01:00
textureFrame = obj->segment.animFrame;
gModelMatrixStackPos++;
2024-01-26 09:12:45 -05:00
f32_matrix_from_rotation_and_scale((f32(*)[4]) gModelMatrixF[gModelMatrixStackPos], angleDiff,
obj->segment.trans.scale, gVideoAspectRatio);
2023-10-06 14:40:45 +01:00
f32_matrix_to_s16_matrix(gModelMatrixF[gModelMatrixStackPos], *mtx);
gModelMatrixS[gModelMatrixStackPos] = *mtx;
gSPMatrix((*dlist)++, OS_PHYSICAL_TO_K0((*mtx)++), G_MTX_DKR_INDEX_2);
gDkrEnableBillboard((*dlist)++);
}
if (gSpriteAnimOff == FALSE) {
2023-10-06 14:40:45 +01:00
textureFrame = ((textureFrame & 0xFF) * arg4->textureCount) >> 8;
}
flags &= ~RENDER_VEHICLE_PART;
if (flags & RENDER_SEMI_TRANSPARENT) {
flags |= RENDER_ANTI_ALIASING;
}
2024-01-26 09:12:45 -05:00
func_8007BF34(dlist, arg4->unk6 | (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);
}
2023-10-06 14:40:45 +01:00
gSPDisplayList((*dlist)++, arg4->unk8[textureFrame + 1]);
gModelMatrixStackPos--;
if (gModelMatrixStackPos == 0) {
textureFrame = 0;
} else {
2023-10-06 14:40:45 +01:00
textureFrame = 1;
}
2023-10-06 14:40:45 +01:00
gDkrInsertMatrix((*dlist)++, 0, textureFrame << 6);
gDkrDisableBillboard((*dlist)++);
return result;
}
2022-10-24 15:37:47 +01:00
2022-12-18 12:39:40 +00:00
/**
2024-01-26 09:12:45 -05:00
* Sets transform and scale matrices to set position and size, loads the texture, sets the rendermodes, then draws the
* result onscreen.
*/
void render_ortho_triangle_image(Gfx **dList, MatrixS **mtx, Vertex **vtx, ObjectSegment *segment, Sprite *sprite,
s32 flags) {
2022-10-24 15:37:47 +01:00
UNUSED s32 pad;
f32 scale;
s32 index;
Vertex *temp_v1;
2023-10-06 14:40:45 +01:00
Matrix aspectMtxF;
Matrix scaleMtxF;
2022-10-24 15:37:47 +01:00
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.
2022-10-24 15:37:47 +01:00
temp_v1->g = 255;
temp_v1->b = 255;
temp_v1->a = 255;
gSPVertexDKR((*dList)++, OS_PHYSICAL_TO_K0(*vtx), 1, 0);
(*vtx)++; // Can't be done in the macro?
2022-12-15 20:19:28 +00:00
index = segment->animFrame;
2024-01-26 09:12:45 -05:00
gModelMatrixStackPos++;
2023-01-23 12:54:17 +00:00
gCameraTransform.y_rotation = -segment->trans.y_rotation;
gCameraTransform.x_rotation = -segment->trans.x_rotation;
2023-10-06 14:40:45 +01:00
gCameraTransform.z_rotation = gCameraSegment[gActiveCameraID].trans.z_rotation + segment->trans.z_rotation;
2023-01-23 12:54:17 +00:00
gCameraTransform.x_position = 0.0f;
gCameraTransform.y_position = 0.0f;
gCameraTransform.z_position = 0.0f;
2022-10-24 15:37:47 +01:00
if (gAdjustViewportHeight) {
scale = segment->trans.scale;
2023-10-06 14:40:45 +01:00
f32_matrix_from_scale(scaleMtxF, scale, scale, 1.0f);
f32_matrix_from_rotation_and_scale(aspectMtxF, 0, 1.0f, gVideoAspectRatio);
f32_matrix_mult(&aspectMtxF, &scaleMtxF, &gCurrentModelMatrixF);
2022-10-24 15:37:47 +01:00
} else {
scale = segment->trans.scale;
2023-10-06 14:40:45 +01:00
f32_matrix_from_scale(gCurrentModelMatrixF, scale, scale, 1.0f);
2022-10-24 15:37:47 +01:00
}
2023-10-06 14:40:45 +01:00
object_transform_to_matrix_2(aspectMtxF, &gCameraTransform);
f32_matrix_mult(&gCurrentModelMatrixF, &aspectMtxF, gModelMatrixF[gModelMatrixStackPos]);
f32_matrix_to_s16_matrix(gModelMatrixF[gModelMatrixStackPos], *mtx);
gModelMatrixS[gModelMatrixStackPos] = *mtx;
gSPMatrix((*dList)++, OS_PHYSICAL_TO_K0((*mtx)++), G_MTX_DKR_INDEX_2);
gDkrEnableBillboard((*dList)++);
if (gSpriteAnimOff == FALSE) {
2024-01-26 09:12:45 -05:00
index = (((u8) index) * sprite->baseTextureId) >> 8;
2022-10-24 15:37:47 +01:00
}
func_8007BF34(dList, sprite->unk6 | flags);
if (index >= sprite->baseTextureId) {
index = sprite->baseTextureId - 1;
2022-10-24 15:37:47 +01:00
}
2023-04-28 14:54:27 -04:00
gSPDisplayList((*dList)++, sprite->unkC.ptr[index]);
2023-10-06 14:40:45 +01:00
if (--gModelMatrixStackPos == 0) {
2022-10-24 15:37:47 +01:00
index = 0;
} else {
index = 1;
}
gDkrInsertMatrix((*dList)++, 0, index << 6);
gDkrDisableBillboard((*dList)++);
2022-10-24 15:37:47 +01:00
}
}
2023-10-06 14:40:45 +01:00
/**
* Generate a matrix with rotation, scaling and shearing and run it.
* Used for wavy type effects like the shield.
2024-01-26 09:12:45 -05:00
*/
2023-10-06 14:40:45 +01:00
void apply_object_shear_matrix(Gfx **dList, MatrixS **mtx, Object *arg2, Object *arg3, f32 shear) {
UNUSED s32 pad;
f32 cossf_x_arg2;
f32 cossf_y_arg2;
f32 sinsf_x_arg2;
f32 sinsf_y_arg2;
f32 sinsf_y_arg3;
f32 sinsf_z_arg3;
f32 arg2_scale;
f32 cossf_x_arg3;
f32 sinsf_x_arg3;
f32 cossf_y_arg3;
f32 cossf_z_arg3;
f32 arg2_xPos;
f32 arg2_yPos;
f32 arg2_zPos;
f32 arg3_xPos;
f32 arg3_yPos;
f32 arg3_zPos;
Matrix matrix_mult;
cossf_x_arg2 = coss_f(arg2->segment.trans.x_rotation);
sinsf_x_arg2 = sins_f(arg2->segment.trans.x_rotation);
cossf_y_arg2 = coss_f(arg2->segment.trans.y_rotation);
sinsf_y_arg2 = sins_f(arg2->segment.trans.y_rotation);
arg2_xPos = arg2->segment.trans.x_position;
arg2_yPos = arg2->segment.trans.y_position;
arg2_zPos = arg2->segment.trans.z_position;
cossf_z_arg3 = coss_f(arg3->segment.trans.z_rotation);
sinsf_z_arg3 = sins_f(arg3->segment.trans.z_rotation);
cossf_x_arg3 = coss_f(arg3->segment.trans.x_rotation);
sinsf_x_arg3 = sins_f(arg3->segment.trans.x_rotation);
cossf_y_arg3 = coss_f(arg3->segment.trans.y_rotation);
sinsf_y_arg3 = sins_f(arg3->segment.trans.y_rotation);
arg3_xPos = arg3->segment.trans.x_position;
arg3_yPos = arg3->segment.trans.y_position;
arg3_zPos = arg3->segment.trans.z_position;
arg2_scale = arg2->segment.trans.scale;
shear *= arg2_scale;
2024-01-26 09:12:45 -05:00
matrix_mult[0][0] =
((((cossf_z_arg3 * cossf_y_arg3) + (sinsf_z_arg3 * (sinsf_x_arg3 * sinsf_y_arg3))) * cossf_y_arg2) +
(-sinsf_y_arg2 * (cossf_x_arg3 * sinsf_y_arg3))) *
arg2_scale;
matrix_mult[0][1] = (((sinsf_z_arg3 * cossf_x_arg3) * cossf_y_arg2) + (-sinsf_y_arg2 * -sinsf_x_arg3)) * arg2_scale;
2024-01-26 09:12:45 -05:00
matrix_mult[0][2] =
((((-sinsf_y_arg3 * cossf_z_arg3) + (sinsf_z_arg3 * (sinsf_x_arg3 * cossf_y_arg3))) * cossf_y_arg2) +
(-sinsf_y_arg2 * (cossf_x_arg3 * cossf_y_arg3))) *
arg2_scale;
matrix_mult[0][3] = 0.0f;
2024-01-26 09:12:45 -05:00
matrix_mult[1][0] =
((((-sinsf_z_arg3 * cossf_y_arg3) + (cossf_z_arg3 * (sinsf_x_arg3 * sinsf_y_arg3))) * cossf_x_arg2) +
(sinsf_x_arg2 *
((sinsf_y_arg2 * ((cossf_z_arg3 * cossf_y_arg3) + (sinsf_z_arg3 * (sinsf_x_arg3 * sinsf_y_arg3)))) +
(cossf_y_arg2 * (cossf_x_arg3 * sinsf_y_arg3))))) *
shear;
matrix_mult[1][1] =
(((cossf_z_arg3 * cossf_x_arg3) * cossf_x_arg2) +
(sinsf_x_arg2 * ((sinsf_y_arg2 * (sinsf_z_arg3 * cossf_x_arg3)) + (cossf_y_arg2 * -sinsf_x_arg3)))) *
shear;
matrix_mult[1][2] =
((((-sinsf_z_arg3 * -sinsf_y_arg3) + (cossf_z_arg3 * (sinsf_x_arg3 * cossf_y_arg3))) * cossf_x_arg2) +
(sinsf_x_arg2 *
((sinsf_y_arg2 * ((-sinsf_y_arg3 * cossf_z_arg3) + (sinsf_z_arg3 * (sinsf_x_arg3 * cossf_y_arg3)))) +
(cossf_y_arg2 * (cossf_x_arg3 * cossf_y_arg3))))) *
shear;
matrix_mult[1][3] = 0.0f;
2024-01-26 09:12:45 -05:00
matrix_mult[2][0] =
((-sinsf_x_arg2 * ((-sinsf_z_arg3 * cossf_y_arg3) + (cossf_z_arg3 * (sinsf_x_arg3 * sinsf_y_arg3)))) +
(cossf_x_arg2 *
((sinsf_y_arg2 * ((cossf_z_arg3 * cossf_y_arg3) + (sinsf_z_arg3 * (sinsf_x_arg3 * sinsf_y_arg3)))) +
(cossf_y_arg2 * (cossf_x_arg3 * sinsf_y_arg3))))) *
arg2_scale;
matrix_mult[2][1] =
((-sinsf_x_arg2 * (cossf_z_arg3 * cossf_x_arg3)) +
(cossf_x_arg2 * ((sinsf_y_arg2 * (sinsf_z_arg3 * cossf_x_arg3)) + (cossf_y_arg2 * -sinsf_x_arg3)))) *
arg2_scale;
matrix_mult[2][2] =
((-sinsf_x_arg2 * ((-sinsf_z_arg3 * -sinsf_y_arg3) + (cossf_z_arg3 * (sinsf_x_arg3 * cossf_y_arg3)))) +
(cossf_x_arg2 *
((sinsf_y_arg2 * ((-sinsf_y_arg3 * cossf_z_arg3) + (sinsf_z_arg3 * (sinsf_x_arg3 * cossf_y_arg3)))) +
(cossf_y_arg2 * (cossf_x_arg3 * cossf_y_arg3))))) *
arg2_scale;
matrix_mult[2][3] = 0.0f;
2024-01-26 09:12:45 -05:00
matrix_mult[3][0] =
(((cossf_z_arg3 * cossf_y_arg3) + (sinsf_z_arg3 * (sinsf_x_arg3 * sinsf_y_arg3))) * arg2_xPos) +
(arg2_yPos * ((-sinsf_z_arg3 * cossf_y_arg3) + (cossf_z_arg3 * (sinsf_x_arg3 * sinsf_y_arg3)))) +
(arg2_zPos * (cossf_x_arg3 * sinsf_y_arg3)) + arg3_xPos;
matrix_mult[3][1] = ((sinsf_z_arg3 * cossf_x_arg3) * arg2_xPos) + (arg2_yPos * (cossf_z_arg3 * cossf_x_arg3)) +
(arg2_zPos * -sinsf_x_arg3) + arg3_yPos;
matrix_mult[3][2] =
(((-sinsf_y_arg3 * cossf_z_arg3) + (sinsf_z_arg3 * (sinsf_x_arg3 * cossf_y_arg3))) * arg2_xPos) +
(arg2_yPos * ((-sinsf_z_arg3 * -sinsf_y_arg3) + (cossf_z_arg3 * (sinsf_x_arg3 * cossf_y_arg3)))) +
(arg2_zPos * (cossf_x_arg3 * cossf_y_arg3)) + arg3_zPos;
matrix_mult[3][3] = 1.0f;
f32_matrix_mult(&matrix_mult, &gViewMatrixF, &gCurrentModelMatrixS);
f32_matrix_to_s16_matrix(&gCurrentModelMatrixS, *mtx);
2023-10-06 14:40:45 +01:00
gSPMatrix((*dList)++, OS_PHYSICAL_TO_K0((*mtx)++), G_MTX_DKR_INDEX_1);
}
2022-10-24 15:37:47 +01:00
2023-04-28 14:54:27 -04:00
/**
* Official Name: camPushModelMtx
2024-01-26 09:12:45 -05:00
*/
2023-04-28 14:54:27 -04:00
void camera_push_model_mtx(Gfx **dList, MatrixS **mtx, ObjectTransform *trans, f32 scale, f32 scaleY) {
2022-10-24 15:37:47 +01:00
f32 tempX;
f32 tempY;
f32 tempZ;
s32 index;
f32 scaleFactor;
2023-10-06 14:40:45 +01:00
object_transform_to_matrix(gCurrentModelMatrixF, trans);
if (scaleY != 0.0f) {
2023-10-06 14:40:45 +01:00
f32_matrix_y_scale(&gCurrentModelMatrixF, scaleY);
2022-10-24 15:37:47 +01:00
}
if (scale != 1.0f) {
2023-10-06 14:40:45 +01:00
f32_matrix_scale(&gCurrentModelMatrixF, scale);
2022-10-24 15:37:47 +01:00
}
2024-01-26 09:12:45 -05:00
f32_matrix_mult(&gCurrentModelMatrixF, gModelMatrixF[gModelMatrixStackPos],
gModelMatrixF[gModelMatrixStackPos + 1]);
f32_matrix_mult(gModelMatrixF[gModelMatrixStackPos + 1], &gViewMatrixF, &gCurrentModelMatrixS);
f32_matrix_to_s16_matrix(&gCurrentModelMatrixS, *mtx);
2023-10-06 14:40:45 +01:00
gModelMatrixStackPos++;
2024-05-25 20:29:41 +01:00
gModelMatrixS[0, gModelMatrixStackPos] = *mtx; // Should be [gModelMatrixStackPos]
if (gModelMatrixStackPos >= ARRAY_COUNT(gModelMatrixS)) {
stubbed_printf("cameraPushModelMtx: model stack overflow!!\n");
}
2024-01-26 09:12:45 -05:00
if (1) {}
if (1) {}; // Fakematch
gSPMatrix((*dList)++, OS_PHYSICAL_TO_K0((*mtx)++), G_MTX_DKR_INDEX_1);
2023-10-06 14:40:45 +01:00
guMtxXFMF(*gModelMatrixF[gModelMatrixStackPos], 0.0f, 0.0f, 0.0f, &tempX, &tempY, &tempZ);
2022-11-20 23:37:50 +00:00
index = gActiveCameraID;
2022-10-24 15:37:47 +01:00
if (gCutsceneCameraActive) {
index += 4;
}
2023-10-06 14:40:45 +01:00
tempX = gCameraSegment[index].trans.x_position - tempX;
tempY = gCameraSegment[index].trans.y_position - tempY;
tempZ = gCameraSegment[index].trans.z_position - tempZ;
2023-01-23 12:54:17 +00:00
gCameraTransform.y_rotation = -trans->y_rotation;
gCameraTransform.x_rotation = -trans->x_rotation;
gCameraTransform.z_rotation = -trans->z_rotation;
gCameraTransform.x_position = 0.0f;
gCameraTransform.y_position = 0.0f;
gCameraTransform.z_position = 0.0f;
gCameraTransform.scale = 1.0f;
2023-10-06 14:40:45 +01:00
object_transform_to_matrix_2(gCurrentModelMatrixF, &gCameraTransform);
guMtxXFMF(gCurrentModelMatrixF, tempX, tempY, tempZ, &tempX, &tempY, &tempZ);
scaleFactor = 1.0f / trans->scale;
2022-10-24 15:37:47 +01:00
tempX *= scaleFactor;
tempY *= scaleFactor;
tempZ *= scaleFactor;
2023-10-06 14:40:45 +01:00
gCameraMatrixPos++;
index = gCameraMatrixPos;
gModelMatrixViewX[index] = tempX;
gModelMatrixViewY[index] = tempY;
gModelMatrixViewZ[index] = tempZ;
2024-05-25 20:29:41 +01:00
if (0) {
stubbed_printf("camPushModelMtx: bsp stack overflow!!\n");
}
2022-10-24 15:37:47 +01:00
}
2023-10-06 14:40:45 +01:00
/**
* Calculate the rotation matrix for an actors head, then run it.
2024-01-26 09:12:45 -05:00
*/
2023-10-06 14:40:45 +01:00
void apply_head_turning_matrix(Gfx **dlist, MatrixS **mtx, Object_68 *objGfx, s16 headAngle) {
f32 coss_headAngle;
f32 sins_headAngle;
f32 offsetX;
f32 offsetY;
f32 offsetZ;
f32 coss_unk1C;
f32 sins_unk1C;
2023-10-06 14:40:45 +01:00
Matrix rotationMtxF;
Matrix headMtxF;
offsetX = (f32) objGfx->offsetX;
offsetY = (f32) objGfx->offsetY;
offsetZ = (f32) objGfx->offsetZ;
2023-10-06 14:40:45 +01:00
coss_unk1C = coss_f(objGfx->unk1C);
sins_unk1C = sins_f(objGfx->unk1C);
coss_headAngle = coss_f(headAngle);
sins_headAngle = sins_f(headAngle);
2023-10-06 14:40:45 +01:00
headMtxF[0][0] = (coss_headAngle * coss_unk1C);
headMtxF[0][1] = (coss_headAngle * sins_unk1C);
headMtxF[0][2] = -sins_headAngle;
headMtxF[0][3] = 0.0f;
headMtxF[1][0] = -sins_unk1C;
headMtxF[1][1] = coss_unk1C;
headMtxF[1][2] = 0.0f;
headMtxF[1][3] = 0.0f;
headMtxF[2][0] = (sins_headAngle * coss_unk1C);
headMtxF[2][1] = (sins_headAngle * sins_unk1C);
headMtxF[2][2] = coss_headAngle;
headMtxF[2][3] = 0.0f;
headMtxF[3][0] = (-offsetX * (coss_headAngle * coss_unk1C)) + (-offsetY * -sins_unk1C) +
(-offsetZ * (sins_headAngle * coss_unk1C)) + offsetX;
headMtxF[3][1] = (-offsetX * (coss_headAngle * sins_unk1C)) + (-offsetY * coss_unk1C) +
(-offsetZ * (sins_headAngle * sins_unk1C)) + offsetY;
headMtxF[3][2] = (-offsetX * -sins_headAngle) + (-offsetZ * coss_headAngle) + offsetZ;
2023-10-06 14:40:45 +01:00
headMtxF[3][3] = 1.0f;
f32_matrix_mult(&headMtxF, &gCurrentModelMatrixS, &rotationMtxF);
2023-10-06 14:40:45 +01:00
f32_matrix_to_s16_matrix(&rotationMtxF, *mtx);
gSPMatrix((*dlist)++, OS_PHYSICAL_TO_K0((*mtx)++), G_MTX_DKR_INDEX_2);
gDkrInsertMatrix((*dlist)++, G_MWO_MATRIX_XX_XY_I, G_MTX_DKR_INDEX_1);
}
2023-10-06 14:40:45 +01:00
/**
* Writes the model matrix vector to the arguments.
2024-01-26 09:12:45 -05:00
*/
2023-10-06 14:40:45 +01:00
UNUSED void get_modelmatrix_vector(f32 *x, f32 *y, f32 *z) {
*x = gModelMatrixViewX[gCameraMatrixPos];
*y = gModelMatrixViewY[gCameraMatrixPos];
*z = gModelMatrixViewZ[gCameraMatrixPos];
}
2023-10-06 14:40:45 +01:00
/**
* Run a matrix from the top of the stack and pop it.
* If the stack pos is less than zero, add a matrix instead.
2024-01-26 09:12:45 -05:00
*/
2023-10-06 14:40:45 +01:00
void apply_matrix_from_stack(Gfx **dlist) {
gCameraMatrixPos--;
gModelMatrixStackPos--;
2024-01-26 09:12:45 -05:00
{
s32 temp = gCameraMatrixPos;
if ((temp && temp) != 0) {}
2024-05-25 20:29:41 +01:00
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");
}
2024-01-26 09:12:45 -05:00
} // Fakematch
2023-10-06 14:40:45 +01:00
if (gModelMatrixStackPos > 0) {
gSPMatrix((*dlist)++, OS_PHYSICAL_TO_K0(gModelMatrixS[gModelMatrixStackPos]), G_MTX_DKR_INDEX_1);
} else {
gDkrInsertMatrix((*dlist)++, G_MWO_MATRIX_XX_XY_I, G_MTX_DKR_INDEX_0);
}
}
2023-10-06 14:40:45 +01:00
/**
* Move the camera with the given velocities.
* Also recalculates which block it's in.
2024-01-26 09:12:45 -05:00
*/
2023-10-06 14:40:45 +01:00
UNUSED void translate_camera_segment(f32 x, f32 y, f32 z) {
gCameraSegment[gActiveCameraID].trans.x_position += x;
gCameraSegment[gActiveCameraID].trans.y_position += y;
gCameraSegment[gActiveCameraID].trans.z_position += z;
2024-01-26 09:12:45 -05:00
gCameraSegment[gActiveCameraID].object.cameraSegmentID = get_level_segment_index_from_position(
gCameraSegment[gActiveCameraID].trans.x_position, gCameraSegment[gActiveCameraID].trans.y_position,
gCameraSegment[gActiveCameraID].trans.z_position);
}
2023-10-06 14:40:45 +01:00
/**
* Move the camera with velocities accounting for face direction.
* Also recalculates which block it's in.
2024-01-26 09:12:45 -05:00
*/
2023-10-06 14:40:45 +01:00
UNUSED void transform_camera_segment(f32 x, UNUSED f32 y, f32 z) {
gCameraSegment[gActiveCameraID].trans.x_position -= x * coss_f(gCameraSegment[gActiveCameraID].trans.y_rotation);
gCameraSegment[gActiveCameraID].trans.z_position -= x * sins_f(gCameraSegment[gActiveCameraID].trans.y_rotation);
gCameraSegment[gActiveCameraID].trans.x_position -= z * sins_f(gCameraSegment[gActiveCameraID].trans.y_rotation);
gCameraSegment[gActiveCameraID].trans.z_position += z * coss_f(gCameraSegment[gActiveCameraID].trans.y_rotation);
2024-01-26 09:12:45 -05:00
gCameraSegment[gActiveCameraID].object.cameraSegmentID = get_level_segment_index_from_position(
gCameraSegment[gActiveCameraID].trans.x_position, gCameraSegment[gActiveCameraID].trans.y_position,
gCameraSegment[gActiveCameraID].trans.z_position);
}
2023-10-06 14:40:45 +01:00
/**
* Rotate the camera with the given angles.
2024-01-26 09:12:45 -05:00
*/
2023-10-06 14:40:45 +01:00
UNUSED void rotate_camera_segment(s32 angleX, s32 angleY, s32 angleZ) {
gCameraSegment[gActiveCameraID].trans.y_rotation += angleX;
gCameraSegment[gActiveCameraID].trans.x_rotation += angleY;
gCameraSegment[gActiveCameraID].trans.z_rotation += angleZ;
}
/**
* Returns the segment data of the active camera, but won't apply the offset for cutscenes.
2024-01-26 09:12:45 -05:00
*/
ObjectSegment *get_active_camera_segment_no_cutscenes(void) {
2023-10-06 14:40:45 +01:00
return &gCameraSegment[gActiveCameraID];
}
2022-12-18 12:39:40 +00:00
/**
* Returns the segment data of the active camera.
2024-01-26 09:12:45 -05:00
*/
2022-12-18 12:39:40 +00:00
ObjectSegment *get_active_camera_segment(void) {
2022-10-24 15:37:47 +01:00
if (gCutsceneCameraActive) {
2023-10-06 14:40:45 +01:00
return &gCameraSegment[gActiveCameraID + 4];
}
2023-10-06 14:40:45 +01:00
return &gCameraSegment[gActiveCameraID];
}
/**
* Returns the segment data of the active cutscene camera.
* If no cutscene is active, return player 1's camera.
2024-01-26 09:12:45 -05:00
*/
ObjectSegment *get_cutscene_camera_segment(void) {
2022-10-24 15:37:47 +01:00
if (gCutsceneCameraActive) {
2023-10-06 14:40:45 +01:00
return &gCameraSegment[4];
}
2023-10-06 14:40:45 +01:00
return &gCameraSegment[PLAYER_ONE];
}
2023-10-06 14:40:45 +01:00
/**
* Return the current floating point projection matrix.
2024-01-26 09:12:45 -05:00
*/
2023-10-06 14:40:45 +01:00
Matrix *get_projection_matrix_f32(void) {
return &gProjectionMatrixF;
}
2023-10-06 14:40:45 +01:00
/**
* Return the current fixed point projection matrix.
2024-01-26 09:12:45 -05:00
*/
2023-10-06 14:40:45 +01:00
MatrixS *get_projection_matrix_s16(void) {
return &gProjectionMatrixS;
}
2023-10-06 14:40:45 +01:00
/**
* Return the current camera matrix.
2024-01-26 09:12:45 -05:00
*/
2023-10-06 14:40:45 +01:00
Matrix *get_camera_matrix(void) {
return &gCameraMatrixF;
}
2023-10-31 16:39:28 +00:00
/**
* Return the screenspace distance to the camera.
2024-01-26 09:12:45 -05:00
*/
2023-10-31 16:39:28 +00:00
f32 get_distance_to_camera(f32 x, f32 y, f32 z) {
f32 ox, oy, oz;
2023-10-06 14:40:45 +01:00
guMtxXFMF(gCameraMatrixF, x, y, z, &ox, &oy, &oz);
return oz;
}
/**
* Apply a shake to the camera based on the distance to the source.
2024-01-26 09:12:45 -05:00
*/
void set_camera_shake_by_distance(f32 x, f32 y, f32 z, f32 dist, f32 magnitude) {
f32 diffX;
f32 distance;
f32 diffZ;
f32 diffY;
s32 i;
for (i = 0; i <= gNumberOfViewports; i++) {
2023-10-06 14:40:45 +01:00
diffX = x - gCameraSegment[i].trans.x_position;
diffY = y - gCameraSegment[i].trans.y_position;
diffZ = z - gCameraSegment[i].trans.z_position;
distance = sqrtf(((diffX * diffX) + (diffY * diffY)) + (diffZ * diffZ));
if (distance < dist) {
2023-10-06 14:40:45 +01:00
gCameraSegment[i].camera.distanceToCamera = ((dist - distance) * magnitude) / dist;
}
}
}
/**
* Apply a shake to all active cameras.
2024-01-26 09:12:45 -05:00
*/
void set_camera_shake(f32 magnitude) {
s32 i;
for (i = 0; i <= gNumberOfViewports; i++) {
2023-10-06 14:40:45 +01:00
gCameraSegment[i].camera.distanceToCamera = magnitude;
}
}
/**
* Unused function that prints out the passed matrix values to the debug output.
* This function prints in fixed point.
*/
UNUSED void debug_print_fixed_matrix_values(s16 *mtx) {
s32 i, j;
s32 val;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
val = mtx[i * 4 + j];
rmonPrintf("%x.", val);
val = mtx[((i + 4) * 4 + j)];
2024-01-26 09:12:45 -05:00
rmonPrintf("%x ", (u16) val & 0xFFFF);
}
rmonPrintf("\n");
2024-01-26 09:12:45 -05:00
if (!val) {} // Fakematch
}
rmonPrintf("\n");
}
/**
* Unused function that prints out the passed matrix values to the debug output.
* This function prints in floating point.
*/
UNUSED void debug_print_float_matrix_values(f32 *mtx) {
s32 i, j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
rmonPrintf("%f ", mtx[i * 4 + j]);
}
rmonPrintf("\n");
}
rmonPrintf("\n");
}