mirror of
https://github.com/izzy2lost/2ship2harkinian-Android.git
synced 2026-06-19 01:20:08 -07:00
'Free/Debug' Camera & Free Look Camera (#323)
* Remove BenPort.h from functions.h * use specific z64 includes * free cam * this -> thisx * fl newline * whitespace * remove debugging stuff * min and max cam heights. use correct func_800CBFA4 arg * document and re-organise free cam * fix linux building * Custom Camera VB * remove redundant section in header * fix hook and re-organise menu * Free Cam * fix control flipping and some speed tweaks * Fix Player flags not being reset * Fix movement under roll: todo fix rotation under roll * six degrees of freedom * Multiple camera mode options, remove black bars, start with focal point by eye * update free look * cvar rename, menu disabling * remove player state flag change * renaming and remove some camera jumpiness * remove scam comment * remove port selection * correct debugcam at initialised position * fix focal point for non roll
This commit is contained in:
@@ -305,6 +305,50 @@ extern std::shared_ptr<HudEditorWindow> mHudEditorWindow;
|
||||
void DrawEnhancementsMenu() {
|
||||
if (UIWidgets::BeginMenu("Enhancements")) {
|
||||
|
||||
if (UIWidgets::BeginMenu("Camera")) {
|
||||
ImGui::SeparatorText("Right Stick Camera");
|
||||
UIWidgets::CVarCheckbox("Invert Camera X Axis", "gEnhancements.Camera.RightStick.InvertXAxis", {
|
||||
.tooltip = "Inverts the Camera X Axis in Free Look."
|
||||
});
|
||||
UIWidgets::CVarCheckbox("Invert Camera Y Axis", "gEnhancements.Camera.RightStick.InvertYAxis", {
|
||||
.tooltip = "Inverts the Camera Y Axis in Free Look.",
|
||||
.defaultValue = true
|
||||
});
|
||||
UIWidgets::CVarSliderFloat("Third-Person Horizontal Sensitivity: %.0f %", "gEnhancements.Camera.RightStick.CameraSensitivity.X", 0.01f, 5.0f, 1.0f);
|
||||
UIWidgets::CVarSliderFloat("Third-Person Vertical Sensitivity: %.0f %", "gEnhancements.Camera.RightStick.CameraSensitivity.Y", 0.01f, 5.0f, 1.0f);
|
||||
|
||||
ImGui::SeparatorText("Free Look");
|
||||
if (UIWidgets::CVarCheckbox("Free Look", "gEnhancements.Camera.FreeLook.Enable", {
|
||||
.tooltip = "Enables free look camera control\nNote: You must remap C buttons off of the right stick in the controller config menu, and map the camera stick to the right stick.",
|
||||
.disabled = CVarGetInteger("gEnhancements.Camera.DebugCam.Enable", 0) != 0
|
||||
})) {
|
||||
RegisterCameraFreeLook();
|
||||
}
|
||||
|
||||
UIWidgets::CVarSliderInt("Camera Distance: %d", "gEnhancements.Camera.FreeLook.MaxCameraDistance", 100, 900, 185);
|
||||
UIWidgets::CVarSliderInt("Camera Transition Speed: %d", "gEnhancements.Camera.FreeLook.TransitionSpeed", 1, 900, 25);
|
||||
UIWidgets::CVarSliderFloat("Max Camera Height Angle: %.0f %°", "gEnhancements.Camera.FreeLook.MaxPitch", -89.0f, 89.0f, 72.0f);
|
||||
UIWidgets::CVarSliderFloat("Min Camera Height Angle: %.0f %°", "gEnhancements.Camera.FreeLook.MinPitch", -89.0f, 89.0f, -49.0f);
|
||||
f32 maxY = CVarGetFloat("gEnhancements.Camera.FreeLook.MaxPitch", 72.0f);
|
||||
f32 minY = CVarGetFloat("gEnhancements.Camera.FreeLook.MinPitch", -49.0f);
|
||||
CVarSetFloat("gEnhancements.Camera.FreeLook.MaxPitch", std::max(maxY, minY));
|
||||
CVarSetFloat("gEnhancements.Camera.FreeLook.MinPitch", std::min(maxY, minY));
|
||||
|
||||
ImGui::SeparatorText("'Debug' Camera");
|
||||
if (UIWidgets::CVarCheckbox("Debug Camera", "gEnhancements.Camera.DebugCam.Enable", {
|
||||
.tooltip = "Enables free camera control.",
|
||||
.disabled = CVarGetInteger("gEnhancements.Camera.FreeLook.Enable", 0) != 0
|
||||
})) {
|
||||
RegisterDebugCam();
|
||||
}
|
||||
UIWidgets::CVarCheckbox("Enable Roll (Six Degrees Of Freedom)", "gEnhancements.Camera.DebugCam.6DOF", {
|
||||
.tooltip = "This allows for all six degrees of movement with the camera, NOTE: Yaw will work differently in this system, instead rotating around the focal point, rather than a polar axis."
|
||||
});
|
||||
UIWidgets::CVarSliderFloat("Camera Speed: %.0f %", "gEnhancements.Camera.DebugCam.CameraSpeed", 0.1f, 3.0f, 0.5f);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (UIWidgets::BeginMenu("Cutscenes")) {
|
||||
UIWidgets::CVarCheckbox("Hide Title Cards", "gEnhancements.Cutscenes.HideTitleCards");
|
||||
UIWidgets::CVarCheckbox("Skip Entrance Cutscenes", "gEnhancements.Cutscenes.SkipEntranceCutscenes");
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef CAMERA_UTILS_H
|
||||
#define CAMERA_UTILS_H
|
||||
#include "ultratypes.h"
|
||||
|
||||
// Camera will reload its paramData. Usually that means setting the read-only data from what is stored in
|
||||
// CameraModeValue arrays. Although sometimes some read-write data is reset as well
|
||||
#define RELOAD_PARAMS(camera) ((camera->animState == 0) || (camera->animState == 10) || (camera->animState == 20))
|
||||
|
||||
/**
|
||||
* Camera data is stored in both read-only data and OREG as s16, and then converted to the appropriate type during
|
||||
* runtime. If a small f32 is being stored as an s16, it is common to store that value 100 times larger than the
|
||||
* original value. This is then scaled back down during runtime with the CAM_RODATA_UNSCALE macro.
|
||||
*/
|
||||
#define CAM_RODATA_SCALE(x) ((x)*100.0f)
|
||||
#define CAM_RODATA_UNSCALE(x) ((x)*0.01f)
|
||||
|
||||
// Load the next value from camera read-only data stored in CameraModeValue
|
||||
#define GET_NEXT_RO_DATA(values) ((values++)->val)
|
||||
// Load the next value and scale down from camera read-only data stored in CameraModeValue
|
||||
#define GET_NEXT_SCALED_RO_DATA(values) CAM_RODATA_UNSCALE(GET_NEXT_RO_DATA(values))
|
||||
|
||||
typedef struct {
|
||||
/* 0x0 */ s16 val;
|
||||
/* 0x2 */ s16 param;
|
||||
} CameraModeValue; // size = 0x4
|
||||
|
||||
typedef struct {
|
||||
/* 0x0 */ s16 funcId;
|
||||
/* 0x2 */ s16 numValues;
|
||||
/* 0x4 */ CameraModeValue* values;
|
||||
} CameraMode; // size = 0x8
|
||||
|
||||
/**
|
||||
* Flags:
|
||||
* (flags & 0xF): Priority (lower value has higher priority)
|
||||
* (flags & 0x40000000): Store previous setting and bgCamData, also ignores water checks
|
||||
* (flags & 0x80000000): Set camera setting based on bg/scene data and reset action function state
|
||||
*/
|
||||
typedef struct {
|
||||
/* 0x0 */ u32 validModes;
|
||||
/* 0x4 */ u32 flags;
|
||||
/* 0x8 */ CameraMode* cameraModes;
|
||||
} CameraSetting; // size = 0xC
|
||||
|
||||
#endif // CAMERA_UTILS_H
|
||||
@@ -0,0 +1,243 @@
|
||||
#include "DebugCam.h"
|
||||
#include <libultraship/bridge.h>
|
||||
#include "Enhancements/GameInteractor/GameInteractor.h"
|
||||
#include "CameraUtils.h"
|
||||
|
||||
extern "C" {
|
||||
#include <macros.h>
|
||||
#include <functions.h>
|
||||
extern PlayState* gPlayState;
|
||||
extern PlayState* sCamPlayState;
|
||||
extern f32 Camera_ScaledStepToCeilF(f32 target, f32 cur, f32 stepScale, f32 minDiff);
|
||||
extern s16 Camera_ScaledStepToCeilS(s16 target, s16 cur, f32 stepScale, s16 minDiff);
|
||||
extern Vec3f Camera_CalcUpVec(s16 pitch, s16 yaw, s16 roll);
|
||||
}
|
||||
|
||||
#define CAMERA_DEBUG_DEFAULT_PORT 1
|
||||
|
||||
// Static Data Used For Free Camera
|
||||
static bool sDebugCamRefreshParams = true;
|
||||
|
||||
Vec3f Camera_RotatePointAroundAxis(Vec3f* point, Vec3f* axis, s16 angle) {
|
||||
f32 q0 = Math_CosS(angle / 2);
|
||||
f32 q1 = Math_SinS(angle / 2) * axis->x;
|
||||
f32 q2 = Math_SinS(angle / 2) * axis->y;
|
||||
f32 q3 = Math_SinS(angle / 2) * axis->z;
|
||||
Vec3f endPoint;
|
||||
|
||||
endPoint.x = (SQ(q0) + SQ(q1) - SQ(q2) - SQ(q3)) * point->x + 2 * (q1 * q2 - q0 * q3) * point->y + 2 * (q1 * q3 + q0 * q2) * point->z;
|
||||
endPoint.y = 2 * (q2 * q1 + q0 * q3) * point->x + (SQ(q0) - SQ(q1) + SQ(q2) - SQ(q3)) * point->y + 2 * (q2 * q3 - q0 * q1) * point->z;
|
||||
endPoint.z = 2 * (q3 * q1 - q0 * q2) * point->x + 2 * (q3 * q2 + q0 * q1) * point->y + (SQ(q0) - SQ(q1) - SQ(q2) + SQ(q3)) * point->z;
|
||||
|
||||
return endPoint;
|
||||
}
|
||||
|
||||
void Camera_SetRollFromUp(Camera* camera) {
|
||||
Vec3f* eyeNext = &camera->eyeNext;
|
||||
Vec3f* at = &camera->at;
|
||||
Vec3f* up = &camera->up;
|
||||
VecGeo diffGeo = OLib_Vec3fDiffToVecGeo(eyeNext, at);
|
||||
f32 pitch = diffGeo.pitch;
|
||||
f32 yaw = diffGeo.yaw;
|
||||
f32 sinP = Math_SinS(pitch);
|
||||
f32 cosP = Math_CosS(pitch);
|
||||
f32 sinY = Math_SinS(yaw);
|
||||
f32 cosY = Math_CosS(yaw);
|
||||
Vec3f preRollUp = { -sinP * sinY, cosP, -sinP * cosY };
|
||||
Vec3f normal;
|
||||
|
||||
f32 dot = DOTXYZ(preRollUp, (*up));
|
||||
Math_Vec3f_Diff(eyeNext, at, &normal);
|
||||
Math3D_Normalize(&normal);
|
||||
// Setup Matrix With Normal
|
||||
// ( preRollUp.x up->x normal.x)
|
||||
// ( preRollUp.y up->y normal.y)
|
||||
// ( preRollUp.z up->z normal.z)
|
||||
f32 det = preRollUp.x * up->y * normal.z + up->x * normal.y * preRollUp.z + normal.x * preRollUp.y * up->z
|
||||
- normal.x * up->y * preRollUp.z - normal.y * up->z * preRollUp.x - normal.z * up->x * preRollUp.y;
|
||||
|
||||
camera->roll = RAD_TO_BINANG(atan2(-det, -dot) - M_PI);
|
||||
}
|
||||
|
||||
void Camera_RotateGeographic(Camera* camera, f32 pitchDiff, f32 yawDiff) {
|
||||
Vec3f* eyeNext = &camera->eyeNext;
|
||||
Vec3f* eye = &camera->eye;
|
||||
Vec3f* at = &camera->at;
|
||||
Vec3f camOut = OLib_Vec3fDistNormalize(at, eye);
|
||||
VecGeo transGeo = OLib_Vec3fToVecGeo(&camOut);
|
||||
transGeo.pitch += pitchDiff;
|
||||
transGeo.pitch = OLib_ClampMaxDist(transGeo.pitch, DEG_TO_BINANG(89.0f));
|
||||
transGeo.yaw += yawDiff;
|
||||
transGeo.r = camera->dist;
|
||||
*eyeNext = OLib_AddVecGeoToVec3f(at, &transGeo);
|
||||
}
|
||||
|
||||
void Camera_Rotate6DOF(Camera* camera, f32 pitchDiff, f32 yawDiff) {
|
||||
Vec3f* eyeNext = &camera->eyeNext;
|
||||
Vec3f* eye = &camera->eye;
|
||||
Vec3f* at = &camera->at;
|
||||
Vec3f* up = &camera->up;
|
||||
|
||||
Vec3f camOut = OLib_Vec3fDistNormalize(at, eye);
|
||||
Math3D_Normalize(&camOut);
|
||||
Math3D_Normalize(up);
|
||||
Vec3f right;
|
||||
Math3D_Vec3f_Cross(up, &camOut, &right);
|
||||
Math3D_Normalize(&right);
|
||||
Vec3f force = {
|
||||
up->x * pitchDiff + right.x * yawDiff,
|
||||
up->y * pitchDiff + right.y * yawDiff,
|
||||
up->z * pitchDiff + right.z * yawDiff
|
||||
};
|
||||
f32 angle = Math3D_Vec3fMagnitude(&force);
|
||||
|
||||
Vec3f rotAxis;
|
||||
Math3D_Vec3f_Cross(&camOut, &force, &rotAxis);
|
||||
Math3D_Normalize(&rotAxis);
|
||||
|
||||
Vec3f transPos = Camera_RotatePointAroundAxis(&camOut, &rotAxis, angle);
|
||||
VecGeo transGeo = OLib_Vec3fToVecGeo(&transPos);
|
||||
transGeo.r = camera->dist;
|
||||
*eyeNext = OLib_AddVecGeoToVec3f(at, &transGeo);
|
||||
*up = Camera_RotatePointAroundAxis(up, &rotAxis, angle);
|
||||
|
||||
Camera_SetRollFromUp(camera);
|
||||
}
|
||||
|
||||
void Camera_DebugCam(Camera* camera) {
|
||||
Vec3f* eye = &camera->eye;
|
||||
Vec3f* at = &camera->at;
|
||||
Vec3f* eyeNext = &camera->eyeNext;
|
||||
VecGeo eyeAdjustment;
|
||||
VecGeo originalEyeGeo = OLib_Vec3fDiffToVecGeo(at, eye);
|
||||
f32 distTarget;
|
||||
|
||||
if (sDebugCamRefreshParams) {
|
||||
// Move camera focus to eye
|
||||
Vec3f unit = OLib_Vec3fDistNormalize(eye, at);
|
||||
Math_Vec3f_Sum(eye, &unit, at);
|
||||
sDebugCamRefreshParams = false;
|
||||
}
|
||||
|
||||
s32 controllerPort = CVarGetInteger("gEnhancements.Camera.DebugCam.Port", CAMERA_DEBUG_DEFAULT_PORT) - 1;
|
||||
if (controllerPort > 3 || controllerPort < 0) {
|
||||
controllerPort = CAMERA_DEBUG_DEFAULT_PORT - 1;
|
||||
CVarSetInteger("gEnhancements.Camera.DebugCam.Port", CAMERA_DEBUG_DEFAULT_PORT);
|
||||
}
|
||||
|
||||
/*
|
||||
Camera Speed
|
||||
*/
|
||||
|
||||
f32 camSpeed = CVarGetFloat("gEnhancements.Camera.DebugCam.CameraSpeed", 0.5f);
|
||||
if (CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_A | BTN_B | BTN_L)) {
|
||||
camSpeed *= 3.0f;
|
||||
}
|
||||
|
||||
/*
|
||||
Camera distance
|
||||
*/
|
||||
|
||||
// Transition speed set to be responsive
|
||||
f32 transitionSpeed = camSpeed * 200.0f;
|
||||
distTarget = camera->dist + (CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_DDOWN) - CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_DUP)) * 1200.0f * camSpeed;
|
||||
distTarget = CLAMP_MIN(distTarget, 0.1f);
|
||||
// Smooth step camera away to max camera distance.
|
||||
camera->dist = Camera_ScaledStepToCeilF(distTarget, camera->dist, transitionSpeed / (ABS(distTarget - camera->dist) + transitionSpeed), 0.0f);
|
||||
|
||||
/*
|
||||
Set Camera Pitch and Yaw
|
||||
*/
|
||||
f32 yawDiff = -sCamPlayState->state.input[controllerPort].cur.right_stick_x * 10.0f * (CVarGetFloat("gEnhancements.Camera.RightStick.CameraSensitivity.X", 1.0f));
|
||||
f32 pitchDiff = sCamPlayState->state.input[controllerPort].cur.right_stick_y * 10.0f * (CVarGetFloat("gEnhancements.Camera.RightStick.CameraSensitivity.Y", 1.0f));
|
||||
|
||||
yawDiff *= (CVarGetInteger("gEnhancements.Camera.RightStick.InvertXAxis", 0) ? -1 : 1);
|
||||
pitchDiff *= (CVarGetInteger("gEnhancements.Camera.RightStick.InvertYAxis", 1) ? 1 : -1);
|
||||
|
||||
// Setup new camera angle based on the calculations from right stick inputs
|
||||
if (CVarGetInteger("gEnhancements.Camera.DebugCam.6DOF", 0)) {
|
||||
Camera_Rotate6DOF(camera, pitchDiff, yawDiff);
|
||||
} else {
|
||||
Camera_RotateGeographic(camera, pitchDiff, yawDiff);
|
||||
}
|
||||
|
||||
/*
|
||||
Camera Roll
|
||||
*/
|
||||
if (CVarGetInteger("gEnhancements.Camera.DebugCam.6DOF", 0)) {
|
||||
camera->roll += (CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_DLEFT) - CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_DRIGHT)) * 1200.0f * camSpeed;
|
||||
} else {
|
||||
camera->roll = Camera_ScaledStepToCeilS(0, camera->roll, 0.1f, 5);
|
||||
}
|
||||
/*
|
||||
Camera Movement
|
||||
*/
|
||||
|
||||
// Movement differences from the point of view of the camera. Use max stick value for buttons scale
|
||||
Vec3f posDiff;
|
||||
posDiff.x = sCamPlayState->state.input[controllerPort].cur.stick_x * camSpeed;
|
||||
posDiff.y = (CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_Z) - CHECK_BTN_ANY(sCamPlayState->state.input[controllerPort].cur.button, BTN_R)) * 120.0f * camSpeed;
|
||||
posDiff.z = -sCamPlayState->state.input[controllerPort].cur.stick_y * camSpeed;
|
||||
|
||||
// Adjust movement to camera's current direction
|
||||
Vec3f camPosDiff = { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
VecGeo diffGeo = OLib_Vec3fDiffToVecGeo(eyeNext, at);
|
||||
Vec3f normX;
|
||||
Vec3f normY = camera->up = Camera_CalcUpVec(diffGeo.pitch, diffGeo.yaw, camera->roll);
|
||||
Vec3f normZ = OLib_Vec3fDistNormalize(at, eyeNext);
|
||||
|
||||
// Cross Product
|
||||
Math3D_Vec3f_Cross(&normY, &normZ, &normX);
|
||||
|
||||
Math_Vec3f_Scale(&normX, posDiff.x);
|
||||
Math_Vec3f_Scale(&normY, posDiff.y);
|
||||
Math_Vec3f_Scale(&normZ, posDiff.z);
|
||||
|
||||
Math_Vec3f_Sum(&camPosDiff, &normX, &camPosDiff);
|
||||
Math_Vec3f_Sum(&camPosDiff, &normY, &camPosDiff);
|
||||
Math_Vec3f_Sum(&camPosDiff, &normZ, &camPosDiff);
|
||||
|
||||
// "Move" camera eye around with controls
|
||||
Math_Vec3f_Sum(at, &camPosDiff, at);
|
||||
Math_Vec3f_Sum(eyeNext, &camPosDiff, eyeNext);
|
||||
|
||||
*eye = *eyeNext;
|
||||
}
|
||||
|
||||
static uint32_t freeCamVBHookId = 0;
|
||||
static uint32_t freeCamDisableInputsId = 0;
|
||||
|
||||
void RegisterDebugCam() {
|
||||
sDebugCamRefreshParams = true;
|
||||
|
||||
if (freeCamVBHookId) {
|
||||
GameInteractor::Instance->UnregisterGameHookForID<GameInteractor::ShouldVanillaBehavior>(freeCamVBHookId);
|
||||
freeCamVBHookId = 0;
|
||||
}
|
||||
|
||||
if (freeCamDisableInputsId) {
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnPassPlayerInputs>(freeCamDisableInputsId);
|
||||
freeCamDisableInputsId = 0;
|
||||
}
|
||||
|
||||
if (CVarGetInteger("gEnhancements.Camera.DebugCam.Enable", 0)) {
|
||||
freeCamVBHookId = REGISTER_VB_SHOULD(GI_VB_USE_CUSTOM_CAMERA, {
|
||||
Camera* camera = static_cast<Camera*>(opt);
|
||||
Camera_DebugCam(camera);
|
||||
*should = false;
|
||||
});
|
||||
|
||||
freeCamDisableInputsId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnPassPlayerInputs>([](Input* input) {
|
||||
s32 controllerPort = CVarGetInteger("gEnhancements.Camera.DebugCam.Port", CAMERA_DEBUG_DEFAULT_PORT) - 1;
|
||||
if (controllerPort > 3 || controllerPort < 0) {
|
||||
controllerPort = CAMERA_DEBUG_DEFAULT_PORT - 1;
|
||||
CVarSetInteger("gEnhancements.Camera.DebugCam.Port", CAMERA_DEBUG_DEFAULT_PORT);
|
||||
}
|
||||
if (controllerPort == 0) {
|
||||
// Disable Link Inputs
|
||||
memset(input, 0, sizeof(Input));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef FREE_CAM_H
|
||||
#define FREE_CAM_H
|
||||
|
||||
void RegisterDebugCam();
|
||||
|
||||
#endif // FREE_CAM_H
|
||||
@@ -0,0 +1,183 @@
|
||||
#include "FreeLook.h"
|
||||
#include <libultraship/bridge.h>
|
||||
#include "Enhancements/GameInteractor/GameInteractor.h"
|
||||
#include "CameraUtils.h"
|
||||
|
||||
extern "C" {
|
||||
#include <macros.h>
|
||||
#include <functions.h>
|
||||
extern PlayState* gPlayState;
|
||||
extern PlayState* sCamPlayState;
|
||||
extern f32 Camera_ScaledStepToCeilF(f32 target, f32 cur, f32 stepScale, f32 minDiff);
|
||||
extern s16 Camera_ScaledStepToCeilS(s16 target, s16 cur, f32 stepScale, s16 minDiff);
|
||||
extern s32 Camera_BgCheckInfo(Camera* camera, Vec3f* from, CameraCollision* to);
|
||||
extern void Camera_ResetActionFuncState(Camera* camera, s32 mode);
|
||||
extern void func_800CBFA4(Camera* camera, Vec3f* arg1, Vec3f* arg2, s32 arg3);
|
||||
extern CameraSetting sCameraSettings[];
|
||||
extern s32 sCameraInterfaceFlags;
|
||||
}
|
||||
|
||||
// Static Data Used For Free Camera
|
||||
static bool sCanFreeLook = false;
|
||||
|
||||
void UpdateFreeLookState(Camera* camera) {
|
||||
if (CAM_MODE_TARGET <= camera->mode && camera->mode <= CAM_MODE_BATTLE) {
|
||||
sCanFreeLook = false;
|
||||
}
|
||||
|
||||
if (CAM_MODE_FIRSTPERSON <= camera->mode && camera->mode <= CAM_MODE_CLIMBZ) {
|
||||
sCanFreeLook = false;
|
||||
}
|
||||
|
||||
if (camera->mode == CAM_MODE_HANGZ) {
|
||||
sCanFreeLook = false;
|
||||
}
|
||||
|
||||
if (CAM_MODE_BOOMERANG <= camera->mode && camera->mode <= CAM_MODE_ZORAFINZ) {
|
||||
sCanFreeLook = false;
|
||||
}
|
||||
|
||||
if (gPlayState != nullptr && Player_InCsMode(gPlayState)) {
|
||||
sCanFreeLook = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Function based on several camera functions, including Camera_Parallel1
|
||||
bool Camera_FreeLook(Camera* camera) {
|
||||
Vec3f* eye = &camera->eye;
|
||||
Vec3f* at = &camera->at;
|
||||
Vec3f* eyeNext = &camera->eyeNext;
|
||||
Player* player = GET_PLAYER(gPlayState);
|
||||
VecGeo eyeAdjustment = OLib_Vec3fDiffToVecGeo(at, eye);
|
||||
Parallel1ReadOnlyData* roData = &camera->paramData.para1.roData;
|
||||
f32 playerHeight;
|
||||
f32 pitch = eyeAdjustment.pitch;
|
||||
f32 yaw = eyeAdjustment.yaw;
|
||||
|
||||
// Smooth step camera 'at' towards player
|
||||
f32 playerYOffset = Player_GetHeight(player) / 1.2f;
|
||||
if (player->rideActor != NULL) {
|
||||
playerYOffset /= 2;
|
||||
}
|
||||
at->x = Camera_ScaledStepToCeilF(player->actor.world.pos.x, at->x, 0.5f, 1.0f);
|
||||
at->y = Camera_ScaledStepToCeilF(player->actor.world.pos.y + playerYOffset, at->y, 0.5f, 1.0f);
|
||||
at->z = Camera_ScaledStepToCeilF(player->actor.world.pos.z, at->z, 0.5f, 1.0f);
|
||||
|
||||
// Equivalent to 'Camera_GetFocalActorHeight'
|
||||
playerHeight = Player_GetHeight(player);
|
||||
|
||||
// Camera param reloading based on Camera_Parallel1, only updating roData as only that seems necessary
|
||||
if (RELOAD_PARAMS(camera)) {
|
||||
CameraModeValue* values = sCameraSettings[camera->setting].cameraModes[camera->mode].values;
|
||||
f32 yNormal = (0.8f - ((68.0f / playerHeight) * -0.2f));
|
||||
|
||||
roData->unk_00 = GET_NEXT_SCALED_RO_DATA(values) * playerHeight * yNormal;
|
||||
roData->unk_04 = GET_NEXT_SCALED_RO_DATA(values) * playerHeight * yNormal;
|
||||
roData->unk_08 = GET_NEXT_SCALED_RO_DATA(values) * playerHeight * yNormal;
|
||||
roData->unk_20 = CAM_DEG_TO_BINANG(GET_NEXT_RO_DATA(values));
|
||||
roData->unk_22 = CAM_DEG_TO_BINANG(GET_NEXT_RO_DATA(values));
|
||||
roData->unk_0C = GET_NEXT_RO_DATA(values);
|
||||
roData->unk_10 = GET_NEXT_RO_DATA(values);
|
||||
roData->unk_14 = GET_NEXT_RO_DATA(values);
|
||||
roData->unk_18 = GET_NEXT_SCALED_RO_DATA(values);
|
||||
roData->interfaceFlags = GET_NEXT_RO_DATA(values);
|
||||
roData->unk_1C = GET_NEXT_SCALED_RO_DATA(values);
|
||||
roData->unk_24 = GET_NEXT_RO_DATA(values);
|
||||
}
|
||||
|
||||
// 1 acts as a default value of sorts for sCameraInterfaceFlags
|
||||
sCameraInterfaceFlags = 1;
|
||||
|
||||
Camera_ResetActionFuncState(camera, camera->mode);
|
||||
|
||||
f32 yawDiff = -sCamPlayState->state.input[0].cur.right_stick_x * 10.0f * (CVarGetFloat("gEnhancements.Camera.RightStick.CameraSensitivity.X", 1.0f));
|
||||
f32 pitchDiff = sCamPlayState->state.input[0].cur.right_stick_y * 10.0f * (CVarGetFloat("gEnhancements.Camera.RightStick.CameraSensitivity.Y", 1.0f));
|
||||
|
||||
yaw += yawDiff * (CVarGetInteger("gEnhancements.Camera.RightStick.InvertXAxis", 0) ? -1 : 1);
|
||||
pitch += pitchDiff * (CVarGetInteger("gEnhancements.Camera.RightStick.InvertYAxis", 1) ? 1 : -1);
|
||||
|
||||
s16 maxPitch = DEG_TO_BINANG(CVarGetFloat("gEnhancements.Camera.FreeLook.MaxPitch", 72.0f));
|
||||
s16 minPitch = DEG_TO_BINANG(CVarGetFloat("gEnhancements.Camera.FreeLook.MinPitch", -49.0f));
|
||||
|
||||
if (pitch > maxPitch) {
|
||||
pitch = maxPitch;
|
||||
}
|
||||
if (pitch < minPitch) {
|
||||
pitch = minPitch;
|
||||
}
|
||||
|
||||
f32 distTarget = CVarGetInteger("gEnhancements.Camera.FreeLook.MaxCameraDistance", roData->unk_04);
|
||||
f32 transitionSpeed = CVarGetInteger("gEnhancements.Camera.FreeLook.TransitionSpeed", 25);
|
||||
// Smooth step camera away to max camera distance. Camera collision is calculated later
|
||||
camera->dist = Camera_ScaledStepToCeilF(distTarget, camera->dist, transitionSpeed / (ABS(distTarget - camera->dist) + transitionSpeed), 0.0f);
|
||||
|
||||
// Setup new camera angle based on the calculations from stick inputs
|
||||
eyeAdjustment.r = camera->dist;
|
||||
eyeAdjustment.yaw = yaw;
|
||||
eyeAdjustment.pitch = pitch;
|
||||
|
||||
*eyeNext = OLib_AddVecGeoToVec3f(at, &eyeAdjustment);
|
||||
// Apply new camera angle only when camera active
|
||||
if (camera->status == CAM_STATUS_ACTIVE) {
|
||||
*eye = *eyeNext;
|
||||
// Adjust camera for collision with floors, walls and ceilings.
|
||||
func_800CBFA4(camera, at, eye, 0);
|
||||
}
|
||||
|
||||
// 65.0f based on value from SoH
|
||||
f32 fovTarget = 65.0f;
|
||||
camera->fov = Camera_ScaledStepToCeilF(fovTarget, camera->fov, camera->fovUpdateRate, 0.1f);
|
||||
camera->roll = Camera_ScaledStepToCeilS(0, camera->roll, 0.5f, 5);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Camera_CanFreeLook(Camera* camera) {
|
||||
f32 camX = sCamPlayState->state.input[0].cur.right_stick_x * 10.0f;
|
||||
f32 camY = sCamPlayState->state.input[0].cur.right_stick_y * 10.0f;
|
||||
if (!sCanFreeLook && (fabsf(camX) >= 15.0f || fabsf(camY) >= 15.0f)) {
|
||||
sCanFreeLook = true;
|
||||
}
|
||||
return sCanFreeLook;
|
||||
}
|
||||
|
||||
static uint32_t freeLookCameraSettingChangeHookId = 0;
|
||||
static uint32_t freeLookCameraVBHookId = 0;
|
||||
|
||||
void RegisterCameraFreeLook() {
|
||||
if (freeLookCameraVBHookId) {
|
||||
GameInteractor::Instance->UnregisterGameHookForID<GameInteractor::ShouldVanillaBehavior>(freeLookCameraVBHookId);
|
||||
freeLookCameraVBHookId = 0;
|
||||
}
|
||||
|
||||
if (freeLookCameraSettingChangeHookId) {
|
||||
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnCameraChangeModeFlags>(freeLookCameraSettingChangeHookId);
|
||||
freeLookCameraSettingChangeHookId = 0;
|
||||
}
|
||||
|
||||
if (CVarGetInteger("gEnhancements.Camera.FreeLook.Enable", 0)) {
|
||||
freeLookCameraVBHookId = REGISTER_VB_SHOULD(GI_VB_USE_CUSTOM_CAMERA, {
|
||||
Camera* camera = static_cast<Camera*>(opt);
|
||||
switch (sCameraSettings[camera->setting].cameraModes[camera->mode].funcId) {
|
||||
case CAM_FUNC_NORMAL0:
|
||||
case CAM_FUNC_NORMAL1:
|
||||
case CAM_FUNC_NORMAL3:
|
||||
case CAM_FUNC_NORMAL4:
|
||||
case CAM_FUNC_JUMP2:
|
||||
case CAM_FUNC_JUMP3:
|
||||
case CAM_FUNC_BATTLE1:
|
||||
case CAM_FUNC_UNIQUE2:
|
||||
if (Camera_CanFreeLook(camera)) {
|
||||
Camera_FreeLook(camera);
|
||||
*should = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
freeLookCameraSettingChangeHookId = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnCameraChangeModeFlags>([](Camera* camera) {
|
||||
UpdateFreeLookState(camera);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef FREE_LOOK_H
|
||||
#define FREE_LOOK_H
|
||||
|
||||
void RegisterCameraFreeLook();
|
||||
|
||||
#endif // FREE_LOOK_H
|
||||
@@ -1,6 +1,10 @@
|
||||
#include "Enhancements.h"
|
||||
|
||||
void InitEnhancements() {
|
||||
// Camera
|
||||
RegisterCameraFreeLook();
|
||||
RegisterDebugCam();
|
||||
|
||||
// Cheats
|
||||
RegisterInfiniteCheats();
|
||||
RegisterMoonJumpOnL();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef ENHANCEMENTS_H
|
||||
#define ENHANCEMENTS_H
|
||||
|
||||
#include "Camera/DebugCam.h"
|
||||
#include "Camera/FreeLook.h"
|
||||
#include "Cheats/MoonJump.h"
|
||||
#include "Cheats/Infinite.h"
|
||||
#include "Cheats/UnbreakableRazorSword.h"
|
||||
|
||||
@@ -117,6 +117,18 @@ void GameInteractor_ExecuteOnFlagUnset(FlagType flagType, u32 flag) {
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnFlagUnset>(flagType, flag);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnCameraChangeModeFlags(Camera* camera) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnCameraChangeModeFlags>(camera);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnCameraChangeModeFlags>(camera->uid, camera);
|
||||
GameInteractor::Instance->ExecuteHooksForPtr<GameInteractor::OnCameraChangeModeFlags>((uintptr_t)camera, camera);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnCameraChangeModeFlags>(camera);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnPassPlayerInputs(Input* input) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnPassPlayerInputs>(input);
|
||||
GameInteractor::Instance->ExecuteHooksForFilter<GameInteractor::OnPassPlayerInputs>(input);
|
||||
}
|
||||
|
||||
void GameInteractor_ExecuteOnOpenText(u16 textId) {
|
||||
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnOpenText>(textId);
|
||||
GameInteractor::Instance->ExecuteHooksForID<GameInteractor::OnOpenText>(textId, textId);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
#include "z64actor.h"
|
||||
#include "z64camera.h"
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -39,6 +40,7 @@ typedef enum {
|
||||
GI_VB_PATCH_SIDEROLL,
|
||||
GI_VB_PREVENT_MASK_TRANSFORMATION_CS,
|
||||
GI_VB_SONG_AVAILABLE_TO_PLAY,
|
||||
GI_VB_USE_CUSTOM_CAMERA,
|
||||
} GIVanillaBehavior;
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -236,6 +238,10 @@ public:
|
||||
DEFINE_HOOK(OnFlagSet, (FlagType flagType, u32 flag));
|
||||
DEFINE_HOOK(OnFlagUnset, (FlagType flagType, u32 flag));
|
||||
|
||||
DEFINE_HOOK(OnCameraChangeModeFlags, (Camera* camera));
|
||||
|
||||
DEFINE_HOOK(OnPassPlayerInputs, (Input* input));
|
||||
|
||||
DEFINE_HOOK(OnOpenText, (u16 textId));
|
||||
|
||||
DEFINE_HOOK(ShouldItemGive, (u8 item, bool* should));
|
||||
@@ -270,6 +276,10 @@ void GameInteractor_ExecuteOnSceneFlagUnset(s16 sceneId, FlagType flagType, u32
|
||||
void GameInteractor_ExecuteOnFlagSet(FlagType flagType, u32 flag);
|
||||
void GameInteractor_ExecuteOnFlagUnset(FlagType flagType, u32 flag);
|
||||
|
||||
void GameInteractor_ExecuteOnCameraChangeModeFlags(Camera* camera);
|
||||
|
||||
void GameInteractor_ExecuteOnPassPlayerInputs(Input* input);
|
||||
|
||||
void GameInteractor_ExecuteOnOpenText(u16 textId);
|
||||
|
||||
bool GameInteractor_ShouldItemGive(u8 item);
|
||||
|
||||
+3
-3
@@ -54,13 +54,13 @@ void guNormalize(float* x, float* y, float* z);
|
||||
|
||||
#endif // 0
|
||||
|
||||
f32 sinf(f32 __x);
|
||||
f32 cosf(f32 __x);
|
||||
// f32 sinf(f32 __x);
|
||||
// f32 cosf(f32 __x);
|
||||
|
||||
s16 sins(u16 x);
|
||||
s16 coss(u16 x);
|
||||
|
||||
f32 sqrtf(f32 f);
|
||||
// f32 sqrtf(f32 f);
|
||||
#ifdef __sgi
|
||||
#pragma intrinsic(sqrtf);
|
||||
#endif
|
||||
|
||||
@@ -63,6 +63,8 @@ Vec3f D_801EDDD0;
|
||||
Vec3f D_801EDDE0;
|
||||
Vec3f D_801EDDF0;
|
||||
#include "2s2h/Enhancements/FrameInterpolation/FrameInterpolation.h"
|
||||
#include "2s2h/Enhancements/GameInteractor/GameInteractor.h"
|
||||
#include "2s2h/Enhancements/Camera/FreeLook.h"
|
||||
|
||||
// Camera will reload its paramData. Usually that means setting the read-only data from what is stored in
|
||||
// CameraModeValue arrays. Although sometimes some read-write data is reset as well
|
||||
@@ -7552,7 +7554,9 @@ Vec3s Camera_Update(Camera* camera) {
|
||||
}
|
||||
|
||||
// Call the camera update function
|
||||
sCameraUpdateHandlers[sCameraSettings[camera->setting].cameraModes[camera->mode].funcId](camera);
|
||||
if (GameInteractor_Should(GI_VB_USE_CUSTOM_CAMERA, true, camera)) {
|
||||
sCameraUpdateHandlers[sCameraSettings[camera->setting].cameraModes[camera->mode].funcId](camera);
|
||||
}
|
||||
|
||||
// Update the interface
|
||||
if (sCameraInitSceneTimer != 0) {
|
||||
@@ -7806,6 +7810,7 @@ s32 Camera_ChangeModeFlags(Camera* camera, s16 mode, u8 forceChange) {
|
||||
|
||||
func_800DF498(camera);
|
||||
camera->mode = mode;
|
||||
GameInteractor_ExecuteOnCameraChangeModeFlags(camera);
|
||||
|
||||
return mode | 0x80000000;
|
||||
}
|
||||
|
||||
@@ -12616,6 +12616,8 @@ void Player_Update(Actor* thisx, PlayState* play) {
|
||||
}
|
||||
}
|
||||
|
||||
GameInteractor_ExecuteOnPassPlayerInputs(&input);
|
||||
|
||||
Player_UpdateCommon(this, play, &input);
|
||||
skipUpdate:
|
||||
play->actorCtx.unk268 = 0;
|
||||
|
||||
Reference in New Issue
Block a user