diff options
author | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
---|---|---|
committer | WlodekM <[email protected]> | 2024-06-16 10:35:45 +0300 |
commit | abef6da56913f1c55528103e60a50451a39628b1 (patch) | |
tree | b3c8092471ecbb73e568cd0d336efa0e7871ee8d /src/Camera.c |
initial commit
Diffstat (limited to 'src/Camera.c')
-rw-r--r-- | src/Camera.c | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/src/Camera.c b/src/Camera.c new file mode 100644 index 0000000..4956d0e --- /dev/null +++ b/src/Camera.c @@ -0,0 +1,355 @@ +#include "Camera.h" +#include "ExtMath.h" +#include "Game.h" +#include "Window.h" +#include "Graphics.h" +#include "Funcs.h" +#include "Gui.h" +#include "Entity.h" +#include "Input.h" +#include "Event.h" +#include "Options.h" +#include "Picking.h" +#include "Platform.h" + +struct _CameraData Camera; +static struct RayTracer cameraClipPos; +static Vec2 cam_rotOffset; +static cc_bool cam_isForwardThird; +static float cam_deltaX, cam_deltaY; + +static void Camera_OnRawMovement(float deltaX, float deltaY) { + cam_deltaX += deltaX; cam_deltaY += deltaY; +} + +void Camera_KeyLookUpdate(float delta) { + if (Gui.InputGrab) return; + /* divide by 25 to have reasonable sensitivity for default mouse sens */ + float amount = (Camera.Sensitivity / 25.0f) * (1000 * delta); + + if (InputBind_IsPressed(BIND_LOOK_UP)) cam_deltaY -= amount; + if (InputBind_IsPressed(BIND_LOOK_DOWN)) cam_deltaY += amount; + if (InputBind_IsPressed(BIND_LOOK_LEFT)) cam_deltaX -= amount; + if (InputBind_IsPressed(BIND_LOOK_RIGHT)) cam_deltaX += amount; +} + +/*########################################################################################################################* +*--------------------------------------------------Perspective camera-----------------------------------------------------* +*#########################################################################################################################*/ +static void PerspectiveCamera_GetProjection(struct Matrix* proj) { + float fovy = Camera.Fov * MATH_DEG2RAD; + float aspectRatio = (float)Game.Width / (float)Game.Height; + Gfx_CalcPerspectiveMatrix(proj, fovy, aspectRatio, (float)Game_ViewDistance); +} + +static void PerspectiveCamera_GetView(struct Matrix* mat) { + Vec3 pos = Camera.CurrentPos; + Vec2 rot = Camera.Active->GetOrientation(); + Matrix_LookRot(mat, pos, rot); + Matrix_MulBy(mat, &Camera.TiltM); +} + +static void PerspectiveCamera_GetPickedBlock(struct RayTracer* t) { + struct LocalPlayer* p = Entities.CurPlayer; + struct Entity* e = &p->Base; + + Vec3 dir = Vec3_GetDirVector(e->Yaw * MATH_DEG2RAD, e->Pitch * MATH_DEG2RAD + Camera.TiltPitch); + Vec3 eyePos = Entity_GetEyePosition(e); + Picking_CalcPickedBlock(&eyePos, &dir, p->ReachDistance, t); +} + +#define CAMERA_SENSI_FACTOR (0.0002f / 3.0f * MATH_RAD2DEG) + +static Vec2 PerspectiveCamera_GetMouseDelta(float delta) { + float sensitivity = CAMERA_SENSI_FACTOR * Camera.Sensitivity; + static float speedX, speedY, newSpeedX, newSpeedY, accelX, accelY; + Vec2 v; + + if (Camera.Smooth) { + accelX = (cam_deltaX - speedX) * 35 / Camera.Mass; + accelY = (cam_deltaY - speedY) * 35 / Camera.Mass; + newSpeedX = accelX * delta + speedX; + newSpeedY = accelY * delta + speedY; + + /* High acceleration means velocity overshoots the correct position on low FPS, */ + /* causing wiggling. If newSpeed has opposite sign of speed, set speed to 0 */ + if (newSpeedX * speedX < 0) speedX = 0; + else speedX = newSpeedX; + if (newSpeedY * speedY < 0) speedY = 0; + else speedY = newSpeedY; + } else { + speedX = cam_deltaX; + speedY = cam_deltaY; + } + + v.x = speedX * sensitivity; v.y = speedY * sensitivity; + if (Camera.Invert) v.y = -v.y; + return v; +} + +static void PerspectiveCamera_UpdateMouseRotation(struct LocalPlayer* p, float delta) { + struct Entity* e = &p->Base; + struct LocationUpdate update; + Vec2 rot = PerspectiveCamera_GetMouseDelta(delta); + + if (Input_IsAltPressed() && Camera.Active->isThirdPerson) { + cam_rotOffset.x += rot.x; cam_rotOffset.y += rot.y; + return; + } + + update.flags = LU_HAS_YAW | LU_HAS_PITCH; + update.yaw = e->next.yaw + rot.x; + update.pitch = e->next.pitch + rot.y; + update.pitch = Math_ClampAngle(update.pitch); + + /* Need to make sure we don't cross the vertical axes, because that gets weird. */ + if (update.pitch >= 90.0f && update.pitch <= 270.0f) { + update.pitch = e->next.pitch < 180.0f ? 90.0f : 270.0f; + } + e->VTABLE->SetLocation(e, &update); +} + +static void PerspectiveCamera_UpdateMouse(struct LocalPlayer* p, float delta) { + if (!Gui.InputGrab && Window_Main.Focused) Window_UpdateRawMouse(); + + PerspectiveCamera_UpdateMouseRotation(p, delta); + cam_deltaX = 0; cam_deltaY = 0; +} + +static void PerspectiveCamera_CalcViewBobbing(struct LocalPlayer* p, float t, float velTiltScale) { + struct Entity* e = &p->Base; + + struct Matrix tiltY, velX; + float vel, fall; + if (!Game_ViewBobbing) { + Camera.TiltM = Matrix_Identity; + Camera.TiltPitch = 0.0f; + return; + } + + Matrix_RotateZ(&Camera.TiltM, -p->Tilt.TiltX * e->Anim.BobStrength); + Matrix_RotateX(&tiltY, Math_AbsF(p->Tilt.TiltY) * 3.0f * e->Anim.BobStrength); + Matrix_MulBy(&Camera.TiltM, &tiltY); + + Camera.BobbingHor = (e->Anim.BobbingHor * 0.3f) * e->Anim.BobStrength; + Camera.BobbingVer = (e->Anim.BobbingVer * 0.6f) * e->Anim.BobStrength; + + /* When standing on the ground, velocity.y is -0.08 (-gravity) */ + /* So add 0.08 to counteract that, so that vel is 0 when standing on ground */ + vel = 0.08f + Math_Lerp(p->OldVelocity.y, e->Velocity.y, t); + fall = -vel * 0.05f * p->Tilt.VelTiltStrength / velTiltScale; + + Matrix_RotateX(&velX, fall); + Matrix_MulBy(&Camera.TiltM, &velX); + if (!Game_ClassicMode) Camera.TiltPitch = fall; +} + + +/*########################################################################################################################* +*---------------------------------------------------First person camera---------------------------------------------------* +*#########################################################################################################################*/ +static Vec2 FirstPersonCamera_GetOrientation(void) { + struct LocalPlayer* p = Entities.CurPlayer; + struct Entity* e = &p->Base; + + Vec2 v; + v.x = e->Yaw * MATH_DEG2RAD; + v.y = e->Pitch * MATH_DEG2RAD; + return v; +} + +static Vec3 FirstPersonCamera_GetPosition(float t) { + struct LocalPlayer* p = Entities.CurPlayer; + struct Entity* e = &p->Base; + + Vec3 camPos = Entity_GetEyePosition(e); + float yaw = e->Yaw * MATH_DEG2RAD; + PerspectiveCamera_CalcViewBobbing(p, t, 1); + + camPos.y += Camera.BobbingVer; + camPos.x += Camera.BobbingHor * Math_CosF(yaw); + camPos.z += Camera.BobbingHor * Math_SinF(yaw); + return camPos; +} + +static cc_bool FirstPersonCamera_Zoom(float amount) { return false; } +static struct Camera cam_FirstPerson = { + false, + PerspectiveCamera_GetProjection, PerspectiveCamera_GetView, + FirstPersonCamera_GetOrientation, FirstPersonCamera_GetPosition, + PerspectiveCamera_UpdateMouse, Camera_OnRawMovement, + Window_EnableRawMouse, Window_DisableRawMouse, + PerspectiveCamera_GetPickedBlock, FirstPersonCamera_Zoom, +}; + + +/*########################################################################################################################* +*---------------------------------------------------Third person camera---------------------------------------------------* +*#########################################################################################################################*/ +#define DEF_ZOOM 3.0f +static float dist_third = DEF_ZOOM, dist_forward = DEF_ZOOM; + +static Vec2 ThirdPersonCamera_GetOrientation(void) { + struct LocalPlayer* p = Entities.CurPlayer; + struct Entity* e = &p->Base; + + Vec2 v; + v.x = e->Yaw * MATH_DEG2RAD; + v.y = e->Pitch * MATH_DEG2RAD; + if (cam_isForwardThird) { v.x += MATH_PI; v.y = -v.y; } + + v.x += cam_rotOffset.x * MATH_DEG2RAD; + v.y += cam_rotOffset.y * MATH_DEG2RAD; + return v; +} + +static float ThirdPersonCamera_GetZoom(struct LocalPlayer* p) { + float dist = cam_isForwardThird ? dist_forward : dist_third; + /* Don't allow zooming out when -fly */ + if (dist > DEF_ZOOM && !LocalPlayer_CheckCanZoom(p)) dist = DEF_ZOOM; + return dist; +} + +static Vec3 ThirdPersonCamera_GetPosition(float t) { + struct LocalPlayer* p = Entities.CurPlayer; + struct Entity* e = &p->Base; + + float dist = ThirdPersonCamera_GetZoom(p); + Vec3 target, dir; + Vec2 rot; + + PerspectiveCamera_CalcViewBobbing(p, t, dist); + target = Entity_GetEyePosition(e); + target.y += Camera.BobbingVer; + + rot = Camera.Active->GetOrientation(); + dir = Vec3_GetDirVector(rot.x, rot.y); + Vec3_Negate(&dir, &dir); + + Picking_ClipCameraPos(&target, &dir, dist, &cameraClipPos); + return cameraClipPos.intersect; +} + +static cc_bool ThirdPersonCamera_Zoom(float amount) { + float* dist = cam_isForwardThird ? &dist_forward : &dist_third; + float newDist = *dist - amount; + + *dist = max(newDist, 2.0f); + return true; +} + +static struct Camera cam_ThirdPerson = { + true, + PerspectiveCamera_GetProjection, PerspectiveCamera_GetView, + ThirdPersonCamera_GetOrientation, ThirdPersonCamera_GetPosition, + PerspectiveCamera_UpdateMouse, Camera_OnRawMovement, + Window_EnableRawMouse, Window_DisableRawMouse, + PerspectiveCamera_GetPickedBlock, ThirdPersonCamera_Zoom, +}; +static struct Camera cam_ForwardThird = { + true, + PerspectiveCamera_GetProjection, PerspectiveCamera_GetView, + ThirdPersonCamera_GetOrientation, ThirdPersonCamera_GetPosition, + PerspectiveCamera_UpdateMouse, Camera_OnRawMovement, + Window_EnableRawMouse, Window_DisableRawMouse, + PerspectiveCamera_GetPickedBlock, ThirdPersonCamera_Zoom, +}; + + +/*########################################################################################################################* +*-----------------------------------------------------General camera------------------------------------------------------* +*#########################################################################################################################*/ +static void OnRawMovement(void* obj, float deltaX, float deltaY) { + Camera.Active->OnRawMovement(deltaX, deltaY); +} + +static void OnAxisUpdate(void* obj, int port, int axis, float x, float y) { + if (!Input.RawMode) return; + if (Gamepad_AxisBehaviour[axis] != AXIS_BEHAVIOUR_CAMERA) return; + + Camera.Active->OnRawMovement(x, y); +} + +static void OnHacksChanged(void* obj) { + struct HacksComp* h = &Entities.CurPlayer->Hacks; + /* Leave third person if not allowed anymore */ + if (!h->CanUseThirdPerson || !h->Enabled) Camera_CycleActive(); +} + +void Camera_CycleActive(void) { + struct LocalPlayer* p = &LocalPlayer_Instances[0]; + if (Game_ClassicMode) return; + Camera.Active = Camera.Active->next; + + if (!p->Hacks.CanUseThirdPerson || !p->Hacks.Enabled) { + Camera.Active = &cam_FirstPerson; + } + cam_isForwardThird = Camera.Active == &cam_ForwardThird; + + /* reset rotation offset when changing cameras */ + cam_rotOffset.x = 0.0f; cam_rotOffset.y = 0.0f; + Camera_UpdateProjection(); +} + +static struct Camera* cams_head; +static struct Camera* cams_tail; +void Camera_Register(struct Camera* cam) { + LinkedList_Append(cam, cams_head, cams_tail); + /* want a circular linked list */ + cam->next = cams_head; +} + +static cc_bool cam_focussed; +void Camera_CheckFocus(void) { + cc_bool focus = Gui.InputGrab == NULL; + if (focus == cam_focussed) return; + cam_focussed = focus; + + if (focus) { + Camera.Active->AcquireFocus(); + } else { + Camera.Active->LoseFocus(); + } +} + +void Camera_SetFov(int fov) { + if (Camera.Fov == fov) return; + Camera.Fov = fov; + Camera_UpdateProjection(); +} + +void Camera_UpdateProjection(void) { + Camera.Active->GetProjection(&Gfx.Projection); + Gfx_LoadMatrix(MATRIX_PROJECTION, &Gfx.Projection); + Event_RaiseVoid(&GfxEvents.ProjectionChanged); +} + +static void OnInit(void) { + Camera_Register(&cam_FirstPerson); + Camera_Register(&cam_ThirdPerson); + Camera_Register(&cam_ForwardThird); + + Camera.Active = &cam_FirstPerson; + Event_Register_(&PointerEvents.RawMoved, NULL, OnRawMovement); + Event_Register_(&ControllerEvents.AxisUpdate, NULL, OnAxisUpdate); + Event_Register_(&UserEvents.HackPermsChanged, NULL, OnHacksChanged); + +#ifdef CC_BUILD_WIN + Camera.Sensitivity = Options_GetInt(OPT_SENSITIVITY, 1, 200, 40); +#else + Camera.Sensitivity = Options_GetInt(OPT_SENSITIVITY, 1, 200, 30); +#endif + Camera.Clipping = Options_GetBool(OPT_CAMERA_CLIPPING, true); + Camera.Invert = Options_GetBool(OPT_INVERT_MOUSE, false); + Camera.Mass = Options_GetFloat(OPT_CAMERA_MASS, 1, 100, 20); + Camera.Smooth = Options_GetBool(OPT_CAMERA_SMOOTH, false); + + Camera.DefaultFov = Options_GetInt(OPT_FIELD_OF_VIEW, 1, 179, 70); + Camera.Fov = Camera.DefaultFov; + Camera.ZoomFov = Camera.DefaultFov; + Camera_UpdateProjection(); +} + +struct IGameComponent Camera_Component = { + OnInit /* Init */ +}; |