mk64/enhancements/flycam.patch

445 lines
14 KiB
Diff

diff --git a/mk64.ld b/mk64.ld
index 70f4820..f36f11c 100644
--- a/mk64.ld
+++ b/mk64.ld
@@ -75,6 +75,7 @@ SECTIONS
BUILD_DIR/src/audio/seqplayer.o(.text);
BUILD_DIR/src/audio/external.o(.text);
BUILD_DIR/src/audio/port_eu.o(.text);
+ BUILD_DIR/src/flycam.o(.text);
#if DEBUG
BUILD_DIR/src/os/osCartRomInit.o(.text);
BUILD_DIR/src/debug/crash_screen_enhancement.o(.text);
@@ -229,6 +230,7 @@ SECTIONS
BUILD_DIR/src/audio/load.o(.data);
BUILD_DIR/src/audio/playback.o(.data);
BUILD_DIR/src/audio/effects.o(.data);
+ BUILD_DIR/src/flycam.o(.data);
#if DEBUG
BUILD_DIR/src/debug/crash_screen_enhancement.o(.data);
BUILD_DIR/src/debug/debug.o(.data);
@@ -277,6 +279,7 @@ SECTIONS
BUILD_DIR/src/audio/seqplayer.o(.rodata);
BUILD_DIR/src/audio/external.o(.rodata);
BUILD_DIR/src/audio/port_eu.o(.rodata);
+ BUILD_DIR/src/flycam.o(.rodata);
#if DEBUG
BUILD_DIR/src/debug/crash_screen_enhancement.o(.rodata);
BUILD_DIR/src/debug/debug.o(.rodata);
@@ -311,6 +314,7 @@ SECTIONS
BUILD_DIR/src/menu_items.jp.o(.bss);
BUILD_DIR/src/code_800AF9B0.o(.bss);
BUILD_DIR/src/menus.o(.bss);
+ BUILD_DIR/src/flycam.o(.bss);
#if DEBUG
BUILD_DIR/src/os/osCartRomInit.o(.bss);
BUILD_DIR/src/debug/crash_screen_enhancement.o(.bss);
diff --git a/src/camera.c b/src/camera.c
index 02275b1..406739d 100644
--- a/src/camera.c
+++ b/src/camera.c
@@ -969,7 +969,9 @@ void func_8001EE98(Player *player, Camera *camera, s8 index) {
func_8001E8E8(camera, player, index);
break;
}
- func_8001E45C(camera, player, index);
+
+ flycam(camera, player, index);
+
break;
case 8:
func_8001E0C4(camera, player, index);
diff --git a/src/render_player.c b/src/render_player.c
index 6b14e27..d10796b 100644
--- a/src/render_player.c
+++ b/src/render_player.c
@@ -65,6 +65,8 @@ void func_8001F9E4(Player *player, Camera *camera, s8 arg2) {
}
}
+extern u32 isFlycam;
+
u16 check_player_camera_collision(Player *player, Camera *camera, f32 arg2, f32 arg3) {
UNUSED f32 pad[6];
f32 sp64;
@@ -79,6 +81,10 @@ u16 check_player_camera_collision(Player *player, Camera *camera, f32 arg2, f32
s16 var_v0;
u16 ret;
+ if (isFlycam) {
+ return 1;
+ }
+
ret = 0;
switch (gActiveScreenMode) { /* irregular */
case SCREEN_MODE_1P:
diff --git a/src/flycam.c b/src/flycam.c
new file mode 100644
index 0000000..5569838
--- /dev/null
+++ b/src/flycam.c
@@ -0,0 +1,328 @@
+#include <ultra64.h>
+#include <PR/os.h>
+#include <macros.h>
++#include <defines.h>
+#include <camera.h>
+#include "main.h"
+#include <libc/math.h>
+#include <common_structs.h>
+#include "racing/collision.h"
+#include <variables.h>
+#include "player_controller.h"
+#include "code_80057C60.h"
+
+// Yaw/pitch rotation sensitivity
+#define SENSITIVITY_X 0.0003f
+#define SENSITIVITY_Y 0.0003f
+
+u32 isFlycam = false;
+u32 fRankIndex = 0;
+u32 fTargetPlayer = false;
+u32 fMode; // flycam mode should probably be an enum
+u32 fModeInit = false;
+
+typedef struct {
+ Vec3f pos;
+ Vec3f lookAt;
+ Vec3s rot;
+} FlycamSaveState;
+
+FlycamSaveState fState;
+
+void flycam_calculate_forward_vector(Camera* camera, Vec3f forwardVector);
+void flycam_move_camera_forward(Camera* camera, struct Controller *controller, f32 distance);
+void flycam_update(Camera* camera, struct Controller *controller);
+void flycam_controller_manager(Camera *camera, struct Controller *controller, Player *player);
+void flycam_target_player(Camera *camera, u32 playerIndex);
+void flycam_move_camera_up(Camera* camera, struct Controller *controller, f32 distance);
+void flycam_save_state(Camera *camera);
+void flycam_load_state(Camera *camera);
+
+
+/**
+ * Controls
+ *
+ * Forward: A
+ * Backward: B
+ *
+ * Go faster: Z
+ *
+ * Up: C-up
+ * Down: C-down
+ *
+ * Targets players based on rank position
+ *
+ * Target player: R-trig
+ * Target next player: C-right
+ * Target previous player: C-left
+ *
+ * Switch camera modes: D-pad left
+ *
+ * Camera mode 1: Enter flycam at the player's position
+ * Camera mode 2: Enter flycam at previous flycam spot
+ *
+*/
+
+void flycam(Camera *camera, Player *player, s8 index) {
+ struct Controller *controller = &gControllers[0];
+ Vec3f forwardVector;
+ f32 dirX;
+ f32 dirY;
+ f32 dirZ;
+ f32 length;
+
+ if (controller->buttonPressed & L_TRIG) {
+ isFlycam = !isFlycam;
+
+ // Don't use `bool = !bool` here as the game code can swap these on you.
+ // Which will confuse the code. This forces it to always be correct
+ if (isFlycam) {
+ player->type |= PLAYER_CPU;
+ } else {
+ player->type &= PLAYER_CPU;
+ }
+
+ gIsHUDVisible = !isFlycam;
+
+ if (isFlycam) {
+
+ if (fMode && fModeInit) {
+ flycam_load_state(camera);
+ } else {
+ // !fMode or fMode not initialized
+ flycam_target_player(camera, get_player_index_for_player(player));
+ }
+
+ return;
+ } else {
+ if(fMode) {
+ flycam_save_state(camera);
+ }
+ }
+ }
+
+ // Driving mode
+ if (!isFlycam) {
+ // Use normal camera code
+ func_8001E45C(camera, &gPlayers[fRankIndex], index);
+ return;
+ }
+
+
+ //if (player == gPlayerOne) { return; }
+
+ //player->type &= ~PLAYER_HUMAN;
+ //player->type |= PLAYER_HUMAN;
+
+ if ((player->type & PLAYER_START_SEQUENCE)) { return; }
+
+
+ flycam_controller_manager(camera, controller, player);
+
+
+
+
+}
+
+void flycam_save_state(Camera *camera) {
+ fState.pos[0] = camera->pos[0];
+ fState.pos[1] = camera->pos[1];
+ fState.pos[2] = camera->pos[2];
+
+ fState.lookAt[0] = camera->lookAt[0];
+ fState.lookAt[1] = camera->lookAt[1];
+ fState.lookAt[2] = camera->lookAt[2];
+
+ fState.rot[0] = camera->rot[0];
+ fState.rot[1] = camera->rot[1];
+ fState.rot[2] = camera->rot[2];
+ fModeInit = true;
+}
+
+void flycam_load_state(Camera *camera) {
+ camera->pos[0] = fState.pos[0];
+ camera->pos[1] = fState.pos[1];
+ camera->pos[2] = fState.pos[2];
+
+ camera->lookAt[0] = fState.lookAt[0];
+ camera->lookAt[1] = fState.lookAt[1];
+ camera->lookAt[2] = fState.lookAt[2];
+
+ camera->rot[0] = fState.rot[0];
+ camera->rot[1] = fState.rot[1];
+ camera->rot[2] = fState.rot[2];
+}
+
+void flycam_controller_manager(Camera *camera, struct Controller *controller, Player *player) {
+
+ if (controller->buttonPressed & U_JPAD) {
+ fMode = !fMode;
+ }
+
+ // Target a player
+ if (controller->buttonPressed & R_TRIG) {
+ fTargetPlayer = !fTargetPlayer;
+ }
+
+ // Target next player
+ if (controller->buttonPressed & L_CBUTTONS) {
+ if (fRankIndex > 0) {
+ fRankIndex--;
+ camera->playerId = fRankIndex;
+ D_800DC5EC->player = &gPlayers[fRankIndex];
+ }
+ }
+
+ // Target previous player
+ if (controller->buttonPressed & R_CBUTTONS) {
+ if (fRankIndex < 7) {
+ fRankIndex++;
+ camera->playerId = fRankIndex;
+ D_800DC5EC->player = &gPlayers[fRankIndex];
+ }
+ }
+
+ // Target camera at chosen player
+ if (fTargetPlayer) {
+ flycam_target_player(camera, gGPCurrentRacePlayerIdByRank[fRankIndex]);
+ // Don't run the other camera code.
+ return;
+ }
+
+ // Rotation
+ if (!fTargetPlayer) {
+ if (controller->stickDirection != 0) {
+ flycam_update(camera, controller);
+ }
+ }
+
+ // Forward
+ if (controller->button & A_BUTTON) {
+ flycam_move_camera_forward(camera, controller, 3.0f);
+ }
+
+ // Backward B button but not A button.
+ if (controller->button & B_BUTTON && !(controller->button & A_BUTTON)) {
+ flycam_move_camera_forward(camera, controller, -3.0f);
+ }
+
+ // Up
+ if (controller->button & U_CBUTTONS) {
+ flycam_move_camera_up(camera, controller, 2.0f);
+ }
+ // Up
+ if (controller->button & D_CBUTTONS) {
+ flycam_move_camera_up(camera, controller, -2.0f);
+ }
+}
+
+// Calculates the forward direction vector based on camera orientation
+void flycam_calculate_forward_vector(Camera* camera, Vec3f forwardVector) {
+ f32 pitch = (camera->rot[2] / 65535.0f) * 360.0f; // Convert pitch from 0-65535 to degrees
+ f32 yaw = (camera->rot[1] / 65535.0f) * 360.0f; // Convert yaw from 0-65535 to degrees
+
+ // Convert degrees to radians
+ pitch = pitch * M_PI / 180.0f;
+ yaw = yaw * M_PI / 180.0f;
+
+ forwardVector[0] = -sinf(yaw) * cosf(pitch);
+ forwardVector[1] = -sinf(pitch);
+ forwardVector[2] = cosf(yaw) * cosf(pitch);
+}
+
+// Function to move the camera forward
+void flycam_move_camera_forward(Camera* camera, struct Controller *controller, f32 distance) {
+ Vec3f forwardVector;
+ Vec3f rightVector;
+ f32 length;
+ flycam_calculate_forward_vector(camera, forwardVector);
+
+ if (controller->button & Z_TRIG) {
+ distance *= 3;
+ }
+
+ // Normalize the forward vector
+ length = sqrtf(forwardVector[0] * forwardVector[0] + forwardVector[1] * forwardVector[1] + forwardVector[2] * forwardVector[2]);
+ forwardVector[0] /= length;
+ forwardVector[1] /= length;
+ forwardVector[2] /= length;
+
+ // Calculate the right vector by taking the cross product of forward and up
+ rightVector[0] = forwardVector[1] * camera->up[2] - forwardVector[2] * camera->up[1];
+ rightVector[1] = forwardVector[2] * camera->up[0] - forwardVector[0] * camera->up[2];
+ rightVector[2] = forwardVector[0] * camera->up[1] - forwardVector[1] * camera->up[0];
+
+ // Move the camera's position along the forward vector while considering its up vector
+ camera->pos[0] += forwardVector[0] * distance;
+ camera->pos[1] += forwardVector[1] * distance;
+ camera->pos[2] += forwardVector[2] * distance;
+
+ // Optionally, you can also adjust the lookAt point to maintain the same relative position
+ camera->lookAt[0] += forwardVector[0] * distance;
+ camera->lookAt[1] += forwardVector[1] * distance;
+ camera->lookAt[2] += forwardVector[2] * distance;
+}
+
+// Function to move the camera forward
+void flycam_move_camera_up(Camera* camera, struct Controller *controller, f32 distance) {
+ // Check if the Z button is pressed (for faster movement)
+ if (controller->button & Z_TRIG) {
+ distance *= 3;
+ }
+
+ // Move the camera's position along its up vector (Y-axis)
+ camera->pos[1] += distance;
+
+ // Optionally, adjust the lookAt point to maintain the same relative position
+ camera->lookAt[1] += distance;
+}
+
+// Update camera rotation and lookAt point based on input
+void flycam_update(Camera* camera, struct Controller *controller) {
+ // Calculate yaw (horizontal movement)
+ f32 yawChange = controller->rawStickX * SENSITIVITY_X;
+ f32 pitchChange = controller->rawStickY * SENSITIVITY_Y;
+ Vec3f forwardVector;
+
+ check_bounding_collision(&camera->collision, 50, camera->pos[0], camera->pos[1], camera->pos[2]);
+
+ camera->rot[1] += (short)(yawChange * 65535.0f / (2 * M_PI)); // Convert radians to 0-65535 range
+
+ camera->rot[2] += (short)(-pitchChange * 65535.0f / (2 * M_PI)); // Convert radians to 0-65535 range
+
+ if (camera->rot[2] > 15999) {
+ camera->rot[2] = 15999;
+ } else if (camera->rot[2] < -15999) {
+ camera->rot[2] = -15999;
+ }
+
+ // Update the lookAt point based on the new orientation
+ flycam_calculate_forward_vector(camera, forwardVector);
+ camera->lookAt[0] = camera->pos[0] + forwardVector[0];
+ camera->lookAt[1] = camera->pos[1] + forwardVector[1];
+ camera->lookAt[2] = camera->pos[2] + forwardVector[2];
+}
+
+void flycam_target_player(Camera *camera, u32 playerIndex) {
+ Vec3f forwardVector;// = 2.0f;
+ Player *player = &gPlayers[playerIndex];
+
+ // Calculate the direction from the player to the camera
+ f32 dirX = player->pos[0] - camera->pos[0];
+ f32 dirY = player->pos[1] - camera->pos[1];
+ f32 dirZ = player->pos[2] - camera->pos[2];
+
+ // Normalize the direction vector (if needed)
+ f32 length = sqrtf(dirX * dirX + dirY * dirY + dirZ * dirZ);
+ if (length > 0) {
+ dirX /= length;
+ dirY /= length;
+ dirZ /= length;
+ }
+
+ // Update the camera's look-at direction
+ camera->lookAt[0] = camera->pos[0] + dirX;
+ camera->lookAt[1] = camera->pos[1] + dirY;
+ camera->lookAt[2] = camera->pos[2] + dirZ;
+}
diff --git a/src/main.c b/src/main.c
index 7c90951..135e98c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -578,6 +578,7 @@ void race_logic_loop(void) {
gTickSpeed = 2;
staff_ghosts_loop();
if (gIsGamePaused == 0) {
+ func_8001EE98(gPlayerOneCopy, camera1, 0);
for (i = 0; i < gTickSpeed; i++) {
if (D_8015011E) {
gCourseTimer += 0.01666666; // 1 / 60
@@ -585,7 +586,6 @@ void race_logic_loop(void) {
func_802909F0();
evaluate_collision_for_players_and_actors();
func_800382DC();
- func_8001EE98(gPlayerOneCopy, camera1, 0);
func_80028F70();
func_8028F474();
func_80059AC8();
diff --git a/src/racing/render_courses.c b/src/racing/render_courses.c
index c2a84aa..338e2bd 100644
--- a/src/racing/render_courses.c
+++ b/src/racing/render_courses.c
@@ -180,6 +180,11 @@ void render_course_segments(uintptr_t addr, struct UnkStruct_800DC5EC *arg1) {
arg1->pathCounter = temp_v1;
temp_v1 = ((temp_v1 - 1) * 4) + var_a3;
+ if (isFlycam) {
+ render_course_credits();
+ return;
+ }
+
gSPDisplayList(gDisplayListHead++, gfx[temp_v1]);
}