mirror of
https://github.com/izzy2lost/2ship2harkinian-Android.git
synced 2026-06-19 01:20:08 -07:00
201 lines
7.9 KiB
C++
201 lines
7.9 KiB
C++
#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) {
|
|
switch (camera->mode) {
|
|
case CAM_MODE_BOWARROWZ:
|
|
case CAM_MODE_FIRSTPERSON:
|
|
case CAM_MODE_FOLLOWBOOMERANG:
|
|
case CAM_MODE_ZORAFIN:
|
|
case CAM_MODE_FOLLOWTARGET:
|
|
case CAM_MODE_TARGET:
|
|
case CAM_MODE_TALK:
|
|
case CAM_MODE_SLINGSHOT:
|
|
case CAM_MODE_BOWARROW:
|
|
case CAM_MODE_BATTLE:
|
|
case CAM_MODE_DEKUHIDE:
|
|
case CAM_MODE_CLIMBZ:
|
|
case CAM_MODE_HOOKSHOT:
|
|
case CAM_MODE_HANGZ:
|
|
case CAM_MODE_DEKUFLYZ:
|
|
case CAM_MODE_BOOMERANG:
|
|
case CAM_MODE_CHARGEZ:
|
|
case CAM_MODE_ZORAFINZ:
|
|
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 * GameInteractor_InvertControl(GI_INVERT_CAMERA_RIGHT_STICK_X);
|
|
pitch += pitchDiff * -GameInteractor_InvertControl(GI_INVERT_CAMERA_RIGHT_STICK_Y);
|
|
|
|
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;
|
|
}
|
|
// Pressing Z will "Reset" Camera
|
|
if (CHECK_BTN_ALL(sCamPlayState->state.input[0].press.button, BTN_Z)) {
|
|
sCanFreeLook = false;
|
|
}
|
|
// Reset camera during cutscenes
|
|
if (gPlayState != nullptr && Player_InCsMode(gPlayState)) {
|
|
sCanFreeLook = false;
|
|
}
|
|
|
|
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:
|
|
case CAM_FUNC_UNIQUE3:
|
|
if (Camera_CanFreeLook(camera)) {
|
|
Camera_FreeLook(camera);
|
|
*should = false;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
});
|
|
freeLookCameraSettingChangeHookId =
|
|
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnCameraChangeModeFlags>(
|
|
[](Camera* camera) { UpdateFreeLookState(camera); });
|
|
}
|
|
}
|