#pragma once #include #include #include #include #include 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(screenWidth_), static_cast(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