#ifndef CAMERA_CLASS_H #define CAMERA_CLASS_H #include #include #include #include #include #include #include #include #include #include "common.h" #include "Window.h" #include "t.h" #include "tFunctions.h" #include "shaderClass.h" const glm::vec3 worldUp = { 0.0f, 1.0f, 0.0f }; // Default mouse sensitivity in cm of mouse travel per 360 degree turn. inline float StartupCmPer360 = 16.0f; inline float StartupMouseDpi = 800.0f; class Camera { public: bool lockedcursor = true; t t; float yaw = 0.0f; float pitch = 0.0f; const float originalspeed = 0.08f; float speed = 0.08f; float sensitivity = 0.001f; float FOV = 110.0f; float screenshake = 0.0f; // 0 still to 1 shaking as hard as it does, wearing off over time float shakeDecay = 1.2f; // of full strength lost a second of game time glm::vec3 shakeMaxAngles = glm::vec3(0.08f, 0.08f, 0.04f); // radians of pitch, yaw and roll at full strength Camera() { if (StartupCmPer360 > 0.0f) SetSensitivityCm(StartupCmPer360, StartupMouseDpi); } // Turn sensitivity into "this many cm of mouse travel per full 360 degree turn" for a mouse // of the given DPI (mouse counts per inch). void SetSensitivityCm(float cmPer360, float dpi) { sensitivity = 6.2831853f / (cmPer360 / 2.54f * dpi); } // Shakes the camera, amount of full strength on top of whatever shake there already is. Around 0.3 for a hit, // 1 for something huge. void AddScreenshake(float amount) { screenshake = std::min(screenshake + amount, 1.0f); } void Matrix(float nearPlane, float farPlane, Shader& shader) { shader.SetMat4("proj", GetProjectionMatrix(nearPlane, farPlane)); shader.SetMat4("view", GetViewMatrix()); shader.Set3F("viewPos", t.GetTranslation()); } glm::mat4 GetViewMatrix() { glm::vec3 front = t.GetFrontVector(); glm::vec3 up = t.GetUpVector(); if (screenshake > 0.0f) { // Apply smooth shake offset stored in shakeOffset glm::quat offsetRot = glm::quat(glm::vec3( shakeOffset.x, shakeOffset.y, shakeOffset.z // roll )); front = glm::normalize(offsetRot * front); up = glm::normalize(offsetRot * up); } return glm::lookAt(t.GetTranslation(), t.GetTranslation() + front, up); } glm::mat4 GetProjectionMatrix(float nearPlane, float farPlane) { // Quake Pro style: FOV is the horizontal angle on a 4:3 screen, so the vertical angle is fixed // and wider windows/fullscreen reveal more to the sides instead of zooming in. const float aspect = (float)window->width / (float)window->height; const float vfov = 2.0f * atan(tan(glm::radians(FOV) * 0.5f) * 3.0f / 4.0f); return glm::perspective(vfov, aspect, nearPlane, farPlane); } void Step(float dt) { if (screenshake <= 0.0f) { shakeOffset = glm::vec3(0.0f); return; } // A smooth wobble on each axis, out of step with each other, scaled by how strong the shake still is shakeTime += dt; auto Wobble = [&](float seed) { return (std::sin(shakeTime * 31.0f + seed) + std::sin(shakeTime * 57.3f + seed * 2.7f)) * 0.5f; }; shakeOffset = shakeMaxAngles * screenshake * glm::vec3(Wobble(0.0f), Wobble(11.0f), Wobble(23.0f)); screenshake = std::max(screenshake - shakeDecay * dt, 0.0f); } // Back to looking where the mouse last had it, after something else has turned the camera void RestoreLook() { t.RotateToEulerAngles({ pitch, yaw, 0.0f }); t.NormalizeRotation(); } void ProcessMouseMovement(float xoffset, float yoffset) { xoffset *= sensitivity; yoffset *= sensitivity; yaw += xoffset; pitch += yoffset; pitch = glm::clamp(pitch, -glm::radians(85.0f), glm::radians(85.0f)); t.RotateToEulerAngles({ pitch, yaw, 0.0f }); t.NormalizeRotation(); } private: glm::vec3 shakeOffset = glm::vec3(0.0f); // this frame's turn from shaking, pitch, yaw and roll float shakeTime = 0.0f; // runs the wobble along }; #endif