281 lines
6.4 KiB
C++
281 lines
6.4 KiB
C++
#pragma once
|
||
|
||
#include <scene/component.h>
|
||
#include <types/math/rect.h>
|
||
#include <types/math/mat4.h>
|
||
#include <types/math/vec2.h>
|
||
|
||
namespace extra2d {
|
||
|
||
/**
|
||
* @brief 相机组件
|
||
*
|
||
* 负责管理相机投影和视图矩阵,支持缩放、旋转和边界限制
|
||
*/
|
||
class CameraComponent : public Component {
|
||
public:
|
||
static constexpr const char* TYPE_NAME = "Camera";
|
||
|
||
/**
|
||
* @brief 投影类型
|
||
*/
|
||
enum class ProjectionType {
|
||
Orthographic, // 正交投影
|
||
Perspective // 透视投影
|
||
};
|
||
|
||
/**
|
||
* @brief 构造函数
|
||
*/
|
||
CameraComponent();
|
||
|
||
/**
|
||
* @brief 获取组件类型名称
|
||
* @return 类型名称
|
||
*/
|
||
const char* getTypeName() const override { return TYPE_NAME; }
|
||
|
||
// ========================================
|
||
// 投影设置
|
||
// ========================================
|
||
|
||
/**
|
||
* @brief 设置投影类型
|
||
* @param type 投影类型
|
||
*/
|
||
void setProjectionType(ProjectionType type);
|
||
|
||
/**
|
||
* @brief 获取投影类型
|
||
* @return 投影类型
|
||
*/
|
||
ProjectionType getProjectionType() const { return projType_; }
|
||
|
||
/**
|
||
* @brief 设置正交投影
|
||
* @param left 左边界
|
||
* @param right 右边界
|
||
* @param bottom 下边界
|
||
* @param top 上边界
|
||
* @param near 近裁剪面
|
||
* @param far 远裁剪面
|
||
*/
|
||
void setOrtho(float left, float right, float bottom, float top, float near, float far);
|
||
|
||
/**
|
||
* @brief 设置透视投影
|
||
* @param fov 视场角(度)
|
||
* @param aspect 宽高比
|
||
* @param near 近裁剪面
|
||
* @param far 远裁剪面
|
||
*/
|
||
void setPerspective(float fov, float aspect, float near, float far);
|
||
|
||
// ========================================
|
||
// 变换属性(缩放、旋转)
|
||
// ========================================
|
||
|
||
/**
|
||
* @brief 设置缩放级别
|
||
* @param zoom 缩放值(1.0为正常大小,>1放大,<1缩小)
|
||
*/
|
||
void setZoom(float zoom);
|
||
|
||
/**
|
||
* @brief 获取缩放级别
|
||
* @return 缩放值
|
||
*/
|
||
float getZoom() const { return zoom_; }
|
||
|
||
/**
|
||
* @brief 设置旋转角度
|
||
* @param degrees 旋转角度(度数)
|
||
*/
|
||
void setRotation(float degrees);
|
||
|
||
/**
|
||
* @brief 获取旋转角度
|
||
* @return 旋转角度(度数)
|
||
*/
|
||
float getRotation() const { return rotation_; }
|
||
|
||
// ========================================
|
||
// 矩阵获取
|
||
// ========================================
|
||
|
||
/**
|
||
* @brief 获取视图矩阵
|
||
* @return 视图矩阵
|
||
*/
|
||
Mat4 getViewMatrix() const;
|
||
|
||
/**
|
||
* @brief 获取投影矩阵
|
||
* @return 投影矩阵
|
||
*/
|
||
Mat4 getProjectionMatrix() const;
|
||
|
||
/**
|
||
* @brief 获取视图投影矩阵
|
||
* @return 视图投影矩阵
|
||
*/
|
||
Mat4 getViewProjectionMatrix() const;
|
||
|
||
// ========================================
|
||
// 坐标转换
|
||
// ========================================
|
||
|
||
/**
|
||
* @brief 将屏幕坐标转换为世界坐标
|
||
* @param screenPos 屏幕坐标
|
||
* @return 世界坐标
|
||
*/
|
||
Vec2 screenToWorld(const Vec2& screenPos) const;
|
||
|
||
/**
|
||
* @brief 将屏幕坐标转换为世界坐标
|
||
* @param x 屏幕X坐标
|
||
* @param y 屏幕Y坐标
|
||
* @return 世界坐标
|
||
*/
|
||
Vec2 screenToWorld(float x, float y) const;
|
||
|
||
/**
|
||
* @brief 将世界坐标转换为屏幕坐标
|
||
* @param worldPos 世界坐标
|
||
* @return 屏幕坐标
|
||
*/
|
||
Vec2 worldToScreen(const Vec2& worldPos) const;
|
||
|
||
/**
|
||
* @brief 将世界坐标转换为屏幕坐标
|
||
* @param x 世界X坐标
|
||
* @param y 世界Y坐标
|
||
* @return 屏幕坐标
|
||
*/
|
||
Vec2 worldToScreen(float x, float y) const;
|
||
|
||
// ========================================
|
||
// 视口
|
||
// ========================================
|
||
|
||
/**
|
||
* @brief 设置视口
|
||
* @param viewport 视口矩形
|
||
*/
|
||
void setViewport(const Rect& viewport);
|
||
|
||
/**
|
||
* @brief 获取视口
|
||
* @return 视口矩形
|
||
*/
|
||
Rect getViewport() const { return viewport_; }
|
||
|
||
// ========================================
|
||
// 边界限制
|
||
// ========================================
|
||
|
||
/**
|
||
* @brief 设置相机边界限制
|
||
* @param bounds 边界矩形
|
||
*/
|
||
void setBounds(const Rect& bounds);
|
||
|
||
/**
|
||
* @brief 清除相机边界限制
|
||
*/
|
||
void clearBounds();
|
||
|
||
/**
|
||
* @brief 检查是否有边界限制
|
||
* @return 是否有边界限制
|
||
*/
|
||
bool hasBounds() const { return hasBounds_; }
|
||
|
||
/**
|
||
* @brief 将相机位置限制在边界内
|
||
*/
|
||
void clampToBounds();
|
||
|
||
// ========================================
|
||
// 移动相机
|
||
// ========================================
|
||
|
||
/**
|
||
* @brief 移动相机位置
|
||
* @param offset 位置偏移量
|
||
*/
|
||
void move(const Vec2& offset);
|
||
|
||
/**
|
||
* @brief 移动相机位置
|
||
* @param x X方向偏移量
|
||
* @param y Y方向偏移量
|
||
*/
|
||
void move(float x, float y);
|
||
|
||
/**
|
||
* @brief 将相机移动到目标位置
|
||
* @param target 目标位置
|
||
*/
|
||
void lookAt(const Vec2& target);
|
||
|
||
private:
|
||
/**
|
||
* @brief 标记视图矩阵为脏
|
||
*/
|
||
void markViewDirty() { viewDirty_ = true; vpDirty_ = true; }
|
||
|
||
/**
|
||
* @brief 标记投影矩阵为脏
|
||
*/
|
||
void markProjDirty() { projDirty_ = true; vpDirty_ = true; }
|
||
|
||
/**
|
||
* @brief 更新视图矩阵
|
||
*/
|
||
void updateViewMatrix() const;
|
||
|
||
/**
|
||
* @brief 更新投影矩阵
|
||
*/
|
||
void updateProjectionMatrix() const;
|
||
|
||
ProjectionType projType_ = ProjectionType::Orthographic;
|
||
|
||
// 投影参数
|
||
float left_ = 0.0f;
|
||
float right_ = 800.0f;
|
||
float bottom_ = 600.0f;
|
||
float top_ = 0.0f;
|
||
float near_ = -1.0f;
|
||
float far_ = 1.0f;
|
||
|
||
// 透视投影参数
|
||
float fov_ = 60.0f;
|
||
float aspect_ = 16.0f / 9.0f;
|
||
|
||
// 变换属性
|
||
float zoom_ = 1.0f;
|
||
float rotation_ = 0.0f;
|
||
|
||
// 视口
|
||
Rect viewport_;
|
||
|
||
// 边界限制
|
||
Rect bounds_;
|
||
bool hasBounds_ = false;
|
||
|
||
// 缓存矩阵(mutable 用于 const 方法中延迟计算)
|
||
mutable Mat4 viewMatrix_ = Mat4(1.0f);
|
||
mutable Mat4 projMatrix_ = Mat4(1.0f);
|
||
mutable Mat4 vpMatrix_ = Mat4(1.0f);
|
||
|
||
// 脏标记
|
||
mutable bool viewDirty_ = true;
|
||
mutable bool projDirty_ = true;
|
||
mutable bool vpDirty_ = true;
|
||
};
|
||
|
||
} // namespace extra2d
|