Extra2D/Extra2D/include/extra2d/render/camera/viewport_adapter.h

255 lines
5.6 KiB
C++

#pragma once
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <string>
namespace extra2d {
/**
* @brief 视口缩放模式
*/
enum class ViewportScaleMode {
None, // 无缩放
Letterbox, // 保持宽高比,黑边
Crop, // 保持宽高比,裁剪
Stretch, // 拉伸填充
IntegerScale // 整数缩放
};
/**
* @brief 视口对齐方式
*/
enum class ViewportAlign {
Center,
TopLeft,
TopCenter,
TopRight,
CenterLeft,
CenterRight,
BottomLeft,
BottomCenter,
BottomRight
};
/**
* @brief 视口配置
*/
struct ViewportConfig {
float designWidth = 1280.0f;
float designHeight = 720.0f;
ViewportScaleMode scaleMode = ViewportScaleMode::Letterbox;
ViewportAlign align = ViewportAlign::Center;
bool integerScaleOnly = false;
float minScale = 0.5f;
float maxScale = 4.0f;
ViewportConfig() = default;
ViewportConfig(float width, float height,
ViewportScaleMode mode = ViewportScaleMode::Letterbox)
: designWidth(width), designHeight(height), scaleMode(mode) {}
/**
* @brief 创建 HD (1280x720) 配置
*/
static ViewportConfig hd() {
return ViewportConfig(1280.0f, 720.0f);
}
/**
* @brief 创建 Full HD (1920x1080) 配置
*/
static ViewportConfig fullHd() {
return ViewportConfig(1920.0f, 1080.0f);
}
/**
* @brief 创建 4K (3840x2160) 配置
*/
static ViewportConfig uhd4k() {
return ViewportConfig(3840.0f, 2160.0f);
}
};
/**
* @brief 视口计算结果
*/
struct ViewportResult {
float x = 0.0f;
float y = 0.0f;
float width = 0.0f;
float height = 0.0f;
float scale = 1.0f;
int offsetX = 0;
int offsetY = 0;
int screenWidth = 0;
int screenHeight = 0;
ViewportResult() = default;
/**
* @brief 获取视口矩形
*/
Rect getRect() const { return Rect(x, y, width, height); }
/**
* @brief 获取缩放后的设计尺寸
*/
Size getScaledDesignSize() const { return Size(width / scale, height / scale); }
};
/**
* @brief 视口适配器
*
* 处理不同屏幕尺寸和宽高比的视口适配
*/
class ViewportAdapter {
public:
ViewportAdapter();
explicit ViewportAdapter(const ViewportConfig& config);
~ViewportAdapter() = default;
// ========================================================================
// 配置
// ========================================================================
/**
* @brief 设置配置
*/
void setConfig(const ViewportConfig& config);
/**
* @brief 获取配置
*/
const ViewportConfig& getConfig() const { return config_; }
/**
* @brief 设置设计尺寸
*/
void setDesignSize(float width, float height);
/**
* @brief 设置缩放模式
*/
void setScaleMode(ViewportScaleMode mode);
/**
* @brief 设置对齐方式
*/
void setAlign(ViewportAlign align);
// ========================================================================
// 更新
// ========================================================================
/**
* @brief 更新视口
*/
void update(int screenWidth, int screenHeight);
/**
* @brief 获取结果
*/
const ViewportResult& getResult() const { return result_; }
// ========================================================================
// 查询
// ========================================================================
/**
* @brief 获取设计宽度
*/
float getDesignWidth() const { return config_.designWidth; }
/**
* @brief 获取设计高度
*/
float getDesignHeight() const { return config_.designHeight; }
/**
* @brief 获取设计宽高比
*/
float getDesignAspectRatio() const;
/**
* @brief 获取屏幕宽度
*/
int getScreenWidth() const { return result_.screenWidth; }
/**
* @brief 获取屏幕高度
*/
int getScreenHeight() const { return result_.screenHeight; }
/**
* @brief 获取屏幕宽高比
*/
float getScreenAspectRatio() const;
/**
* @brief 获取当前缩放
*/
float getScale() const { return result_.scale; }
/**
* @brief 获取视口偏移 X
*/
int getOffsetX() const { return result_.offsetX; }
/**
* @brief 获取视口偏移 Y
*/
int getOffsetY() const { return result_.offsetY; }
// ========================================================================
// 坐标转换
// ========================================================================
/**
* @brief 屏幕坐标转设计坐标
*/
Vec2 screenToDesign(const Vec2& screenPos) const;
/**
* @brief 设计坐标转屏幕坐标
*/
Vec2 designToScreen(const Vec2& designPos) const;
// ========================================================================
// 调试
// ========================================================================
/**
* @brief 获取调试名称
*/
const std::string& getDebugName() const { return debugName_; }
/**
* @brief 设置调试名称
*/
void setDebugName(const std::string& name) { debugName_ = name; }
private:
/**
* @brief 计算视口
*/
void calculateViewport();
/**
* @brief 计算缩放
*/
float calculateScale() const;
/**
* @brief 计算偏移
*/
void calculateOffset();
ViewportConfig config_;
ViewportResult result_;
std::string debugName_;
};
} // namespace extra2d