Make freecam work on DX and fix controller

This commit is contained in:
MegaMech 2025-01-06 17:38:16 -07:00
parent cb21fc1209
commit 9400f9e9ce
5 changed files with 165 additions and 233 deletions

View File

@ -150,6 +150,7 @@ file(GLOB_RECURSE ALL_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
"src/enhancements/*.c"
"src/enhancements/*.h"
"src/enhancements/freecam/*.c"
"src/enhancements/freecam/*.cpp"
"src/enhancements/freecam/*.h"
"src/engine/*.cpp"
"src/engine/*.h"

View File

@ -1,4 +1,11 @@
#include <libultraship.h>
#include <window/Window.h>
#include "port/Engine.h"
#include "port/Game.h"
#include <controller/controldevice/controller/mapping/keyboard/KeyboardScancodes.h>
#include <window/Window.h>
extern "C" {
#include <macros.h>
#include <defines.h>
#include <camera.h>
@ -12,10 +19,10 @@
#include "code_80005FD0.h"
#include <SDL2/SDL.h>
#include "freecam_engine.h"
#include "n64_freecam.h"
#include "math_util.h"
#include "skybox_and_splitscreen.h"
#include "freecam.h"
}
#include "engine/Engine.h"
#include "engine/courses/Course.h"
@ -123,14 +130,10 @@ void freecam(Camera* camera, Player* player, s8 index) {
// if ((player->type & PLAYER_START_SEQUENCE)) { return; }
// Mouse/Keyboard
if (gFreecamControllerType == 0) {
freecam_calculate_forward_vector_allow_rotation(camera, freeCam.forwardVector);
freecam_mouse_manager(camera, freeCam.forwardVector);
freecam_keyboard_manager(camera, freeCam.forwardVector);
} else { // Stock N64 controller
freecam_n64_controller_manager(camera, controller, player);
}
freecam_calculate_forward_vector_allow_rotation(camera, freeCam.forwardVector);
freecam_mouse_manager(camera, freeCam.forwardVector);
freecam_keyboard_manager(camera, freeCam.forwardVector);
if (!fTargetPlayer) {
freecam_update(camera, freeCam.forwardVector);
}
@ -168,19 +171,23 @@ void freecam_load_state(Camera* camera) {
f32 gFreecamRotateSmoothingFactor = 0.85f;
void freecam_mouse_manager(Camera* camera, Vec3f forwardVector) {
int mouseX, mouseY;
static int prevMouseX = 0, prevMouseY = 0;
Uint32 mouseState = SDL_GetRelativeMouseState(&mouseX, &mouseY);
auto wnd = GameEngine::Instance->context->GetWindow();
Ship::Coords mouse = wnd->GetMouseDelta();
mouseX = (mouseX + prevMouseX) / 2;
mouseY = (mouseY + prevMouseY) / 2;
prevMouseX = mouseX;
prevMouseY = mouseY;
//Uint32 mouseState = SDL_GetRelativeMouseState(&mouse.x, &mouse.y);
if (mouseState & SDL_BUTTON(SDL_BUTTON_RIGHT)) {
//printf("MOUSE %d %d\n", mouse.x, mouse.y);
mouse.x = (mouse.x + prevMouseX) / 2;
mouse.y = (mouse.y + prevMouseY) / 2;
prevMouseX = mouse.x;
prevMouseY = mouse.y;
if (wnd->GetMouseState(Ship::LUS_MOUSE_BTN_RIGHT)) {
// Calculate yaw (left/right) and pitch (up/down) changes
f32 yawChange = mouseX * MOUSE_SENSITIVITY_X;
f32 pitchChange = mouseY * MOUSE_SENSITIVITY_Y;
f32 yawChange = mouse.x * MOUSE_SENSITIVITY_X;
f32 pitchChange = mouse.y * MOUSE_SENSITIVITY_Y;
// Smoothly update yaw and pitch
camera->rot[1] += (short) (yawChange * 65535.0f / (2 * M_PI)); // Yaw (left/right)
@ -212,13 +219,14 @@ f32 gFreecamSpeed = 3.0f;
f32 gFreecamSpeedMultiplier = 2.0f;
void freecam_keyboard_manager(Camera* camera, Vec3f forwardVector) {
const uint8_t* keystate = SDL_GetKeyboardState(NULL);
auto wnd = GameEngine::Instance->context->GetWindow();
float moveSpeed = gFreecamSpeed;
Controller* controller = &gControllers[0];
// Fast movement with Ctrl
if (keystate[SDL_SCANCODE_LCTRL] || keystate[SDL_SCANCODE_RCTRL]) {
moveSpeed *= gFreecamSpeedMultiplier;
}
//if (wnd->KeyDown(SDL_SCANCODE_LCTRL) || wnd->KeyDown(SDL_SCANCODE_RCTRL)) {
// moveSpeed *= gFreecamSpeedMultiplier;
//}
// Determine movement direction based on keys pressed
Vec3f totalMove = { 0.0f, 0.0f, 0.0f };
@ -232,52 +240,153 @@ void freecam_keyboard_manager(Camera* camera, Vec3f forwardVector) {
// fTargetPlayer = false;
// }
// Target next player
if (keystate[SDL_SCANCODE_N]) {
if (fRankIndex > 0) {
fRankIndex--;
camera->playerId = fRankIndex;
D_800DC5EC->player = &gPlayers[fRankIndex];
bool TargetNextPlayer = false, TargetPreviousPlayer = false;
bool Forward = false, PanLeft = false, Backward = false, PanRight = false;
bool Up = false, Down = false, RSHIFT_Down = false;
// Use n64 controls for use with a controller
//! @todo configure this properly
if (gFreecamControllerType == 1) {
// Targeting /fMode is broken
// if (controller->buttonPressed & U_JPAD) {
// fMode = !fMode;
// }
// Target a player
// if (controller->buttonPressed & R_TRIG) {
// fTargetPlayer = !fTargetPlayer;
// }
if (controller->buttonPressed & L_CBUTTONS) {
TargetNextPlayer = true;
}
if (controller->buttonPressed & R_CBUTTONS) {
TargetPreviousPlayer = true;
}
if (controller->button & A_BUTTON) {
Forward = true;
}
if (controller->button & B_BUTTON) {
Backward = true;
}
if (controller->button & L_JPAD) {
PanLeft = true;
}
if (controller->button & R_JPAD) {
PanLeft = true;
}
if (controller->button & U_CBUTTONS) {
Down = true;
}
if (controller->button & U_CBUTTONS) {
Up = true;
}
// Keyboard and mouse DX
} else if (wnd->GetWindowBackend() == Ship::WindowBackend::FAST3D_DXGI_DX11) {
if (GetKeyState('N') & 0x8000) {
TargetNextPlayer = true;
}
if (GetKeyState('M') & 0x8000) {
TargetPreviousPlayer = true;
}
if (GetKeyState('W') & 0x8000) {
Forward = true;
}
if (GetKeyState('S') & 0x8000) {
Backward = true;
}
if (GetKeyState('D') & 0x8000) {
PanRight = true;
}
if (GetKeyState('A') & 0x8000) {
PanLeft = true;
}
if (GetKeyState(VK_SPACE) & 0x8000) {
Up = true;
}
if (GetKeyState(VK_LSHIFT) & 0x8000) {
Down = true;
}
if (GetKeyState(VK_RSHIFT) & 0x8000) {
RSHIFT_Down = true;
}
// Keyboard/mouse OpenGL/SDL
} else if (wnd->GetWindowBackend() == Ship::WindowBackend::FAST3D_SDL_OPENGL) {
const uint8_t* keystate = SDL_GetKeyboardState(NULL);
if (keystate[SDL_SCANCODE_N]) {
TargetNextPlayer = true;
}
if (keystate[SDL_SCANCODE_M]) {
TargetPreviousPlayer = true;
}
if (keystate[SDL_SCANCODE_W]) {
Forward = true;
}
if (keystate[SDL_SCANCODE_S]) {
Backward = true;
}
if (keystate[SDL_SCANCODE_D]) {
PanRight = true;
}
if (keystate[SDL_SCANCODE_A]) {
PanLeft = true;
}
if (keystate[SDL_SCANCODE_SPACE]) {
Up = true;
}
if (keystate[SDL_SCANCODE_LSHIFT]) {
Down = true;
}
if (keystate[SDL_SCANCODE_RSHIFT]) {
RSHIFT_Down = true;
}
}
// Target next player
if (TargetNextPlayer) {
if (fRankIndex > 0) {
fRankIndex--;
camera->playerId = fRankIndex;
D_800DC5EC->player = &gPlayers[fRankIndex];
}
}
// Target previous player
if (keystate[SDL_SCANCODE_M]) {
if (fRankIndex < 7) {
fRankIndex++;
camera->playerId = fRankIndex;
D_800DC5EC->player = &gPlayers[fRankIndex];
}
if (TargetPreviousPlayer) {
if (fRankIndex < 7) {
fRankIndex++;
camera->playerId = fRankIndex;
D_800DC5EC->player = &gPlayers[fRankIndex];
}
}
// Target camera at chosen player
if (fRankIndex != -1) {
freecam_target_player(camera, gGPCurrentRacePlayerIdByRank[fRankIndex]);
// Don't run the other camera code.
return;
freecam_target_player(camera, gGPCurrentRacePlayerIdByRank[fRankIndex]);
// Don't run the other camera code.
return;
}
if (keystate[SDL_SCANCODE_W]) {
totalMove[0] += forwardVector[0] * moveSpeed;
totalMove[2] += forwardVector[2] * moveSpeed;
if (Forward) {
totalMove[0] += forwardVector[0] * moveSpeed;
totalMove[2] += forwardVector[2] * moveSpeed;
}
if (keystate[SDL_SCANCODE_S]) {
totalMove[0] -= forwardVector[0] * moveSpeed;
totalMove[2] -= forwardVector[2] * moveSpeed;
if (Backward) {
totalMove[0] -= forwardVector[0] * moveSpeed;
totalMove[2] -= forwardVector[2] * moveSpeed;
}
if (keystate[SDL_SCANCODE_D]) {
totalMove[0] -= forwardVector[2] * moveSpeed; // Pan right
totalMove[2] += forwardVector[0] * moveSpeed;
if (PanRight) {
totalMove[0] -= forwardVector[2] * moveSpeed; // Pan right
totalMove[2] += forwardVector[0] * moveSpeed;
}
if (keystate[SDL_SCANCODE_A]) {
totalMove[0] += forwardVector[2] * moveSpeed; // Pan left
totalMove[2] -= forwardVector[0] * moveSpeed;
if (PanLeft) {
totalMove[0] += forwardVector[2] * moveSpeed; // Pan left
totalMove[2] -= forwardVector[0] * moveSpeed;
}
if (keystate[SDL_SCANCODE_SPACE]) {
totalMove[1] += moveSpeed; // Move up
if (Up) {
totalMove[1] += moveSpeed; // Move up
}
if (keystate[SDL_SCANCODE_LSHIFT] || keystate[SDL_SCANCODE_RSHIFT]) {
totalMove[1] -= moveSpeed; // Move down
if (Down || RSHIFT_Down) {
totalMove[1] -= moveSpeed; // Move down
}
freeCam.velocity[0] += totalMove[0];
freeCam.velocity[1] += totalMove[1];
@ -288,70 +397,6 @@ void freecam_keyboard_manager(Camera* camera, Vec3f forwardVector) {
camera->lookAt[2] = camera->pos[2] + forwardVector[2];
}
// Control the camera using the n64 controller
void freecam_n64_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) {
freecam_target_player(camera, gGPCurrentRacePlayerIdByRank[fRankIndex]);
// Don't run the other camera code.
return;
}
// Rotation
if (!fTargetPlayer) {
if (controller->stickDirection != 0) {
freecam_n64_update(camera, controller);
}
}
// Forward
if (controller->button & A_BUTTON) {
freecam_n64_move_camera_forward(camera, controller, 3.0f);
}
// Backward B button but not A button.
if (controller->button & B_BUTTON && !(controller->button & A_BUTTON)) {
freecam_n64_move_camera_forward(camera, controller, -3.0f);
}
// Up
if (controller->button & U_CBUTTONS) {
freecam_n64_move_camera_up(camera, controller, 2.0f);
}
// Up
if (controller->button & D_CBUTTONS) {
freecam_n64_move_camera_up(camera, controller, -2.0f);
}
}
void freecam_render_setup(void) {
u16 perspNorm;
Mat4 matrix;

View File

@ -1,102 +0,0 @@
#include <libultraship.h>
#include <defines.h>
#include <macros.h>
#include "code_80057C60.h"
#include "code_800029B0.h"
#include "code_80005FD0.h"
#include "camera.h"
#include <common_structs.h>
#include "player_controller.h"
#include "collision.h"
#include "freecam_engine.h"
#define N64_SENSITIVITY_X 0.0003f
#define N64_SENSITIVITY_Y 0.0003f
// Calculates the forward direction vector based on camera orientation
void freecam_n64_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 freecam_n64_move_camera_forward(Camera* camera, struct Controller* controller, f32 distance) {
Vec3f forwardVector;
Vec3f rightVector;
f32 length;
freecam_n64_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 freecam_n64_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 freecam_n64_update(Camera* camera, struct Controller* controller) {
// Calculate yaw (horizontal movement)
f32 yawChange = controller->rawStickX * N64_SENSITIVITY_X;
f32 pitchChange = controller->rawStickY * N64_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
freecam_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];
}

View File

@ -1,12 +0,0 @@
#ifndef N64_FREECAM_H
#define N64_FREECAM_H
#include <libultraship.h>
void freecam_n64_move_camera_up(Camera* camera, struct Controller* controller, f32 distance);
void freecam_n64_controller_manager(Camera* camera, struct Controller* controller, Player* player);
void freecam_n64_calculate_forward_vector(Camera* camera, Vec3f forwardVector);
void freecam_n64_move_camera_forward(Camera* camera, struct Controller* controller, f32 distance);
void freecam_n64_update(Camera* camera, struct Controller* controller);
#endif // N64_FREECAM_H

View File

@ -53,9 +53,9 @@ void FreecamWindow::DrawElement() {
const float deltatime = ImGui::GetIO().DeltaTime;
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::Text("Freecam: Mouse/Keyboard Requires OpenGL. DX is not supported");
ImGui::Text("Controller mode is not configured yet.");
const char* items[] = { "Mouse/Keyboard", "N64 Controls" };
const char* items[] = { "Mouse/Keyboard", "Controller" };
static int current_item = 0;
if (ImGui::Combo("Dropdown", &current_item, items, IM_ARRAYSIZE(items))) {
gFreecamControllerType = current_item;