140 lines
4.1 KiB
C++
140 lines
4.1 KiB
C++
#pragma once
|
|
|
|
#include <types/base/types.h>
|
|
#include <types/math/vec2.h>
|
|
#include <types/math/rect.h>
|
|
#include <types/math/color.h>
|
|
#include <glm/mat4x4.hpp>
|
|
|
|
namespace extra2d {
|
|
|
|
/**
|
|
* @brief 视口适配模式枚举
|
|
*/
|
|
enum class ViewportMode {
|
|
AspectRatio, // 保持宽高比,可能有黑边
|
|
Stretch, // 拉伸以填满屏幕
|
|
Center, // 居中显示
|
|
Custom // 自定义
|
|
};
|
|
|
|
/**
|
|
* @brief 黑边位置枚举
|
|
*/
|
|
enum class LetterboxPosition {
|
|
Center,
|
|
LeftTop,
|
|
RightTop,
|
|
LeftBottom,
|
|
RightBottom
|
|
};
|
|
|
|
/**
|
|
* @brief 视口配置结构体
|
|
*/
|
|
struct ViewportConfig {
|
|
float logicWidth = 1280.0f; // 逻辑宽度
|
|
float logicHeight = 720.0f; // 逻辑高度
|
|
ViewportMode mode = ViewportMode::AspectRatio;
|
|
LetterboxPosition letterboxPosition = LetterboxPosition::Center;
|
|
Color letterboxColor = Color::Black;
|
|
bool autoScaleInCenterMode = true;
|
|
float customScale = 1.0f;
|
|
Vec2 customOffset = Vec2::Zero;
|
|
Rect customViewport = Rect::Zero;
|
|
};
|
|
|
|
/**
|
|
* @brief 视口计算结果结构体
|
|
*/
|
|
struct ViewportResult {
|
|
Rect viewport; // 视口矩形
|
|
float scaleX = 1.0f; // X方向缩放
|
|
float scaleY = 1.0f; // Y方向缩放
|
|
float uniformScale = 1.0f; // 统一缩放
|
|
Vec2 offset; // 视口偏移
|
|
bool hasLetterbox = false; // 是否有黑边
|
|
|
|
struct Letterbox {
|
|
Rect top;
|
|
Rect bottom;
|
|
Rect left;
|
|
Rect right;
|
|
} letterbox;
|
|
};
|
|
|
|
/**
|
|
* @brief 视口适配器类
|
|
*
|
|
* 处理不同屏幕尺寸的适配,保持逻辑分辨率与屏幕分辨率的映射关系
|
|
*/
|
|
class ViewportAdapter {
|
|
public:
|
|
ViewportAdapter();
|
|
ViewportAdapter(float logicWidth, float logicHeight);
|
|
~ViewportAdapter() = default;
|
|
|
|
// 配置设置
|
|
void setConfig(const ViewportConfig& config);
|
|
const ViewportConfig& getConfig() const { return config_; }
|
|
|
|
void setLogicSize(float width, float height);
|
|
void setMode(ViewportMode mode);
|
|
void setLetterboxPosition(LetterboxPosition position);
|
|
void setLetterboxColor(const Color& color);
|
|
|
|
// 更新和计算
|
|
void update(int screenWidth, int screenHeight);
|
|
const ViewportResult& getResult() const { return result_; }
|
|
|
|
// 坐标转换
|
|
Vec2 screenToLogic(const Vec2& screenPos) const;
|
|
Vec2 logicToScreen(const Vec2& logicPos) const;
|
|
Vec2 screenToLogic(float x, float y) const;
|
|
Vec2 logicToScreen(float x, float y) const;
|
|
|
|
// 矩阵获取
|
|
glm::mat4 getMatrix() const;
|
|
glm::mat4 getInvMatrix() const;
|
|
|
|
// 区域检测
|
|
bool isInViewport(const Vec2& screenPos) const;
|
|
bool isInLetterbox(const Vec2& screenPos) const;
|
|
|
|
// Getter 方法
|
|
float getLogicWidth() const { return config_.logicWidth; }
|
|
float getLogicHeight() const { return config_.logicHeight; }
|
|
Size getLogicSize() const { return Size(config_.logicWidth, config_.logicHeight); }
|
|
|
|
int getScreenWidth() const { return screenWidth_; }
|
|
int getScreenHeight() const { return screenHeight_; }
|
|
Size getScreenSize() const { return Size(static_cast<float>(screenWidth_), static_cast<float>(screenHeight_)); }
|
|
|
|
float getScaleX() const { return result_.scaleX; }
|
|
float getScaleY() const { return result_.scaleY; }
|
|
float getUniformScale() const { return result_.uniformScale; }
|
|
Vec2 getOffset() const { return result_.offset; }
|
|
Rect getViewport() const { return result_.viewport; }
|
|
bool hasLetterbox() const { return result_.hasLetterbox; }
|
|
const ViewportResult::Letterbox& getLetterbox() const { return result_.letterbox; }
|
|
|
|
private:
|
|
void calculateAspectRatio();
|
|
void calculateStretch();
|
|
void calculateCenter();
|
|
void calculateCustom();
|
|
void calculateLetterbox();
|
|
void applyLetterboxPosition(float extraWidth, float extraHeight);
|
|
|
|
ViewportConfig config_;
|
|
ViewportResult result_;
|
|
int screenWidth_ = 0;
|
|
int screenHeight_ = 0;
|
|
|
|
mutable glm::mat4 viewportMatrix_;
|
|
mutable glm::mat4 inverseViewportMatrix_;
|
|
mutable bool matrixDirty_ = true;
|
|
};
|
|
|
|
} // namespace extra2d
|