diff --git a/include/inexor/vulkan-renderer/camera.hpp b/include/inexor/vulkan-renderer/camera.hpp index e68acd457..b9479abcd 100644 --- a/include/inexor/vulkan-renderer/camera.hpp +++ b/include/inexor/vulkan-renderer/camera.hpp @@ -5,76 +5,81 @@ #include #include +#include +#include #include namespace inexor::vulkan_renderer { namespace directions { -/// The default value of the camera's front vector. +/// The default value of the camera's front vector constexpr glm::vec3 DEFAULT_FRONT{1.0f, 0.0f, 0.0f}; -/// The default value of the camera's right vector. +/// The default value of the camera's right vector constexpr glm::vec3 DEFAULT_RIGHT{0.0f, 1.0f, 0.0f}; -/// The default value of the camera's up vector. +/// The default value of the camera's up vector constexpr glm::vec3 DEFAULT_UP{0.0f, 0.0f, 1.0f}; } // namespace directions enum class CameraMovement { FORWARD, BACKWARD, LEFT, RIGHT }; -// TODO: Implement more camera types. +// TODO: Implement more camera types enum class CameraType { LOOK_AT }; -/// @warning Not thread safe! +/// A wrapper class for cameras +/// @note This class uses ``std::shared_mutex`` to ensure thread safety class Camera { private: - /// The type of the camera. Currently only one type is implemented. + mutable std::shared_mutex m_cam_mutex; + + /// The type of the camera CameraType m_type{CameraType::LOOK_AT}; - /// The start position of the camera. + /// The start position of the camera glm::vec3 m_position{0.0f, 0.0f, 0.0f}; - /// The vector of direction in which the camera is looking. + /// The vector of direction in which the camera is looking glm::vec3 m_front{directions::DEFAULT_FRONT}; - /// The vector of direction which points to the right. + /// The vector of direction which points to the right glm::vec3 m_right{directions::DEFAULT_RIGHT}; - /// The vector which indicates "upwards". + /// The vector which indicates "upwards" glm::vec3 m_up{directions::DEFAULT_UP}; - /// The world vector which indicates "upwards". + /// The world vector which indicates "upwards" glm::vec3 m_world_up{directions::DEFAULT_UP}; glm::mat4 m_view_matrix{}; glm::mat4 m_perspective_matrix{}; - /// The camera's yaw angle. + /// The camera's yaw angle float m_yaw{0.0f}; - /// The camera's roll angle. + /// The camera's roll angle float m_roll{0.0f}; - /// The camera's pitch angle. + /// The camera's pitch angle float m_pitch{0.0f}; - /// The camera's minimum pitch angle. - /// Looking straight downwards is the maximum pitch angle. + /// The camera's minimum pitch angle + /// Looking straight downwards is the maximum pitch angle float m_pitch_min{-89.0f}; - /// The camera's maximum pitch angle. - /// Looking straight upwards is the maximum pitch angle. + /// The camera's maximum pitch angle + /// Looking straight upwards is the maximum pitch angle float m_pitch_max{+89.0f}; - /// The camera's horizontal field of view. + /// The camera's horizontal field of view float m_fov{90.0f}; - /// The camera's maximum field of view. + /// The camera's maximum field of view float m_fov_max{90.0f}; - /// The camera's minimum field of view. + /// The camera's minimum field of view float m_fov_min{20.0f}; - /// The zoom step when zooming in or out. + /// The zoom step when zooming in or out float m_zoom_step{10.0f}; - /// The camera's rotation speed. + /// The camera's rotation speed float m_rotation_speed{1.0f}; - /// The camera's movement speed. + /// The camera's movement speed float m_movement_speed{2.0f}; - /// The camera's aspect ratio (width divided by height). + /// The camera's aspect ratio (width divided by height) float m_aspect_ratio{1920.0f / 1080.0f}; - /// The sensitivity of the mouse. + /// The sensitivity of the mouse float m_mouse_sensitivity{0.005f}; - /// The camera's near plane. + /// The camera's near plane float m_near_plane{0.001f}; - /// The camera's far plane. + /// The camera's far plane float m_far_plane{1000.0f}; - /// The keys for the movement FORWARD, BACKWARD, LEFT, RIGHT. + /// The keys for the movement FORWARD, BACKWARD, LEFT, RIGHT std::array m_keys{false, false, false, false}; float m_vertical_fov{0.0f}; @@ -83,144 +88,163 @@ class Camera { bool m_update_view_matrix{false}; bool m_update_perspective_matrix{false}; + /// @note We are not using a shared mutex in here because this private method will only be called by other methods void update_vectors(); + /// @note We are not using a shared mutex in here because this private method will only be called by other methods void update_matrices(); [[nodiscard]] bool is_moving() const; public: - /// @brief Default constructor. - /// @param position The camera's position. - /// @param yaw The camera's yaw angle in degrees. - /// @param pitch The camera's pitch angle in degrees. - /// @param window_width The width of the window. - /// @param window_height The height of the window. + /// Default constructor + /// @param position The camera's position + /// @param yaw The camera's yaw angle in degrees + /// @param pitch The camera's pitch angle in degrees + /// @param window_width The width of the window + /// @param window_height The height of the window + // @note We don't use the shared mutex in the constructor because there is no case where multiple threads can + // construct the same object, meaning the constructor is thread-safe by default Camera(const glm::vec3 &position, float yaw, float pitch, float window_width, float window_height); - // TODO: Add more overloaded constructors. - - /// @brief Set the camera type. - /// @note We will implement more camera types in the future. - /// @param type The camera type. - void set_type(CameraType type); + /// Set the camera type + /// @note We will implement more camera types in the future + /// @param type The camera type + Camera &set_type(CameraType type); [[nodiscard]] const CameraType &type() const { + std::shared_lock lock(m_cam_mutex); return m_type; } - /// @brief Notify the camera if a certain key is pressed or released. - /// @param key The key which was pressed or released. - /// @param pressed ``true`` if the key is pressed. - void set_movement_state(CameraMovement key, bool pressed); + /// Notify the camera if a certain key is pressed or released + /// @param key The key which was pressed or released + /// @param pressed ``true`` if the key is pressed + Camera &set_movement_state(CameraMovement key, bool pressed); - /// @brief Set the position of the camera. - /// @param position The position of the camera. - void set_position(glm::vec3 position); + /// Set the position of the camera + /// @param position The position of the camera + Camera &set_position(glm::vec3 position); [[nodiscard]] const glm::vec3 &position() const { + std::shared_lock lock(m_cam_mutex); return m_position; } - /// @brief Set the aspect ratio (window width divided by window height) of the camera view matrix. - /// @param width The width of the window. - /// @param height The height of the window. - void set_aspect_ratio(float width, float height); + /// Set the aspect ratio (window width divided by window height) of the camera view matrix + /// @param width The width of the window + /// @param height The height of the window + Camera &set_aspect_ratio(float width, float height); [[nodiscard]] float aspect_ratio() const { + std::shared_lock lock(m_cam_mutex); return m_aspect_ratio; } [[nodiscard]] float fov() const { + std::shared_lock lock(m_cam_mutex); return m_fov; } - /// @brief Set the movement speed of the camera. - /// @param speed The movement speed of the camera. - void set_movement_speed(float speed); + /// Set the movement speed of the camera + /// @param speed The movement speed of the camera + Camera &set_movement_speed(float speed); [[nodiscard]] float movement_speed() const { + std::shared_lock lock(m_cam_mutex); return m_movement_speed; } - /// @brief Set the rotation speed of the camera. - /// @param speed The rotation speed of the camera. - void set_rotation_speed(float speed); + /// Set the rotation speed of the camera + /// @param speed The rotation speed of the camera + Camera &set_rotation_speed(float speed); [[nodiscard]] float rotation_speed() const { + std::shared_lock lock(m_cam_mutex); return m_rotation_speed; } - /// @brief Rotates the camera around x, y, and z axis. - /// @param delta_yaw The yaw angle. - /// @param delta_pitch The pitch angle. - /// @param delta_roll The roll angle. - void rotate(float delta_yaw, float delta_pitch, float delta_roll = 0.0f); + /// Rotates the camera around x, y, and z axis + /// @param delta_yaw The yaw angle + /// @param delta_pitch The pitch angle + /// @param delta_roll The roll angle + Camera &rotate(float delta_yaw, float delta_pitch, float delta_roll = 0.0f); - /// @brief Set the camera's rotation. - /// @param yaw The yaw angle. - /// @param pitch The pitch angle. - /// @param roll The roll angle. - void set_rotation(float yaw, float pitch, float roll); + /// Set the camera's rotation + /// @param yaw The yaw angle + /// @param pitch The pitch angle + /// @param roll The roll angle + Camera &set_rotation(float yaw, float pitch, float roll); [[nodiscard]] const glm::vec3 &rotation() const { + std::shared_lock lock(m_cam_mutex); return m_front; } [[nodiscard]] float yaw() const { + std::shared_lock lock(m_cam_mutex); return m_yaw; } [[nodiscard]] float pitch() const { + std::shared_lock lock(m_cam_mutex); return m_pitch; } [[nodiscard]] float roll() const { + std::shared_lock lock(m_cam_mutex); return m_roll; } [[nodiscard]] const glm::vec3 &front() const { + std::shared_lock lock(m_cam_mutex); return m_front; } [[nodiscard]] const glm::vec3 &up() const { + std::shared_lock lock(m_cam_mutex); return m_up; } [[nodiscard]] const glm::vec3 &right() const { + std::shared_lock lock(m_cam_mutex); return m_right; } - /// @brief Set the near plane distance of the camera. - /// @param near_plane The near plane distance. - void set_near_plane(float near_plane); + /// Set the near plane distance of the camera + /// @param near_plane The near plane distance + Camera &set_near_plane(float near_plane); [[nodiscard]] float near_plane() const { + std::shared_lock lock(m_cam_mutex); return m_near_plane; } - /// @brief Set the far plane distance of the camera. - /// @param far_plane The far plane distance. - void set_far_plane(float far_plane); + /// Set the far plane distance of the camera + /// @param far_plane The far plane distance + Camera &set_far_plane(float far_plane); [[nodiscard]] float far_plane() const { + std::shared_lock lock(m_cam_mutex); return m_far_plane; } - /// @brief Change the zoom of the camera. - /// @param offset The mouse wheel offset change. - void change_zoom(float offset); + /// Change the zoom of the camera + /// @param offset The mouse wheel offset change + Camera &change_zoom(float offset); - /// @brief Update the camera (recalculate vectors and matrices). - /// @param delta_time The change in time since the last frame. - void update(float delta_time); + /// Update the camera (recalculate vectors and matrices) + /// @param delta_time The change in time since the last frame + Camera &update(float delta_time); [[nodiscard]] const glm::mat4 &view_matrix() { + std::scoped_lock lock(m_cam_mutex); update_matrices(); return m_view_matrix; } [[nodiscard]] const glm::mat4 &perspective_matrix() { + std::scoped_lock lock(m_cam_mutex); update_matrices(); return m_perspective_matrix; } diff --git a/src/vulkan-renderer/application.cpp b/src/vulkan-renderer/application.cpp index f2bcd95b0..d2a3b4077 100644 --- a/src/vulkan-renderer/application.cpp +++ b/src/vulkan-renderer/application.cpp @@ -502,6 +502,12 @@ Application::Application(int argc, char **argv) { generate_octree_indices(); m_window->show(); + + m_camera = std::make_unique(glm::vec3(6.0f, 10.0f, 2.0f), 180.0f, 0.0f, + static_cast(m_window->width()), static_cast(m_window->height())); + + m_camera->set_movement_speed(5.0f).set_rotation_speed(0.5f); + recreate_swapchain(); } @@ -568,10 +574,10 @@ void Application::process_mouse_input() { m_camera->rotate(static_cast(cursor_pos_delta[0]), -static_cast(cursor_pos_delta[1])); } - m_camera->set_movement_state(CameraMovement::FORWARD, m_input_data->is_key_pressed(GLFW_KEY_W)); - m_camera->set_movement_state(CameraMovement::LEFT, m_input_data->is_key_pressed(GLFW_KEY_A)); - m_camera->set_movement_state(CameraMovement::BACKWARD, m_input_data->is_key_pressed(GLFW_KEY_S)); - m_camera->set_movement_state(CameraMovement::RIGHT, m_input_data->is_key_pressed(GLFW_KEY_D)); + m_camera->set_movement_state(CameraMovement::FORWARD, m_input_data->is_key_pressed(GLFW_KEY_W)) + .set_movement_state(CameraMovement::LEFT, m_input_data->is_key_pressed(GLFW_KEY_A)) + .set_movement_state(CameraMovement::BACKWARD, m_input_data->is_key_pressed(GLFW_KEY_S)) + .set_movement_state(CameraMovement::RIGHT, m_input_data->is_key_pressed(GLFW_KEY_D)); } void Application::check_octree_collisions() { diff --git a/src/vulkan-renderer/camera.cpp b/src/vulkan-renderer/camera.cpp index 30fc37a65..5b6c066d2 100644 --- a/src/vulkan-renderer/camera.cpp +++ b/src/vulkan-renderer/camera.cpp @@ -22,7 +22,6 @@ void Camera::update_vectors() { m_front = glm::normalize(front); m_right = glm::normalize(glm::cross(m_front, m_world_up)); m_up = glm::normalize(glm::cross(m_right, m_front)); - m_update_view_matrix = true; } } @@ -48,11 +47,14 @@ bool Camera::is_moving() const { return m_keys[0] || m_keys[1] || m_keys[2] || m_keys[3]; } -void Camera::set_type(const CameraType type) { +Camera &Camera::set_type(const CameraType type) { + std::scoped_lock lock(m_cam_mutex); m_type = type; + return *this; } -void Camera::set_movement_state(const CameraMovement key, const bool pressed) { +Camera &Camera::set_movement_state(const CameraMovement key, const bool pressed) { + std::scoped_lock lock(m_cam_mutex); switch (key) { case CameraMovement::FORWARD: m_keys[0] = pressed; @@ -67,53 +69,71 @@ void Camera::set_movement_state(const CameraMovement key, const bool pressed) { m_keys[3] = pressed; break; } + return *this; } -void Camera::set_position(const glm::vec3 position) { +Camera &Camera::set_position(const glm::vec3 position) { + std::scoped_lock lock(m_cam_mutex); m_position = position; m_update_view_matrix = true; + return *this; } -void Camera::set_aspect_ratio(const float width, const float height) { +Camera &Camera::set_aspect_ratio(const float width, const float height) { + std::scoped_lock lock(m_cam_mutex); m_aspect_ratio = width / height; m_update_perspective_matrix = true; m_update_vertical_fov = true; + return *this; } -void Camera::set_movement_speed(const float speed) { +Camera &Camera::set_movement_speed(const float speed) { + std::scoped_lock lock(m_cam_mutex); m_movement_speed = speed; + return *this; } -void Camera::set_rotation_speed(const float speed) { +Camera &Camera::set_rotation_speed(const float speed) { + std::scoped_lock lock(m_cam_mutex); m_rotation_speed = speed; + return *this; } -void Camera::rotate(const float delta_yaw, const float delta_pitch, const float delta_roll) { +Camera &Camera::rotate(const float delta_yaw, const float delta_pitch, const float delta_roll) { + std::scoped_lock lock(m_cam_mutex); m_yaw += delta_yaw; m_yaw = std::fmod(m_yaw, 360.0f); m_pitch += delta_pitch; m_roll += delta_roll; m_pitch = std::clamp(m_pitch, m_pitch_min, m_pitch_max); update_vectors(); + return *this; } -void Camera::set_rotation(const float yaw, const float pitch, const float roll) { +Camera &Camera::set_rotation(const float yaw, const float pitch, const float roll) { + std::scoped_lock lock(m_cam_mutex); m_yaw = m_mouse_sensitivity * yaw; m_pitch = m_mouse_sensitivity * pitch; m_roll = m_mouse_sensitivity * roll; + return *this; } -void Camera::set_near_plane(const float near_plane) { +Camera &Camera::set_near_plane(const float near_plane) { + std::scoped_lock lock(m_cam_mutex); m_near_plane = near_plane; m_update_perspective_matrix = true; + return *this; } -void Camera::set_far_plane(const float far_plane) { +Camera &Camera::set_far_plane(const float far_plane) { + std::scoped_lock lock(m_cam_mutex); m_far_plane = far_plane; m_update_perspective_matrix = true; + return *this; } -void Camera::change_zoom(const float offset) { +Camera &Camera::change_zoom(const float offset) { + std::scoped_lock lock(m_cam_mutex); m_fov -= offset * m_zoom_step; // Make sure field of view is in range between specified minimum and maximum value. @@ -121,9 +141,11 @@ void Camera::change_zoom(const float offset) { m_update_vertical_fov = true; m_update_perspective_matrix = true; + return *this; } -void Camera::update(const float delta_time) { +Camera &Camera::update(const float delta_time) { + std::scoped_lock lock(m_cam_mutex); if (m_type == CameraType::LOOK_AT && is_moving()) { const float move_speed = delta_time * m_movement_speed; @@ -142,6 +164,7 @@ void Camera::update(const float delta_time) { m_update_view_matrix = true; } + return *this; } } // namespace inexor::vulkan_renderer diff --git a/src/vulkan-renderer/renderer.cpp b/src/vulkan-renderer/renderer.cpp index d45d13a21..db608bc5b 100644 --- a/src/vulkan-renderer/renderer.cpp +++ b/src/vulkan-renderer/renderer.cpp @@ -84,12 +84,6 @@ void VulkanRenderer::recreate_swapchain() { m_frame_finished_fence = std::make_unique(*m_device, "Farme finished fence", true); m_image_available_semaphore = std::make_unique(*m_device, "Image available semaphore"); - m_camera = std::make_unique(glm::vec3(6.0f, 10.0f, 2.0f), 180.0f, 0.0f, - static_cast(m_window->width()), static_cast(m_window->height())); - - m_camera->set_movement_speed(5.0f); - m_camera->set_rotation_speed(0.5f); - m_imgui_overlay.reset(); m_imgui_overlay = std::make_unique(*m_device, *m_swapchain, m_render_graph.get(), m_back_buffer); m_render_graph->compile(m_back_buffer);