Extra2D/include/renderer/viewport_adapter.h

140 lines
4.1 KiB
C
Raw Normal View History

#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