#pragma once #include #include #define CAMERA_MAX_ZOOM 90.0f #define CAMERA_MIN_ZOOM 1.0f class Camera { public: inline glm::vec3 defaultOrigin() { return glm::vec3(0.0f, 0.0f, 1.0f); } inline glm::vec3 defaultTarget() { return glm::vec3(0.0f, 0.0f, 0.0f); } private: // Camera state glm::vec3 _position; glm::vec3 _right; glm::vec3 _front; glm::vec3 _up; float _yaw = 0.0f; float _pitch = 0.0f; float _zoom = 45.0f; private: // World settings glm::vec3 _worldUp = glm::vec3(0.0f, 1.0f, 0.0f); public: Camera(); Camera(glm::vec3 position, glm::vec3 target); Camera(glm::vec3 position, glm::vec3 direction, glm::vec3 right, glm::vec3 up); Camera(glm::vec3 position, float yaw, float pitch); public: inline glm::vec3 front() const { return _front; } inline float zoomVal() const { return _zoom; } inline glm::mat4 viewMatrix(); inline glm::vec3 position() const { return _position; } public: inline void move(glm::vec2 offset); inline void setPosition(glm::vec3 position); inline void pitch(float deltaAngle); inline void setPitch(float angle); inline void yaw(float deltaAngle); inline void setYaw(float angle); inline void rotate(float deltaPitchAngle, float deltaYawAngle); inline void setRotation(float pitchAngle, float yawAngle); void rotate(glm::vec3 center, float deltaPitchAngle, float deltaYawAngle); void setRotation(glm::vec3 center, float pitchAngle, float yawAngle); inline void zoom(float deltaZoom); inline void setZoom(float zoom); inline void push(float distance); private: void updateCameraState(); }; inline void Camera::move(glm::vec2 offset) { // Offset describe the movement on the xy plane in the camera's coordinate system // Should convert to the movement of position vector in world coordinate system glm::vec3 worldSpaceOffset = offset.x * _right + offset.y * _up; _position += worldSpaceOffset; updateCameraState(); } inline void Camera::setPosition(glm::vec3 position) { _position = position; updateCameraState(); } inline void Camera::pitch(float deltaAngle) { _pitch += deltaAngle; updateCameraState(); } inline void Camera::setPitch(float angle) { _pitch = angle; updateCameraState(); } inline void Camera::yaw(float deltaAngle) { _yaw += deltaAngle; updateCameraState(); } inline void Camera::setYaw(float angle) { _yaw = angle; updateCameraState(); } inline void Camera::rotate(float deltaPitchAngle, float deltaYawAngle) { _pitch += deltaPitchAngle; if (_pitch > 89.0f) { _pitch = 89.0f; } if (_pitch < -89.0f) { _pitch = -89.0f; } _yaw += deltaYawAngle; if (_yaw > 360.0f) { _yaw -= 360.0f; } if (_yaw < 0.0f) { _yaw += 360.0f; } updateCameraState(); } inline void Camera::setRotation(float pitchAngle, float yawAngle) { _pitch = pitchAngle; _yaw = yawAngle; updateCameraState(); } inline void Camera::zoom(float deltaZoom) { _zoom += deltaZoom; if (_zoom > CAMERA_MAX_ZOOM) { _zoom = CAMERA_MAX_ZOOM; } else if (_zoom < CAMERA_MIN_ZOOM) { _zoom = CAMERA_MIN_ZOOM; } updateCameraState(); } inline void Camera::setZoom(float zoom) { _zoom = zoom; if (_zoom > CAMERA_MAX_ZOOM) { _zoom = CAMERA_MAX_ZOOM; } else if (_zoom < CAMERA_MIN_ZOOM) { _zoom = CAMERA_MIN_ZOOM; } updateCameraState(); } inline void Camera::push(float distance) { _position += distance * _front; updateCameraState(); } inline glm::mat4 Camera::viewMatrix() { float temp = glm::sqrt(_position.x * _position.x + _position.y * _position.y + _position.z * _position.z); return glm::lookAt(-_front*temp, glm::vec3(0.0f), _up); }