#pragma once #include #include #include #define _USE_MATH_DEFINES #ifndef M_PI #define M_PI 3.14159265358979323846 #endif namespace Donut { enum class CameraMode { FPS, Orbital }; class Camera { public: Camera(float fov = 45.0f, float aspect_ratio = 16.0f / 9.0f, float near_plane = 0.1f, float far_plane = 100.0f); ~Camera() = default; void set_position(const glm::vec3& position) { m_position = position; recalculate_view_matrix(); } void set_rotation(const glm::vec3& rotation) { m_rotation = rotation; recalculate_view_matrix(); } const glm::vec3& get_position() const { return m_position; } const glm::vec3& get_rotation() const { return m_rotation; } glm::vec3 get_forward_direction() const; glm::vec3 get_right_direction() const; glm::vec3 get_up_direction() const; const glm::mat4& get_projection_matrix() const { return m_projection_matrix; } const glm::mat4& get_view_matrix() const { return m_view_matrix; } const glm::mat4& get_view_projection_matrix() const { return m_view_projection_matrix; } void set_projection(float fov, float aspect_ratio, float near_plane, float far_plane); void on_mouse_move(float x_offset, float y_offset, bool constrain_pitch = true); void move_forward(float delta_time); void move_backward(float delta_time); void move_right(float delta_time); void move_left(float delta_time); void move_up(float delta_time); void move_down(float delta_time); void set_mouse_sensitivity(float sensitivity) { m_mouse_sensitivity = sensitivity; } float get_mouse_sensitivity() const { return m_mouse_sensitivity; } void set_movement_speed(float speed) { m_movement_speed = speed; } float get_movement_speed() const { return m_movement_speed; } void set_orbital_mode(bool enabled); bool is_orbital_mode() const { return m_camera_mode == CameraMode::Orbital; } void set_target(const glm::vec3& target) { m_target = target; } const glm::vec3& get_target() const { return m_target; } void set_radius(double radius) { m_radius = radius; } double get_radius() const { return m_radius; } void set_min_radius(double min_radius) { m_min_radius = min_radius; } double get_min_radius() const { return m_min_radius; } void set_max_radius(double max_radius) { m_max_radius = max_radius; } double get_max_radius() const { return m_max_radius; } void set_azimuth(float azimuth) { m_azimuth = azimuth; } float get_azimuth() const { return m_azimuth; } void set_elevation(float elevation) { m_elevation = elevation; } float get_elevation() const { return m_elevation; } void set_orbit_speed(float orbit_speed) { m_orbit_speed = orbit_speed; } float get_orbit_speed() const { return m_orbit_speed; } void set_zoom_speed(double zoom_speed) { m_zoom_speed = zoom_speed; } double get_zoom_speed() const { return m_zoom_speed; } glm::vec3 get_orbital_position() const; void process_orbital_mouse_move(double x, double y); void process_orbital_mouse_button(int button, int action, int mods); void process_orbital_scroll(double x_offset, double y_offset); bool is_dragging() const { return m_dragging; } bool is_panning() const { return m_panning; } bool is_moving() const { return m_moving; } private: void recalculate_view_matrix(); void recalculate_projection_matrix(); void update_orbital_state(); private: CameraMode m_camera_mode = CameraMode::FPS; glm::mat4 m_projection_matrix; glm::mat4 m_view_matrix; glm::mat4 m_view_projection_matrix; glm::vec3 m_position = { 0.0f, 0.0f, 3.0f }; glm::vec3 m_rotation = { 0.0f, 0.0f, 0.0f }; float m_fov = 45.0f; float m_aspect_ratio = 16.0f / 9.0f; float m_near_plane = 0.1f; float m_far_plane = 100.0f; float m_mouse_sensitivity = 0.1f; float m_movement_speed = 5.0f; bool m_first_mouse = true; float m_last_x = 0.0f; float m_last_y = 0.0f; glm::vec3 m_target = glm::vec3(0.0f, 0.0f, 0.0f); double m_radius = 6.34194e10; double m_min_radius = 1e10; double m_max_radius = 1e12; float m_azimuth = 0.0f; float m_elevation = static_cast(M_PI) / 2.0f; float m_orbit_speed = 0.01f; double m_zoom_speed = 25e9f; bool m_dragging = false; bool m_panning = false; bool m_moving = false; double m_orbital_last_x = 0.0; double m_orbital_last_y = 0.0; }; }