#pragma once #include #include #include "Entity.h" #include class Camera : public Entity { private: GLFWwindow* _window; InputSystem* _inputSystem; glm::mat4 _projection; float _distance; glm::quat _orientation; glm::vec2 _dragStart; bool _wasMouseClicked; float _scrollPositionPrevious; float _scrollPositionDelta; glm::mat4 _initialCameraView; static inline float cameraDistance = 8.15f; static inline Camera* _instance; public: const glm::mat4& View() const { return LocalToWorld(); } const glm::mat4& Projection() const { return _projection; } public: Camera(GLFWwindow* window, InputSystem* inputSystem) : Entity(nullptr) { _instance = this; _window = window; _inputSystem = inputSystem; _distance = 0.0f; _wasMouseClicked = false; _initialCameraView = glm::lookAt(glm::vec3(0.0f, 0.0f, cameraDistance), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); SetTransform(_initialCameraView); _projection = glm::mat4(1.0f); } void Update(double deltaTime) override { int screenWidth; int screenHeight; glfwGetFramebufferSize(_window, &screenWidth, &screenHeight); float aspec = (float)screenWidth / (float)screenHeight; _projection = glm::perspective(glm::radians(45.0f), aspec, 0.1f, 100.0f); if (_inputSystem->WasKeyPressed(GLFW_KEY_SPACE)) _orientation = glm::quat(1.0f, glm::vec3(0.0f, 0.0f, 0.0f)); glm::fvec2 velocity(0.0f, 0.0f); if (_inputSystem->IsKeyPressed(GLFW_KEY_UP)) velocity.x = glm::radians(90.0f); if (_inputSystem->IsKeyPressed(GLFW_KEY_DOWN)) velocity.x = glm::radians(-90.0f); if (_inputSystem->IsKeyPressed(GLFW_KEY_RIGHT)) velocity.y = glm::radians(90.0f); if (_inputSystem->IsKeyPressed(GLFW_KEY_LEFT)) velocity.y = glm::radians(-90.0f); if (!_wasMouseClicked && _inputSystem->IsRightMouseDown()) { _inputSystem->GetMousePos(_dragStart); } if (_wasMouseClicked && _inputSystem->IsRightMouseDown()) { glm::vec2 currentMousePositions; _inputSystem->GetMousePos(currentMousePositions); glm::vec2 dragDiff = currentMousePositions - _dragStart; _dragStart = currentMousePositions; _orientation = glm::quat(1.0f, glm::vec3(dragDiff.y, dragDiff.x, 0.0f) * 0.008f) * _orientation; _orientation = glm::normalize(_orientation); } _wasMouseClicked = _inputSystem->IsRightMouseDown(); glm::quat velocityQuaternion = glm::quat(0.0f, glm::vec3(velocity.x, velocity.y, 0.0f)); _orientation += 0.5f * (float)deltaTime * velocityQuaternion * _orientation; _orientation = glm::normalize(_orientation); _distance += _scrollPositionDelta; _scrollPositionDelta = 0.0f; SetTransform(_initialCameraView * glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, _distance)) * glm::mat4_cast(_orientation)); // since callbacks need to be static use a singleton glfwSetScrollCallback(_window, Camera::scrollCallbackGlobal); } static void scrollCallbackGlobal(GLFWwindow* window, double xOffset, double yOffset) { _instance->scrollCallback(window, xOffset, yOffset); } void scrollCallback(GLFWwindow* window, double xOffset, double yOffset) { _scrollPositionDelta = yOffset; } void SetAspectRatio(float aspec) { _projection = glm::perspective(glm::radians(45.0f), aspec, 0.1f, 100.0f); } };