-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
'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
- Loading branch information
1 parent
0c94bda
commit 1004fdc
Showing
13 changed files
with
566 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)); | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#ifndef FREE_CAM_H | ||
#define FREE_CAM_H | ||
|
||
void RegisterDebugCam(); | ||
|
||
#endif // FREE_CAM_H |
Oops, something went wrong.