refactor(render): 重构渲染模块结构,将图形相关代码迁移至render目录
- 将graphics目录重命名为render,调整相关头文件引用路径 - 添加RenderModule类作为应用模块集成渲染器 - 实现GLContext类管理OpenGL上下文状态 - 重构Camera和ViewportAdapter类,改进视口适配逻辑 - 统一渲染命令数据结构,优化形状节点渲染 - 更新构建脚本以适配新的目录结构
This commit is contained in:
parent
89d1612336
commit
1f2ed0942d
|
|
@ -13,8 +13,6 @@
|
|||
#include <extra2d/core/compression.h>
|
||||
#include <extra2d/core/aes_cipher.h>
|
||||
|
||||
// Config removed - app info now in Application class
|
||||
|
||||
// Platform
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
|
|
@ -23,17 +21,26 @@
|
|||
#include <extra2d/platform/backend_factory.h>
|
||||
#include <extra2d/platform/window_module.h>
|
||||
|
||||
// Graphics
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/texture/font.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_module.h>
|
||||
#include <extra2d/graphics/shader/shader_manager.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/graphics/core/render_target.h>
|
||||
#include <extra2d/graphics/camera/viewport_adapter.h>
|
||||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#include <extra2d/graphics/texture/texture_pool.h>
|
||||
// Render Core
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/render/core/render_context.h>
|
||||
#include <extra2d/render/core/render_queue.h>
|
||||
#include <extra2d/render/core/render_stats.h>
|
||||
#include <extra2d/render/core/render_module.h>
|
||||
#include <extra2d/render/core/backend_factory.h>
|
||||
|
||||
// Render Camera
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/camera/viewport_adapter.h>
|
||||
|
||||
// Render Batch
|
||||
#include <extra2d/render/batch/sprite_batcher.h>
|
||||
#include <extra2d/render/batch/shape_batcher.h>
|
||||
#include <extra2d/render/batch/text_batcher.h>
|
||||
|
||||
// Render Renderer
|
||||
#include <extra2d/render/renderer.h>
|
||||
|
||||
// RHI (Render Hardware Interface)
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief OpenGL 版本信息
|
||||
*/
|
||||
struct GLVersion {
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief OpenGL 上下文管理类
|
||||
*
|
||||
* 单例模式,管理 OpenGL 上下文初始化和状态查询
|
||||
*/
|
||||
class GLContext {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取单例实例
|
||||
*/
|
||||
static GLContext& get();
|
||||
|
||||
/**
|
||||
* @brief 初始化 OpenGL 上下文
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* @brief 关闭 OpenGL 上下文
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
*/
|
||||
bool isInitialized() const { return initialized_; }
|
||||
|
||||
// ========================================================================
|
||||
// 版本信息
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取 OpenGL 版本
|
||||
*/
|
||||
GLVersion getVersion() const { return version_; }
|
||||
|
||||
/**
|
||||
* @brief 获取版本字符串
|
||||
*/
|
||||
std::string getVersionString() const;
|
||||
|
||||
/**
|
||||
* @brief 获取渲染器名称
|
||||
*/
|
||||
const std::string& getRenderer() const { return renderer_; }
|
||||
|
||||
/**
|
||||
* @brief 获取供应商名称
|
||||
*/
|
||||
const std::string& getVendor() const { return vendor_; }
|
||||
|
||||
// ========================================================================
|
||||
// 能力查询
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取最大纹理尺寸
|
||||
*/
|
||||
int getMaxTextureSize() const { return maxTextureSize_; }
|
||||
|
||||
/**
|
||||
* @brief 获取最大纹理单元数
|
||||
*/
|
||||
int getMaxTextureUnits() const { return maxTextureUnits_; }
|
||||
|
||||
/**
|
||||
* @brief 获取最大顶点属性数
|
||||
*/
|
||||
int getMaxVertexAttribs() const { return maxVertexAttribs_; }
|
||||
|
||||
/**
|
||||
* @brief 获取最大 Uniform 缓冲区绑定数
|
||||
*/
|
||||
int getMaxUniformBufferBindings() const { return maxUniformBufferBindings_; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持扩展
|
||||
*/
|
||||
bool hasExtension(const std::string& extension) const;
|
||||
|
||||
// ========================================================================
|
||||
// 状态管理
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 检查 OpenGL 错误
|
||||
*/
|
||||
bool checkError(const char* operation = nullptr);
|
||||
|
||||
/**
|
||||
* @brief 清除错误状态
|
||||
*/
|
||||
void clearErrors();
|
||||
|
||||
private:
|
||||
GLContext() = default;
|
||||
~GLContext() = default;
|
||||
GLContext(const GLContext&) = delete;
|
||||
GLContext& operator=(const GLContext&) = delete;
|
||||
|
||||
/**
|
||||
* @brief 查询 OpenGL 能力
|
||||
*/
|
||||
void queryCapabilities();
|
||||
|
||||
/**
|
||||
* @brief 解析版本字符串
|
||||
*/
|
||||
void parseVersion();
|
||||
|
||||
bool initialized_ = false;
|
||||
|
||||
GLVersion version_;
|
||||
std::string renderer_;
|
||||
std::string vendor_;
|
||||
std::string glslVersion_;
|
||||
|
||||
int maxTextureSize_ = 0;
|
||||
int maxTextureUnits_ = 0;
|
||||
int maxVertexAttribs_ = 0;
|
||||
int maxUniformBufferBindings_ = 0;
|
||||
|
||||
std::unordered_set<std::string> extensions_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,302 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/rhi/rhi_device.h>
|
||||
#include <extra2d/render/backends/opengl/gl_rhi_device.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <stack>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class IWindow;
|
||||
|
||||
/**
|
||||
* @brief OpenGL 渲染后端实现
|
||||
*
|
||||
* 实现 RenderBackend 接口,使用 OpenGL 作为底层图形 API
|
||||
*/
|
||||
class GLRenderBackend : public RenderBackend {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
GLRenderBackend();
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~GLRenderBackend() override;
|
||||
|
||||
// ========================================================================
|
||||
// 生命周期
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 初始化渲染后端
|
||||
* @param window 窗口接口
|
||||
* @param config 配置参数
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
bool init(IWindow *window, const RenderBackendConfig &config = {}) override;
|
||||
|
||||
/**
|
||||
* @brief 关闭渲染后端
|
||||
*/
|
||||
void shutdown() override;
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
*/
|
||||
bool isValid() const override;
|
||||
|
||||
// ========================================================================
|
||||
// 帧管理
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始帧渲染
|
||||
* @param clearColor 清屏颜色
|
||||
*/
|
||||
void beginFrame(const Color &clearColor = Colors::Black) override;
|
||||
|
||||
/**
|
||||
* @brief 结束帧渲染
|
||||
*/
|
||||
void endFrame() override;
|
||||
|
||||
/**
|
||||
* @brief 呈现帧
|
||||
*/
|
||||
void present() override;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染状态
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
*/
|
||||
void setViewport(int x, int y, int width, int height) override;
|
||||
|
||||
/**
|
||||
* @brief 设置裁剪区域
|
||||
*/
|
||||
void setScissor(int x, int y, int width, int height) override;
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用裁剪测试
|
||||
*/
|
||||
void setScissorEnabled(bool enabled) override;
|
||||
|
||||
/**
|
||||
* @brief 设置投影矩阵
|
||||
*/
|
||||
void setProjectionMatrix(const glm::mat4 &matrix) override;
|
||||
|
||||
/**
|
||||
* @brief 设置视图矩阵
|
||||
*/
|
||||
void setViewMatrix(const glm::mat4 &matrix) override;
|
||||
|
||||
/**
|
||||
* @brief 设置垂直同步
|
||||
*/
|
||||
void setVSync(bool enabled) override;
|
||||
|
||||
/**
|
||||
* @brief 获取垂直同步状态
|
||||
*/
|
||||
bool isVSyncEnabled() const override;
|
||||
|
||||
// ========================================================================
|
||||
// 精灵渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵
|
||||
*/
|
||||
void drawSprite(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect = Rect(0, 0, 1, 1),
|
||||
const Color &color = Colors::White,
|
||||
float rotation = 0.0f, bool flipX = false,
|
||||
bool flipY = false) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵(使用变换矩阵)
|
||||
*/
|
||||
void drawSprite(Ptr<rhi::RHITexture> texture,
|
||||
const glm::mat4 &transform,
|
||||
const Rect &srcRect = Rect(0, 0, 1, 1),
|
||||
const Color &color = Colors::White) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制九宫格精灵
|
||||
*/
|
||||
void draw9Slice(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect, const Vec2 &borderSize,
|
||||
const Color &color = Colors::White) override;
|
||||
|
||||
// ========================================================================
|
||||
// 文本渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制文本
|
||||
*/
|
||||
void drawText(const std::string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color = Colors::White) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制文本(UTF-32)
|
||||
*/
|
||||
void drawText(const std::u32string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color = Colors::White) override;
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸
|
||||
*/
|
||||
Vec2 measureText(const std::string &text, float fontSize) override;
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸(UTF-32)
|
||||
*/
|
||||
Vec2 measureText(const std::u32string &text, float fontSize) override;
|
||||
|
||||
// ========================================================================
|
||||
// 形状渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制矩形
|
||||
*/
|
||||
void drawRect(const Rect &rect, const Color &color,
|
||||
float lineWidth = 1.0f) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充矩形
|
||||
*/
|
||||
void fillRect(const Rect &rect, const Color &color) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制圆形
|
||||
*/
|
||||
void drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
float lineWidth = 1.0f, uint32_t segments = 32) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充圆形
|
||||
*/
|
||||
void fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
uint32_t segments = 32) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制线段
|
||||
*/
|
||||
void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
||||
float lineWidth = 1.0f) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制多边形
|
||||
*/
|
||||
void drawPolygon(const Vec2 *points, size_t count, const Color &color,
|
||||
float lineWidth = 1.0f) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充多边形
|
||||
*/
|
||||
void fillPolygon(const Vec2 *points, size_t count,
|
||||
const Color &color) override;
|
||||
|
||||
// ========================================================================
|
||||
// 批处理控制
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始精灵批处理
|
||||
*/
|
||||
void beginSpriteBatch() override;
|
||||
|
||||
/**
|
||||
* @brief 结束精灵批处理
|
||||
*/
|
||||
void endSpriteBatch() override;
|
||||
|
||||
/**
|
||||
* @brief 刷新当前批次
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
/**
|
||||
* @brief 设置渲染排序键
|
||||
*/
|
||||
void setSortKey(uint64_t key) override;
|
||||
|
||||
/**
|
||||
* @brief 设置渲染层
|
||||
*/
|
||||
void setLayer(int layer) override;
|
||||
|
||||
/**
|
||||
* @brief 设置混合模式
|
||||
*/
|
||||
void setBlendMode(rhi::BlendState blend) override;
|
||||
|
||||
// ========================================================================
|
||||
// 访问器
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取 RHI 设备
|
||||
*/
|
||||
rhi::RHIDevice *getDevice() const override;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口宽度
|
||||
*/
|
||||
int getWidth() const override;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口高度
|
||||
*/
|
||||
int getHeight() const override;
|
||||
|
||||
/**
|
||||
* @brief 获取渲染统计
|
||||
*/
|
||||
const RenderStats &getStats() const override;
|
||||
|
||||
/**
|
||||
* @brief 重置渲染统计
|
||||
*/
|
||||
void resetStats() override;
|
||||
|
||||
/**
|
||||
* @brief 获取图形 API 类型
|
||||
*/
|
||||
rhi::GraphicsAPI getAPI() const override;
|
||||
|
||||
/**
|
||||
* @brief 获取设备能力
|
||||
*/
|
||||
const rhi::DeviceCaps &getCaps() const override;
|
||||
|
||||
private:
|
||||
bool initialized_ = false;
|
||||
IWindow *window_ = nullptr;
|
||||
RenderBackendConfig config_;
|
||||
RenderStats stats_;
|
||||
|
||||
Ptr<rhi::RHIDevice> device_;
|
||||
glm::mat4 projectionMatrix_ = glm::mat4(1.0f);
|
||||
glm::mat4 viewMatrix_ = glm::mat4(1.0f);
|
||||
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
|
||||
uint64_t sortKey_ = 0;
|
||||
int layer_ = 0;
|
||||
rhi::BlendState blendState_ = rhi::BlendState::alphaBlend();
|
||||
bool inBatch_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -3,9 +3,7 @@
|
|||
#include <extra2d/render/rhi/rhi_device.h>
|
||||
#include <extra2d/render/rhi/rhi_framebuffer.h>
|
||||
#include <glad/glad.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -20,180 +18,193 @@ namespace rhi {
|
|||
*/
|
||||
class GLRHIDevice : public RHIDevice {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
GLRHIDevice();
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
GLRHIDevice();
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~GLRHIDevice() override;
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~GLRHIDevice() override;
|
||||
|
||||
// ========================================================================
|
||||
// 生命周期
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 生命周期
|
||||
// ========================================================================
|
||||
|
||||
bool init(IWindow* window) override;
|
||||
void shutdown() override;
|
||||
bool isValid() const override { return initialized_; }
|
||||
GraphicsAPI getAPI() const override { return GraphicsAPI::OpenGL; }
|
||||
const DeviceCaps& getCaps() const override { return caps_; }
|
||||
bool init(IWindow *window) override;
|
||||
void shutdown() override;
|
||||
bool isValid() const override { return initialized_; }
|
||||
GraphicsAPI getAPI() const override { return GraphicsAPI::OpenGL; }
|
||||
const DeviceCaps &getCaps() const override { return caps_; }
|
||||
|
||||
// ========================================================================
|
||||
// 帧管理
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 帧管理
|
||||
// ========================================================================
|
||||
|
||||
void beginFrame() override;
|
||||
void endFrame() override;
|
||||
void present() override;
|
||||
void setVSync(bool enabled) override;
|
||||
bool isVSyncEnabled() const override { return vsyncEnabled_; }
|
||||
void setDefaultFramebufferSize(uint32_t width, uint32_t height) override;
|
||||
void beginFrame() override;
|
||||
void endFrame() override;
|
||||
void present() override;
|
||||
void setVSync(bool enabled) override;
|
||||
bool isVSyncEnabled() const override { return vsyncEnabled_; }
|
||||
void setDefaultFramebufferSize(uint32_t width, uint32_t height) override;
|
||||
|
||||
// ========================================================================
|
||||
// 资源创建 - 缓冲区
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 资源创建 - 缓冲区
|
||||
// ========================================================================
|
||||
|
||||
Ptr<RHIBuffer> createBuffer(const BufferDesc& desc) override;
|
||||
Ptr<RHIVertexBuffer> createVertexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
|
||||
const void* data = nullptr) override;
|
||||
Ptr<RHIIndexBuffer> createIndexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
|
||||
const void* data = nullptr) override;
|
||||
Ptr<RHIUniformBuffer> createUniformBuffer(size_t size, BufferUsage usage = BufferUsage::Dynamic) override;
|
||||
Ptr<RHIBuffer> createBuffer(const BufferDesc &desc) override;
|
||||
Ptr<RHIVertexBuffer>
|
||||
createVertexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
|
||||
const void *data = nullptr) override;
|
||||
Ptr<RHIIndexBuffer> createIndexBuffer(size_t size,
|
||||
BufferUsage usage = BufferUsage::Static,
|
||||
const void *data = nullptr) override;
|
||||
Ptr<RHIUniformBuffer>
|
||||
createUniformBuffer(size_t size,
|
||||
BufferUsage usage = BufferUsage::Dynamic) override;
|
||||
|
||||
// ========================================================================
|
||||
// 资源创建 - 纹理
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 资源创建 - 纹理
|
||||
// ========================================================================
|
||||
|
||||
Ptr<RHITexture> createTexture(const TextureDesc& desc) override;
|
||||
Ptr<RHITexture> createTexture2D(uint32_t width, uint32_t height, Format format,
|
||||
const void* data = nullptr) override;
|
||||
Ptr<RHISampler> createSampler(const SamplerDesc& desc) override;
|
||||
Ptr<RHITextureView> createTextureView(Ptr<RHITexture> texture, const TextureViewDesc& desc) override;
|
||||
Ptr<RHITexture> createTexture(const TextureDesc &desc) override;
|
||||
Ptr<RHITexture> createTexture2D(uint32_t width, uint32_t height,
|
||||
Format format,
|
||||
const void *data = nullptr) override;
|
||||
Ptr<RHISampler> createSampler(const SamplerDesc &desc) override;
|
||||
Ptr<RHITextureView> createTextureView(Ptr<RHITexture> texture,
|
||||
const TextureViewDesc &desc) override;
|
||||
|
||||
// ========================================================================
|
||||
// 资源创建 - 着色器
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 资源创建 - 着色器
|
||||
// ========================================================================
|
||||
|
||||
Ptr<RHIShader> createShader(const ShaderDesc& desc) override;
|
||||
Ptr<RHIShader> createShaderFromSource(const std::string& name,
|
||||
const std::string& vertexSource,
|
||||
const std::string& fragmentSource) override;
|
||||
Ptr<RHIShader> createShaderFromFile(const std::string& vertexPath,
|
||||
const std::string& fragmentPath) override;
|
||||
Ptr<RHIShader> createShader(const ShaderDesc &desc) override;
|
||||
Ptr<RHIShader>
|
||||
createShaderFromSource(const std::string &name,
|
||||
const std::string &vertexSource,
|
||||
const std::string &fragmentSource) override;
|
||||
Ptr<RHIShader> createShaderFromFile(const std::string &vertexPath,
|
||||
const std::string &fragmentPath) override;
|
||||
|
||||
// ========================================================================
|
||||
// 资源创建 - 管线
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 资源创建 - 管线
|
||||
// ========================================================================
|
||||
|
||||
Ptr<RHIPipeline> createPipeline(const PipelineDesc& desc, Ptr<RHIShader> shader) override;
|
||||
Ptr<RHIPipeline> createPipeline(const PipelineBuilder& builder) override;
|
||||
Ptr<RHIPipeline> createPipeline(const PipelineDesc &desc,
|
||||
Ptr<RHIShader> shader) override;
|
||||
Ptr<RHIPipeline> createPipeline(const PipelineBuilder &builder) override;
|
||||
|
||||
// ========================================================================
|
||||
// 资源创建 - 帧缓冲
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 资源创建 - 帧缓冲
|
||||
// ========================================================================
|
||||
|
||||
Ptr<RHIFramebuffer> createFramebuffer(const FramebufferDesc& desc) override;
|
||||
Ptr<RHIFramebuffer> createFramebuffer(const FramebufferBuilder& builder) override;
|
||||
Ptr<RHIFramebuffer> createFramebuffer(const FramebufferDesc &desc) override;
|
||||
Ptr<RHIFramebuffer>
|
||||
createFramebuffer(const FramebufferBuilder &builder) override;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染状态设置
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 渲染状态设置
|
||||
// ========================================================================
|
||||
|
||||
void setViewport(const Viewport& viewport) override;
|
||||
void setScissorRect(const ScissorRect& rect) override;
|
||||
void setScissorEnabled(bool enabled) override;
|
||||
void setViewport(const Viewport &viewport) override;
|
||||
void setScissorRect(const ScissorRect &rect) override;
|
||||
void setScissorEnabled(bool enabled) override;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染命令 - 绑定资源
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 渲染命令 - 绑定资源
|
||||
// ========================================================================
|
||||
|
||||
void setPipeline(Ptr<RHIPipeline> pipeline) override;
|
||||
void setShader(Ptr<RHIShader> shader) override;
|
||||
void setVertexBuffer(uint32_t slot, Ptr<RHIBuffer> buffer, uint32_t offset = 0) override;
|
||||
void setIndexBuffer(Ptr<RHIBuffer> buffer, IndexFormat format) override;
|
||||
void setTexture(uint32_t slot, Ptr<RHITexture> texture, Ptr<RHISampler> sampler = nullptr) override;
|
||||
void setUniformBuffer(uint32_t slot, Ptr<RHIBuffer> buffer) override;
|
||||
void setFramebuffer(Ptr<RHIFramebuffer> framebuffer) override;
|
||||
void setDefaultFramebuffer() override;
|
||||
void setPipeline(Ptr<RHIPipeline> pipeline) override;
|
||||
void setShader(Ptr<RHIShader> shader) override;
|
||||
void setVertexBuffer(uint32_t slot, Ptr<RHIBuffer> buffer,
|
||||
uint32_t offset = 0) override;
|
||||
void setIndexBuffer(Ptr<RHIBuffer> buffer, IndexFormat format) override;
|
||||
void setTexture(uint32_t slot, Ptr<RHITexture> texture,
|
||||
Ptr<RHISampler> sampler = nullptr) override;
|
||||
void setUniformBuffer(uint32_t slot, Ptr<RHIBuffer> buffer) override;
|
||||
void setFramebuffer(Ptr<RHIFramebuffer> framebuffer) override;
|
||||
void setDefaultFramebuffer() override;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染命令 - Uniform 设置
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 渲染命令 - Uniform 设置
|
||||
// ========================================================================
|
||||
|
||||
void setUniformFloat(const std::string& name, float value) override;
|
||||
void setUniformVec2(const std::string& name, const glm::vec2& value) override;
|
||||
void setUniformVec3(const std::string& name, const glm::vec3& value) override;
|
||||
void setUniformVec4(const std::string& name, const glm::vec4& value) override;
|
||||
void setUniformMat4(const std::string& name, const glm::mat4& value) override;
|
||||
void setUniformInt(const std::string& name, int value) override;
|
||||
void setUniformFloat(const std::string &name, float value) override;
|
||||
void setUniformVec2(const std::string &name, const glm::vec2 &value) override;
|
||||
void setUniformVec3(const std::string &name, const glm::vec3 &value) override;
|
||||
void setUniformVec4(const std::string &name, const glm::vec4 &value) override;
|
||||
void setUniformMat4(const std::string &name, const glm::mat4 &value) override;
|
||||
void setUniformInt(const std::string &name, int value) override;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染命令 - 绘制
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 渲染命令 - 绘制
|
||||
// ========================================================================
|
||||
|
||||
void draw(const DrawCommand& cmd) override;
|
||||
void drawIndexed(const DrawIndexedCommand& cmd) override;
|
||||
void drawIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) override;
|
||||
void drawIndexedIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) override;
|
||||
void draw(const DrawCommand &cmd) override;
|
||||
void drawIndexed(const DrawIndexedCommand &cmd) override;
|
||||
void drawIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) override;
|
||||
void drawIndexedIndirect(Ptr<RHIBuffer> indirectBuffer,
|
||||
size_t offset) override;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染命令 - 清除
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 渲染命令 - 清除
|
||||
// ========================================================================
|
||||
|
||||
void clearColor(const ColorValue& color) override;
|
||||
void clearDepth(float depth = 1.0f) override;
|
||||
void clearStencil(uint8_t stencil = 0) override;
|
||||
void clear(const ColorValue& color, float depth = 1.0f, uint8_t stencil = 0) override;
|
||||
void clearColor(const ColorValue &color) override;
|
||||
void clearDepth(float depth = 1.0f) override;
|
||||
void clearStencil(uint8_t stencil = 0) override;
|
||||
void clear(const ColorValue &color, float depth = 1.0f,
|
||||
uint8_t stencil = 0) override;
|
||||
|
||||
// ========================================================================
|
||||
// 统计与调试
|
||||
// ========================================================================
|
||||
// ========================================================================
|
||||
// 统计与调试
|
||||
// ========================================================================
|
||||
|
||||
const DeviceStats& getStats() const override { return stats_; }
|
||||
void resetStats() override;
|
||||
bool checkError() override;
|
||||
const std::string& getDebugName() const override { return debugName_; }
|
||||
void setDebugName(const std::string& name) override { debugName_ = name; }
|
||||
const DeviceStats &getStats() const override { return stats_; }
|
||||
void resetStats() override;
|
||||
bool checkError() override;
|
||||
const std::string &getDebugName() const override { return debugName_; }
|
||||
void setDebugName(const std::string &name) override { debugName_ = name; }
|
||||
|
||||
private:
|
||||
bool initialized_ = false;
|
||||
bool vsyncEnabled_ = true;
|
||||
IWindow* window_ = nullptr;
|
||||
DeviceCaps caps_;
|
||||
DeviceStats stats_;
|
||||
std::string debugName_;
|
||||
bool initialized_ = false;
|
||||
bool vsyncEnabled_ = true;
|
||||
IWindow *window_ = nullptr;
|
||||
DeviceCaps caps_;
|
||||
DeviceStats stats_;
|
||||
std::string debugName_;
|
||||
|
||||
// 当前绑定的资源
|
||||
Ptr<RHIPipeline> currentPipeline_;
|
||||
Ptr<RHIShader> currentShader_;
|
||||
Ptr<RHIFramebuffer> currentFramebuffer_;
|
||||
IndexFormat currentIndexFormat_ = IndexFormat::UInt16;
|
||||
// 当前绑定的资源
|
||||
Ptr<RHIPipeline> currentPipeline_;
|
||||
Ptr<RHIShader> currentShader_;
|
||||
Ptr<RHIFramebuffer> currentFramebuffer_;
|
||||
IndexFormat currentIndexFormat_ = IndexFormat::UInt16;
|
||||
|
||||
// 默认帧缓冲尺寸
|
||||
uint32_t defaultFBWidth_ = 0;
|
||||
uint32_t defaultFBHeight_ = 0;
|
||||
// 默认帧缓冲尺寸
|
||||
uint32_t defaultFBWidth_ = 0;
|
||||
uint32_t defaultFBHeight_ = 0;
|
||||
|
||||
// 裁剪测试状态
|
||||
bool scissorEnabled_ = false;
|
||||
// 裁剪测试状态
|
||||
bool scissorEnabled_ = false;
|
||||
|
||||
/**
|
||||
* @brief 初始化设备能力
|
||||
*/
|
||||
void initCaps();
|
||||
/**
|
||||
* @brief 初始化设备能力
|
||||
*/
|
||||
void initCaps();
|
||||
|
||||
/**
|
||||
* @brief 设置默认状态
|
||||
*/
|
||||
void setDefaultState();
|
||||
/**
|
||||
* @brief 设置默认状态
|
||||
*/
|
||||
void setDefaultState();
|
||||
|
||||
/**
|
||||
* @brief 应用管线状态
|
||||
*/
|
||||
void applyPipelineState(const BlendState& blend,
|
||||
const DepthStencilState& depthStencil,
|
||||
const RasterizerState& rasterizer);
|
||||
/**
|
||||
* @brief 应用管线状态
|
||||
*/
|
||||
void applyPipelineState(const BlendState &blend,
|
||||
const DepthStencilState &depthStencil,
|
||||
const RasterizerState &rasterizer);
|
||||
};
|
||||
|
||||
} // namespace rhi
|
||||
|
|
|
|||
|
|
@ -0,0 +1,230 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class ViewportAdapter;
|
||||
|
||||
/**
|
||||
* @brief 相机类
|
||||
*
|
||||
* 2D 相机,支持平移、缩放、旋转和边界限制
|
||||
*/
|
||||
class Camera {
|
||||
public:
|
||||
Camera();
|
||||
Camera(float left, float right, float bottom, float top);
|
||||
~Camera() = default;
|
||||
|
||||
// ========================================================================
|
||||
// 视口设置
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
*/
|
||||
void setViewport(float left, float right, float bottom, float top);
|
||||
|
||||
/**
|
||||
* @brief 设置视口尺寸
|
||||
*/
|
||||
void setViewportSize(float width, float height);
|
||||
|
||||
/**
|
||||
* @brief 获取视口
|
||||
*/
|
||||
Rect getViewport() const;
|
||||
|
||||
/**
|
||||
* @brief 获取视口宽度
|
||||
*/
|
||||
float getViewportWidth() const { return right_ - left_; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口高度
|
||||
*/
|
||||
float getViewportHeight() const { return top_ - bottom_; }
|
||||
|
||||
// ========================================================================
|
||||
// 位置和变换
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置位置
|
||||
*/
|
||||
void setPos(const Vec2& position);
|
||||
void setPos(float x, float y);
|
||||
|
||||
/**
|
||||
* @brief 获取位置
|
||||
*/
|
||||
Vec2 getPosition() const { return position_; }
|
||||
|
||||
/**
|
||||
* @brief 移动相机
|
||||
*/
|
||||
void move(const Vec2& offset);
|
||||
void move(float x, float y);
|
||||
|
||||
/**
|
||||
* @brief 设置旋转角度(度)
|
||||
*/
|
||||
void setRotation(float degrees);
|
||||
|
||||
/**
|
||||
* @brief 获取旋转角度(度)
|
||||
*/
|
||||
float getRotation() const { return rotation_; }
|
||||
|
||||
/**
|
||||
* @brief 旋转相机
|
||||
*/
|
||||
void rotate(float degrees);
|
||||
|
||||
/**
|
||||
* @brief 设置缩放
|
||||
*/
|
||||
void setZoom(float zoom);
|
||||
|
||||
/**
|
||||
* @brief 获取缩放
|
||||
*/
|
||||
float getZoom() const { return zoom_; }
|
||||
|
||||
/**
|
||||
* @brief 缩放相机
|
||||
*/
|
||||
void zoomBy(float factor);
|
||||
|
||||
// ========================================================================
|
||||
// 边界限制
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置边界
|
||||
*/
|
||||
void setBounds(const Rect& bounds);
|
||||
|
||||
/**
|
||||
* @brief 清除边界
|
||||
*/
|
||||
void clearBounds();
|
||||
|
||||
/**
|
||||
* @brief 获取边界
|
||||
*/
|
||||
Rect getBounds() const { return bounds_; }
|
||||
|
||||
/**
|
||||
* @brief 是否有边界限制
|
||||
*/
|
||||
bool hasBounds() const { return hasBounds_; }
|
||||
|
||||
// ========================================================================
|
||||
// 矩阵
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取视图矩阵
|
||||
*/
|
||||
glm::mat4 getViewMatrix() const;
|
||||
|
||||
/**
|
||||
* @brief 获取投影矩阵
|
||||
*/
|
||||
glm::mat4 getProjectionMatrix() const;
|
||||
|
||||
/**
|
||||
* @brief 获取视图投影矩阵
|
||||
*/
|
||||
glm::mat4 getViewProjectionMatrix() const;
|
||||
|
||||
/**
|
||||
* @brief 更新矩阵
|
||||
*/
|
||||
void updateMatrices();
|
||||
|
||||
// ========================================================================
|
||||
// 坐标转换
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 屏幕坐标转世界坐标
|
||||
*/
|
||||
Vec2 screenToWorld(const Vec2& screenPos) const;
|
||||
|
||||
/**
|
||||
* @brief 世界坐标转屏幕坐标
|
||||
*/
|
||||
Vec2 worldToScreen(const Vec2& worldPos) const;
|
||||
|
||||
/**
|
||||
* @brief 注视目标
|
||||
*/
|
||||
void lookAt(const Vec2& target);
|
||||
|
||||
// ========================================================================
|
||||
// 视口适配器
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口适配器
|
||||
*/
|
||||
void setViewportAdapter(ViewportAdapter* adapter) { viewportAdapter_ = adapter; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口适配器
|
||||
*/
|
||||
ViewportAdapter* getViewportAdapter() const { return viewportAdapter_; }
|
||||
|
||||
/**
|
||||
* @brief 应用视口适配器
|
||||
*/
|
||||
void applyViewportAdapter();
|
||||
|
||||
// ========================================================================
|
||||
// 调试
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取调试名称
|
||||
*/
|
||||
const std::string& getDebugName() const { return debugName_; }
|
||||
|
||||
/**
|
||||
* @brief 设置调试名称
|
||||
*/
|
||||
void setDebugName(const std::string& name) { debugName_ = name; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 应用边界限制
|
||||
*/
|
||||
void applyBounds();
|
||||
|
||||
Vec2 position_;
|
||||
float rotation_;
|
||||
float zoom_;
|
||||
|
||||
float left_;
|
||||
float right_;
|
||||
float bottom_;
|
||||
float top_;
|
||||
|
||||
Rect bounds_;
|
||||
bool hasBounds_;
|
||||
|
||||
glm::mat4 viewMatrix_;
|
||||
glm::mat4 projectionMatrix_;
|
||||
glm::mat4 viewProjectionMatrix_;
|
||||
bool matricesDirty_;
|
||||
|
||||
ViewportAdapter* viewportAdapter_;
|
||||
std::string debugName_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
#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
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 渲染后端工厂
|
||||
*
|
||||
* 管理渲染后端的注册和创建
|
||||
* 支持多后端(OpenGL、Vulkan、DirectX 等)
|
||||
*/
|
||||
class BackendFactory {
|
||||
public:
|
||||
/**
|
||||
* @brief 后端创建函数类型
|
||||
*/
|
||||
using BackendFn = std::function<UniquePtr<RenderBackend>()>;
|
||||
|
||||
/**
|
||||
* @brief 后端注册信息
|
||||
*/
|
||||
struct BackendInfo {
|
||||
std::string name;
|
||||
BackendFn createFn;
|
||||
std::vector<std::string> compatibleWindowBackends;
|
||||
rhi::GraphicsAPI api;
|
||||
std::string description;
|
||||
int priority;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 注册渲染后端
|
||||
* @param name 后端名称(如 "opengl", "vulkan")
|
||||
* @param backend 后端创建函数
|
||||
* @param windowBackends 兼容的窗口后端列表
|
||||
* @param api 图形 API 类型
|
||||
* @param description 后端描述
|
||||
* @param priority 优先级(用于默认选择)
|
||||
*/
|
||||
static void reg(const std::string& name,
|
||||
BackendFn backend,
|
||||
const std::vector<std::string>& windowBackends = {},
|
||||
rhi::GraphicsAPI api = rhi::GraphicsAPI::OpenGL,
|
||||
const std::string& description = "",
|
||||
int priority = 0);
|
||||
|
||||
/**
|
||||
* @brief 注销渲染后端
|
||||
* @param name 后端名称
|
||||
*/
|
||||
static void unreg(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 创建渲染后端
|
||||
* @param name 后端名称
|
||||
* @return 后端实例,失败返回 nullptr
|
||||
*/
|
||||
static UniquePtr<RenderBackend> createBackend(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 创建默认渲染后端
|
||||
*
|
||||
* 按优先级选择最佳可用后端
|
||||
* @return 后端实例,失败返回 nullptr
|
||||
*/
|
||||
static UniquePtr<RenderBackend> createDefaultBackend();
|
||||
|
||||
/**
|
||||
* @brief 根据窗口后端创建兼容的渲染后端
|
||||
* @param windowBackend 窗口后端名称
|
||||
* @return 后端实例,失败返回 nullptr
|
||||
*/
|
||||
static UniquePtr<RenderBackend> createBackendForWindow(const std::string& windowBackend);
|
||||
|
||||
/**
|
||||
* @brief 根据图形 API 创建后端
|
||||
* @param api 图形 API 类型
|
||||
* @return 后端实例,失败返回 nullptr
|
||||
*/
|
||||
static UniquePtr<RenderBackend> createBackendForAPI(rhi::GraphicsAPI api);
|
||||
|
||||
/**
|
||||
* @brief 检查后端是否已注册
|
||||
* @param name 后端名称
|
||||
*/
|
||||
static bool hasBackend(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 获取所有已注册的后端名称
|
||||
*/
|
||||
static std::vector<std::string> getBackendNames();
|
||||
|
||||
/**
|
||||
* @brief 获取后端信息
|
||||
* @param name 后端名称
|
||||
* @return 后端信息,不存在返回 nullptr
|
||||
*/
|
||||
static const BackendInfo* getBackendInfo(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 获取所有后端信息
|
||||
*/
|
||||
static std::vector<BackendInfo> getAllBackendInfos();
|
||||
|
||||
/**
|
||||
* @brief 获取兼容指定窗口后端的所有渲染后端
|
||||
* @param windowBackend 窗口后端名称
|
||||
*/
|
||||
static std::vector<std::string> getCompatibleBackends(const std::string& windowBackend);
|
||||
|
||||
/**
|
||||
* @brief 清除所有注册的后端
|
||||
*/
|
||||
static void clear();
|
||||
|
||||
/**
|
||||
* @brief 获取默认后端名称
|
||||
*/
|
||||
static std::string getDefaultBackendName();
|
||||
|
||||
/**
|
||||
* @brief 设置默认后端名称
|
||||
*/
|
||||
static void setDefaultBackendName(const std::string& name);
|
||||
|
||||
private:
|
||||
static std::unordered_map<std::string, BackendInfo>& getRegistry();
|
||||
static std::mutex& getMutex();
|
||||
static std::string& getDefaultName();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 后端自动注册器
|
||||
*
|
||||
* 用于静态初始化时自动注册后端
|
||||
*/
|
||||
class BackendRegistrar {
|
||||
public:
|
||||
BackendRegistrar(const std::string& name,
|
||||
BackendFactory::BackendFn backend,
|
||||
const std::vector<std::string>& windowBackends = {},
|
||||
rhi::GraphicsAPI api = rhi::GraphicsAPI::OpenGL,
|
||||
const std::string& description = "",
|
||||
int priority = 0) {
|
||||
BackendFactory::reg(name, backend, windowBackends, api, description, priority);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 渲染后端注册宏
|
||||
*
|
||||
* 使用方法:
|
||||
* E2D_REG_RENDER_BACKEND(opengl, GLRenderBackend, {"sdl2", "glfw"})
|
||||
*/
|
||||
#define E2D_REG_RENDER_BACKEND(name, BackendClass, windowBackends) \
|
||||
static ::extra2d::BackendRegistrar E2D_CONCAT(backend_reg_, name)( \
|
||||
#name, \
|
||||
[]() -> ::extra2d::UniquePtr<::extra2d::RenderBackend> { \
|
||||
return ::extra2d::makeUnique<BackendClass>(); \
|
||||
}, \
|
||||
windowBackends)
|
||||
|
||||
/**
|
||||
* @brief 渲染后端注册宏(带优先级)
|
||||
*/
|
||||
#define E2D_REG_RENDER_BACKEND_EX(name, BackendClass, windowBackends, api, desc, prio) \
|
||||
static ::extra2d::BackendRegistrar E2D_CONCAT(backend_reg_, name)( \
|
||||
#name, \
|
||||
[]() -> ::extra2d::UniquePtr<::extra2d::RenderBackend> { \
|
||||
return ::extra2d::makeUnique<BackendClass>(); \
|
||||
}, \
|
||||
windowBackends, api, desc, prio)
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,324 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/render/rhi/rhi_device.h>
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class IWindow;
|
||||
|
||||
/**
|
||||
* @brief 渲染统计信息
|
||||
*/
|
||||
struct RenderStats {
|
||||
uint32_t drawCalls = 0;
|
||||
uint32_t spriteCount = 0;
|
||||
uint32_t textCharCount = 0;
|
||||
uint32_t shapeCount = 0;
|
||||
uint32_t batchCount = 0;
|
||||
uint32_t textureBinds = 0;
|
||||
uint32_t shaderBinds = 0;
|
||||
|
||||
void reset() {
|
||||
drawCalls = 0;
|
||||
spriteCount = 0;
|
||||
textCharCount = 0;
|
||||
shapeCount = 0;
|
||||
batchCount = 0;
|
||||
textureBinds = 0;
|
||||
shaderBinds = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 渲染后端配置
|
||||
*/
|
||||
struct RenderBackendConfig {
|
||||
rhi::GraphicsAPI api = rhi::GraphicsAPI::OpenGL;
|
||||
bool vsync = true;
|
||||
uint32_t maxBatchSize = 10000;
|
||||
bool enableDebug = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 高层渲染后端接口
|
||||
*
|
||||
* 封装 RHI 层,提供游戏逻辑使用的简化渲染接口
|
||||
* 支持精灵、文本、形状等高层渲染功能
|
||||
*/
|
||||
class RenderBackend {
|
||||
public:
|
||||
virtual ~RenderBackend() = default;
|
||||
|
||||
// ========================================================================
|
||||
// 生命周期
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 初始化渲染后端
|
||||
* @param window 窗口接口
|
||||
* @param config 配置参数
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
virtual bool init(IWindow *window,
|
||||
const RenderBackendConfig &config = {}) = 0;
|
||||
|
||||
/**
|
||||
* @brief 关闭渲染后端
|
||||
*/
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
*/
|
||||
virtual bool isValid() const = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 帧管理
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始帧渲染
|
||||
* @param clearColor 清屏颜色
|
||||
*/
|
||||
virtual void beginFrame(const Color &clearColor = Colors::Black) = 0;
|
||||
|
||||
/**
|
||||
* @brief 结束帧渲染
|
||||
*/
|
||||
virtual void endFrame() = 0;
|
||||
|
||||
/**
|
||||
* @brief 呈现帧
|
||||
*/
|
||||
virtual void present() = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染状态
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
*/
|
||||
virtual void setViewport(int x, int y, int width, int height) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置裁剪区域
|
||||
*/
|
||||
virtual void setScissor(int x, int y, int width, int height) = 0;
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用裁剪测试
|
||||
*/
|
||||
virtual void setScissorEnabled(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置投影矩阵
|
||||
*/
|
||||
virtual void setProjectionMatrix(const glm::mat4 &matrix) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置视图矩阵
|
||||
*/
|
||||
virtual void setViewMatrix(const glm::mat4 &matrix) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置垂直同步
|
||||
*/
|
||||
virtual void setVSync(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取垂直同步状态
|
||||
*/
|
||||
virtual bool isVSyncEnabled() const = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 精灵渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵
|
||||
* @param texture 纹理
|
||||
* @param destRect 目标矩形
|
||||
* @param srcRect 源矩形(纹理坐标)
|
||||
* @param color 颜色调制
|
||||
* @param rotation 旋转角度(度)
|
||||
* @param flipX 水平翻转
|
||||
* @param flipY 垂直翻转
|
||||
*/
|
||||
virtual void drawSprite(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect = Rect(0, 0, 1, 1),
|
||||
const Color &color = Colors::White,
|
||||
float rotation = 0.0f, bool flipX = false,
|
||||
bool flipY = false) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵(使用变换矩阵)
|
||||
*/
|
||||
virtual void drawSprite(Ptr<rhi::RHITexture> texture,
|
||||
const glm::mat4 &transform,
|
||||
const Rect &srcRect = Rect(0, 0, 1, 1),
|
||||
const Color &color = Colors::White) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制九宫格精灵
|
||||
*/
|
||||
virtual void draw9Slice(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect, const Vec2 &borderSize,
|
||||
const Color &color = Colors::White) = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 文本渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制文本
|
||||
* @param text UTF-8 编码文本
|
||||
* @param position 位置
|
||||
* @param fontSize 字体大小
|
||||
* @param color 颜色
|
||||
*/
|
||||
virtual void drawText(const std::string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color = Colors::White) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制文本(UTF-32)
|
||||
*/
|
||||
virtual void drawText(const std::u32string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color = Colors::White) = 0;
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸
|
||||
*/
|
||||
virtual Vec2 measureText(const std::string &text, float fontSize) = 0;
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸(UTF-32)
|
||||
*/
|
||||
virtual Vec2 measureText(const std::u32string &text, float fontSize) = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 形状渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制矩形
|
||||
*/
|
||||
virtual void drawRect(const Rect &rect, const Color &color,
|
||||
float lineWidth = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充矩形
|
||||
*/
|
||||
virtual void fillRect(const Rect &rect, const Color &color) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制圆形
|
||||
*/
|
||||
virtual void drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
float lineWidth = 1.0f, uint32_t segments = 32) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充圆形
|
||||
*/
|
||||
virtual void fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
uint32_t segments = 32) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制线段
|
||||
*/
|
||||
virtual void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
||||
float lineWidth = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制多边形
|
||||
*/
|
||||
virtual void drawPolygon(const Vec2 *points, size_t count, const Color &color,
|
||||
float lineWidth = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充多边形
|
||||
*/
|
||||
virtual void fillPolygon(const Vec2 *points, size_t count,
|
||||
const Color &color) = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 批处理控制
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始精灵批处理
|
||||
*/
|
||||
virtual void beginSpriteBatch() = 0;
|
||||
|
||||
/**
|
||||
* @brief 结束精灵批处理
|
||||
*/
|
||||
virtual void endSpriteBatch() = 0;
|
||||
|
||||
/**
|
||||
* @brief 刷新当前批次
|
||||
*/
|
||||
virtual void flush() = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置渲染排序键
|
||||
*/
|
||||
virtual void setSortKey(uint64_t key) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置渲染层
|
||||
*/
|
||||
virtual void setLayer(int layer) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置混合模式
|
||||
*/
|
||||
virtual void setBlendMode(rhi::BlendState blend) = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 访问器
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取 RHI 设备
|
||||
*/
|
||||
virtual rhi::RHIDevice *getDevice() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口宽度
|
||||
*/
|
||||
virtual int getWidth() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口高度
|
||||
*/
|
||||
virtual int getHeight() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取渲染统计
|
||||
*/
|
||||
virtual const RenderStats &getStats() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 重置渲染统计
|
||||
*/
|
||||
virtual void resetStats() = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取图形 API 类型
|
||||
*/
|
||||
virtual rhi::GraphicsAPI getAPI() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取设备能力
|
||||
*/
|
||||
virtual const rhi::DeviceCaps &getCaps() const = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -30,6 +30,7 @@ enum class RenderCommandType : uint8_t {
|
|||
* @brief 形状类型枚举
|
||||
*/
|
||||
enum class ShapeType : uint8_t {
|
||||
Point,
|
||||
Line,
|
||||
Rect,
|
||||
FilledRect,
|
||||
|
|
|
|||
|
|
@ -3,64 +3,30 @@
|
|||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_queue.h>
|
||||
#include <extra2d/render/rhi/rhi_device.h>
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class IWindow;
|
||||
|
||||
/**
|
||||
* @brief 渲染统计信息
|
||||
*/
|
||||
struct RenderStats {
|
||||
uint32_t drawCalls;
|
||||
uint32_t batchCount;
|
||||
uint32_t vertexCount;
|
||||
uint32_t triangleCount;
|
||||
uint32_t spriteCount;
|
||||
uint32_t textCount;
|
||||
uint32_t shapeCount;
|
||||
float frameTime;
|
||||
float renderTime;
|
||||
|
||||
RenderStats()
|
||||
: drawCalls(0), batchCount(0), vertexCount(0), triangleCount(0),
|
||||
spriteCount(0), textCount(0), shapeCount(0), frameTime(0.0f), renderTime(0.0f) {}
|
||||
|
||||
void reset() {
|
||||
drawCalls = 0;
|
||||
batchCount = 0;
|
||||
vertexCount = 0;
|
||||
triangleCount = 0;
|
||||
spriteCount = 0;
|
||||
textCount = 0;
|
||||
shapeCount = 0;
|
||||
frameTime = 0.0f;
|
||||
renderTime = 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 渲染上下文配置
|
||||
*/
|
||||
struct RenderContextConfig {
|
||||
uint32_t maxBatchSize;
|
||||
bool enableBatching;
|
||||
bool enableScissor;
|
||||
bool enableStats;
|
||||
rhi::GraphicsAPI preferredAPI;
|
||||
uint32_t maxBatchSize;
|
||||
bool enableBatching;
|
||||
bool enableScissor;
|
||||
bool enableStats;
|
||||
rhi::GraphicsAPI preferredAPI;
|
||||
|
||||
RenderContextConfig()
|
||||
: maxBatchSize(10000),
|
||||
enableBatching(true),
|
||||
enableScissor(true),
|
||||
enableStats(true),
|
||||
preferredAPI(rhi::GraphicsAPI::OpenGL) {}
|
||||
RenderContextConfig()
|
||||
: maxBatchSize(10000), enableBatching(true), enableScissor(true),
|
||||
enableStats(true), preferredAPI(rhi::GraphicsAPI::OpenGL) {}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -70,150 +36,150 @@ struct RenderContextConfig {
|
|||
*/
|
||||
class RenderContext {
|
||||
public:
|
||||
static constexpr uint32_t DEFAULT_MAX_BATCH_SIZE = 10000;
|
||||
static constexpr uint32_t DEFAULT_MAX_BATCH_SIZE = 10000;
|
||||
|
||||
RenderContext();
|
||||
explicit RenderContext(const RenderContextConfig& config);
|
||||
~RenderContext();
|
||||
RenderContext();
|
||||
explicit RenderContext(const RenderContextConfig &config);
|
||||
~RenderContext();
|
||||
|
||||
/**
|
||||
* @brief 初始化渲染上下文
|
||||
*/
|
||||
bool init(IWindow* window);
|
||||
bool init(IWindow* window, rhi::GraphicsAPI api);
|
||||
/**
|
||||
* @brief 初始化渲染上下文
|
||||
*/
|
||||
bool init(IWindow *window);
|
||||
bool init(IWindow *window, rhi::GraphicsAPI api);
|
||||
|
||||
/**
|
||||
* @brief 关闭渲染上下文
|
||||
*/
|
||||
void shutdown();
|
||||
/**
|
||||
* @brief 关闭渲染上下文
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief 检查是否有效
|
||||
*/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* @brief 检查是否有效
|
||||
*/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* @brief 开始帧
|
||||
*/
|
||||
void beginFrame();
|
||||
/**
|
||||
* @brief 开始帧
|
||||
*/
|
||||
void beginFrame();
|
||||
|
||||
/**
|
||||
* @brief 结束帧
|
||||
*/
|
||||
void endFrame();
|
||||
/**
|
||||
* @brief 结束帧
|
||||
*/
|
||||
void endFrame();
|
||||
|
||||
/**
|
||||
* @brief 呈现帧
|
||||
*/
|
||||
void present();
|
||||
/**
|
||||
* @brief 呈现帧
|
||||
*/
|
||||
void present();
|
||||
|
||||
/**
|
||||
* @brief 清除屏幕
|
||||
*/
|
||||
void clear(const Color& color = Colors::Black);
|
||||
void clear(const Color& color, float depth, uint8_t stencil = 0);
|
||||
/**
|
||||
* @brief 清除屏幕
|
||||
*/
|
||||
void clear(const Color &color = Colors::Black);
|
||||
void clear(const Color &color, float depth, uint8_t stencil = 0);
|
||||
|
||||
/**
|
||||
* @brief 获取/设置视口
|
||||
*/
|
||||
void setViewport(const rhi::Viewport& viewport);
|
||||
void setViewport(float x, float y, float width, float height);
|
||||
rhi::Viewport getViewport() const;
|
||||
/**
|
||||
* @brief 获取/设置视口
|
||||
*/
|
||||
void setViewport(const rhi::Viewport &viewport);
|
||||
void setViewport(float x, float y, float width, float height);
|
||||
rhi::Viewport getViewport() const;
|
||||
|
||||
/**
|
||||
* @brief 获取/设置裁剪区域
|
||||
*/
|
||||
void setScissorRect(const rhi::ScissorRect& rect);
|
||||
void setScissorRect(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
void setScissorEnabled(bool enabled);
|
||||
rhi::ScissorRect getScissorRect() const;
|
||||
/**
|
||||
* @brief 获取/设置裁剪区域
|
||||
*/
|
||||
void setScissorRect(const rhi::ScissorRect &rect);
|
||||
void setScissorRect(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
void setScissorEnabled(bool enabled);
|
||||
rhi::ScissorRect getScissorRect() const;
|
||||
|
||||
/**
|
||||
* @brief 变换矩阵栈操作
|
||||
*/
|
||||
void pushTransform(const glm::mat4& transform);
|
||||
void popTransform();
|
||||
void resetTransform();
|
||||
glm::mat4 getCurrentTransform() const;
|
||||
/**
|
||||
* @brief 变换矩阵栈操作
|
||||
*/
|
||||
void pushTransform(const glm::mat4 &transform);
|
||||
void popTransform();
|
||||
void resetTransform();
|
||||
glm::mat4 getCurrentTransform() const;
|
||||
|
||||
/**
|
||||
* @brief 混合状态操作
|
||||
*/
|
||||
void setBlendState(const rhi::BlendState& blend);
|
||||
rhi::BlendState getBlendState() const;
|
||||
void pushBlendState(const rhi::BlendState& blend);
|
||||
void popBlendState();
|
||||
/**
|
||||
* @brief 混合状态操作
|
||||
*/
|
||||
void setBlendState(const rhi::BlendState &blend);
|
||||
rhi::BlendState getBlendState() const;
|
||||
void pushBlendState(const rhi::BlendState &blend);
|
||||
void popBlendState();
|
||||
|
||||
/**
|
||||
* @brief 渲染队列操作
|
||||
*/
|
||||
RenderQueue& getQueue() { return queue_; }
|
||||
const RenderQueue& getQueue() const { return queue_; }
|
||||
void clearQueue();
|
||||
/**
|
||||
* @brief 渲染队列操作
|
||||
*/
|
||||
RenderQueue &getQueue() { return queue_; }
|
||||
const RenderQueue &getQueue() const { return queue_; }
|
||||
void clearQueue();
|
||||
|
||||
/**
|
||||
* @brief 提交渲染队列
|
||||
*/
|
||||
void flushQueue();
|
||||
/**
|
||||
* @brief 提交渲染队列
|
||||
*/
|
||||
void flushQueue();
|
||||
|
||||
/**
|
||||
* @brief 获取 RHI 设备
|
||||
*/
|
||||
Ptr<rhi::RHIDevice> getDevice() const { return device_; }
|
||||
/**
|
||||
* @brief 获取 RHI 设备
|
||||
*/
|
||||
Ptr<rhi::RHIDevice> getDevice() const { return device_; }
|
||||
|
||||
/**
|
||||
* @brief 获取窗口
|
||||
*/
|
||||
IWindow* getWindow() const { return window_; }
|
||||
/**
|
||||
* @brief 获取窗口
|
||||
*/
|
||||
IWindow *getWindow() const { return window_; }
|
||||
|
||||
/**
|
||||
* @brief 获取统计信息
|
||||
*/
|
||||
const RenderStats& getStats() const { return stats_; }
|
||||
void resetStats();
|
||||
/**
|
||||
* @brief 获取统计信息
|
||||
*/
|
||||
const RenderStats &getStats() const { return stats_; }
|
||||
void resetStats();
|
||||
|
||||
/**
|
||||
* @brief 获取配置
|
||||
*/
|
||||
const RenderContextConfig& getConfig() const { return config_; }
|
||||
void setConfig(const RenderContextConfig& config);
|
||||
/**
|
||||
* @brief 获取配置
|
||||
*/
|
||||
const RenderContextConfig &getConfig() const { return config_; }
|
||||
void setConfig(const RenderContextConfig &config);
|
||||
|
||||
/**
|
||||
* @brief 获取帧缓冲尺寸
|
||||
*/
|
||||
uint32_t getFramebufferWidth() const { return fbWidth_; }
|
||||
uint32_t getFramebufferHeight() const { return fbHeight_; }
|
||||
/**
|
||||
* @brief 获取帧缓冲尺寸
|
||||
*/
|
||||
uint32_t getFramebufferWidth() const { return fbWidth_; }
|
||||
uint32_t getFramebufferHeight() const { return fbHeight_; }
|
||||
|
||||
/**
|
||||
* @brief 设置垂直同步
|
||||
*/
|
||||
void setVSync(bool enabled);
|
||||
bool isVSyncEnabled() const;
|
||||
/**
|
||||
* @brief 设置垂直同步
|
||||
*/
|
||||
void setVSync(bool enabled);
|
||||
bool isVSyncEnabled() const;
|
||||
|
||||
/**
|
||||
* @brief 设置默认帧缓冲尺寸
|
||||
*/
|
||||
void setDefaultFramebufferSize(uint32_t width, uint32_t height);
|
||||
/**
|
||||
* @brief 设置默认帧缓冲尺寸
|
||||
*/
|
||||
void setDefaultFramebufferSize(uint32_t width, uint32_t height);
|
||||
|
||||
private:
|
||||
void initDefaultState();
|
||||
void initDefaultState();
|
||||
|
||||
Ptr<rhi::RHIDevice> device_;
|
||||
IWindow* window_;
|
||||
RenderQueue queue_;
|
||||
RenderStats stats_;
|
||||
RenderContextConfig config_;
|
||||
Ptr<rhi::RHIDevice> device_;
|
||||
IWindow *window_;
|
||||
RenderQueue queue_;
|
||||
RenderStats stats_;
|
||||
RenderContextConfig config_;
|
||||
|
||||
std::stack<glm::mat4> transformStack_;
|
||||
std::stack<rhi::BlendState> blendStack_;
|
||||
rhi::BlendState currentBlend_;
|
||||
rhi::Viewport viewport_;
|
||||
rhi::ScissorRect scissorRect_;
|
||||
bool scissorEnabled_;
|
||||
std::stack<glm::mat4> transformStack_;
|
||||
std::stack<rhi::BlendState> blendStack_;
|
||||
rhi::BlendState currentBlend_;
|
||||
rhi::Viewport viewport_;
|
||||
rhi::ScissorRect scissorRect_;
|
||||
bool scissorEnabled_;
|
||||
|
||||
uint32_t fbWidth_;
|
||||
uint32_t fbHeight_;
|
||||
bool initialized_;
|
||||
uint32_t fbWidth_;
|
||||
uint32_t fbHeight_;
|
||||
bool initialized_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -0,0 +1,145 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/module.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class IWindow;
|
||||
class Renderer;
|
||||
|
||||
/**
|
||||
* @brief 渲染模块配置
|
||||
*/
|
||||
struct RenderModuleConfig {
|
||||
rhi::GraphicsAPI api = rhi::GraphicsAPI::OpenGL;
|
||||
bool vsync = true;
|
||||
uint32_t maxBatchSize = 10000;
|
||||
bool enableDebug = false;
|
||||
float designWidth = 1280.0f;
|
||||
float designHeight = 720.0f;
|
||||
|
||||
RenderModuleConfig() = default;
|
||||
|
||||
/**
|
||||
* @brief 创建 OpenGL 配置
|
||||
*/
|
||||
static RenderModuleConfig opengl() {
|
||||
RenderModuleConfig config;
|
||||
config.api = rhi::GraphicsAPI::OpenGL;
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建 HD 配置 (1280x720)
|
||||
*/
|
||||
static RenderModuleConfig hd() {
|
||||
RenderModuleConfig config;
|
||||
config.designWidth = 1280.0f;
|
||||
config.designHeight = 720.0f;
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建 Full HD 配置 (1920x1080)
|
||||
*/
|
||||
static RenderModuleConfig fullHd() {
|
||||
RenderModuleConfig config;
|
||||
config.designWidth = 1920.0f;
|
||||
config.designHeight = 1080.0f;
|
||||
return config;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 渲染模块
|
||||
*
|
||||
* 作为 Module 集成到 Application 中
|
||||
* 管理渲染器的生命周期
|
||||
*/
|
||||
class RenderModule : public Module {
|
||||
public:
|
||||
RenderModule();
|
||||
explicit RenderModule(const RenderModuleConfig& config);
|
||||
~RenderModule() override;
|
||||
|
||||
// ========================================================================
|
||||
// Module 接口实现
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 初始化模块
|
||||
*/
|
||||
bool init() override;
|
||||
|
||||
/**
|
||||
* @brief 关闭模块
|
||||
*/
|
||||
void shutdown() override;
|
||||
|
||||
/**
|
||||
* @brief 检查模块是否就绪
|
||||
*/
|
||||
bool ok() const override { return initialized_; }
|
||||
|
||||
/**
|
||||
* @brief 获取模块名称
|
||||
*/
|
||||
const char* name() const override { return "RenderModule"; }
|
||||
|
||||
/**
|
||||
* @brief 获取模块优先级
|
||||
*/
|
||||
int priority() const override { return 10; }
|
||||
|
||||
/**
|
||||
* @brief 获取模块依赖
|
||||
*/
|
||||
std::vector<std::type_index> deps() const override;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染器访问
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取渲染器
|
||||
*/
|
||||
class Renderer* getRenderer() const { return renderer_.get(); }
|
||||
|
||||
/**
|
||||
* @brief 获取渲染器(智能指针)
|
||||
*/
|
||||
Ptr<Renderer> getRendererPtr() const { return renderer_; }
|
||||
|
||||
// ========================================================================
|
||||
// 配置
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取配置
|
||||
*/
|
||||
const RenderModuleConfig& getConfig() const { return config_; }
|
||||
|
||||
/**
|
||||
* @brief 设置配置
|
||||
*/
|
||||
void setConfig(const RenderModuleConfig& config);
|
||||
|
||||
// ========================================================================
|
||||
// 静态工厂
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 创建渲染模块
|
||||
*/
|
||||
static Ptr<RenderModule> create(const RenderModuleConfig& config = {});
|
||||
|
||||
private:
|
||||
RenderModuleConfig config_;
|
||||
Ptr<Renderer> renderer_;
|
||||
bool initialized_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,326 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/module.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/render/batch/shape_batcher.h>
|
||||
#include <extra2d/render/batch/sprite_batcher.h>
|
||||
#include <extra2d/render/batch/text_batcher.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/camera/viewport_adapter.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_context.h>
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class IWindow;
|
||||
class Scene;
|
||||
|
||||
/**
|
||||
* @brief 渲染器配置
|
||||
*/
|
||||
struct RendererConfig {
|
||||
rhi::GraphicsAPI api = rhi::GraphicsAPI::OpenGL;
|
||||
bool vsync = true;
|
||||
uint32_t maxBatchSize = 10000;
|
||||
bool enableDebug = false;
|
||||
ViewportConfig viewportConfig;
|
||||
|
||||
RendererConfig() = default;
|
||||
|
||||
/**
|
||||
* @brief 创建 OpenGL 配置
|
||||
*/
|
||||
static RendererConfig opengl() {
|
||||
RendererConfig config;
|
||||
config.api = rhi::GraphicsAPI::OpenGL;
|
||||
return config;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 高层渲染器
|
||||
*
|
||||
* 整合渲染后端、批处理器和相机系统
|
||||
* 提供统一的渲染接口供游戏逻辑使用
|
||||
*/
|
||||
class Renderer : public Module {
|
||||
public:
|
||||
Renderer();
|
||||
explicit Renderer(const RendererConfig &config);
|
||||
~Renderer() override;
|
||||
|
||||
// ========================================================================
|
||||
// Module 接口实现
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 初始化渲染器
|
||||
*/
|
||||
bool init() override;
|
||||
|
||||
/**
|
||||
* @brief 关闭渲染器
|
||||
*/
|
||||
void shutdown() override;
|
||||
|
||||
/**
|
||||
* @brief 检查渲染器是否就绪
|
||||
*/
|
||||
bool ok() const override { return initialized_; }
|
||||
|
||||
/**
|
||||
* @brief 获取模块名称
|
||||
*/
|
||||
const char *name() const override { return "Renderer"; }
|
||||
|
||||
/**
|
||||
* @brief 获取模块优先级
|
||||
*/
|
||||
int priority() const override { return 10; }
|
||||
|
||||
// ========================================================================
|
||||
// 初始化
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 使用窗口初始化
|
||||
*/
|
||||
bool init(IWindow *window);
|
||||
|
||||
/**
|
||||
* @brief 使用窗口和配置初始化
|
||||
*/
|
||||
bool init(IWindow *window, const RendererConfig &config);
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
*/
|
||||
bool isInitialized() const { return initialized_; }
|
||||
|
||||
// ========================================================================
|
||||
// 帧管理
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始帧渲染
|
||||
*/
|
||||
void beginFrame(const Color &clearColor = Colors::Black);
|
||||
|
||||
/**
|
||||
* @brief 结束帧渲染
|
||||
*/
|
||||
void endFrame();
|
||||
|
||||
/**
|
||||
* @brief 呈现帧
|
||||
*/
|
||||
void present();
|
||||
|
||||
// ========================================================================
|
||||
// 场景渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 渲染场景
|
||||
*/
|
||||
void renderScene(Scene *scene);
|
||||
|
||||
/**
|
||||
* @brief 渲染场景(指定相机)
|
||||
*/
|
||||
void renderScene(Scene *scene, Camera *camera);
|
||||
|
||||
// ========================================================================
|
||||
// 相机系统
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置活动相机
|
||||
*/
|
||||
void setActiveCamera(Ptr<Camera> camera);
|
||||
|
||||
/**
|
||||
* @brief 获取活动相机
|
||||
*/
|
||||
Ptr<Camera> getActiveCamera() const;
|
||||
|
||||
/**
|
||||
* @brief 获取默认相机
|
||||
*/
|
||||
Ptr<Camera> getDefaultCamera() const { return defaultCamera_; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口适配器
|
||||
*/
|
||||
ViewportAdapter &getViewportAdapter() { return viewportAdapter_; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口适配器(const)
|
||||
*/
|
||||
const ViewportAdapter &getViewportAdapter() const { return viewportAdapter_; }
|
||||
|
||||
// ========================================================================
|
||||
// 渲染状态
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
*/
|
||||
void setViewport(int x, int y, int width, int height);
|
||||
|
||||
/**
|
||||
* @brief 设置裁剪区域
|
||||
*/
|
||||
void setScissor(int x, int y, int width, int height);
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用裁剪测试
|
||||
*/
|
||||
void setScissorEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* @brief 设置垂直同步
|
||||
*/
|
||||
void setVSync(bool enabled);
|
||||
|
||||
/**
|
||||
* @brief 获取垂直同步状态
|
||||
*/
|
||||
bool isVSyncEnabled() const;
|
||||
|
||||
// ========================================================================
|
||||
// 批处理器访问
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取精灵批处理器
|
||||
*/
|
||||
SpriteBatcher *getSpriteBatcher() const { return spriteBatcher_.get(); }
|
||||
|
||||
/**
|
||||
* @brief 获取形状批处理器
|
||||
*/
|
||||
ShapeBatcher *getShapeBatcher() const { return shapeBatcher_.get(); }
|
||||
|
||||
/**
|
||||
* @brief 获取文本批处理器
|
||||
*/
|
||||
TextBatcher *getTextBatcher() const { return textBatcher_.get(); }
|
||||
|
||||
// ========================================================================
|
||||
// 渲染上下文
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取渲染上下文
|
||||
*/
|
||||
RenderContext *getContext() const { return context_.get(); }
|
||||
|
||||
/**
|
||||
* @brief 获取渲染后端
|
||||
*/
|
||||
RenderBackend *getBackend() const { return backend_.get(); }
|
||||
|
||||
/**
|
||||
* @brief 获取 RHI 设备
|
||||
*/
|
||||
rhi::RHIDevice *getDevice() const;
|
||||
|
||||
// ========================================================================
|
||||
// 统计信息
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取渲染统计
|
||||
*/
|
||||
const RenderStats &getStats() const;
|
||||
|
||||
/**
|
||||
* @brief 重置统计
|
||||
*/
|
||||
void resetStats();
|
||||
|
||||
// ========================================================================
|
||||
// 配置
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取配置
|
||||
*/
|
||||
const RendererConfig &getConfig() const { return config_; }
|
||||
|
||||
/**
|
||||
* @brief 设置配置
|
||||
*/
|
||||
void setConfig(const RendererConfig &config);
|
||||
|
||||
// ========================================================================
|
||||
// 窗口信息
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取窗口宽度
|
||||
*/
|
||||
int getWidth() const { return width_; }
|
||||
|
||||
/**
|
||||
* @brief 获取窗口高度
|
||||
*/
|
||||
int getHeight() const { return height_; }
|
||||
|
||||
/**
|
||||
* @brief 获取窗口
|
||||
*/
|
||||
IWindow *getWindow() const { return window_; }
|
||||
|
||||
// ========================================================================
|
||||
// 静态工厂
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 创建渲染器
|
||||
*/
|
||||
static Ptr<Renderer> create(const RendererConfig &config = {});
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 创建批处理器
|
||||
*/
|
||||
bool createBatchers();
|
||||
|
||||
/**
|
||||
* @brief 创建默认相机
|
||||
*/
|
||||
void createDefaultCamera();
|
||||
|
||||
/**
|
||||
* @brief 更新视口适配器
|
||||
*/
|
||||
void updateViewportAdapter();
|
||||
|
||||
/**
|
||||
* @brief 应用相机变换
|
||||
*/
|
||||
void applyCameraTransform(Camera *camera);
|
||||
|
||||
IWindow *window_;
|
||||
RendererConfig config_;
|
||||
|
||||
UniquePtr<RenderContext> context_;
|
||||
UniquePtr<RenderBackend> backend_;
|
||||
UniquePtr<SpriteBatcher> spriteBatcher_;
|
||||
UniquePtr<ShapeBatcher> shapeBatcher_;
|
||||
UniquePtr<TextBatcher> textBatcher_;
|
||||
|
||||
ViewportAdapter viewportAdapter_;
|
||||
Ptr<Camera> activeCamera_;
|
||||
Ptr<Camera> defaultCamera_;
|
||||
|
||||
int width_;
|
||||
int height_;
|
||||
bool initialized_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/render/rhi/rhi_texture.h>
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 纹理过滤模式
|
||||
*/
|
||||
enum class TextureFilter {
|
||||
Nearest,
|
||||
Linear,
|
||||
NearestMipmapNearest,
|
||||
LinearMipmapNearest,
|
||||
NearestMipmapLinear,
|
||||
LinearMipmapLinear
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 纹理寻址模式
|
||||
*/
|
||||
enum class TextureWrap {
|
||||
Repeat,
|
||||
MirroredRepeat,
|
||||
ClampToEdge,
|
||||
ClampToBorder
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 纹理配置
|
||||
*/
|
||||
struct TextureConfig {
|
||||
TextureFilter minFilter = TextureFilter::Linear;
|
||||
TextureFilter magFilter = TextureFilter::Linear;
|
||||
TextureWrap wrapU = TextureWrap::ClampToEdge;
|
||||
TextureWrap wrapV = TextureWrap::ClampToEdge;
|
||||
bool generateMipmaps = true;
|
||||
bool premultipliedAlpha = false;
|
||||
|
||||
TextureConfig() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 纹理类
|
||||
*
|
||||
* 封装 RHI 纹理,提供高层纹理管理功能
|
||||
*/
|
||||
class Texture {
|
||||
public:
|
||||
Texture();
|
||||
explicit Texture(Ptr<rhi::RHITexture> rhiTexture);
|
||||
~Texture() = default;
|
||||
|
||||
// ========================================================================
|
||||
// 工厂方法
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 从文件加载纹理
|
||||
*/
|
||||
static Ptr<Texture> load(const std::string& path, const TextureConfig& config = {});
|
||||
|
||||
/**
|
||||
* @brief 从内存创建纹理
|
||||
*/
|
||||
static Ptr<Texture> create(uint32_t width, uint32_t height,
|
||||
const void* data = nullptr,
|
||||
rhi::Format format = rhi::Format::RGBA8_UNORM,
|
||||
const TextureConfig& config = {});
|
||||
|
||||
/**
|
||||
* @brief 创建纯色纹理
|
||||
*/
|
||||
static Ptr<Texture> createSolidColor(uint32_t width, uint32_t height, const Color& color);
|
||||
|
||||
// ========================================================================
|
||||
// 属性
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取宽度
|
||||
*/
|
||||
uint32_t getWidth() const { return width_; }
|
||||
|
||||
/**
|
||||
* @brief 获取高度
|
||||
*/
|
||||
uint32_t getHeight() const { return height_; }
|
||||
|
||||
/**
|
||||
* @brief 获取尺寸
|
||||
*/
|
||||
Size getSize() const { return Size(static_cast<float>(width_), static_cast<float>(height_)); }
|
||||
|
||||
/**
|
||||
* @brief 获取格式
|
||||
*/
|
||||
rhi::Format getFormat() const { return format_; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否有效
|
||||
*/
|
||||
bool isValid() const { return rhiTexture_ != nullptr; }
|
||||
|
||||
/**
|
||||
* @brief 获取 RHI 纹理
|
||||
*/
|
||||
Ptr<rhi::RHITexture> getRHITexture() const { return rhiTexture_; }
|
||||
|
||||
// ========================================================================
|
||||
// 数据操作
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 更新纹理数据
|
||||
*/
|
||||
bool updateData(const void* data, uint32_t x = 0, uint32_t y = 0,
|
||||
uint32_t width = 0, uint32_t height = 0);
|
||||
|
||||
/**
|
||||
* @brief 获取纹理数据
|
||||
*/
|
||||
std::vector<uint8_t> getData() const;
|
||||
|
||||
// ========================================================================
|
||||
// 配置
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置过滤模式
|
||||
*/
|
||||
void setFilter(TextureFilter minFilter, TextureFilter magFilter);
|
||||
|
||||
/**
|
||||
* @brief 设置寻址模式
|
||||
*/
|
||||
void setWrap(TextureWrap wrapU, TextureWrap wrapV);
|
||||
|
||||
/**
|
||||
* @brief 生成 Mipmap
|
||||
*/
|
||||
void generateMipmaps();
|
||||
|
||||
// ========================================================================
|
||||
// 路径
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取源文件路径
|
||||
*/
|
||||
const std::string& getPath() const { return path_; }
|
||||
|
||||
/**
|
||||
* @brief 设置源文件路径
|
||||
*/
|
||||
void setPath(const std::string& path) { path_ = path; }
|
||||
|
||||
// ========================================================================
|
||||
// 调试
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取调试名称
|
||||
*/
|
||||
const std::string& getDebugName() const { return debugName_; }
|
||||
|
||||
/**
|
||||
* @brief 设置调试名称
|
||||
*/
|
||||
void setDebugName(const std::string& name) { debugName_ = name; }
|
||||
|
||||
private:
|
||||
Ptr<rhi::RHITexture> rhiTexture_;
|
||||
uint32_t width_ = 0;
|
||||
uint32_t height_ = 0;
|
||||
rhi::Format format_ = rhi::Format::RGBA8_UNORM;
|
||||
std::string path_;
|
||||
std::string debugName_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -16,182 +16,182 @@ class RenderQueue;
|
|||
*/
|
||||
class Scene : public Node {
|
||||
public:
|
||||
Scene();
|
||||
~Scene() override = default;
|
||||
Scene();
|
||||
~Scene() override = default;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 场景属性
|
||||
// -------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// 场景属性
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 设置背景颜色
|
||||
* @param color 背景颜色
|
||||
*/
|
||||
void setBackgroundColor(const Color& color) { backgroundColor_ = color; }
|
||||
/**
|
||||
* @brief 设置背景颜色
|
||||
* @param color 背景颜色
|
||||
*/
|
||||
void setBackgroundColor(const Color &color) { backgroundColor_ = color; }
|
||||
|
||||
/**
|
||||
* @brief 获取背景颜色
|
||||
* @return 背景颜色
|
||||
*/
|
||||
Color getBackgroundColor() const { return backgroundColor_; }
|
||||
/**
|
||||
* @brief 获取背景颜色
|
||||
* @return 背景颜色
|
||||
*/
|
||||
Color getBackgroundColor() const { return backgroundColor_; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 摄像机
|
||||
// -------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// 摄像机
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 设置场景相机
|
||||
* @param camera 相机智能指针
|
||||
*/
|
||||
void setCamera(Ptr<Camera> camera);
|
||||
/**
|
||||
* @brief 设置场景相机
|
||||
* @param camera 相机智能指针
|
||||
*/
|
||||
void setCamera(Ptr<Camera> camera);
|
||||
|
||||
/**
|
||||
* @brief 获取场景相机
|
||||
* @return 相机智能指针
|
||||
*/
|
||||
Ptr<Camera> getCamera() const { return camera_; }
|
||||
/**
|
||||
* @brief 获取场景相机
|
||||
* @return 相机智能指针
|
||||
*/
|
||||
Ptr<Camera> getCamera() const { return camera_; }
|
||||
|
||||
/**
|
||||
* @brief 获取活动相机
|
||||
* @return 活动相机指针(优先返回设置的相机,否则返回默认相机)
|
||||
*/
|
||||
Camera* getActiveCamera() const {
|
||||
return camera_ ? camera_.get() : defaultCamera_.get();
|
||||
}
|
||||
/**
|
||||
* @brief 获取活动相机
|
||||
* @return 活动相机指针(优先返回设置的相机,否则返回默认相机)
|
||||
*/
|
||||
Camera *getActiveCamera() const {
|
||||
return camera_ ? camera_.get() : defaultCamera_.get();
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 视口和尺寸
|
||||
// -------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// 视口和尺寸
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 设置视口大小
|
||||
* @param width 视口宽度
|
||||
* @param height 视口高度
|
||||
*/
|
||||
void setViewportSize(float width, float height);
|
||||
/**
|
||||
* @brief 设置视口大小
|
||||
* @param width 视口宽度
|
||||
* @param height 视口高度
|
||||
*/
|
||||
void setViewportSize(float width, float height);
|
||||
|
||||
/**
|
||||
* @brief 设置视口大小
|
||||
* @param size 视口尺寸结构体
|
||||
*/
|
||||
void setViewportSize(const Size& size);
|
||||
/**
|
||||
* @brief 设置视口大小
|
||||
* @param size 视口尺寸结构体
|
||||
*/
|
||||
void setViewportSize(const Size &size);
|
||||
|
||||
/**
|
||||
* @brief 获取视口大小
|
||||
* @return 视口尺寸
|
||||
*/
|
||||
Size getViewportSize() const { return viewportSize_; }
|
||||
/**
|
||||
* @brief 获取视口大小
|
||||
* @return 视口尺寸
|
||||
*/
|
||||
Size getViewportSize() const { return viewportSize_; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口宽度
|
||||
* @return 视口宽度
|
||||
*/
|
||||
float getWidth() const { return viewportSize_.width; }
|
||||
/**
|
||||
* @brief 获取视口宽度
|
||||
* @return 视口宽度
|
||||
*/
|
||||
float getWidth() const { return viewportSize_.width; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口高度
|
||||
* @return 视口高度
|
||||
*/
|
||||
float getHeight() const { return viewportSize_.height; }
|
||||
/**
|
||||
* @brief 获取视口高度
|
||||
* @return 视口高度
|
||||
*/
|
||||
float getHeight() const { return viewportSize_.height; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 场景状态
|
||||
// -------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// 场景状态
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 检查场景是否暂停
|
||||
* @return 如果场景暂停返回true
|
||||
*/
|
||||
bool isPaused() const { return paused_; }
|
||||
/**
|
||||
* @brief 检查场景是否暂停
|
||||
* @return 如果场景暂停返回true
|
||||
*/
|
||||
bool isPaused() const { return paused_; }
|
||||
|
||||
/**
|
||||
* @brief 暂停场景
|
||||
*/
|
||||
void pause() { paused_ = true; }
|
||||
/**
|
||||
* @brief 暂停场景
|
||||
*/
|
||||
void pause() { paused_ = true; }
|
||||
|
||||
/**
|
||||
* @brief 恢复场景
|
||||
*/
|
||||
void resume() { paused_ = false; }
|
||||
/**
|
||||
* @brief 恢复场景
|
||||
*/
|
||||
void resume() { paused_ = false; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 渲染和更新
|
||||
// -------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// 渲染和更新
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 渲染场景
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
void renderScene(RenderBackend& renderer);
|
||||
/**
|
||||
* @brief 渲染场景
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
void renderScene(RenderBackend &renderer);
|
||||
|
||||
/**
|
||||
* @brief 渲染场景内容
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
virtual void renderContent(RenderBackend& renderer);
|
||||
/**
|
||||
* @brief 渲染场景内容
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
virtual void renderContent(RenderBackend &renderer);
|
||||
|
||||
/**
|
||||
* @brief 更新场景
|
||||
* @param dt 帧间隔时间(秒)
|
||||
*/
|
||||
void updateScene(float dt);
|
||||
/**
|
||||
* @brief 更新场景
|
||||
* @param dt 帧间隔时间(秒)
|
||||
*/
|
||||
void updateScene(float dt);
|
||||
|
||||
/**
|
||||
* @brief 收集渲染命令
|
||||
* @param commands 渲染命令输出向量
|
||||
* @param parentZOrder 父节点的Z序
|
||||
*/
|
||||
void collectRenderCommands(std::vector<RenderCommand>& commands,
|
||||
int parentZOrder = 0) override;
|
||||
/**
|
||||
* @brief 收集渲染命令
|
||||
* @param commands 渲染命令输出向量
|
||||
* @param parentZOrder 父节点的Z序
|
||||
*/
|
||||
void collectRenderCommands(std::vector<RenderCommand> &commands,
|
||||
int parentZOrder = 0) override;
|
||||
|
||||
/**
|
||||
* @brief 收集渲染命令到队列
|
||||
* @param queue 渲染队列引用
|
||||
*/
|
||||
void collectRenderCommandsToQueue(RenderQueue& queue) override;
|
||||
/**
|
||||
* @brief 收集渲染命令到队列
|
||||
* @param queue 渲染队列引用
|
||||
*/
|
||||
void collectRenderCommandsToQueue(RenderQueue &queue) override;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 静态创建方法
|
||||
// -------------------------------------------------------------------------
|
||||
// -------------------------------------------------------------------------
|
||||
// 静态创建方法
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief 创建场景对象
|
||||
* @return 新创建的场景智能指针
|
||||
*/
|
||||
static Ptr<Scene> create();
|
||||
/**
|
||||
* @brief 创建场景对象
|
||||
* @return 新创建的场景智能指针
|
||||
*/
|
||||
static Ptr<Scene> create();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 场景进入时的回调
|
||||
*/
|
||||
void onEnter() override;
|
||||
/**
|
||||
* @brief 场景进入时的回调
|
||||
*/
|
||||
void onEnter() override;
|
||||
|
||||
/**
|
||||
* @brief 场景退出时的回调
|
||||
*/
|
||||
void onExit() override;
|
||||
/**
|
||||
* @brief 场景退出时的回调
|
||||
*/
|
||||
void onExit() override;
|
||||
|
||||
/**
|
||||
* @brief 过渡场景开始时的回调(供 TransitionScene 使用)
|
||||
*/
|
||||
virtual void onExitTransitionDidStart() {}
|
||||
/**
|
||||
* @brief 过渡场景开始时的回调(供 TransitionScene 使用)
|
||||
*/
|
||||
virtual void onExitTransitionDidStart() {}
|
||||
|
||||
/**
|
||||
* @brief 过渡场景结束时的回调(供 TransitionScene 使用)
|
||||
*/
|
||||
virtual void onEnterTransitionDidFinish() {}
|
||||
/**
|
||||
* @brief 过渡场景结束时的回调(供 TransitionScene 使用)
|
||||
*/
|
||||
virtual void onEnterTransitionDidFinish() {}
|
||||
|
||||
friend class SceneManager;
|
||||
friend class TransitionScene;
|
||||
friend class SceneManager;
|
||||
friend class TransitionScene;
|
||||
|
||||
private:
|
||||
Color backgroundColor_ = Colors::Black;
|
||||
Size viewportSize_ = Size::Zero();
|
||||
Color backgroundColor_ = Colors::Black;
|
||||
Size viewportSize_ = Size::Zero();
|
||||
|
||||
Ptr<Camera> camera_;
|
||||
Ptr<Camera> defaultCamera_;
|
||||
Ptr<Camera> camera_;
|
||||
Ptr<Camera> defaultCamera_;
|
||||
|
||||
bool paused_ = false;
|
||||
bool paused_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -2,16 +2,12 @@
|
|||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 形状类型
|
||||
// ============================================================================
|
||||
enum class ShapeType { Point, Line, Rect, Circle, Triangle, Polygon };
|
||||
|
||||
// ============================================================================
|
||||
// 形状节点 - 用于绘制几何形状
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/resources/texture.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/camera/viewport_adapter.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/camera/viewport_adapter.h>
|
||||
#include <functional>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/registry.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_module.h>
|
||||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <extra2d/platform/input_module.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/platform/window_module.h>
|
||||
#include <extra2d/render/camera/viewport_adapter.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_module.h>
|
||||
#include <extra2d/render/renderer.h>
|
||||
#include <extra2d/services/camera_service.h>
|
||||
#include <extra2d/services/event_service.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <extra2d/services/scene_service.h>
|
||||
#include <extra2d/services/timer_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
static double getTimeSeconds() {
|
||||
|
|
@ -81,9 +81,9 @@ void Application::configureCameraService() {
|
|||
static_cast<float>(win->height()), 0);
|
||||
|
||||
ViewportConfig vpConfig;
|
||||
vpConfig.logicWidth = static_cast<float>(win->width());
|
||||
vpConfig.logicHeight = static_cast<float>(win->height());
|
||||
vpConfig.mode = ViewportMode::AspectRatio;
|
||||
vpConfig.designWidth = static_cast<float>(win->width());
|
||||
vpConfig.designHeight = static_cast<float>(win->height());
|
||||
vpConfig.scaleMode = ViewportScaleMode::Letterbox;
|
||||
cameraService->setViewportConfig(vpConfig);
|
||||
cameraService->updateViewport(win->width(), win->height());
|
||||
|
||||
|
|
@ -97,8 +97,6 @@ void Application::shutdown() {
|
|||
if (!initialized_)
|
||||
return;
|
||||
|
||||
VRAMMgr::get().printStats();
|
||||
|
||||
ServiceLocator::instance().shutdownAll();
|
||||
ServiceLocator::instance().clear();
|
||||
Registry::instance().shutdown();
|
||||
|
|
@ -176,8 +174,7 @@ void Application::mainLoop() {
|
|||
|
||||
// 帧率限制
|
||||
auto *renderMod = get<RenderModule>();
|
||||
if (renderMod && renderMod->renderer()) {
|
||||
// 这里可以添加帧率限制逻辑
|
||||
if (renderMod && renderMod->getRenderer()) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -192,29 +189,28 @@ void Application::update() {
|
|||
|
||||
void Application::render() {
|
||||
auto *renderMod = get<RenderModule>();
|
||||
if (!renderMod || !renderMod->renderer())
|
||||
if (!renderMod || !renderMod->getRenderer())
|
||||
return;
|
||||
|
||||
auto *renderer = renderMod->renderer();
|
||||
auto *renderer = renderMod->getRenderer();
|
||||
auto *winMod = get<WindowModule>();
|
||||
if (!winMod || !winMod->win())
|
||||
return;
|
||||
|
||||
auto cameraService = ServiceLocator::instance().getService<ICameraService>();
|
||||
if (cameraService) {
|
||||
const auto &vp = cameraService->getViewportResult().viewport;
|
||||
const auto &vpResult = cameraService->getViewportResult();
|
||||
renderer->setViewport(
|
||||
static_cast<int>(vp.origin.x), static_cast<int>(vp.origin.y),
|
||||
static_cast<int>(vp.size.width), static_cast<int>(vp.size.height));
|
||||
renderer->setViewProjection(cameraService->getViewProjectionMatrix());
|
||||
vpResult.offsetX, vpResult.offsetY,
|
||||
static_cast<int>(vpResult.width), static_cast<int>(vpResult.height));
|
||||
} else {
|
||||
renderer->setViewport(0, 0, winMod->win()->width(),
|
||||
winMod->win()->height());
|
||||
}
|
||||
|
||||
auto sceneService = ServiceLocator::instance().getService<ISceneService>();
|
||||
if (sceneService) {
|
||||
sceneService->render(*renderer);
|
||||
if (sceneService && renderer->getBackend()) {
|
||||
sceneService->render(*renderer->getBackend());
|
||||
}
|
||||
|
||||
winMod->win()->swap();
|
||||
|
|
@ -227,7 +223,7 @@ IWindow *Application::window() {
|
|||
|
||||
RenderBackend *Application::renderer() {
|
||||
auto *renderMod = get<RenderModule>();
|
||||
return renderMod ? renderMod->renderer() : nullptr;
|
||||
return renderMod ? (renderMod->getRenderer() ? renderMod->getRenderer()->getBackend() : nullptr) : nullptr;
|
||||
}
|
||||
|
||||
IInput *Application::input() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
#include <extra2d/render/backends/opengl/gl_context.h>
|
||||
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
GLContext& GLContext::get() {
|
||||
static GLContext instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool GLContext::init() {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!gladLoadGL()) {
|
||||
E2D_LOG_ERROR("Failed to load OpenGL functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
parseVersion();
|
||||
queryCapabilities();
|
||||
|
||||
initialized_ = true;
|
||||
|
||||
E2D_LOG_INFO("OpenGL Context initialized");
|
||||
E2D_LOG_INFO(" Version: {}.{}", version_.major, version_.minor);
|
||||
E2D_LOG_INFO(" Renderer: {}", renderer_);
|
||||
E2D_LOG_INFO(" Vendor: {}", vendor_);
|
||||
E2D_LOG_INFO(" GLSL: {}", glslVersion_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext::shutdown() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
extensions_.clear();
|
||||
initialized_ = false;
|
||||
|
||||
E2D_LOG_INFO("OpenGL Context shutdown");
|
||||
}
|
||||
|
||||
std::string GLContext::getVersionString() const {
|
||||
std::ostringstream oss;
|
||||
oss << version_.major << "." << version_.minor;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
bool GLContext::hasExtension(const std::string& extension) const {
|
||||
return extensions_.find(extension) != extensions_.end();
|
||||
}
|
||||
|
||||
bool GLContext::checkError(const char* operation) {
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR) {
|
||||
if (operation) {
|
||||
E2D_LOG_ERROR("OpenGL error during {}: 0x{:X}", operation, error);
|
||||
} else {
|
||||
E2D_LOG_ERROR("OpenGL error: 0x{:X}", error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext::clearErrors() {
|
||||
while (glGetError() != GL_NO_ERROR) {
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::queryCapabilities() {
|
||||
const char* rendererStr = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
const char* vendorStr = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
const char* glslStr = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
|
||||
renderer_ = rendererStr ? rendererStr : "Unknown";
|
||||
vendor_ = vendorStr ? vendorStr : "Unknown";
|
||||
glslVersion_ = glslStr ? glslStr : "Unknown";
|
||||
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize_);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits_);
|
||||
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs_);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings_);
|
||||
|
||||
GLint numExtensions = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
|
||||
for (GLint i = 0; i < numExtensions; ++i) {
|
||||
const char* ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
|
||||
if (ext) {
|
||||
extensions_.insert(ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::parseVersion() {
|
||||
const char* versionStr = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
||||
if (!versionStr) {
|
||||
version_ = {4, 5};
|
||||
return;
|
||||
}
|
||||
|
||||
int major = 0, minor = 0;
|
||||
const char* ptr = versionStr;
|
||||
|
||||
while (*ptr && (*ptr < '0' || *ptr > '9')) {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (*ptr) {
|
||||
major = std::atoi(ptr);
|
||||
while (*ptr && *ptr != '.') {
|
||||
ptr++;
|
||||
}
|
||||
if (*ptr == '.') {
|
||||
ptr++;
|
||||
minor = std::atoi(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
version_ = {major, minor};
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,521 @@
|
|||
#include <extra2d/render/backends/opengl/gl_render_backend.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <cmath>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
GLRenderBackend::GLRenderBackend()
|
||||
: initialized_(false)
|
||||
, window_(nullptr)
|
||||
, config_()
|
||||
, stats_()
|
||||
, device_(nullptr)
|
||||
, projectionMatrix_(1.0f)
|
||||
, viewMatrix_(1.0f)
|
||||
, width_(0)
|
||||
, height_(0)
|
||||
, sortKey_(0)
|
||||
, layer_(0)
|
||||
, blendState_(rhi::BlendState::alphaBlend())
|
||||
, inBatch_(false) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
GLRenderBackend::~GLRenderBackend() {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 生命周期
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 初始化渲染后端
|
||||
*/
|
||||
bool GLRenderBackend::init(IWindow *window, const RenderBackendConfig &config) {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
window_ = window;
|
||||
config_ = config;
|
||||
width_ = window->width();
|
||||
height_ = window->height();
|
||||
|
||||
device_ = rhi::RHIDevice::create(rhi::GraphicsAPI::OpenGL);
|
||||
if (!device_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!device_->init(window)) {
|
||||
device_.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
projectionMatrix_ = glm::ortho(0.0f, static_cast<float>(width_),
|
||||
static_cast<float>(height_), 0.0f,
|
||||
-1.0f, 1.0f);
|
||||
viewMatrix_ = glm::mat4(1.0f);
|
||||
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭渲染后端
|
||||
*/
|
||||
void GLRenderBackend::shutdown() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (device_) {
|
||||
device_->shutdown();
|
||||
device_.reset();
|
||||
}
|
||||
|
||||
window_ = nullptr;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
initialized_ = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
*/
|
||||
bool GLRenderBackend::isValid() const {
|
||||
return initialized_ && device_ && device_->isValid();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 帧管理
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始帧渲染
|
||||
*/
|
||||
void GLRenderBackend::beginFrame(const Color &clearColor) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.reset();
|
||||
device_->beginFrame();
|
||||
device_->resetStats();
|
||||
|
||||
rhi::ColorValue cv(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
|
||||
device_->clearColor(cv);
|
||||
|
||||
device_->setViewport(rhi::Viewport(0.0f, 0.0f,
|
||||
static_cast<float>(width_),
|
||||
static_cast<float>(height_)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 结束帧渲染
|
||||
*/
|
||||
void GLRenderBackend::endFrame() {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (inBatch_) {
|
||||
endSpriteBatch();
|
||||
}
|
||||
|
||||
device_->endFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 呈现帧
|
||||
*/
|
||||
void GLRenderBackend::present() {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_->present();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 渲染状态
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
*/
|
||||
void GLRenderBackend::setViewport(int x, int y, int width, int height) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_->setViewport(rhi::Viewport(
|
||||
static_cast<float>(x),
|
||||
static_cast<float>(y),
|
||||
static_cast<float>(width),
|
||||
static_cast<float>(height)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置裁剪区域
|
||||
*/
|
||||
void GLRenderBackend::setScissor(int x, int y, int width, int height) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_->setScissorRect(rhi::ScissorRect(x, y,
|
||||
static_cast<uint32_t>(width),
|
||||
static_cast<uint32_t>(height)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用裁剪测试
|
||||
*/
|
||||
void GLRenderBackend::setScissorEnabled(bool enabled) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_->setScissorEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置投影矩阵
|
||||
*/
|
||||
void GLRenderBackend::setProjectionMatrix(const glm::mat4 &matrix) {
|
||||
projectionMatrix_ = matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置视图矩阵
|
||||
*/
|
||||
void GLRenderBackend::setViewMatrix(const glm::mat4 &matrix) {
|
||||
viewMatrix_ = matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置垂直同步
|
||||
*/
|
||||
void GLRenderBackend::setVSync(bool enabled) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_->setVSync(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取垂直同步状态
|
||||
*/
|
||||
bool GLRenderBackend::isVSyncEnabled() const {
|
||||
return isValid() ? device_->isVSyncEnabled() : false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 精灵渲染
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵
|
||||
*/
|
||||
void GLRenderBackend::drawSprite(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect, const Color &color,
|
||||
float rotation, bool flipX, bool flipY) {
|
||||
if (!isValid() || !texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.spriteCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵(使用变换矩阵)
|
||||
*/
|
||||
void GLRenderBackend::drawSprite(Ptr<rhi::RHITexture> texture,
|
||||
const glm::mat4 &transform,
|
||||
const Rect &srcRect, const Color &color) {
|
||||
if (!isValid() || !texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.spriteCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制九宫格精灵
|
||||
*/
|
||||
void GLRenderBackend::draw9Slice(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect, const Vec2 &borderSize,
|
||||
const Color &color) {
|
||||
if (!isValid() || !texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.spriteCount += 9;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 文本渲染
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制文本
|
||||
*/
|
||||
void GLRenderBackend::drawText(const std::string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color) {
|
||||
if (!isValid() || text.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.textCharCount += static_cast<uint32_t>(text.length());
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制文本(UTF-32)
|
||||
*/
|
||||
void GLRenderBackend::drawText(const std::u32string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color) {
|
||||
if (!isValid() || text.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.textCharCount += static_cast<uint32_t>(text.length());
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸
|
||||
*/
|
||||
Vec2 GLRenderBackend::measureText(const std::string &text, float fontSize) {
|
||||
float width = static_cast<float>(text.length()) * fontSize * 0.6f;
|
||||
return Vec2(width, fontSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸(UTF-32)
|
||||
*/
|
||||
Vec2 GLRenderBackend::measureText(const std::u32string &text, float fontSize) {
|
||||
float width = static_cast<float>(text.length()) * fontSize * 0.6f;
|
||||
return Vec2(width, fontSize);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 形状渲染
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制矩形
|
||||
*/
|
||||
void GLRenderBackend::drawRect(const Rect &rect, const Color &color, float lineWidth) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制填充矩形
|
||||
*/
|
||||
void GLRenderBackend::fillRect(const Rect &rect, const Color &color) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制圆形
|
||||
*/
|
||||
void GLRenderBackend::drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
float lineWidth, uint32_t segments) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制填充圆形
|
||||
*/
|
||||
void GLRenderBackend::fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
uint32_t segments) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制线段
|
||||
*/
|
||||
void GLRenderBackend::drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
||||
float lineWidth) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制多边形
|
||||
*/
|
||||
void GLRenderBackend::drawPolygon(const Vec2 *points, size_t count, const Color &color,
|
||||
float lineWidth) {
|
||||
if (!isValid() || !points || count < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制填充多边形
|
||||
*/
|
||||
void GLRenderBackend::fillPolygon(const Vec2 *points, size_t count, const Color &color) {
|
||||
if (!isValid() || !points || count < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 批处理控制
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始精灵批处理
|
||||
*/
|
||||
void GLRenderBackend::beginSpriteBatch() {
|
||||
inBatch_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 结束精灵批处理
|
||||
*/
|
||||
void GLRenderBackend::endSpriteBatch() {
|
||||
if (!inBatch_) {
|
||||
return;
|
||||
}
|
||||
|
||||
flush();
|
||||
inBatch_ = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 刷新当前批次
|
||||
*/
|
||||
void GLRenderBackend::flush() {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.batchCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置渲染排序键
|
||||
*/
|
||||
void GLRenderBackend::setSortKey(uint64_t key) {
|
||||
sortKey_ = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置渲染层
|
||||
*/
|
||||
void GLRenderBackend::setLayer(int layer) {
|
||||
layer_ = layer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置混合模式
|
||||
*/
|
||||
void GLRenderBackend::setBlendMode(rhi::BlendState blend) {
|
||||
blendState_ = blend;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 访问器
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取 RHI 设备
|
||||
*/
|
||||
rhi::RHIDevice *GLRenderBackend::getDevice() const {
|
||||
return device_.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取窗口宽度
|
||||
*/
|
||||
int GLRenderBackend::getWidth() const {
|
||||
return width_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取窗口高度
|
||||
*/
|
||||
int GLRenderBackend::getHeight() const {
|
||||
return height_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取渲染统计
|
||||
*/
|
||||
const RenderStats &GLRenderBackend::getStats() const {
|
||||
return stats_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重置渲染统计
|
||||
*/
|
||||
void GLRenderBackend::resetStats() {
|
||||
stats_.reset();
|
||||
if (device_) {
|
||||
device_->resetStats();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取图形 API 类型
|
||||
*/
|
||||
rhi::GraphicsAPI GLRenderBackend::getAPI() const {
|
||||
return rhi::GraphicsAPI::OpenGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取设备能力
|
||||
*/
|
||||
const rhi::DeviceCaps &GLRenderBackend::getCaps() const {
|
||||
static rhi::DeviceCaps empty;
|
||||
return device_ ? device_->getCaps() : empty;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
#include <extra2d/render/backends/opengl/gl_rhi_texture.h>
|
||||
#include <extra2d/render/backends/opengl/gl_rhi_shader.h>
|
||||
#include <extra2d/render/backends/opengl/gl_rhi_pipeline.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_context.h>
|
||||
#include <extra2d/render/backends/opengl/gl_context.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <fstream>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,203 @@
|
|||
#include <extra2d/render/camera/camera.h>
|
||||
|
||||
#include <extra2d/render/camera/viewport_adapter.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
Camera::Camera()
|
||||
: position_(0.0f, 0.0f), rotation_(0.0f), zoom_(1.0f), left_(-640.0f),
|
||||
right_(640.0f), bottom_(-360.0f), top_(360.0f), hasBounds_(false),
|
||||
matricesDirty_(true), viewportAdapter_(nullptr) {
|
||||
updateMatrices();
|
||||
}
|
||||
|
||||
Camera::Camera(float left, float right, float bottom, float top)
|
||||
: position_(0.0f, 0.0f), rotation_(0.0f), zoom_(1.0f), left_(left),
|
||||
right_(right), bottom_(bottom), top_(top), hasBounds_(false),
|
||||
matricesDirty_(true), viewportAdapter_(nullptr) {
|
||||
updateMatrices();
|
||||
}
|
||||
|
||||
void Camera::setViewport(float left, float right, float bottom, float top) {
|
||||
left_ = left;
|
||||
right_ = right;
|
||||
bottom_ = bottom;
|
||||
top_ = top;
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
void Camera::setViewportSize(float width, float height) {
|
||||
float halfWidth = width / 2.0f;
|
||||
float halfHeight = height / 2.0f;
|
||||
left_ = -halfWidth;
|
||||
right_ = halfWidth;
|
||||
bottom_ = -halfHeight;
|
||||
top_ = halfHeight;
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
Rect Camera::getViewport() const {
|
||||
return Rect(left_, bottom_, right_ - left_, top_ - bottom_);
|
||||
}
|
||||
|
||||
void Camera::setPos(const Vec2 &position) {
|
||||
position_ = position;
|
||||
applyBounds();
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
void Camera::setPos(float x, float y) { setPos(Vec2(x, y)); }
|
||||
|
||||
void Camera::move(const Vec2 &offset) {
|
||||
position_ += offset;
|
||||
applyBounds();
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
void Camera::move(float x, float y) { move(Vec2(x, y)); }
|
||||
|
||||
void Camera::setRotation(float degrees) {
|
||||
rotation_ = degrees;
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
void Camera::rotate(float degrees) {
|
||||
rotation_ += degrees;
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
void Camera::setZoom(float zoom) {
|
||||
zoom_ = std::max(0.001f, zoom);
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
void Camera::zoomBy(float factor) {
|
||||
zoom_ *= factor;
|
||||
zoom_ = std::max(0.001f, zoom_);
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
void Camera::setBounds(const Rect &bounds) {
|
||||
bounds_ = bounds;
|
||||
hasBounds_ = true;
|
||||
applyBounds();
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
void Camera::clearBounds() {
|
||||
hasBounds_ = false;
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
glm::mat4 Camera::getViewMatrix() const {
|
||||
if (matricesDirty_) {
|
||||
const_cast<Camera *>(this)->updateMatrices();
|
||||
}
|
||||
return viewMatrix_;
|
||||
}
|
||||
|
||||
glm::mat4 Camera::getProjectionMatrix() const {
|
||||
if (matricesDirty_) {
|
||||
const_cast<Camera *>(this)->updateMatrices();
|
||||
}
|
||||
return projectionMatrix_;
|
||||
}
|
||||
|
||||
glm::mat4 Camera::getViewProjectionMatrix() const {
|
||||
if (matricesDirty_) {
|
||||
const_cast<Camera *>(this)->updateMatrices();
|
||||
}
|
||||
return viewProjectionMatrix_;
|
||||
}
|
||||
|
||||
void Camera::updateMatrices() {
|
||||
glm::mat4 transform = glm::mat4(1.0f);
|
||||
transform =
|
||||
glm::translate(transform, glm::vec3(position_.x, position_.y, 0.0f));
|
||||
transform = glm::rotate(transform, rotation_ * DEG_TO_RAD,
|
||||
glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
transform = glm::scale(transform, glm::vec3(zoom_, zoom_, 1.0f));
|
||||
|
||||
viewMatrix_ = glm::inverse(transform);
|
||||
|
||||
projectionMatrix_ = glm::ortho(left_, right_, bottom_, top_, -1.0f, 1.0f);
|
||||
|
||||
viewProjectionMatrix_ = projectionMatrix_ * viewMatrix_;
|
||||
|
||||
matricesDirty_ = false;
|
||||
}
|
||||
|
||||
Vec2 Camera::screenToWorld(const Vec2 &screenPos) const {
|
||||
if (matricesDirty_) {
|
||||
const_cast<Camera *>(this)->updateMatrices();
|
||||
}
|
||||
|
||||
glm::vec4 ndc(screenPos.x, screenPos.y, 0.0f, 1.0f);
|
||||
glm::mat4 invVP = glm::inverse(viewProjectionMatrix_);
|
||||
glm::vec4 world = invVP * ndc;
|
||||
|
||||
return Vec2(world.x, world.y);
|
||||
}
|
||||
|
||||
Vec2 Camera::worldToScreen(const Vec2 &worldPos) const {
|
||||
if (matricesDirty_) {
|
||||
const_cast<Camera *>(this)->updateMatrices();
|
||||
}
|
||||
|
||||
glm::vec4 world(worldPos.x, worldPos.y, 0.0f, 1.0f);
|
||||
glm::vec4 screen = viewProjectionMatrix_ * world;
|
||||
|
||||
return Vec2(screen.x, screen.y);
|
||||
}
|
||||
|
||||
void Camera::lookAt(const Vec2 &target) {
|
||||
position_ = -target;
|
||||
applyBounds();
|
||||
matricesDirty_ = true;
|
||||
}
|
||||
|
||||
void Camera::applyViewportAdapter() {
|
||||
if (!viewportAdapter_) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ViewportResult &result = viewportAdapter_->getResult();
|
||||
float designWidth = viewportAdapter_->getDesignWidth();
|
||||
float designHeight = viewportAdapter_->getDesignHeight();
|
||||
|
||||
float halfWidth = designWidth / 2.0f;
|
||||
float halfHeight = designHeight / 2.0f;
|
||||
|
||||
setViewport(-halfWidth, halfWidth, -halfHeight, halfHeight);
|
||||
setZoom(result.scale);
|
||||
}
|
||||
|
||||
void Camera::applyBounds() {
|
||||
if (!hasBounds_) {
|
||||
return;
|
||||
}
|
||||
|
||||
float viewWidth = (right_ - left_) / zoom_;
|
||||
float viewHeight = (top_ - bottom_) / zoom_;
|
||||
|
||||
float minX = bounds_.left() + viewWidth / 2.0f;
|
||||
float maxX = bounds_.right() - viewWidth / 2.0f;
|
||||
float minY = bounds_.top() + viewHeight / 2.0f;
|
||||
float maxY = bounds_.bottom() - viewHeight / 2.0f;
|
||||
|
||||
if (minX > maxX) {
|
||||
position_.x = (bounds_.left() + bounds_.right()) / 2.0f;
|
||||
} else {
|
||||
position_.x = std::clamp(position_.x, minX, maxX);
|
||||
}
|
||||
|
||||
if (minY > maxY) {
|
||||
position_.y = (bounds_.top() + bounds_.bottom()) / 2.0f;
|
||||
} else {
|
||||
position_.y = std::clamp(position_.y, minY, maxY);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
#include <extra2d/render/camera/viewport_adapter.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
ViewportAdapter::ViewportAdapter() : config_(ViewportConfig::hd()) {}
|
||||
|
||||
ViewportAdapter::ViewportAdapter(const ViewportConfig& config) : config_(config) {}
|
||||
|
||||
void ViewportAdapter::setConfig(const ViewportConfig& config) {
|
||||
config_ = config;
|
||||
calculateViewport();
|
||||
}
|
||||
|
||||
void ViewportAdapter::setDesignSize(float width, float height) {
|
||||
config_.designWidth = width;
|
||||
config_.designHeight = height;
|
||||
calculateViewport();
|
||||
}
|
||||
|
||||
void ViewportAdapter::setScaleMode(ViewportScaleMode mode) {
|
||||
config_.scaleMode = mode;
|
||||
calculateViewport();
|
||||
}
|
||||
|
||||
void ViewportAdapter::setAlign(ViewportAlign align) {
|
||||
config_.align = align;
|
||||
calculateViewport();
|
||||
}
|
||||
|
||||
void ViewportAdapter::update(int screenWidth, int screenHeight) {
|
||||
result_.screenWidth = screenWidth;
|
||||
result_.screenHeight = screenHeight;
|
||||
calculateViewport();
|
||||
}
|
||||
|
||||
float ViewportAdapter::getDesignAspectRatio() const {
|
||||
if (config_.designHeight <= 0.0f) {
|
||||
return 1.0f;
|
||||
}
|
||||
return config_.designWidth / config_.designHeight;
|
||||
}
|
||||
|
||||
float ViewportAdapter::getScreenAspectRatio() const {
|
||||
if (result_.screenHeight <= 0) {
|
||||
return 1.0f;
|
||||
}
|
||||
return static_cast<float>(result_.screenWidth) / static_cast<float>(result_.screenHeight);
|
||||
}
|
||||
|
||||
Vec2 ViewportAdapter::screenToDesign(const Vec2& screenPos) const {
|
||||
float x = (screenPos.x - static_cast<float>(result_.offsetX)) / result_.scale;
|
||||
float y = (screenPos.y - static_cast<float>(result_.offsetY)) / result_.scale;
|
||||
return Vec2(x, y);
|
||||
}
|
||||
|
||||
Vec2 ViewportAdapter::designToScreen(const Vec2& designPos) const {
|
||||
float x = designPos.x * result_.scale + static_cast<float>(result_.offsetX);
|
||||
float y = designPos.y * result_.scale + static_cast<float>(result_.offsetY);
|
||||
return Vec2(x, y);
|
||||
}
|
||||
|
||||
void ViewportAdapter::calculateViewport() {
|
||||
if (result_.screenWidth <= 0 || result_.screenHeight <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
result_.scale = calculateScale();
|
||||
|
||||
result_.width = config_.designWidth * result_.scale;
|
||||
result_.height = config_.designHeight * result_.scale;
|
||||
|
||||
calculateOffset();
|
||||
}
|
||||
|
||||
float ViewportAdapter::calculateScale() const {
|
||||
float scaleX = static_cast<float>(result_.screenWidth) / config_.designWidth;
|
||||
float scaleY = static_cast<float>(result_.screenHeight) / config_.designHeight;
|
||||
|
||||
float scale = 1.0f;
|
||||
|
||||
switch (config_.scaleMode) {
|
||||
case ViewportScaleMode::None:
|
||||
scale = 1.0f;
|
||||
break;
|
||||
|
||||
case ViewportScaleMode::Letterbox:
|
||||
scale = std::min(scaleX, scaleY);
|
||||
break;
|
||||
|
||||
case ViewportScaleMode::Crop:
|
||||
scale = std::max(scaleX, scaleY);
|
||||
break;
|
||||
|
||||
case ViewportScaleMode::Stretch:
|
||||
scale = 1.0f;
|
||||
break;
|
||||
|
||||
case ViewportScaleMode::IntegerScale:
|
||||
scale = std::min(scaleX, scaleY);
|
||||
scale = std::floor(scale);
|
||||
if (scale < 1.0f) {
|
||||
scale = 1.0f;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
scale = std::clamp(scale, config_.minScale, config_.maxScale);
|
||||
|
||||
return scale;
|
||||
}
|
||||
|
||||
void ViewportAdapter::calculateOffset() {
|
||||
switch (config_.align) {
|
||||
case ViewportAlign::TopLeft:
|
||||
result_.offsetX = 0;
|
||||
result_.offsetY = 0;
|
||||
break;
|
||||
|
||||
case ViewportAlign::TopCenter:
|
||||
result_.offsetX = (result_.screenWidth - static_cast<int>(result_.width)) / 2;
|
||||
result_.offsetY = 0;
|
||||
break;
|
||||
|
||||
case ViewportAlign::TopRight:
|
||||
result_.offsetX = result_.screenWidth - static_cast<int>(result_.width);
|
||||
result_.offsetY = 0;
|
||||
break;
|
||||
|
||||
case ViewportAlign::CenterLeft:
|
||||
result_.offsetX = 0;
|
||||
result_.offsetY = (result_.screenHeight - static_cast<int>(result_.height)) / 2;
|
||||
break;
|
||||
|
||||
case ViewportAlign::Center:
|
||||
default:
|
||||
result_.offsetX = (result_.screenWidth - static_cast<int>(result_.width)) / 2;
|
||||
result_.offsetY = (result_.screenHeight - static_cast<int>(result_.height)) / 2;
|
||||
break;
|
||||
|
||||
case ViewportAlign::CenterRight:
|
||||
result_.offsetX = result_.screenWidth - static_cast<int>(result_.width);
|
||||
result_.offsetY = (result_.screenHeight - static_cast<int>(result_.height)) / 2;
|
||||
break;
|
||||
|
||||
case ViewportAlign::BottomLeft:
|
||||
result_.offsetX = 0;
|
||||
result_.offsetY = result_.screenHeight - static_cast<int>(result_.height);
|
||||
break;
|
||||
|
||||
case ViewportAlign::BottomCenter:
|
||||
result_.offsetX = (result_.screenWidth - static_cast<int>(result_.width)) / 2;
|
||||
result_.offsetY = result_.screenHeight - static_cast<int>(result_.height);
|
||||
break;
|
||||
|
||||
case ViewportAlign::BottomRight:
|
||||
result_.offsetX = result_.screenWidth - static_cast<int>(result_.width);
|
||||
result_.offsetY = result_.screenHeight - static_cast<int>(result_.height);
|
||||
break;
|
||||
}
|
||||
|
||||
result_.x = static_cast<float>(result_.offsetX);
|
||||
result_.y = static_cast<float>(result_.offsetY);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,262 @@
|
|||
#include <extra2d/render/core/backend_factory.h>
|
||||
#include <extra2d/render/backends/opengl/gl_render_backend.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
std::unordered_map<std::string, BackendFactory::BackendInfo>& BackendFactory::getRegistry() {
|
||||
static std::unordered_map<std::string, BackendInfo> registry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
std::mutex& BackendFactory::getMutex() {
|
||||
static std::mutex mutex;
|
||||
return mutex;
|
||||
}
|
||||
|
||||
std::string& BackendFactory::getDefaultName() {
|
||||
static std::string defaultName = "opengl";
|
||||
return defaultName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注册渲染后端
|
||||
*/
|
||||
void BackendFactory::reg(const std::string& name,
|
||||
BackendFn backend,
|
||||
const std::vector<std::string>& windowBackends,
|
||||
rhi::GraphicsAPI api,
|
||||
const std::string& description,
|
||||
int priority) {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
|
||||
BackendInfo info;
|
||||
info.name = name;
|
||||
info.createFn = backend;
|
||||
info.compatibleWindowBackends = windowBackends;
|
||||
info.api = api;
|
||||
info.description = description;
|
||||
info.priority = priority;
|
||||
|
||||
getRegistry()[name] = info;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 注销渲染后端
|
||||
*/
|
||||
void BackendFactory::unreg(const std::string& name) {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
getRegistry().erase(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建渲染后端
|
||||
*/
|
||||
UniquePtr<RenderBackend> BackendFactory::createBackend(const std::string& name) {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
|
||||
auto& registry = getRegistry();
|
||||
auto it = registry.find(name);
|
||||
if (it != registry.end() && it->second.createFn) {
|
||||
return it->second.createFn();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建默认渲染后端
|
||||
*/
|
||||
UniquePtr<RenderBackend> BackendFactory::createDefaultBackend() {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
|
||||
auto& registry = getRegistry();
|
||||
if (registry.empty()) {
|
||||
return makeUnique<GLRenderBackend>();
|
||||
}
|
||||
|
||||
std::string defaultName = getDefaultName();
|
||||
auto it = registry.find(defaultName);
|
||||
if (it != registry.end() && it->second.createFn) {
|
||||
return it->second.createFn();
|
||||
}
|
||||
|
||||
std::vector<BackendInfo*> sorted;
|
||||
for (auto& pair : registry) {
|
||||
sorted.push_back(&pair.second);
|
||||
}
|
||||
std::sort(sorted.begin(), sorted.end(),
|
||||
[](const BackendInfo* a, const BackendInfo* b) {
|
||||
return a->priority > b->priority;
|
||||
});
|
||||
|
||||
if (!sorted.empty() && sorted.front()->createFn) {
|
||||
return sorted.front()->createFn();
|
||||
}
|
||||
|
||||
return makeUnique<GLRenderBackend>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据窗口后端创建兼容的渲染后端
|
||||
*/
|
||||
UniquePtr<RenderBackend> BackendFactory::createBackendForWindow(const std::string& windowBackend) {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
|
||||
auto& registry = getRegistry();
|
||||
|
||||
std::vector<BackendInfo*> compatible;
|
||||
for (auto& pair : registry) {
|
||||
const auto& windowBackends = pair.second.compatibleWindowBackends;
|
||||
if (windowBackends.empty() ||
|
||||
std::find(windowBackends.begin(), windowBackends.end(), windowBackend) != windowBackends.end()) {
|
||||
compatible.push_back(&pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(compatible.begin(), compatible.end(),
|
||||
[](const BackendInfo* a, const BackendInfo* b) {
|
||||
return a->priority > b->priority;
|
||||
});
|
||||
|
||||
if (!compatible.empty() && compatible.front()->createFn) {
|
||||
return compatible.front()->createFn();
|
||||
}
|
||||
|
||||
return makeUnique<GLRenderBackend>();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据图形 API 创建后端
|
||||
*/
|
||||
UniquePtr<RenderBackend> BackendFactory::createBackendForAPI(rhi::GraphicsAPI api) {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
|
||||
auto& registry = getRegistry();
|
||||
|
||||
std::vector<BackendInfo*> matching;
|
||||
for (auto& pair : registry) {
|
||||
if (pair.second.api == api) {
|
||||
matching.push_back(&pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(matching.begin(), matching.end(),
|
||||
[](const BackendInfo* a, const BackendInfo* b) {
|
||||
return a->priority > b->priority;
|
||||
});
|
||||
|
||||
if (!matching.empty() && matching.front()->createFn) {
|
||||
return matching.front()->createFn();
|
||||
}
|
||||
|
||||
if (api == rhi::GraphicsAPI::OpenGL) {
|
||||
return makeUnique<GLRenderBackend>();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查后端是否已注册
|
||||
*/
|
||||
bool BackendFactory::hasBackend(const std::string& name) {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
return getRegistry().find(name) != getRegistry().end();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取所有已注册的后端名称
|
||||
*/
|
||||
std::vector<std::string> BackendFactory::getBackendNames() {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
|
||||
std::vector<std::string> names;
|
||||
for (const auto& pair : getRegistry()) {
|
||||
names.push_back(pair.first);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取后端信息
|
||||
*/
|
||||
const BackendFactory::BackendInfo* BackendFactory::getBackendInfo(const std::string& name) {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
|
||||
auto& registry = getRegistry();
|
||||
auto it = registry.find(name);
|
||||
if (it != registry.end()) {
|
||||
return &it->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取所有后端信息
|
||||
*/
|
||||
std::vector<BackendFactory::BackendInfo> BackendFactory::getAllBackendInfos() {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
|
||||
std::vector<BackendInfo> infos;
|
||||
for (const auto& pair : getRegistry()) {
|
||||
infos.push_back(pair.second);
|
||||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取兼容指定窗口后端的所有渲染后端
|
||||
*/
|
||||
std::vector<std::string> BackendFactory::getCompatibleBackends(const std::string& windowBackend) {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
|
||||
std::vector<std::string> names;
|
||||
for (const auto& pair : getRegistry()) {
|
||||
const auto& windowBackends = pair.second.compatibleWindowBackends;
|
||||
if (windowBackends.empty() ||
|
||||
std::find(windowBackends.begin(), windowBackends.end(), windowBackend) != windowBackends.end()) {
|
||||
names.push_back(pair.first);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清除所有注册的后端
|
||||
*/
|
||||
void BackendFactory::clear() {
|
||||
std::lock_guard<std::mutex> lock(getMutex());
|
||||
getRegistry().clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取默认后端名称
|
||||
*/
|
||||
std::string BackendFactory::getDefaultBackendName() {
|
||||
return getDefaultName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置默认后端名称
|
||||
*/
|
||||
void BackendFactory::setDefaultBackendName(const std::string& name) {
|
||||
getDefaultName() = name;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
static BackendRegistrar s_openglBackendReg(
|
||||
"opengl",
|
||||
[]() -> UniquePtr<RenderBackend> {
|
||||
return makeUnique<GLRenderBackend>();
|
||||
},
|
||||
{"sdl2", "glfw"},
|
||||
rhi::GraphicsAPI::OpenGL,
|
||||
"OpenGL 4.5 Core Profile",
|
||||
100
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -245,7 +245,7 @@ void RenderContext::flushQueue() {
|
|||
const RenderQueueStats& queueStats = queue_.getStats();
|
||||
|
||||
stats_.spriteCount = queueStats.spriteCommands;
|
||||
stats_.textCount = queueStats.textCommands;
|
||||
stats_.textCharCount = queueStats.textCommands;
|
||||
stats_.shapeCount = queueStats.shapeCommands;
|
||||
|
||||
stats_.batchCount = queueStats.batchCount;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
#include <extra2d/platform/window_module.h>
|
||||
#include <extra2d/render/core/render_module.h>
|
||||
#include <extra2d/render/renderer.h>
|
||||
|
||||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <typeindex>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
RenderModule::RenderModule() : initialized_(false) {}
|
||||
|
||||
RenderModule::RenderModule(const RenderModuleConfig &config)
|
||||
: config_(config), initialized_(false) {}
|
||||
|
||||
RenderModule::~RenderModule() { shutdown(); }
|
||||
|
||||
bool RenderModule::init() {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!app_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IWindow *window = nullptr;
|
||||
|
||||
renderer_ = Renderer::create();
|
||||
|
||||
if (!renderer_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RendererConfig rendererConfig;
|
||||
rendererConfig.api = config_.api;
|
||||
rendererConfig.vsync = config_.vsync;
|
||||
rendererConfig.maxBatchSize = config_.maxBatchSize;
|
||||
rendererConfig.enableDebug = config_.enableDebug;
|
||||
rendererConfig.viewportConfig =
|
||||
ViewportConfig(config_.designWidth, config_.designHeight);
|
||||
|
||||
renderer_->setConfig(rendererConfig);
|
||||
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderModule::shutdown() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderer_.reset();
|
||||
initialized_ = false;
|
||||
}
|
||||
|
||||
std::vector<std::type_index> RenderModule::deps() const {
|
||||
return {std::type_index(typeid(class WindowModule))};
|
||||
}
|
||||
|
||||
void RenderModule::setConfig(const RenderModuleConfig &config) {
|
||||
config_ = config;
|
||||
|
||||
if (renderer_ && initialized_) {
|
||||
RendererConfig rendererConfig;
|
||||
rendererConfig.api = config_.api;
|
||||
rendererConfig.vsync = config_.vsync;
|
||||
rendererConfig.maxBatchSize = config_.maxBatchSize;
|
||||
rendererConfig.enableDebug = config_.enableDebug;
|
||||
rendererConfig.viewportConfig =
|
||||
ViewportConfig(config_.designWidth, config_.designHeight);
|
||||
renderer_->setConfig(rendererConfig);
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<RenderModule> RenderModule::create(const RenderModuleConfig &config) {
|
||||
return makePtr<RenderModule>(config);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,349 @@
|
|||
#include <extra2d/render/renderer.h>
|
||||
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/render/core/backend_factory.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/scene/scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
Renderer::Renderer()
|
||||
: window_(nullptr), width_(0), height_(0), initialized_(false) {}
|
||||
|
||||
Renderer::Renderer(const RendererConfig &config)
|
||||
: window_(nullptr), config_(config), width_(0), height_(0),
|
||||
initialized_(false) {}
|
||||
|
||||
Renderer::~Renderer() { shutdown(); }
|
||||
|
||||
bool Renderer::init() { return initialized_; }
|
||||
|
||||
bool Renderer::init(IWindow *window) { return init(window, config_); }
|
||||
|
||||
bool Renderer::init(IWindow *window, const RendererConfig &config) {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
window_ = window;
|
||||
config_ = config;
|
||||
width_ = window->width();
|
||||
height_ = window->height();
|
||||
|
||||
viewportAdapter_.setConfig(config.viewportConfig);
|
||||
viewportAdapter_.update(width_, height_);
|
||||
|
||||
RenderBackendConfig backendConfig;
|
||||
backendConfig.api = config.api;
|
||||
backendConfig.vsync = config.vsync;
|
||||
backendConfig.maxBatchSize = config.maxBatchSize;
|
||||
backendConfig.enableDebug = config.enableDebug;
|
||||
|
||||
backend_ = BackendFactory::createBackendForAPI(config.api);
|
||||
if (!backend_ || !backend_->init(window, backendConfig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderContextConfig contextConfig;
|
||||
contextConfig.maxBatchSize = config.maxBatchSize;
|
||||
contextConfig.preferredAPI = config.api;
|
||||
|
||||
context_ = makeUnique<RenderContext>(contextConfig);
|
||||
if (!context_->init(window, config.api)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!createBatchers()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
createDefaultCamera();
|
||||
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::shutdown() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
textBatcher_.reset();
|
||||
shapeBatcher_.reset();
|
||||
spriteBatcher_.reset();
|
||||
context_.reset();
|
||||
backend_.reset();
|
||||
|
||||
activeCamera_.reset();
|
||||
defaultCamera_.reset();
|
||||
|
||||
window_ = nullptr;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
initialized_ = false;
|
||||
}
|
||||
|
||||
void Renderer::beginFrame(const Color &clearColor) {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (backend_) {
|
||||
backend_->beginFrame(clearColor);
|
||||
}
|
||||
|
||||
if (context_) {
|
||||
context_->beginFrame();
|
||||
context_->clear(clearColor);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::endFrame() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spriteBatcher_) {
|
||||
spriteBatcher_->end();
|
||||
}
|
||||
if (shapeBatcher_) {
|
||||
shapeBatcher_->end();
|
||||
}
|
||||
if (textBatcher_) {
|
||||
textBatcher_->end();
|
||||
}
|
||||
|
||||
if (context_) {
|
||||
context_->endFrame();
|
||||
}
|
||||
|
||||
if (backend_) {
|
||||
backend_->endFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::present() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (backend_) {
|
||||
backend_->present();
|
||||
}
|
||||
|
||||
if (context_) {
|
||||
context_->present();
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::renderScene(Scene *scene) {
|
||||
if (!initialized_ || !scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
Camera *camera = activeCamera_ ? activeCamera_.get() : defaultCamera_.get();
|
||||
if (!camera) {
|
||||
camera = scene->getActiveCamera();
|
||||
}
|
||||
|
||||
renderScene(scene, camera);
|
||||
}
|
||||
|
||||
void Renderer::renderScene(Scene *scene, Camera *camera) {
|
||||
if (!initialized_ || !scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!camera) {
|
||||
camera = defaultCamera_.get();
|
||||
}
|
||||
|
||||
if (camera) {
|
||||
camera->setViewportAdapter(&viewportAdapter_);
|
||||
camera->applyViewportAdapter();
|
||||
}
|
||||
|
||||
applyCameraTransform(camera);
|
||||
|
||||
scene->renderScene(*backend_);
|
||||
}
|
||||
|
||||
void Renderer::setActiveCamera(Ptr<Camera> camera) { activeCamera_ = camera; }
|
||||
|
||||
Ptr<Camera> Renderer::getActiveCamera() const {
|
||||
return activeCamera_ ? activeCamera_ : defaultCamera_;
|
||||
}
|
||||
|
||||
void Renderer::setViewport(int x, int y, int width, int height) {
|
||||
if (context_) {
|
||||
context_->setViewport(x, y, width, height);
|
||||
}
|
||||
if (backend_) {
|
||||
backend_->setViewport(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::setScissor(int x, int y, int width, int height) {
|
||||
if (context_) {
|
||||
context_->setScissorRect(x, y, width, height);
|
||||
}
|
||||
if (backend_) {
|
||||
backend_->setScissor(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::setScissorEnabled(bool enabled) {
|
||||
if (context_) {
|
||||
context_->setScissorEnabled(enabled);
|
||||
}
|
||||
if (backend_) {
|
||||
backend_->setScissorEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::setVSync(bool enabled) {
|
||||
if (context_) {
|
||||
context_->setVSync(enabled);
|
||||
}
|
||||
if (backend_) {
|
||||
backend_->setVSync(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
bool Renderer::isVSyncEnabled() const {
|
||||
if (backend_) {
|
||||
return backend_->isVSyncEnabled();
|
||||
}
|
||||
if (context_) {
|
||||
return context_->isVSyncEnabled();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
rhi::RHIDevice *Renderer::getDevice() const {
|
||||
if (backend_) {
|
||||
return backend_->getDevice();
|
||||
}
|
||||
if (context_) {
|
||||
return context_->getDevice().get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const RenderStats &Renderer::getStats() const {
|
||||
if (backend_) {
|
||||
return backend_->getStats();
|
||||
}
|
||||
if (context_) {
|
||||
return context_->getStats();
|
||||
}
|
||||
static RenderStats empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
void Renderer::resetStats() {
|
||||
if (backend_) {
|
||||
backend_->resetStats();
|
||||
}
|
||||
if (context_) {
|
||||
context_->resetStats();
|
||||
}
|
||||
if (spriteBatcher_) {
|
||||
spriteBatcher_->resetStats();
|
||||
}
|
||||
if (shapeBatcher_) {
|
||||
shapeBatcher_->resetStats();
|
||||
}
|
||||
if (textBatcher_) {
|
||||
textBatcher_->resetStats();
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::setConfig(const RendererConfig &config) {
|
||||
config_ = config;
|
||||
viewportAdapter_.setConfig(config.viewportConfig);
|
||||
updateViewportAdapter();
|
||||
}
|
||||
|
||||
bool Renderer::createBatchers() {
|
||||
auto device = getDevice();
|
||||
if (!device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto devicePtr = context_ ? context_->getDevice() : nullptr;
|
||||
if (!devicePtr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SpriteBatcherConfig spriteConfig;
|
||||
spriteConfig.maxBatchSize = config_.maxBatchSize;
|
||||
spriteBatcher_ = makeUnique<SpriteBatcher>(spriteConfig);
|
||||
if (!spriteBatcher_->init(devicePtr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ShapeBatcherConfig shapeConfig;
|
||||
shapeConfig.maxBatchSize = config_.maxBatchSize / 2;
|
||||
shapeBatcher_ = makeUnique<ShapeBatcher>(shapeConfig);
|
||||
if (!shapeBatcher_->init(devicePtr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextBatcherConfig textConfig;
|
||||
textConfig.maxBatchSize = config_.maxBatchSize / 2;
|
||||
textBatcher_ = makeUnique<TextBatcher>(textConfig);
|
||||
if (!textBatcher_->init(devicePtr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::createDefaultCamera() {
|
||||
float designWidth = viewportAdapter_.getDesignWidth();
|
||||
float designHeight = viewportAdapter_.getDesignHeight();
|
||||
|
||||
defaultCamera_ = makePtr<Camera>();
|
||||
defaultCamera_->setViewport(0, designWidth, 0, designHeight);
|
||||
defaultCamera_->setViewportAdapter(&viewportAdapter_);
|
||||
defaultCamera_->setDebugName("DefaultCamera");
|
||||
}
|
||||
|
||||
void Renderer::updateViewportAdapter() {
|
||||
viewportAdapter_.update(width_, height_);
|
||||
}
|
||||
|
||||
void Renderer::applyCameraTransform(Camera *camera) {
|
||||
if (!camera) {
|
||||
return;
|
||||
}
|
||||
|
||||
camera->updateMatrices();
|
||||
glm::mat4 viewProj = camera->getViewProjectionMatrix();
|
||||
|
||||
if (spriteBatcher_) {
|
||||
spriteBatcher_->setViewProjection(viewProj);
|
||||
}
|
||||
if (shapeBatcher_) {
|
||||
shapeBatcher_->setViewProjection(viewProj);
|
||||
}
|
||||
if (textBatcher_) {
|
||||
textBatcher_->setViewProjection(viewProj);
|
||||
}
|
||||
|
||||
if (backend_) {
|
||||
backend_->setProjectionMatrix(camera->getProjectionMatrix());
|
||||
backend_->setViewMatrix(camera->getViewMatrix());
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<Renderer> Renderer::create(const RendererConfig &config) {
|
||||
return makePtr<Renderer>(config);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,5 +1,5 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/render/core/render_queue.h>
|
||||
#include <extra2d/scene/scene.h>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#include <algorithm>
|
||||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_command.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <extra2d/scene/scene_manager.h>
|
||||
#include <extra2d/scene/transition_box_scene.h>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_command.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/scene/shape_node.h>
|
||||
#include <limits>
|
||||
|
||||
|
|
@ -196,24 +196,18 @@ Ptr<ShapeNode> ShapeNode::createFilledPolygon(const std::vector<Vec2> &points,
|
|||
* @brief 设置形状的所有顶点
|
||||
* @param points 顶点坐标数组
|
||||
*/
|
||||
void ShapeNode::setPoints(const std::vector<Vec2> &points) {
|
||||
points_ = points;
|
||||
}
|
||||
void ShapeNode::setPoints(const std::vector<Vec2> &points) { points_ = points; }
|
||||
|
||||
/**
|
||||
* @brief 添加一个顶点到形状
|
||||
* @param point 要添加的顶点坐标
|
||||
*/
|
||||
void ShapeNode::addPoint(const Vec2 &point) {
|
||||
points_.push_back(point);
|
||||
}
|
||||
void ShapeNode::addPoint(const Vec2 &point) { points_.push_back(point); }
|
||||
|
||||
/**
|
||||
* @brief 清除所有顶点
|
||||
*/
|
||||
void ShapeNode::clearPoints() {
|
||||
points_.clear();
|
||||
}
|
||||
void ShapeNode::clearPoints() { points_.clear(); }
|
||||
|
||||
/**
|
||||
* @brief 获取形状的边界矩形
|
||||
|
|
@ -319,7 +313,7 @@ void ShapeNode::onDraw(RenderBackend &renderer) {
|
|||
case ShapeType::Triangle:
|
||||
if (points_.size() >= 3) {
|
||||
if (filled_) {
|
||||
renderer.fillTriangle(points_[0], points_[1], points_[2], color_);
|
||||
renderer.fillPolygon(points_.data(), 3, color_);
|
||||
} else {
|
||||
renderer.drawLine(points_[0], points_[1], color_, lineWidth_);
|
||||
renderer.drawLine(points_[1], points_[2], color_, lineWidth_);
|
||||
|
|
@ -331,9 +325,9 @@ void ShapeNode::onDraw(RenderBackend &renderer) {
|
|||
case ShapeType::Polygon:
|
||||
if (!points_.empty()) {
|
||||
if (filled_) {
|
||||
renderer.fillPolygon(points_, color_);
|
||||
renderer.fillPolygon(points_.data(), points_.size(), color_);
|
||||
} else {
|
||||
renderer.drawPolygon(points_, color_, lineWidth_);
|
||||
renderer.drawPolygon(points_.data(), points_.size(), color_, lineWidth_);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -354,71 +348,44 @@ void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
|
|||
}
|
||||
|
||||
Vec2 offset = getPosition();
|
||||
RenderCommand cmd;
|
||||
cmd.layer = zOrder;
|
||||
|
||||
switch (shapeType_) {
|
||||
case ShapeType::Point:
|
||||
if (!points_.empty()) {
|
||||
cmd.type = RenderCommandType::FilledCircle;
|
||||
cmd.data =
|
||||
CircleCommandData{points_[0] + offset, lineWidth_ * 0.5f, color_, 8, 0.0f, true};
|
||||
commands.push_back(RenderCommand::makeCircle(
|
||||
points_[0] + offset, lineWidth_ * 0.5f, color_, 8, true, zOrder));
|
||||
}
|
||||
break;
|
||||
|
||||
case ShapeType::Line:
|
||||
if (points_.size() >= 2) {
|
||||
cmd.type = RenderCommandType::Line;
|
||||
cmd.data = LineCommandData{points_[0] + offset, points_[1] + offset, color_,
|
||||
lineWidth_};
|
||||
commands.push_back(RenderCommand::makeLine(
|
||||
points_[0] + offset, points_[1] + offset, color_, lineWidth_, zOrder));
|
||||
}
|
||||
break;
|
||||
|
||||
case ShapeType::Rect:
|
||||
if (points_.size() >= 4) {
|
||||
if (filled_) {
|
||||
cmd.type = RenderCommandType::FilledRect;
|
||||
Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x,
|
||||
points_[2].y - points_[0].y);
|
||||
cmd.data =
|
||||
RectCommandData{Rect(rect.origin + offset, rect.size), color_, 0.0f, true};
|
||||
} else {
|
||||
cmd.type = RenderCommandType::Rect;
|
||||
Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x,
|
||||
points_[2].y - points_[0].y);
|
||||
cmd.data =
|
||||
RectCommandData{Rect(rect.origin + offset, rect.size), color_, lineWidth_, false};
|
||||
}
|
||||
Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x,
|
||||
points_[2].y - points_[0].y);
|
||||
commands.push_back(RenderCommand::makeRect(
|
||||
Rect(rect.origin + offset, rect.size), color_, lineWidth_, filled_, zOrder));
|
||||
}
|
||||
break;
|
||||
|
||||
case ShapeType::Circle:
|
||||
if (points_.size() >= 2) {
|
||||
float radius = points_[1].x;
|
||||
if (filled_) {
|
||||
cmd.type = RenderCommandType::FilledCircle;
|
||||
cmd.data =
|
||||
CircleCommandData{points_[0] + offset, radius, color_, segments_, 0.0f, true};
|
||||
} else {
|
||||
cmd.type = RenderCommandType::Circle;
|
||||
cmd.data = CircleCommandData{points_[0] + offset, radius, color_, segments_,
|
||||
lineWidth_, false};
|
||||
}
|
||||
commands.push_back(RenderCommand::makeCircle(
|
||||
points_[0] + offset, radius, color_, segments_, filled_, zOrder));
|
||||
}
|
||||
break;
|
||||
|
||||
case ShapeType::Triangle:
|
||||
if (points_.size() >= 3) {
|
||||
Vec2 p1 = points_[0] + offset;
|
||||
Vec2 p2 = points_[1] + offset;
|
||||
Vec2 p3 = points_[2] + offset;
|
||||
if (filled_) {
|
||||
cmd.type = RenderCommandType::FilledTriangle;
|
||||
cmd.data = TriangleCommandData{p1, p2, p3, color_, 0.0f, true};
|
||||
} else {
|
||||
cmd.type = RenderCommandType::Triangle;
|
||||
cmd.data = TriangleCommandData{p1, p2, p3, color_, lineWidth_, false};
|
||||
}
|
||||
commands.push_back(RenderCommand::makeTriangle(
|
||||
points_[0] + offset, points_[1] + offset, points_[2] + offset,
|
||||
color_, filled_, zOrder));
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -429,19 +396,11 @@ void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
|
|||
for (const auto &p : points_) {
|
||||
transformedPoints.push_back(p + offset);
|
||||
}
|
||||
|
||||
if (filled_) {
|
||||
cmd.type = RenderCommandType::FilledPolygon;
|
||||
cmd.data = PolygonCommandData{transformedPoints, color_, 0.0f, true};
|
||||
} else {
|
||||
cmd.type = RenderCommandType::Polygon;
|
||||
cmd.data = PolygonCommandData{transformedPoints, color_, lineWidth_, false};
|
||||
}
|
||||
commands.push_back(RenderCommand::makePolygon(
|
||||
transformedPoints, color_, filled_, zOrder));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
commands.push_back(std::move(cmd));
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_command.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/scene/sprite.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
@ -168,8 +167,8 @@ void Sprite::onDraw(RenderBackend &renderer) {
|
|||
// 从世界变换矩阵中提取旋转角度
|
||||
float worldRotation = std::atan2(worldTransform[0][1], worldTransform[0][0]);
|
||||
|
||||
renderer.drawSprite(*texture_, destRect, srcRect, color_, worldRotation,
|
||||
anchor);
|
||||
renderer.drawSprite(texture_->getRHITexture(), destRect, srcRect, color_, worldRotation,
|
||||
flipX_, flipY_);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -225,8 +224,8 @@ void Sprite::generateRenderCommand(std::vector<RenderCommand> &commands,
|
|||
RenderCommand cmd;
|
||||
cmd.type = RenderCommandType::Sprite;
|
||||
cmd.layer = zOrder;
|
||||
cmd.data = SpriteCommandData{texture_.get(), destRect, srcRect, color_,
|
||||
worldRotation, anchor, 0};
|
||||
cmd.data = SpriteRenderData{texture_->getRHITexture(), destRect, srcRect, color_,
|
||||
worldRotation, anchor, rhi::BlendState::alphaBlend(), 0};
|
||||
|
||||
commands.push_back(std::move(cmd));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <extra2d/scene/transition_box_scene.h>
|
||||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <algorithm>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
|
@ -76,7 +76,8 @@ void TransitionBoxScene::renderContent(RenderBackend &renderer) {
|
|||
|
||||
glm::mat4 overlayVP =
|
||||
glm::ortho(0.0f, windowWidth, windowHeight, 0.0f, -1.0f, 1.0f);
|
||||
renderer.setViewProjection(overlayVP);
|
||||
renderer.setProjectionMatrix(overlayVP);
|
||||
renderer.setViewMatrix(glm::mat4(1.0f));
|
||||
|
||||
for (int idx = visible; idx < total; ++idx) {
|
||||
int x = idx % div;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/scene/transition_fade_scene.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
|
@ -75,7 +75,8 @@ void TransitionFadeScene::renderContent(RenderBackend &renderer) {
|
|||
|
||||
glm::mat4 overlayVP =
|
||||
glm::ortho(0.0f, windowWidth, windowHeight, 0.0f, -1.0f, 1.0f);
|
||||
renderer.setViewProjection(overlayVP);
|
||||
renderer.setProjectionMatrix(overlayVP);
|
||||
renderer.setViewMatrix(glm::mat4(1.0f));
|
||||
|
||||
Color maskColor = maskColor_;
|
||||
maskColor.a = maskAlpha;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <extra2d/scene/transition_flip_scene.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <extra2d/scene/transition_scale_scene.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <extra2d/scene/transition_slide_scene.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
|
|||
|
|
@ -34,13 +34,13 @@ function define_extra2d_engine()
|
|||
|
||||
-- 渲染后端源文件
|
||||
local render_backend = get_render_backend()
|
||||
-- 图形后端工厂(始终编译)
|
||||
add_files("Extra2D/src/graphics/backends/backend_factory.cpp")
|
||||
-- 渲染后端工厂
|
||||
add_files("Extra2D/src/render/core/backend_factory.cpp")
|
||||
if render_backend == "vulkan" then
|
||||
add_files("Extra2D/src/graphics/backends/vulkan/*.cpp")
|
||||
add_files("Extra2D/src/render/backends/vulkan/*.cpp")
|
||||
add_defines("E2D_BACKEND_VULKAN")
|
||||
else
|
||||
add_files("Extra2D/src/graphics/backends/opengl/*.cpp")
|
||||
add_files("Extra2D/src/render/backends/opengl/*.cpp")
|
||||
add_files("Extra2D/src/glad/glad.c")
|
||||
add_defines("E2D_BACKEND_OPENGL")
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue