sm64coopdx/src/game/first_person_cam.c
PeachyPeach 8db6356754
Improving math functions (#813)
* Improving math functions

* Isaac review
2025-05-21 23:50:49 +02:00

205 lines
7.9 KiB
C

#include "first_person_cam.h"
#include "sm64.h"
#include "behavior_data.h"
#include "camera.h"
#include "level_update.h"
#include "object_list_processor.h"
#include "object_helpers.h"
#include "mario.h"
#include "hardcoded.h"
#include "save_file.h"
#include "engine/math_util.h"
#include "pc/controller/controller_mouse.h"
#include "pc/djui/djui.h"
#include "pc/djui/djui_hud_utils.h"
#include "pc/lua/utils/smlua_camera_utils.h"
#include "pc/lua/smlua_hooks.h"
struct FirstPersonCamera gFirstPersonCamera = {
.enabled = false,
.forcePitch = false,
.forceYaw = false,
.forceRoll = true,
.centerL = true,
.pitch = 0,
.yaw = 0,
.crouch = 0,
.fov = FIRST_PERSON_DEFAULT_FOV,
.offset = { 0, 0, 0 }
};
extern s16 gMenuMode;
bool first_person_check_cancels(struct MarioState *m) {
if (m->action == ACT_FIRST_PERSON || m->action == ACT_IN_CANNON || m->action == ACT_READING_NPC_DIALOG || m->action == ACT_DISAPPEARED || m->action == ACT_FLYING) {
return true;
}
if (find_object_with_behavior(smlua_override_behavior(bhvActSelector)) != NULL) { return true; }
if (gLuaLoadingMod != NULL) { return false; }
struct Object *bowser = find_object_with_behavior(smlua_override_behavior(bhvBowser));
if ((gCurrLevelNum == LEVEL_BOWSER_1 || gCurrLevelNum == LEVEL_BOWSER_2 || gCurrLevelNum == LEVEL_BOWSER_3) &&
bowser != NULL &&
(bowser->oAction == 5 || bowser->oAction == 6)) {
return true;
}
return false;
}
bool get_first_person_enabled(void) {
return gFirstPersonCamera.enabled && !first_person_check_cancels(&gMarioStates[0]);
}
void set_first_person_enabled(bool enable) {
gFirstPersonCamera.enabled = enable;
}
static void first_person_camera_update(void) {
struct MarioState *m = &gMarioStates[0];
f32 sensX = 0.3f * camera_config_get_x_sensitivity();
f32 sensY = 0.4f * camera_config_get_y_sensitivity();
s16 invX = camera_config_is_x_inverted() ? 1 : -1;
s16 invY = camera_config_is_y_inverted() ? 1 : -1;
if (mouse_relative_enabled) {
// hack: make c buttons work for moving the camera
s16 extStickX = m->controller->extStickX;
s16 extStickY = m->controller->extStickY;
if (extStickX == 0) {
extStickX = (clamp(m->controller->buttonDown & R_CBUTTONS, 0, 1) - clamp(m->controller->buttonDown & L_CBUTTONS, 0, 1)) * 32;
}
if (extStickY == 0) {
extStickY = (clamp(m->controller->buttonDown & U_CBUTTONS, 0, 1) - clamp(m->controller->buttonDown & D_CBUTTONS, 0, 1)) * 24;
}
// update pitch
if (!gFirstPersonCamera.forcePitch) {
gFirstPersonCamera.pitch -= sensY * (invY * extStickY - 1.5f * mouse_y);
gFirstPersonCamera.pitch = clamp(gFirstPersonCamera.pitch, -0x3F00, 0x3F00);
}
// update yaw
if (!gFirstPersonCamera.forceYaw) {
if (m->controller->buttonDown & L_TRIG && gFirstPersonCamera.centerL) {
gFirstPersonCamera.yaw = m->faceAngle[1] + 0x8000;
} else {
gFirstPersonCamera.yaw += sensX * (invX * extStickX - 1.5f * mouse_x);
}
}
}
// fix yaw for some specific actions
// if the left stick is held, use Mario's yaw to set the camera's yaw
// otherwise, set Mario's yaw to the camera's yaw
u32 actions[] = { ACT_FLYING, ACT_HOLDING_BOWSER, ACT_TORNADO_TWIRLING, ACT_FLAG_ON_POLE, ACT_FLAG_SWIMMING, ACT_FLAG_SWIMMING_OR_FLYING };
for (s32 i = 0; i < 6; i++) {
u32 flag = actions[i];
if ((m->action & flag) == flag) {
if (ABS(m->controller->stickX) > 4) {
gFirstPersonCamera.yaw = m->faceAngle[1] + 0x8000;
} else {
m->faceAngle[1] = gFirstPersonCamera.yaw - 0x8000;
}
break;
}
}
if (m->action == ACT_LEDGE_GRAB) {
gFirstPersonCamera.yaw = m->faceAngle[1] + 0x8000;
}
gLakituState.yaw = gFirstPersonCamera.yaw;
m->area->camera->yaw = gFirstPersonCamera.yaw;
// update crouch
if (mario_is_crouching(m) || m->action == ACT_LEDGE_GRAB) {
bool up = (m->controller->buttonDown & Z_TRIG) != 0 || m->action == ACT_CROUCH_SLIDE || m->action == ACT_LEDGE_GRAB;
f32 inc = 10 * (up ? 1 : -1);
gFirstPersonCamera.crouch = clamp(gFirstPersonCamera.crouch + inc, 0, FIRST_PERSON_MARIO_HEAD_POS - FIRST_PERSON_MARIO_HEAD_POS_SHORT);
} else {
gFirstPersonCamera.crouch = clamp(gFirstPersonCamera.crouch - 10, 0, FIRST_PERSON_MARIO_HEAD_POS - FIRST_PERSON_MARIO_HEAD_POS_SHORT);
}
if (m->action == ACT_LEDGE_GRAB) {
gFirstPersonCamera.crouch = FIRST_PERSON_MARIO_HEAD_POS - FIRST_PERSON_MARIO_HEAD_POS_SHORT;
}
// update pos
gLakituState.pos[0] = (m->pos[0] + gFirstPersonCamera.offset[0]) + coss(gFirstPersonCamera.pitch) * sins(gFirstPersonCamera.yaw);
gLakituState.pos[1] = (m->pos[1] + gFirstPersonCamera.offset[1]) + sins(gFirstPersonCamera.pitch) + (FIRST_PERSON_MARIO_HEAD_POS - gFirstPersonCamera.crouch);
gLakituState.pos[2] = (m->pos[2] + gFirstPersonCamera.offset[2]) + coss(gFirstPersonCamera.pitch) * coss(gFirstPersonCamera.yaw);
vec3f_copy(m->area->camera->pos, gLakituState.pos);
vec3f_copy(gLakituState.curPos, gLakituState.pos);
vec3f_copy(gLakituState.goalPos, gLakituState.pos);
// update focus
gLakituState.focus[0] = (m->pos[0] + gFirstPersonCamera.offset[0]) - 100 * coss(gFirstPersonCamera.pitch) * sins(gFirstPersonCamera.yaw);
gLakituState.focus[1] = (m->pos[1] + gFirstPersonCamera.offset[1]) - 100 * sins(gFirstPersonCamera.pitch) + (FIRST_PERSON_MARIO_HEAD_POS - gFirstPersonCamera.crouch);
gLakituState.focus[2] = (m->pos[2] + gFirstPersonCamera.offset[2]) - 100 * coss(gFirstPersonCamera.pitch) * coss(gFirstPersonCamera.yaw);
vec3f_copy(m->area->camera->focus, gLakituState.focus);
vec3f_copy(gLakituState.curFocus, gLakituState.focus);
vec3f_copy(gLakituState.goalFocus, gLakituState.focus);
// set other values
if (gFirstPersonCamera.forceRoll) {
gLakituState.roll = 0;
}
gLakituState.posHSpeed = 0;
gLakituState.posVSpeed = 0;
gLakituState.focHSpeed = 0;
gLakituState.focVSpeed = 0;
vec3s_set(gLakituState.shakeMagnitude, 0, 0, 0);
}
void first_person_update(void) {
if (gFirstPersonCamera.enabled && !gDjuiInMainMenu) {
struct MarioState *m = &gMarioStates[0];
// check cancels
bool cancel = first_person_check_cancels(m);
if (cancel) { return; }
if (m->action == ACT_SHOT_FROM_CANNON && m->area->camera->mode == CAMERA_MODE_INSIDE_CANNON) {
gFirstPersonCamera.yaw = m->faceAngle[1] + 0x8000;
m->area->camera->mode = CAMERA_MODE_FREE_ROAM;
}
if (gFirstPersonCamera.pitch <= -0x3F00 &&
m->floor && m->floor->type == SURFACE_LOOK_UP_WARP &&
save_file_get_total_star_count(gCurrSaveFileNum - 1, COURSE_MIN - 1, COURSE_MAX - 1) >= gLevelValues.wingCapLookUpReq &&
m->forwardVel == 0 &&
sCurrPlayMode != PLAY_MODE_PAUSED) {
level_trigger_warp(m, WARP_OP_LOOK_UP);
}
m->marioBodyState->modelState = 0x100;
if (m->heldObj) {
Vec3f camDir = {
m->area->camera->focus[0] - m->area->camera->pos[0],
m->area->camera->focus[1] - m->area->camera->pos[1],
m->area->camera->focus[2] - m->area->camera->pos[2]
};
vec3f_normalize(camDir);
vec3f_mul(camDir, 100);
vec3f_sum(m->marioObj->header.gfx.pos, m->pos, camDir);
}
first_person_camera_update();
}
}
void first_person_reset(void) {
gFirstPersonCamera.forceRoll = false;
gFirstPersonCamera.centerL = true;
gFirstPersonCamera.pitch = 0;
gFirstPersonCamera.yaw = 0;
gFirstPersonCamera.crouch = 0;
gFirstPersonCamera.fov = FIRST_PERSON_DEFAULT_FOV;
gFirstPersonCamera.offset[0] = 0;
gFirstPersonCamera.offset[1] = 0;
gFirstPersonCamera.offset[2] = 0;
}