mirror of https://github.com/n64decomp/mk64.git
445 lines
14 KiB
Diff
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]);
|
|
}
|
|
|