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/compression.h>
|
||||||
#include <extra2d/core/aes_cipher.h>
|
#include <extra2d/core/aes_cipher.h>
|
||||||
|
|
||||||
// Config removed - app info now in Application class
|
|
||||||
|
|
||||||
// Platform
|
// Platform
|
||||||
#include <extra2d/platform/iinput.h>
|
#include <extra2d/platform/iinput.h>
|
||||||
#include <extra2d/platform/iwindow.h>
|
#include <extra2d/platform/iwindow.h>
|
||||||
|
|
@ -23,17 +21,26 @@
|
||||||
#include <extra2d/platform/backend_factory.h>
|
#include <extra2d/platform/backend_factory.h>
|
||||||
#include <extra2d/platform/window_module.h>
|
#include <extra2d/platform/window_module.h>
|
||||||
|
|
||||||
// Graphics
|
// Render Core
|
||||||
#include <extra2d/graphics/camera/camera.h>
|
#include <extra2d/render/core/render_backend.h>
|
||||||
#include <extra2d/graphics/texture/font.h>
|
#include <extra2d/render/core/render_command.h>
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
#include <extra2d/render/core/render_context.h>
|
||||||
#include <extra2d/graphics/core/render_module.h>
|
#include <extra2d/render/core/render_queue.h>
|
||||||
#include <extra2d/graphics/shader/shader_manager.h>
|
#include <extra2d/render/core/render_stats.h>
|
||||||
#include <extra2d/graphics/texture/texture.h>
|
#include <extra2d/render/core/render_module.h>
|
||||||
#include <extra2d/graphics/core/render_target.h>
|
#include <extra2d/render/core/backend_factory.h>
|
||||||
#include <extra2d/graphics/camera/viewport_adapter.h>
|
|
||||||
#include <extra2d/graphics/memory/vram_manager.h>
|
// Render Camera
|
||||||
#include <extra2d/graphics/texture/texture_pool.h>
|
#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)
|
// RHI (Render Hardware Interface)
|
||||||
#include <extra2d/render/rhi/rhi_types.h>
|
#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_device.h>
|
||||||
#include <extra2d/render/rhi/rhi_framebuffer.h>
|
#include <extra2d/render/rhi/rhi_framebuffer.h>
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include <memory>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
|
@ -34,11 +32,11 @@ public:
|
||||||
// 生命周期
|
// 生命周期
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
bool init(IWindow* window) override;
|
bool init(IWindow *window) override;
|
||||||
void shutdown() override;
|
void shutdown() override;
|
||||||
bool isValid() const override { return initialized_; }
|
bool isValid() const override { return initialized_; }
|
||||||
GraphicsAPI getAPI() const override { return GraphicsAPI::OpenGL; }
|
GraphicsAPI getAPI() const override { return GraphicsAPI::OpenGL; }
|
||||||
const DeviceCaps& getCaps() const override { return caps_; }
|
const DeviceCaps &getCaps() const override { return caps_; }
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
// 帧管理
|
// 帧管理
|
||||||
|
|
@ -55,54 +53,63 @@ public:
|
||||||
// 资源创建 - 缓冲区
|
// 资源创建 - 缓冲区
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
Ptr<RHIBuffer> createBuffer(const BufferDesc& desc) override;
|
Ptr<RHIBuffer> createBuffer(const BufferDesc &desc) override;
|
||||||
Ptr<RHIVertexBuffer> createVertexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
|
Ptr<RHIVertexBuffer>
|
||||||
const void* data = nullptr) override;
|
createVertexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
|
||||||
Ptr<RHIIndexBuffer> createIndexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
|
const void *data = nullptr) override;
|
||||||
const void* data = nullptr) override;
|
Ptr<RHIIndexBuffer> createIndexBuffer(size_t size,
|
||||||
Ptr<RHIUniformBuffer> createUniformBuffer(size_t size, BufferUsage usage = BufferUsage::Dynamic) override;
|
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> createTexture(const TextureDesc &desc) override;
|
||||||
Ptr<RHITexture> createTexture2D(uint32_t width, uint32_t height, Format format,
|
Ptr<RHITexture> createTexture2D(uint32_t width, uint32_t height,
|
||||||
const void* data = nullptr) override;
|
Format format,
|
||||||
Ptr<RHISampler> createSampler(const SamplerDesc& desc) override;
|
const void *data = nullptr) override;
|
||||||
Ptr<RHITextureView> createTextureView(Ptr<RHITexture> texture, const TextureViewDesc& desc) 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> createShader(const ShaderDesc &desc) override;
|
||||||
Ptr<RHIShader> createShaderFromSource(const std::string& name,
|
Ptr<RHIShader>
|
||||||
const std::string& vertexSource,
|
createShaderFromSource(const std::string &name,
|
||||||
const std::string& fragmentSource) override;
|
const std::string &vertexSource,
|
||||||
Ptr<RHIShader> createShaderFromFile(const std::string& vertexPath,
|
const std::string &fragmentSource) override;
|
||||||
const std::string& fragmentPath) 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 PipelineDesc &desc,
|
||||||
Ptr<RHIPipeline> createPipeline(const PipelineBuilder& builder) override;
|
Ptr<RHIShader> shader) override;
|
||||||
|
Ptr<RHIPipeline> createPipeline(const PipelineBuilder &builder) override;
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
// 资源创建 - 帧缓冲
|
// 资源创建 - 帧缓冲
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
Ptr<RHIFramebuffer> createFramebuffer(const FramebufferDesc& desc) override;
|
Ptr<RHIFramebuffer> createFramebuffer(const FramebufferDesc &desc) override;
|
||||||
Ptr<RHIFramebuffer> createFramebuffer(const FramebufferBuilder& builder) override;
|
Ptr<RHIFramebuffer>
|
||||||
|
createFramebuffer(const FramebufferBuilder &builder) override;
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
// 渲染状态设置
|
// 渲染状态设置
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
void setViewport(const Viewport& viewport) override;
|
void setViewport(const Viewport &viewport) override;
|
||||||
void setScissorRect(const ScissorRect& rect) override;
|
void setScissorRect(const ScissorRect &rect) override;
|
||||||
void setScissorEnabled(bool enabled) override;
|
void setScissorEnabled(bool enabled) override;
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
@ -111,9 +118,11 @@ public:
|
||||||
|
|
||||||
void setPipeline(Ptr<RHIPipeline> pipeline) override;
|
void setPipeline(Ptr<RHIPipeline> pipeline) override;
|
||||||
void setShader(Ptr<RHIShader> shader) override;
|
void setShader(Ptr<RHIShader> shader) override;
|
||||||
void setVertexBuffer(uint32_t slot, Ptr<RHIBuffer> buffer, uint32_t offset = 0) override;
|
void setVertexBuffer(uint32_t slot, Ptr<RHIBuffer> buffer,
|
||||||
|
uint32_t offset = 0) override;
|
||||||
void setIndexBuffer(Ptr<RHIBuffer> buffer, IndexFormat format) override;
|
void setIndexBuffer(Ptr<RHIBuffer> buffer, IndexFormat format) override;
|
||||||
void setTexture(uint32_t slot, Ptr<RHITexture> texture, Ptr<RHISampler> sampler = nullptr) override;
|
void setTexture(uint32_t slot, Ptr<RHITexture> texture,
|
||||||
|
Ptr<RHISampler> sampler = nullptr) override;
|
||||||
void setUniformBuffer(uint32_t slot, Ptr<RHIBuffer> buffer) override;
|
void setUniformBuffer(uint32_t slot, Ptr<RHIBuffer> buffer) override;
|
||||||
void setFramebuffer(Ptr<RHIFramebuffer> framebuffer) override;
|
void setFramebuffer(Ptr<RHIFramebuffer> framebuffer) override;
|
||||||
void setDefaultFramebuffer() override;
|
void setDefaultFramebuffer() override;
|
||||||
|
|
@ -122,45 +131,47 @@ public:
|
||||||
// 渲染命令 - Uniform 设置
|
// 渲染命令 - Uniform 设置
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
void setUniformFloat(const std::string& name, float value) override;
|
void setUniformFloat(const std::string &name, float value) override;
|
||||||
void setUniformVec2(const std::string& name, const glm::vec2& 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 setUniformVec3(const std::string &name, const glm::vec3 &value) override;
|
||||||
void setUniformVec4(const std::string& name, const glm::vec4& 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 setUniformMat4(const std::string &name, const glm::mat4 &value) override;
|
||||||
void setUniformInt(const std::string& name, int value) override;
|
void setUniformInt(const std::string &name, int value) override;
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
// 渲染命令 - 绘制
|
// 渲染命令 - 绘制
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
void draw(const DrawCommand& cmd) override;
|
void draw(const DrawCommand &cmd) override;
|
||||||
void drawIndexed(const DrawIndexedCommand& cmd) override;
|
void drawIndexed(const DrawIndexedCommand &cmd) override;
|
||||||
void drawIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) override;
|
void drawIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) override;
|
||||||
void drawIndexedIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) override;
|
void drawIndexedIndirect(Ptr<RHIBuffer> indirectBuffer,
|
||||||
|
size_t offset) override;
|
||||||
|
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
// 渲染命令 - 清除
|
// 渲染命令 - 清除
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
|
|
||||||
void clearColor(const ColorValue& color) override;
|
void clearColor(const ColorValue &color) override;
|
||||||
void clearDepth(float depth = 1.0f) override;
|
void clearDepth(float depth = 1.0f) override;
|
||||||
void clearStencil(uint8_t stencil = 0) override;
|
void clearStencil(uint8_t stencil = 0) override;
|
||||||
void clear(const ColorValue& color, float depth = 1.0f, 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_; }
|
const DeviceStats &getStats() const override { return stats_; }
|
||||||
void resetStats() override;
|
void resetStats() override;
|
||||||
bool checkError() override;
|
bool checkError() override;
|
||||||
const std::string& getDebugName() const override { return debugName_; }
|
const std::string &getDebugName() const override { return debugName_; }
|
||||||
void setDebugName(const std::string& name) override { debugName_ = name; }
|
void setDebugName(const std::string &name) override { debugName_ = name; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool initialized_ = false;
|
bool initialized_ = false;
|
||||||
bool vsyncEnabled_ = true;
|
bool vsyncEnabled_ = true;
|
||||||
IWindow* window_ = nullptr;
|
IWindow *window_ = nullptr;
|
||||||
DeviceCaps caps_;
|
DeviceCaps caps_;
|
||||||
DeviceStats stats_;
|
DeviceStats stats_;
|
||||||
std::string debugName_;
|
std::string debugName_;
|
||||||
|
|
@ -191,9 +202,9 @@ private:
|
||||||
/**
|
/**
|
||||||
* @brief 应用管线状态
|
* @brief 应用管线状态
|
||||||
*/
|
*/
|
||||||
void applyPipelineState(const BlendState& blend,
|
void applyPipelineState(const BlendState &blend,
|
||||||
const DepthStencilState& depthStencil,
|
const DepthStencilState &depthStencil,
|
||||||
const RasterizerState& rasterizer);
|
const RasterizerState &rasterizer);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace rhi
|
} // 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 形状类型枚举
|
* @brief 形状类型枚举
|
||||||
*/
|
*/
|
||||||
enum class ShapeType : uint8_t {
|
enum class ShapeType : uint8_t {
|
||||||
|
Point,
|
||||||
Line,
|
Line,
|
||||||
Rect,
|
Rect,
|
||||||
FilledRect,
|
FilledRect,
|
||||||
|
|
|
||||||
|
|
@ -3,48 +3,17 @@
|
||||||
#include <extra2d/core/color.h>
|
#include <extra2d/core/color.h>
|
||||||
#include <extra2d/core/math_types.h>
|
#include <extra2d/core/math_types.h>
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
|
#include <extra2d/render/core/render_backend.h>
|
||||||
#include <extra2d/render/core/render_queue.h>
|
#include <extra2d/render/core/render_queue.h>
|
||||||
#include <extra2d/render/rhi/rhi_device.h>
|
#include <extra2d/render/rhi/rhi_device.h>
|
||||||
#include <extra2d/render/rhi/rhi_types.h>
|
#include <extra2d/render/rhi/rhi_types.h>
|
||||||
#include <glm/mat4x4.hpp>
|
#include <glm/mat4x4.hpp>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
class IWindow;
|
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 渲染上下文配置
|
* @brief 渲染上下文配置
|
||||||
*/
|
*/
|
||||||
|
|
@ -56,11 +25,8 @@ struct RenderContextConfig {
|
||||||
rhi::GraphicsAPI preferredAPI;
|
rhi::GraphicsAPI preferredAPI;
|
||||||
|
|
||||||
RenderContextConfig()
|
RenderContextConfig()
|
||||||
: maxBatchSize(10000),
|
: maxBatchSize(10000), enableBatching(true), enableScissor(true),
|
||||||
enableBatching(true),
|
enableStats(true), preferredAPI(rhi::GraphicsAPI::OpenGL) {}
|
||||||
enableScissor(true),
|
|
||||||
enableStats(true),
|
|
||||||
preferredAPI(rhi::GraphicsAPI::OpenGL) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -73,14 +39,14 @@ public:
|
||||||
static constexpr uint32_t DEFAULT_MAX_BATCH_SIZE = 10000;
|
static constexpr uint32_t DEFAULT_MAX_BATCH_SIZE = 10000;
|
||||||
|
|
||||||
RenderContext();
|
RenderContext();
|
||||||
explicit RenderContext(const RenderContextConfig& config);
|
explicit RenderContext(const RenderContextConfig &config);
|
||||||
~RenderContext();
|
~RenderContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 初始化渲染上下文
|
* @brief 初始化渲染上下文
|
||||||
*/
|
*/
|
||||||
bool init(IWindow* window);
|
bool init(IWindow *window);
|
||||||
bool init(IWindow* window, rhi::GraphicsAPI api);
|
bool init(IWindow *window, rhi::GraphicsAPI api);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 关闭渲染上下文
|
* @brief 关闭渲染上下文
|
||||||
|
|
@ -110,20 +76,20 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief 清除屏幕
|
* @brief 清除屏幕
|
||||||
*/
|
*/
|
||||||
void clear(const Color& color = Colors::Black);
|
void clear(const Color &color = Colors::Black);
|
||||||
void clear(const Color& color, float depth, uint8_t stencil = 0);
|
void clear(const Color &color, float depth, uint8_t stencil = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取/设置视口
|
* @brief 获取/设置视口
|
||||||
*/
|
*/
|
||||||
void setViewport(const rhi::Viewport& viewport);
|
void setViewport(const rhi::Viewport &viewport);
|
||||||
void setViewport(float x, float y, float width, float height);
|
void setViewport(float x, float y, float width, float height);
|
||||||
rhi::Viewport getViewport() const;
|
rhi::Viewport getViewport() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取/设置裁剪区域
|
* @brief 获取/设置裁剪区域
|
||||||
*/
|
*/
|
||||||
void setScissorRect(const rhi::ScissorRect& rect);
|
void setScissorRect(const rhi::ScissorRect &rect);
|
||||||
void setScissorRect(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
void setScissorRect(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||||
void setScissorEnabled(bool enabled);
|
void setScissorEnabled(bool enabled);
|
||||||
rhi::ScissorRect getScissorRect() const;
|
rhi::ScissorRect getScissorRect() const;
|
||||||
|
|
@ -131,7 +97,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief 变换矩阵栈操作
|
* @brief 变换矩阵栈操作
|
||||||
*/
|
*/
|
||||||
void pushTransform(const glm::mat4& transform);
|
void pushTransform(const glm::mat4 &transform);
|
||||||
void popTransform();
|
void popTransform();
|
||||||
void resetTransform();
|
void resetTransform();
|
||||||
glm::mat4 getCurrentTransform() const;
|
glm::mat4 getCurrentTransform() const;
|
||||||
|
|
@ -139,16 +105,16 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief 混合状态操作
|
* @brief 混合状态操作
|
||||||
*/
|
*/
|
||||||
void setBlendState(const rhi::BlendState& blend);
|
void setBlendState(const rhi::BlendState &blend);
|
||||||
rhi::BlendState getBlendState() const;
|
rhi::BlendState getBlendState() const;
|
||||||
void pushBlendState(const rhi::BlendState& blend);
|
void pushBlendState(const rhi::BlendState &blend);
|
||||||
void popBlendState();
|
void popBlendState();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 渲染队列操作
|
* @brief 渲染队列操作
|
||||||
*/
|
*/
|
||||||
RenderQueue& getQueue() { return queue_; }
|
RenderQueue &getQueue() { return queue_; }
|
||||||
const RenderQueue& getQueue() const { return queue_; }
|
const RenderQueue &getQueue() const { return queue_; }
|
||||||
void clearQueue();
|
void clearQueue();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -164,19 +130,19 @@ public:
|
||||||
/**
|
/**
|
||||||
* @brief 获取窗口
|
* @brief 获取窗口
|
||||||
*/
|
*/
|
||||||
IWindow* getWindow() const { return window_; }
|
IWindow *getWindow() const { return window_; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取统计信息
|
* @brief 获取统计信息
|
||||||
*/
|
*/
|
||||||
const RenderStats& getStats() const { return stats_; }
|
const RenderStats &getStats() const { return stats_; }
|
||||||
void resetStats();
|
void resetStats();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取配置
|
* @brief 获取配置
|
||||||
*/
|
*/
|
||||||
const RenderContextConfig& getConfig() const { return config_; }
|
const RenderContextConfig &getConfig() const { return config_; }
|
||||||
void setConfig(const RenderContextConfig& config);
|
void setConfig(const RenderContextConfig &config);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取帧缓冲尺寸
|
* @brief 获取帧缓冲尺寸
|
||||||
|
|
@ -199,7 +165,7 @@ private:
|
||||||
void initDefaultState();
|
void initDefaultState();
|
||||||
|
|
||||||
Ptr<rhi::RHIDevice> device_;
|
Ptr<rhi::RHIDevice> device_;
|
||||||
IWindow* window_;
|
IWindow *window_;
|
||||||
RenderQueue queue_;
|
RenderQueue queue_;
|
||||||
RenderStats stats_;
|
RenderStats stats_;
|
||||||
RenderContextConfig config_;
|
RenderContextConfig config_;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#include <extra2d/core/math_types.h>
|
#include <extra2d/core/math_types.h>
|
||||||
#include <extra2d/core/types.h>
|
#include <extra2d/core/types.h>
|
||||||
#include <extra2d/event/event_dispatcher.h>
|
#include <extra2d/event/event_dispatcher.h>
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
#include <extra2d/render/core/render_backend.h>
|
||||||
#include <extra2d/scene/component.h>
|
#include <extra2d/scene/component.h>
|
||||||
#include <extra2d/scene/components/transform_component.h>
|
#include <extra2d/scene/components/transform_component.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
@ -31,7 +31,7 @@ public:
|
||||||
* @param name 节点名称
|
* @param name 节点名称
|
||||||
* @return 创建的节点智能指针
|
* @return 创建的节点智能指针
|
||||||
*/
|
*/
|
||||||
static Ptr<Node> create(const std::string& name = "");
|
static Ptr<Node> create(const std::string &name = "");
|
||||||
|
|
||||||
Node();
|
Node();
|
||||||
virtual ~Node();
|
virtual ~Node();
|
||||||
|
|
@ -50,7 +50,7 @@ public:
|
||||||
* @brief 批量添加子节点
|
* @brief 批量添加子节点
|
||||||
* @param children 子节点列表
|
* @param children 子节点列表
|
||||||
*/
|
*/
|
||||||
void addChildren(std::vector<Ptr<Node>>&& children);
|
void addChildren(std::vector<Ptr<Node>> &&children);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 移除子节点
|
* @brief 移除子节点
|
||||||
|
|
@ -62,7 +62,7 @@ public:
|
||||||
* @brief 通过名称移除子节点
|
* @brief 通过名称移除子节点
|
||||||
* @param name 子节点的名称
|
* @param name 子节点的名称
|
||||||
*/
|
*/
|
||||||
void removeChildByName(const std::string& name);
|
void removeChildByName(const std::string &name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 从父节点分离
|
* @brief 从父节点分离
|
||||||
|
|
@ -84,14 +84,14 @@ public:
|
||||||
* @brief 获取所有子节点
|
* @brief 获取所有子节点
|
||||||
* @return 子节点列表的常量引用
|
* @return 子节点列表的常量引用
|
||||||
*/
|
*/
|
||||||
const std::vector<Ptr<Node>>& getChildren() const { return children_; }
|
const std::vector<Ptr<Node>> &getChildren() const { return children_; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 通过名称查找子节点
|
* @brief 通过名称查找子节点
|
||||||
* @param name 子节点的名称
|
* @param name 子节点的名称
|
||||||
* @return 找到的子节点智能指针,未找到返回nullptr
|
* @return 找到的子节点智能指针,未找到返回nullptr
|
||||||
*/
|
*/
|
||||||
Ptr<Node> findChild(const std::string& name) const;
|
Ptr<Node> findChild(const std::string &name) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 通过标签查找子节点
|
* @brief 通过标签查找子节点
|
||||||
|
|
@ -111,8 +111,7 @@ public:
|
||||||
* @param args 构造函数参数
|
* @param args 构造函数参数
|
||||||
* @return 创建的组件指针
|
* @return 创建的组件指针
|
||||||
*/
|
*/
|
||||||
template<typename T, typename... Args>
|
template <typename T, typename... Args> T *addComponent(Args &&...args) {
|
||||||
T* addComponent(Args&&... args) {
|
|
||||||
static_assert(std::is_base_of<Component, T>::value,
|
static_assert(std::is_base_of<Component, T>::value,
|
||||||
"T must derive from Component");
|
"T must derive from Component");
|
||||||
|
|
||||||
|
|
@ -121,7 +120,7 @@ public:
|
||||||
// 检查是否已存在相同类型的组件
|
// 检查是否已存在相同类型的组件
|
||||||
auto it = components_.find(typeId);
|
auto it = components_.find(typeId);
|
||||||
if (it != components_.end()) {
|
if (it != components_.end()) {
|
||||||
return static_cast<T*>(it->second.get());
|
return static_cast<T *>(it->second.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建新组件
|
// 创建新组件
|
||||||
|
|
@ -140,15 +139,14 @@ public:
|
||||||
* @tparam T 组件类型
|
* @tparam T 组件类型
|
||||||
* @return 组件指针,不存在返回nullptr
|
* @return 组件指针,不存在返回nullptr
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template <typename T> T *getComponent() const {
|
||||||
T* getComponent() const {
|
|
||||||
static_assert(std::is_base_of<Component, T>::value,
|
static_assert(std::is_base_of<Component, T>::value,
|
||||||
"T must derive from Component");
|
"T must derive from Component");
|
||||||
|
|
||||||
uint32_t typeId = T::getStaticTypeId();
|
uint32_t typeId = T::getStaticTypeId();
|
||||||
auto it = components_.find(typeId);
|
auto it = components_.find(typeId);
|
||||||
if (it != components_.end()) {
|
if (it != components_.end()) {
|
||||||
return static_cast<T*>(it->second.get());
|
return static_cast<T *>(it->second.get());
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -158,8 +156,7 @@ public:
|
||||||
* @tparam T 组件类型
|
* @tparam T 组件类型
|
||||||
* @return 如果存在返回true
|
* @return 如果存在返回true
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template <typename T> bool hasComponent() const {
|
||||||
bool hasComponent() const {
|
|
||||||
return getComponent<T>() != nullptr;
|
return getComponent<T>() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,8 +164,7 @@ public:
|
||||||
* @brief 移除组件
|
* @brief 移除组件
|
||||||
* @tparam T 组件类型
|
* @tparam T 组件类型
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template <typename T> void removeComponent() {
|
||||||
void removeComponent() {
|
|
||||||
static_assert(std::is_base_of<Component, T>::value,
|
static_assert(std::is_base_of<Component, T>::value,
|
||||||
"T must derive from Component");
|
"T must derive from Component");
|
||||||
|
|
||||||
|
|
@ -186,7 +182,7 @@ public:
|
||||||
* @brief 获取变换组件
|
* @brief 获取变换组件
|
||||||
* @return 变换组件指针
|
* @return 变换组件指针
|
||||||
*/
|
*/
|
||||||
TransformComponent* getTransform() const { return transform_; }
|
TransformComponent *getTransform() const { return transform_; }
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// 变换属性(便捷方法,委托给TransformComponent)
|
// 变换属性(便捷方法,委托给TransformComponent)
|
||||||
|
|
@ -196,7 +192,7 @@ public:
|
||||||
* @brief 设置节点位置
|
* @brief 设置节点位置
|
||||||
* @param pos 新的位置坐标
|
* @param pos 新的位置坐标
|
||||||
*/
|
*/
|
||||||
void setPos(const Vec2& pos);
|
void setPos(const Vec2 &pos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 设置节点位置
|
* @brief 设置节点位置
|
||||||
|
|
@ -227,7 +223,7 @@ public:
|
||||||
* @brief 设置节点缩放
|
* @brief 设置节点缩放
|
||||||
* @param scale 缩放向量
|
* @param scale 缩放向量
|
||||||
*/
|
*/
|
||||||
void setScale(const Vec2& scale);
|
void setScale(const Vec2 &scale);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 设置节点统一缩放
|
* @brief 设置节点统一缩放
|
||||||
|
|
@ -252,7 +248,7 @@ public:
|
||||||
* @brief 设置节点锚点
|
* @brief 设置节点锚点
|
||||||
* @param anchor 锚点位置(0-1范围)
|
* @param anchor 锚点位置(0-1范围)
|
||||||
*/
|
*/
|
||||||
void setAnchor(const Vec2& anchor);
|
void setAnchor(const Vec2 &anchor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 设置节点锚点
|
* @brief 设置节点锚点
|
||||||
|
|
@ -271,7 +267,7 @@ public:
|
||||||
* @brief 设置节点斜切
|
* @brief 设置节点斜切
|
||||||
* @param skew 斜切角度向量
|
* @param skew 斜切角度向量
|
||||||
*/
|
*/
|
||||||
void setSkew(const Vec2& skew);
|
void setSkew(const Vec2 &skew);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 设置节点斜切
|
* @brief 设置节点斜切
|
||||||
|
|
@ -295,14 +291,14 @@ public:
|
||||||
* @param localPos 本地坐标位置
|
* @param localPos 本地坐标位置
|
||||||
* @return 世界坐标位置
|
* @return 世界坐标位置
|
||||||
*/
|
*/
|
||||||
Vec2 toWorld(const Vec2& localPos) const;
|
Vec2 toWorld(const Vec2 &localPos) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 将世界坐标转换为本地坐标
|
* @brief 将世界坐标转换为本地坐标
|
||||||
* @param worldPos 世界坐标位置
|
* @param worldPos 世界坐标位置
|
||||||
* @return 本地坐标位置
|
* @return 本地坐标位置
|
||||||
*/
|
*/
|
||||||
Vec2 toLocal(const Vec2& worldPos) const;
|
Vec2 toLocal(const Vec2 &worldPos) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取本地变换矩阵
|
* @brief 获取本地变换矩阵
|
||||||
|
|
@ -364,7 +360,7 @@ public:
|
||||||
* @brief 设置颜色
|
* @brief 设置颜色
|
||||||
* @param color RGB颜色
|
* @param color RGB颜色
|
||||||
*/
|
*/
|
||||||
void setColor(const Color3B& color);
|
void setColor(const Color3B &color);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取颜色
|
* @brief 获取颜色
|
||||||
|
|
@ -412,13 +408,13 @@ public:
|
||||||
* @brief 设置名称
|
* @brief 设置名称
|
||||||
* @param name 节点名称
|
* @param name 节点名称
|
||||||
*/
|
*/
|
||||||
void setName(const std::string& name) { name_ = name; }
|
void setName(const std::string &name) { name_ = name; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取名称
|
* @brief 获取名称
|
||||||
* @return 节点名称
|
* @return 节点名称
|
||||||
*/
|
*/
|
||||||
const std::string& getName() const { return name_; }
|
const std::string &getName() const { return name_; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 设置标签
|
* @brief 设置标签
|
||||||
|
|
@ -456,13 +452,13 @@ public:
|
||||||
* @brief 渲染回调
|
* @brief 渲染回调
|
||||||
* @param renderer 渲染后端引用
|
* @param renderer 渲染后端引用
|
||||||
*/
|
*/
|
||||||
virtual void onRender(RenderBackend& renderer);
|
virtual void onRender(RenderBackend &renderer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 附加到场景时的回调
|
* @brief 附加到场景时的回调
|
||||||
* @param scene 所属场景指针
|
* @param scene 所属场景指针
|
||||||
*/
|
*/
|
||||||
virtual void onAttachToScene(Scene* scene);
|
virtual void onAttachToScene(Scene *scene);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 从场景分离时的回调
|
* @brief 从场景分离时的回调
|
||||||
|
|
@ -487,7 +483,7 @@ public:
|
||||||
* @brief 获取事件分发器
|
* @brief 获取事件分发器
|
||||||
* @return 事件分发器引用
|
* @return 事件分发器引用
|
||||||
*/
|
*/
|
||||||
EventDispatcher& getEventDispatcher() { return eventDispatcher_; }
|
EventDispatcher &getEventDispatcher() { return eventDispatcher_; }
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// 内部方法
|
// 内部方法
|
||||||
|
|
@ -503,7 +499,7 @@ public:
|
||||||
* @brief 渲染节点
|
* @brief 渲染节点
|
||||||
* @param renderer 渲染后端引用
|
* @param renderer 渲染后端引用
|
||||||
*/
|
*/
|
||||||
void render(RenderBackend& renderer);
|
void render(RenderBackend &renderer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 对子节点排序
|
* @brief 对子节点排序
|
||||||
|
|
@ -520,28 +516,28 @@ public:
|
||||||
* @brief 获取所属场景
|
* @brief 获取所属场景
|
||||||
* @return 所属场景指针
|
* @return 所属场景指针
|
||||||
*/
|
*/
|
||||||
Scene* getScene() const { return scene_; }
|
Scene *getScene() const { return scene_; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 收集渲染命令
|
* @brief 收集渲染命令
|
||||||
* @param commands 渲染命令输出向量
|
* @param commands 渲染命令输出向量
|
||||||
* @param parentZOrder 父节点的Z序
|
* @param parentZOrder 父节点的Z序
|
||||||
*/
|
*/
|
||||||
virtual void collectRenderCommands(std::vector<RenderCommand>& commands,
|
virtual void collectRenderCommands(std::vector<RenderCommand> &commands,
|
||||||
int parentZOrder = 0);
|
int parentZOrder = 0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 收集渲染命令到队列
|
* @brief 收集渲染命令到队列
|
||||||
* @param queue 渲染队列引用
|
* @param queue 渲染队列引用
|
||||||
*/
|
*/
|
||||||
virtual void collectRenderCommandsToQueue(RenderQueue& queue);
|
virtual void collectRenderCommandsToQueue(RenderQueue &queue);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief 绘制回调(子类重写)
|
* @brief 绘制回调(子类重写)
|
||||||
* @param renderer 渲染后端引用
|
* @param renderer 渲染后端引用
|
||||||
*/
|
*/
|
||||||
virtual void onDraw(RenderBackend& renderer) {}
|
virtual void onDraw(RenderBackend &renderer) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 节点更新回调(子类重写)
|
* @brief 节点更新回调(子类重写)
|
||||||
|
|
@ -554,14 +550,14 @@ protected:
|
||||||
* @param commands 渲染命令输出向量
|
* @param commands 渲染命令输出向量
|
||||||
* @param zOrder Z序
|
* @param zOrder Z序
|
||||||
*/
|
*/
|
||||||
virtual void generateRenderCommand(std::vector<RenderCommand>& commands,
|
virtual void generateRenderCommand(std::vector<RenderCommand> &commands,
|
||||||
int zOrder) {}
|
int zOrder) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 生成渲染命令到队列(子类重写)
|
* @brief 生成渲染命令到队列(子类重写)
|
||||||
* @param queue 渲染队列引用
|
* @param queue 渲染队列引用
|
||||||
*/
|
*/
|
||||||
virtual void generateRenderCommandToQueue(RenderQueue& queue) { (void)queue; }
|
virtual void generateRenderCommandToQueue(RenderQueue &queue) { (void)queue; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
@ -588,7 +584,7 @@ private:
|
||||||
WeakPtr<Node> parent_;
|
WeakPtr<Node> parent_;
|
||||||
|
|
||||||
// 6. 变换组件(内置)
|
// 6. 变换组件(内置)
|
||||||
TransformComponent* transform_ = nullptr;
|
TransformComponent *transform_ = nullptr;
|
||||||
|
|
||||||
// 7. 浮点属性
|
// 7. 浮点属性
|
||||||
float opacity_ = 1.0f;
|
float opacity_ = 1.0f;
|
||||||
|
|
@ -605,7 +601,7 @@ private:
|
||||||
bool flipY_ = false;
|
bool flipY_ = false;
|
||||||
|
|
||||||
// 11. 场景指针
|
// 11. 场景指针
|
||||||
Scene* scene_ = nullptr;
|
Scene *scene_ = nullptr;
|
||||||
|
|
||||||
// 12. 布尔标志(打包在一起)
|
// 12. 布尔标志(打包在一起)
|
||||||
mutable bool transformDirty_ = true;
|
mutable bool transformDirty_ = true;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <extra2d/core/color.h>
|
#include <extra2d/core/color.h>
|
||||||
#include <extra2d/graphics/camera/camera.h>
|
#include <extra2d/render/camera/camera.h>
|
||||||
#include <extra2d/scene/node.h>
|
#include <extra2d/scene/node.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
@ -27,7 +27,7 @@ public:
|
||||||
* @brief 设置背景颜色
|
* @brief 设置背景颜色
|
||||||
* @param color 背景颜色
|
* @param color 背景颜色
|
||||||
*/
|
*/
|
||||||
void setBackgroundColor(const Color& color) { backgroundColor_ = color; }
|
void setBackgroundColor(const Color &color) { backgroundColor_ = color; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取背景颜色
|
* @brief 获取背景颜色
|
||||||
|
|
@ -55,7 +55,7 @@ public:
|
||||||
* @brief 获取活动相机
|
* @brief 获取活动相机
|
||||||
* @return 活动相机指针(优先返回设置的相机,否则返回默认相机)
|
* @return 活动相机指针(优先返回设置的相机,否则返回默认相机)
|
||||||
*/
|
*/
|
||||||
Camera* getActiveCamera() const {
|
Camera *getActiveCamera() const {
|
||||||
return camera_ ? camera_.get() : defaultCamera_.get();
|
return camera_ ? camera_.get() : defaultCamera_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,7 +74,7 @@ public:
|
||||||
* @brief 设置视口大小
|
* @brief 设置视口大小
|
||||||
* @param size 视口尺寸结构体
|
* @param size 视口尺寸结构体
|
||||||
*/
|
*/
|
||||||
void setViewportSize(const Size& size);
|
void setViewportSize(const Size &size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取视口大小
|
* @brief 获取视口大小
|
||||||
|
|
@ -122,13 +122,13 @@ public:
|
||||||
* @brief 渲染场景
|
* @brief 渲染场景
|
||||||
* @param renderer 渲染后端引用
|
* @param renderer 渲染后端引用
|
||||||
*/
|
*/
|
||||||
void renderScene(RenderBackend& renderer);
|
void renderScene(RenderBackend &renderer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 渲染场景内容
|
* @brief 渲染场景内容
|
||||||
* @param renderer 渲染后端引用
|
* @param renderer 渲染后端引用
|
||||||
*/
|
*/
|
||||||
virtual void renderContent(RenderBackend& renderer);
|
virtual void renderContent(RenderBackend &renderer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 更新场景
|
* @brief 更新场景
|
||||||
|
|
@ -141,14 +141,14 @@ public:
|
||||||
* @param commands 渲染命令输出向量
|
* @param commands 渲染命令输出向量
|
||||||
* @param parentZOrder 父节点的Z序
|
* @param parentZOrder 父节点的Z序
|
||||||
*/
|
*/
|
||||||
void collectRenderCommands(std::vector<RenderCommand>& commands,
|
void collectRenderCommands(std::vector<RenderCommand> &commands,
|
||||||
int parentZOrder = 0) override;
|
int parentZOrder = 0) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 收集渲染命令到队列
|
* @brief 收集渲染命令到队列
|
||||||
* @param queue 渲染队列引用
|
* @param queue 渲染队列引用
|
||||||
*/
|
*/
|
||||||
void collectRenderCommandsToQueue(RenderQueue& queue) override;
|
void collectRenderCommandsToQueue(RenderQueue &queue) override;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// 静态创建方法
|
// 静态创建方法
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,12 @@
|
||||||
|
|
||||||
#include <extra2d/core/color.h>
|
#include <extra2d/core/color.h>
|
||||||
#include <extra2d/core/math_types.h>
|
#include <extra2d/core/math_types.h>
|
||||||
|
#include <extra2d/render/core/render_command.h>
|
||||||
#include <extra2d/scene/node.h>
|
#include <extra2d/scene/node.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// 形状类型
|
|
||||||
// ============================================================================
|
|
||||||
enum class ShapeType { Point, Line, Rect, Circle, Triangle, Polygon };
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// 形状节点 - 用于绘制几何形状
|
// 形状节点 - 用于绘制几何形状
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <extra2d/graphics/texture/texture.h>
|
#include <extra2d/resources/texture.h>
|
||||||
#include <extra2d/scene/node.h>
|
#include <extra2d/scene/node.h>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
#include <extra2d/core/service_interface.h>
|
#include <extra2d/core/service_interface.h>
|
||||||
#include <extra2d/core/service_locator.h>
|
#include <extra2d/core/service_locator.h>
|
||||||
#include <extra2d/graphics/camera/camera.h>
|
#include <extra2d/render/camera/camera.h>
|
||||||
#include <extra2d/graphics/camera/viewport_adapter.h>
|
#include <extra2d/render/camera/viewport_adapter.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
#include <extra2d/app/application.h>
|
#include <extra2d/app/application.h>
|
||||||
#include <extra2d/core/registry.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/iinput.h>
|
||||||
#include <extra2d/platform/input_module.h>
|
#include <extra2d/platform/input_module.h>
|
||||||
#include <extra2d/platform/iwindow.h>
|
#include <extra2d/platform/iwindow.h>
|
||||||
#include <extra2d/platform/window_module.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/camera_service.h>
|
||||||
#include <extra2d/services/event_service.h>
|
#include <extra2d/services/event_service.h>
|
||||||
#include <extra2d/services/logger_service.h>
|
#include <extra2d/services/logger_service.h>
|
||||||
#include <extra2d/services/scene_service.h>
|
#include <extra2d/services/scene_service.h>
|
||||||
#include <extra2d/services/timer_service.h>
|
#include <extra2d/services/timer_service.h>
|
||||||
|
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
static double getTimeSeconds() {
|
static double getTimeSeconds() {
|
||||||
|
|
@ -81,9 +81,9 @@ void Application::configureCameraService() {
|
||||||
static_cast<float>(win->height()), 0);
|
static_cast<float>(win->height()), 0);
|
||||||
|
|
||||||
ViewportConfig vpConfig;
|
ViewportConfig vpConfig;
|
||||||
vpConfig.logicWidth = static_cast<float>(win->width());
|
vpConfig.designWidth = static_cast<float>(win->width());
|
||||||
vpConfig.logicHeight = static_cast<float>(win->height());
|
vpConfig.designHeight = static_cast<float>(win->height());
|
||||||
vpConfig.mode = ViewportMode::AspectRatio;
|
vpConfig.scaleMode = ViewportScaleMode::Letterbox;
|
||||||
cameraService->setViewportConfig(vpConfig);
|
cameraService->setViewportConfig(vpConfig);
|
||||||
cameraService->updateViewport(win->width(), win->height());
|
cameraService->updateViewport(win->width(), win->height());
|
||||||
|
|
||||||
|
|
@ -97,8 +97,6 @@ void Application::shutdown() {
|
||||||
if (!initialized_)
|
if (!initialized_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
VRAMMgr::get().printStats();
|
|
||||||
|
|
||||||
ServiceLocator::instance().shutdownAll();
|
ServiceLocator::instance().shutdownAll();
|
||||||
ServiceLocator::instance().clear();
|
ServiceLocator::instance().clear();
|
||||||
Registry::instance().shutdown();
|
Registry::instance().shutdown();
|
||||||
|
|
@ -176,8 +174,7 @@ void Application::mainLoop() {
|
||||||
|
|
||||||
// 帧率限制
|
// 帧率限制
|
||||||
auto *renderMod = get<RenderModule>();
|
auto *renderMod = get<RenderModule>();
|
||||||
if (renderMod && renderMod->renderer()) {
|
if (renderMod && renderMod->getRenderer()) {
|
||||||
// 这里可以添加帧率限制逻辑
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -192,29 +189,28 @@ void Application::update() {
|
||||||
|
|
||||||
void Application::render() {
|
void Application::render() {
|
||||||
auto *renderMod = get<RenderModule>();
|
auto *renderMod = get<RenderModule>();
|
||||||
if (!renderMod || !renderMod->renderer())
|
if (!renderMod || !renderMod->getRenderer())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto *renderer = renderMod->renderer();
|
auto *renderer = renderMod->getRenderer();
|
||||||
auto *winMod = get<WindowModule>();
|
auto *winMod = get<WindowModule>();
|
||||||
if (!winMod || !winMod->win())
|
if (!winMod || !winMod->win())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto cameraService = ServiceLocator::instance().getService<ICameraService>();
|
auto cameraService = ServiceLocator::instance().getService<ICameraService>();
|
||||||
if (cameraService) {
|
if (cameraService) {
|
||||||
const auto &vp = cameraService->getViewportResult().viewport;
|
const auto &vpResult = cameraService->getViewportResult();
|
||||||
renderer->setViewport(
|
renderer->setViewport(
|
||||||
static_cast<int>(vp.origin.x), static_cast<int>(vp.origin.y),
|
vpResult.offsetX, vpResult.offsetY,
|
||||||
static_cast<int>(vp.size.width), static_cast<int>(vp.size.height));
|
static_cast<int>(vpResult.width), static_cast<int>(vpResult.height));
|
||||||
renderer->setViewProjection(cameraService->getViewProjectionMatrix());
|
|
||||||
} else {
|
} else {
|
||||||
renderer->setViewport(0, 0, winMod->win()->width(),
|
renderer->setViewport(0, 0, winMod->win()->width(),
|
||||||
winMod->win()->height());
|
winMod->win()->height());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sceneService = ServiceLocator::instance().getService<ISceneService>();
|
auto sceneService = ServiceLocator::instance().getService<ISceneService>();
|
||||||
if (sceneService) {
|
if (sceneService && renderer->getBackend()) {
|
||||||
sceneService->render(*renderer);
|
sceneService->render(*renderer->getBackend());
|
||||||
}
|
}
|
||||||
|
|
||||||
winMod->win()->swap();
|
winMod->win()->swap();
|
||||||
|
|
@ -227,7 +223,7 @@ IWindow *Application::window() {
|
||||||
|
|
||||||
RenderBackend *Application::renderer() {
|
RenderBackend *Application::renderer() {
|
||||||
auto *renderMod = get<RenderModule>();
|
auto *renderMod = get<RenderModule>();
|
||||||
return renderMod ? renderMod->renderer() : nullptr;
|
return renderMod ? (renderMod->getRenderer() ? renderMod->getRenderer()->getBackend() : nullptr) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
IInput *Application::input() {
|
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_texture.h>
|
||||||
#include <extra2d/render/backends/opengl/gl_rhi_shader.h>
|
#include <extra2d/render/backends/opengl/gl_rhi_shader.h>
|
||||||
#include <extra2d/render/backends/opengl/gl_rhi_pipeline.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/services/logger_service.h>
|
||||||
#include <extra2d/platform/iwindow.h>
|
#include <extra2d/platform/iwindow.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,23 @@
|
||||||
|
#include <cmath>
|
||||||
#include <extra2d/render/batch/shape_batcher.h>
|
#include <extra2d/render/batch/shape_batcher.h>
|
||||||
#include <extra2d/resources/shader_manager.h>
|
#include <extra2d/resources/shader_manager.h>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
ShapeBatcher::ShapeBatcher()
|
ShapeBatcher::ShapeBatcher()
|
||||||
: device_(nullptr), shader_(nullptr), pipeline_(nullptr), linePipeline_(nullptr),
|
: device_(nullptr), shader_(nullptr), pipeline_(nullptr),
|
||||||
vertexBuffer_(nullptr), indexBuffer_(nullptr), uniformBuffer_(nullptr),
|
linePipeline_(nullptr), vertexBuffer_(nullptr), indexBuffer_(nullptr),
|
||||||
viewProj_(1.0f), currentBlend_(rhi::BlendState::alphaBlend()),
|
uniformBuffer_(nullptr), viewProj_(1.0f),
|
||||||
currentVertexIndex_(0), currentIndexIndex_(0),
|
currentBlend_(rhi::BlendState::alphaBlend()), currentVertexIndex_(0),
|
||||||
drawCallCount_(0), shapeCount_(0), batchCount_(0),
|
currentIndexIndex_(0), drawCallCount_(0), shapeCount_(0), batchCount_(0),
|
||||||
initialized_(false), inBatch_(false) {
|
initialized_(false), inBatch_(false) {}
|
||||||
}
|
|
||||||
|
|
||||||
ShapeBatcher::ShapeBatcher(const ShapeBatcherConfig& config)
|
ShapeBatcher::ShapeBatcher(const ShapeBatcherConfig &config) : ShapeBatcher() {
|
||||||
: ShapeBatcher() {
|
|
||||||
config_ = config;
|
config_ = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShapeBatcher::~ShapeBatcher() {
|
ShapeBatcher::~ShapeBatcher() { shutdown(); }
|
||||||
shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ShapeBatcher::init(Ptr<rhi::RHIDevice> device) {
|
bool ShapeBatcher::init(Ptr<rhi::RHIDevice> device) {
|
||||||
if (initialized_) {
|
if (initialized_) {
|
||||||
|
|
@ -73,11 +69,9 @@ void ShapeBatcher::shutdown() {
|
||||||
inBatch_ = false;
|
inBatch_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::begin() {
|
void ShapeBatcher::begin() { begin(viewProj_); }
|
||||||
begin(viewProj_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ShapeBatcher::begin(const glm::mat4& viewProj) {
|
void ShapeBatcher::begin(const glm::mat4 &viewProj) {
|
||||||
if (!initialized_ || inBatch_) {
|
if (!initialized_ || inBatch_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -109,8 +103,8 @@ void ShapeBatcher::end() {
|
||||||
inBatch_ = false;
|
inBatch_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawLine(const Vec2& start, const Vec2& end,
|
void ShapeBatcher::drawLine(const Vec2 &start, const Vec2 &end,
|
||||||
const Color& color, float width) {
|
const Color &color, float width) {
|
||||||
if (!initialized_ || !inBatch_) {
|
if (!initialized_ || !inBatch_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -124,8 +118,8 @@ void ShapeBatcher::drawLine(const Vec2& start, const Vec2& end,
|
||||||
shapeCount_++;
|
shapeCount_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawLines(const std::vector<Vec2>& points,
|
void ShapeBatcher::drawLines(const std::vector<Vec2> &points,
|
||||||
const Color& color, float width) {
|
const Color &color, float width) {
|
||||||
if (!initialized_ || !inBatch_ || points.size() < 2) {
|
if (!initialized_ || !inBatch_ || points.size() < 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -135,8 +129,8 @@ void ShapeBatcher::drawLines(const std::vector<Vec2>& points,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawPolyline(const std::vector<Vec2>& points,
|
void ShapeBatcher::drawPolyline(const std::vector<Vec2> &points,
|
||||||
const Color& color, float width) {
|
const Color &color, float width) {
|
||||||
if (!initialized_ || !inBatch_ || points.size() < 2) {
|
if (!initialized_ || !inBatch_ || points.size() < 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -146,7 +140,7 @@ void ShapeBatcher::drawPolyline(const std::vector<Vec2>& points,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawRect(const Rect& rect, const Color& color, float width) {
|
void ShapeBatcher::drawRect(const Rect &rect, const Color &color, float width) {
|
||||||
if (!initialized_ || !inBatch_) {
|
if (!initialized_ || !inBatch_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -162,15 +156,19 @@ void ShapeBatcher::drawRect(const Rect& rect, const Color& color, float width) {
|
||||||
drawLine(p4, p1, color, width);
|
drawLine(p4, p1, color, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawFilledRect(const Rect& rect, const Color& color) {
|
void ShapeBatcher::drawFilledRect(const Rect &rect, const Color &color) {
|
||||||
if (!initialized_ || !inBatch_) {
|
if (!initialized_ || !inBatch_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t i0 = addVertex(Vec2(rect.origin.x, rect.origin.y), color);
|
uint32_t i0 = addVertex(Vec2(rect.origin.x, rect.origin.y), color);
|
||||||
uint32_t i1 = addVertex(Vec2(rect.origin.x + rect.size.width, rect.origin.y), color);
|
uint32_t i1 =
|
||||||
uint32_t i2 = addVertex(Vec2(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height), color);
|
addVertex(Vec2(rect.origin.x + rect.size.width, rect.origin.y), color);
|
||||||
uint32_t i3 = addVertex(Vec2(rect.origin.x, rect.origin.y + rect.size.height), color);
|
uint32_t i2 = addVertex(
|
||||||
|
Vec2(rect.origin.x + rect.size.width, rect.origin.y + rect.size.height),
|
||||||
|
color);
|
||||||
|
uint32_t i3 =
|
||||||
|
addVertex(Vec2(rect.origin.x, rect.origin.y + rect.size.height), color);
|
||||||
|
|
||||||
addIndex(i0);
|
addIndex(i0);
|
||||||
addIndex(i1);
|
addIndex(i1);
|
||||||
|
|
@ -182,8 +180,8 @@ void ShapeBatcher::drawFilledRect(const Rect& rect, const Color& color) {
|
||||||
shapeCount_++;
|
shapeCount_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawCircle(const Vec2& center, float radius,
|
void ShapeBatcher::drawCircle(const Vec2 ¢er, float radius,
|
||||||
const Color& color, int segments, float width) {
|
const Color &color, int segments, float width) {
|
||||||
if (!initialized_ || !inBatch_ || radius <= 0.0f) {
|
if (!initialized_ || !inBatch_ || radius <= 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -198,8 +196,8 @@ void ShapeBatcher::drawCircle(const Vec2& center, float radius,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawFilledCircle(const Vec2& center, float radius,
|
void ShapeBatcher::drawFilledCircle(const Vec2 ¢er, float radius,
|
||||||
const Color& color, int segments) {
|
const Color &color, int segments) {
|
||||||
if (!initialized_ || !inBatch_ || radius <= 0.0f) {
|
if (!initialized_ || !inBatch_ || radius <= 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -222,8 +220,8 @@ void ShapeBatcher::drawFilledCircle(const Vec2& center, float radius,
|
||||||
shapeCount_++;
|
shapeCount_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawEllipse(const Vec2& center, float radiusX, float radiusY,
|
void ShapeBatcher::drawEllipse(const Vec2 ¢er, float radiusX, float radiusY,
|
||||||
const Color& color, int segments, float width) {
|
const Color &color, int segments, float width) {
|
||||||
if (!initialized_ || !inBatch_ || radiusX <= 0.0f || radiusY <= 0.0f) {
|
if (!initialized_ || !inBatch_ || radiusX <= 0.0f || radiusY <= 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -238,8 +236,9 @@ void ShapeBatcher::drawEllipse(const Vec2& center, float radiusX, float radiusY,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawFilledEllipse(const Vec2& center, float radiusX, float radiusY,
|
void ShapeBatcher::drawFilledEllipse(const Vec2 ¢er, float radiusX,
|
||||||
const Color& color, int segments) {
|
float radiusY, const Color &color,
|
||||||
|
int segments) {
|
||||||
if (!initialized_ || !inBatch_ || radiusX <= 0.0f || radiusY <= 0.0f) {
|
if (!initialized_ || !inBatch_ || radiusX <= 0.0f || radiusY <= 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -262,8 +261,8 @@ void ShapeBatcher::drawFilledEllipse(const Vec2& center, float radiusX, float ra
|
||||||
shapeCount_++;
|
shapeCount_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3,
|
void ShapeBatcher::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
|
||||||
const Color& color, float width) {
|
const Color &color, float width) {
|
||||||
if (!initialized_ || !inBatch_) {
|
if (!initialized_ || !inBatch_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -273,8 +272,8 @@ void ShapeBatcher::drawTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3,
|
||||||
drawLine(p3, p1, color, width);
|
drawLine(p3, p1, color, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawFilledTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3,
|
void ShapeBatcher::drawFilledTriangle(const Vec2 &p1, const Vec2 &p2,
|
||||||
const Color& color) {
|
const Vec2 &p3, const Color &color) {
|
||||||
if (!initialized_ || !inBatch_) {
|
if (!initialized_ || !inBatch_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -290,8 +289,8 @@ void ShapeBatcher::drawFilledTriangle(const Vec2& p1, const Vec2& p2, const Vec2
|
||||||
shapeCount_++;
|
shapeCount_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawPolygon(const std::vector<Vec2>& points,
|
void ShapeBatcher::drawPolygon(const std::vector<Vec2> &points,
|
||||||
const Color& color, float width) {
|
const Color &color, float width) {
|
||||||
if (!initialized_ || !inBatch_ || points.size() < 3) {
|
if (!initialized_ || !inBatch_ || points.size() < 3) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -302,8 +301,8 @@ void ShapeBatcher::drawPolygon(const std::vector<Vec2>& points,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawFilledPolygon(const std::vector<Vec2>& points,
|
void ShapeBatcher::drawFilledPolygon(const std::vector<Vec2> &points,
|
||||||
const Color& color) {
|
const Color &color) {
|
||||||
if (!initialized_ || !inBatch_ || points.size() < 3) {
|
if (!initialized_ || !inBatch_ || points.size() < 3) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -322,9 +321,9 @@ void ShapeBatcher::drawFilledPolygon(const std::vector<Vec2>& points,
|
||||||
shapeCount_++;
|
shapeCount_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::drawArc(const Vec2& center, float radius,
|
void ShapeBatcher::drawArc(const Vec2 ¢er, float radius, float startAngle,
|
||||||
float startAngle, float endAngle,
|
float endAngle, const Color &color, int segments,
|
||||||
const Color& color, int segments, float width) {
|
float width) {
|
||||||
if (!initialized_ || !inBatch_ || radius <= 0.0f) {
|
if (!initialized_ || !inBatch_ || radius <= 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -344,12 +343,12 @@ void ShapeBatcher::drawArc(const Vec2& center, float radius,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::draw(const RenderCommand& command) {
|
void ShapeBatcher::draw(const RenderCommand &command) {
|
||||||
if (command.type != RenderCommandType::Shape) {
|
if (command.type != RenderCommandType::Shape) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& data = std::get<ShapeRenderData>(command.data);
|
const auto &data = std::get<ShapeRenderData>(command.data);
|
||||||
|
|
||||||
switch (data.shapeType) {
|
switch (data.shapeType) {
|
||||||
case ShapeType::Line:
|
case ShapeType::Line:
|
||||||
|
|
@ -375,7 +374,8 @@ void ShapeBatcher::draw(const RenderCommand& command) {
|
||||||
break;
|
break;
|
||||||
case ShapeType::Circle:
|
case ShapeType::Circle:
|
||||||
if (data.points.size() >= 1) {
|
if (data.points.size() >= 1) {
|
||||||
drawCircle(data.points[0], data.radius, data.color, data.segments, data.lineWidth);
|
drawCircle(data.points[0], data.radius, data.color, data.segments,
|
||||||
|
data.lineWidth);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ShapeType::FilledCircle:
|
case ShapeType::FilledCircle:
|
||||||
|
|
@ -385,13 +385,14 @@ void ShapeBatcher::draw(const RenderCommand& command) {
|
||||||
break;
|
break;
|
||||||
case ShapeType::Triangle:
|
case ShapeType::Triangle:
|
||||||
if (data.points.size() >= 3) {
|
if (data.points.size() >= 3) {
|
||||||
drawTriangle(data.points[0], data.points[1], data.points[2],
|
drawTriangle(data.points[0], data.points[1], data.points[2], data.color,
|
||||||
data.color, data.lineWidth);
|
data.lineWidth);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ShapeType::FilledTriangle:
|
case ShapeType::FilledTriangle:
|
||||||
if (data.points.size() >= 3) {
|
if (data.points.size() >= 3) {
|
||||||
drawFilledTriangle(data.points[0], data.points[1], data.points[2], data.color);
|
drawFilledTriangle(data.points[0], data.points[1], data.points[2],
|
||||||
|
data.color);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ShapeType::Polygon:
|
case ShapeType::Polygon:
|
||||||
|
|
@ -403,7 +404,7 @@ void ShapeBatcher::draw(const RenderCommand& command) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::setViewProjection(const glm::mat4& viewProj) {
|
void ShapeBatcher::setViewProjection(const glm::mat4 &viewProj) {
|
||||||
viewProj_ = viewProj;
|
viewProj_ = viewProj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -413,16 +414,14 @@ void ShapeBatcher::resetStats() {
|
||||||
batchCount_ = 0;
|
batchCount_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::setConfig(const ShapeBatcherConfig& config) {
|
void ShapeBatcher::setConfig(const ShapeBatcherConfig &config) {
|
||||||
config_ = config;
|
config_ = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::setShader(Ptr<rhi::RHIShader> shader) {
|
void ShapeBatcher::setShader(Ptr<rhi::RHIShader> shader) { shader_ = shader; }
|
||||||
shader_ = shader;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ShapeBatcher::createShader() {
|
bool ShapeBatcher::createShader() {
|
||||||
ShaderManager& shaderManager = ShaderManager::getInstance();
|
ShaderManager &shaderManager = ShaderManager::getInstance();
|
||||||
|
|
||||||
auto shaderHandle = shaderManager.getBuiltin("shape");
|
auto shaderHandle = shaderManager.getBuiltin("shape");
|
||||||
if (!shaderHandle) {
|
if (!shaderHandle) {
|
||||||
|
|
@ -442,9 +441,12 @@ bool ShapeBatcher::createPipeline() {
|
||||||
builder.setShader(shader_)
|
builder.setShader(shader_)
|
||||||
.setBlendState(rhi::BlendState::alphaBlend())
|
.setBlendState(rhi::BlendState::alphaBlend())
|
||||||
.setPrimitiveType(rhi::PrimitiveType::Triangles)
|
.setPrimitiveType(rhi::PrimitiveType::Triangles)
|
||||||
.addVertexAttribute(rhi::VertexAttribute(0, rhi::Format::RG32_FLOAT, 0, 0))
|
.addVertexAttribute(
|
||||||
.addVertexAttribute(rhi::VertexAttribute(1, rhi::Format::RGBA32_FLOAT, 8, 0))
|
rhi::VertexAttribute(0, rhi::Format::RG32_FLOAT, 0, 0))
|
||||||
.addVertexBufferBinding(rhi::VertexBufferBinding(0, sizeof(ShapeVertex), 0));
|
.addVertexAttribute(
|
||||||
|
rhi::VertexAttribute(1, rhi::Format::RGBA32_FLOAT, 8, 0))
|
||||||
|
.addVertexBufferBinding(
|
||||||
|
rhi::VertexBufferBinding(0, sizeof(ShapeVertex), 0));
|
||||||
|
|
||||||
pipeline_ = device_->createPipeline(builder);
|
pipeline_ = device_->createPipeline(builder);
|
||||||
if (!pipeline_) {
|
if (!pipeline_) {
|
||||||
|
|
@ -455,9 +457,12 @@ bool ShapeBatcher::createPipeline() {
|
||||||
lineBuilder.setShader(shader_)
|
lineBuilder.setShader(shader_)
|
||||||
.setBlendState(rhi::BlendState::alphaBlend())
|
.setBlendState(rhi::BlendState::alphaBlend())
|
||||||
.setPrimitiveType(rhi::PrimitiveType::Lines)
|
.setPrimitiveType(rhi::PrimitiveType::Lines)
|
||||||
.addVertexAttribute(rhi::VertexAttribute(0, rhi::Format::RG32_FLOAT, 0, 0))
|
.addVertexAttribute(
|
||||||
.addVertexAttribute(rhi::VertexAttribute(1, rhi::Format::RGBA32_FLOAT, 8, 0))
|
rhi::VertexAttribute(0, rhi::Format::RG32_FLOAT, 0, 0))
|
||||||
.addVertexBufferBinding(rhi::VertexBufferBinding(0, sizeof(ShapeVertex), 0));
|
.addVertexAttribute(
|
||||||
|
rhi::VertexAttribute(1, rhi::Format::RGBA32_FLOAT, 8, 0))
|
||||||
|
.addVertexBufferBinding(
|
||||||
|
rhi::VertexBufferBinding(0, sizeof(ShapeVertex), 0));
|
||||||
|
|
||||||
linePipeline_ = device_->createPipeline(lineBuilder);
|
linePipeline_ = device_->createPipeline(lineBuilder);
|
||||||
return linePipeline_ != nullptr;
|
return linePipeline_ != nullptr;
|
||||||
|
|
@ -467,12 +472,14 @@ bool ShapeBatcher::createBuffers() {
|
||||||
size_t vertexBufferSize = config_.maxBatchSize * 4 * sizeof(ShapeVertex);
|
size_t vertexBufferSize = config_.maxBatchSize * 4 * sizeof(ShapeVertex);
|
||||||
size_t indexBufferSize = config_.maxBatchSize * 6 * sizeof(uint32_t);
|
size_t indexBufferSize = config_.maxBatchSize * 6 * sizeof(uint32_t);
|
||||||
|
|
||||||
vertexBuffer_ = device_->createVertexBuffer(vertexBufferSize, rhi::BufferUsage::Dynamic);
|
vertexBuffer_ =
|
||||||
|
device_->createVertexBuffer(vertexBufferSize, rhi::BufferUsage::Dynamic);
|
||||||
if (!vertexBuffer_) {
|
if (!vertexBuffer_) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
indexBuffer_ = device_->createIndexBuffer(indexBufferSize, rhi::BufferUsage::Dynamic);
|
indexBuffer_ =
|
||||||
|
device_->createIndexBuffer(indexBufferSize, rhi::BufferUsage::Dynamic);
|
||||||
if (!indexBuffer_) {
|
if (!indexBuffer_) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -485,16 +492,18 @@ bool ShapeBatcher::createBuffers() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::flushBatch(rhi::PrimitiveType primitiveType, float lineWidth) {
|
void ShapeBatcher::flushBatch(rhi::PrimitiveType primitiveType,
|
||||||
|
float lineWidth) {
|
||||||
if (vertices_.empty()) {
|
if (vertices_.empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vertexBuffer_->setData(vertices_.data(), vertices_.size() * sizeof(ShapeVertex));
|
vertexBuffer_->setData(vertices_.data(),
|
||||||
|
vertices_.size() * sizeof(ShapeVertex));
|
||||||
uniformBuffer_->setValue(viewProj_);
|
uniformBuffer_->setValue(viewProj_);
|
||||||
|
|
||||||
Ptr<rhi::RHIPipeline> activePipeline = (primitiveType == rhi::PrimitiveType::Lines)
|
Ptr<rhi::RHIPipeline> activePipeline =
|
||||||
? linePipeline_ : pipeline_;
|
(primitiveType == rhi::PrimitiveType::Lines) ? linePipeline_ : pipeline_;
|
||||||
|
|
||||||
device_->setPipeline(activePipeline);
|
device_->setPipeline(activePipeline);
|
||||||
device_->setShader(shader_);
|
device_->setShader(shader_);
|
||||||
|
|
@ -519,7 +528,7 @@ void ShapeBatcher::flushBatch(rhi::PrimitiveType primitiveType, float lineWidth)
|
||||||
currentIndexIndex_ = 0;
|
currentIndexIndex_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ShapeBatcher::addVertex(const Vec2& position, const Color& color) {
|
uint32_t ShapeBatcher::addVertex(const Vec2 &position, const Color &color) {
|
||||||
vertices_.push_back(ShapeVertex(position, color));
|
vertices_.push_back(ShapeVertex(position, color));
|
||||||
return currentVertexIndex_++;
|
return currentVertexIndex_++;
|
||||||
}
|
}
|
||||||
|
|
@ -529,12 +538,14 @@ void ShapeBatcher::addIndex(uint32_t index) {
|
||||||
currentIndexIndex_++;
|
currentIndexIndex_++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::generateCircleVertices(const Vec2& center, float radius,
|
void ShapeBatcher::generateCircleVertices(const Vec2 ¢er, float radius,
|
||||||
int segments, std::vector<Vec2>& vertices) const {
|
int segments,
|
||||||
|
std::vector<Vec2> &vertices) const {
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
vertices.reserve(segments);
|
vertices.reserve(segments);
|
||||||
|
|
||||||
float angleStep = 2.0f * 3.14159265358979323846f / static_cast<float>(segments);
|
float angleStep =
|
||||||
|
2.0f * 3.14159265358979323846f / static_cast<float>(segments);
|
||||||
|
|
||||||
for (int i = 0; i < segments; ++i) {
|
for (int i = 0; i < segments; ++i) {
|
||||||
float angle = angleStep * static_cast<float>(i);
|
float angle = angleStep * static_cast<float>(i);
|
||||||
|
|
@ -544,12 +555,14 @@ void ShapeBatcher::generateCircleVertices(const Vec2& center, float radius,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapeBatcher::generateEllipseVertices(const Vec2& center, float radiusX, float radiusY,
|
void ShapeBatcher::generateEllipseVertices(const Vec2 ¢er, float radiusX,
|
||||||
int segments, std::vector<Vec2>& vertices) const {
|
float radiusY, int segments,
|
||||||
|
std::vector<Vec2> &vertices) const {
|
||||||
vertices.clear();
|
vertices.clear();
|
||||||
vertices.reserve(segments);
|
vertices.reserve(segments);
|
||||||
|
|
||||||
float angleStep = 2.0f * 3.14159265358979323846f / static_cast<float>(segments);
|
float angleStep =
|
||||||
|
2.0f * 3.14159265358979323846f / static_cast<float>(segments);
|
||||||
|
|
||||||
for (int i = 0; i < segments; ++i) {
|
for (int i = 0; i < segments; ++i) {
|
||||||
float angle = angleStep * static_cast<float>(i);
|
float angle = angleStep * static_cast<float>(i);
|
||||||
|
|
|
||||||
|
|
@ -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();
|
const RenderQueueStats& queueStats = queue_.getStats();
|
||||||
|
|
||||||
stats_.spriteCount = queueStats.spriteCommands;
|
stats_.spriteCount = queueStats.spriteCommands;
|
||||||
stats_.textCount = queueStats.textCommands;
|
stats_.textCharCount = queueStats.textCommands;
|
||||||
stats_.shapeCount = queueStats.shapeCommands;
|
stats_.shapeCount = queueStats.shapeCommands;
|
||||||
|
|
||||||
stats_.batchCount = queueStats.batchCount;
|
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
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
|
||||||
#include <extra2d/core/service_locator.h>
|
#include <extra2d/core/service_locator.h>
|
||||||
#include <extra2d/render/core/render_command.h>
|
#include <extra2d/render/core/render_command.h>
|
||||||
#include <extra2d/scene/node.h>
|
#include <extra2d/scene/node.h>
|
||||||
|
|
@ -13,7 +12,7 @@ namespace extra2d {
|
||||||
* @param name 节点名称
|
* @param name 节点名称
|
||||||
* @return 创建的节点智能指针
|
* @return 创建的节点智能指针
|
||||||
*/
|
*/
|
||||||
Ptr<Node> Node::create(const std::string& name) {
|
Ptr<Node> Node::create(const std::string &name) {
|
||||||
auto node = makePtr<Node>();
|
auto node = makePtr<Node>();
|
||||||
node->setName(name);
|
node->setName(name);
|
||||||
return node;
|
return node;
|
||||||
|
|
@ -41,7 +40,7 @@ Node::~Node() {
|
||||||
clearChildren();
|
clearChildren();
|
||||||
|
|
||||||
// 销毁所有组件
|
// 销毁所有组件
|
||||||
for (auto& pair : components_) {
|
for (auto &pair : components_) {
|
||||||
pair.second->destroy();
|
pair.second->destroy();
|
||||||
pair.second->setNode(nullptr);
|
pair.second->setNode(nullptr);
|
||||||
}
|
}
|
||||||
|
|
@ -86,13 +85,13 @@ void Node::addChild(Ptr<Node> child) {
|
||||||
* @brief 批量添加子节点
|
* @brief 批量添加子节点
|
||||||
* @param children 要添加的子节点数组(右值引用)
|
* @param children 要添加的子节点数组(右值引用)
|
||||||
*/
|
*/
|
||||||
void Node::addChildren(std::vector<Ptr<Node>>&& children) {
|
void Node::addChildren(std::vector<Ptr<Node>> &&children) {
|
||||||
size_t newSize = children_.size() + children.size();
|
size_t newSize = children_.size() + children.size();
|
||||||
if (newSize > children_.capacity()) {
|
if (newSize > children_.capacity()) {
|
||||||
children_.reserve(newSize);
|
children_.reserve(newSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& child : children) {
|
for (auto &child : children) {
|
||||||
if (!child || child.get() == this) {
|
if (!child || child.get() == this) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -151,7 +150,7 @@ void Node::removeChild(Ptr<Node> child) {
|
||||||
* @brief 通过名称移除子节点
|
* @brief 通过名称移除子节点
|
||||||
* @param name 子节点的名称
|
* @param name 子节点的名称
|
||||||
*/
|
*/
|
||||||
void Node::removeChildByName(const std::string& name) {
|
void Node::removeChildByName(const std::string &name) {
|
||||||
auto child = findChild(name);
|
auto child = findChild(name);
|
||||||
if (child) {
|
if (child) {
|
||||||
removeChild(child);
|
removeChild(child);
|
||||||
|
|
@ -167,7 +166,7 @@ void Node::detach() {
|
||||||
Ptr<Node> self;
|
Ptr<Node> self;
|
||||||
try {
|
try {
|
||||||
self = shared_from_this();
|
self = shared_from_this();
|
||||||
} catch (const std::bad_weak_ptr&) {
|
} catch (const std::bad_weak_ptr &) {
|
||||||
parent_.reset();
|
parent_.reset();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -179,7 +178,7 @@ void Node::detach() {
|
||||||
* @brief 清除所有子节点
|
* @brief 清除所有子节点
|
||||||
*/
|
*/
|
||||||
void Node::clearChildren() {
|
void Node::clearChildren() {
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
if (running_) {
|
if (running_) {
|
||||||
child->onDetachFromScene();
|
child->onDetachFromScene();
|
||||||
child->onExit();
|
child->onExit();
|
||||||
|
|
@ -196,7 +195,7 @@ void Node::clearChildren() {
|
||||||
* @param name 子节点的名称
|
* @param name 子节点的名称
|
||||||
* @return 找到的子节点智能指针,未找到返回nullptr
|
* @return 找到的子节点智能指针,未找到返回nullptr
|
||||||
*/
|
*/
|
||||||
Ptr<Node> Node::findChild(const std::string& name) const {
|
Ptr<Node> Node::findChild(const std::string &name) const {
|
||||||
auto it = nameIndex_.find(name);
|
auto it = nameIndex_.find(name);
|
||||||
if (it != nameIndex_.end()) {
|
if (it != nameIndex_.end()) {
|
||||||
return it->second.lock();
|
return it->second.lock();
|
||||||
|
|
@ -225,7 +224,7 @@ Ptr<Node> Node::findChildByTag(int tag) const {
|
||||||
* @brief 设置节点位置
|
* @brief 设置节点位置
|
||||||
* @param pos 新的位置坐标
|
* @param pos 新的位置坐标
|
||||||
*/
|
*/
|
||||||
void Node::setPos(const Vec2& pos) {
|
void Node::setPos(const Vec2 &pos) {
|
||||||
if (transform_) {
|
if (transform_) {
|
||||||
transform_->setPosition(pos);
|
transform_->setPosition(pos);
|
||||||
}
|
}
|
||||||
|
|
@ -237,9 +236,7 @@ void Node::setPos(const Vec2& pos) {
|
||||||
* @param x X坐标
|
* @param x X坐标
|
||||||
* @param y Y坐标
|
* @param y Y坐标
|
||||||
*/
|
*/
|
||||||
void Node::setPos(float x, float y) {
|
void Node::setPos(float x, float y) { setPos(Vec2(x, y)); }
|
||||||
setPos(Vec2(x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取节点位置
|
* @brief 获取节点位置
|
||||||
|
|
@ -278,7 +275,7 @@ float Node::getRotation() const {
|
||||||
* @brief 设置节点缩放
|
* @brief 设置节点缩放
|
||||||
* @param scale 缩放向量
|
* @param scale 缩放向量
|
||||||
*/
|
*/
|
||||||
void Node::setScale(const Vec2& scale) {
|
void Node::setScale(const Vec2 &scale) {
|
||||||
if (transform_) {
|
if (transform_) {
|
||||||
transform_->setScale(scale);
|
transform_->setScale(scale);
|
||||||
}
|
}
|
||||||
|
|
@ -289,18 +286,14 @@ void Node::setScale(const Vec2& scale) {
|
||||||
* @brief 设置节点统一缩放
|
* @brief 设置节点统一缩放
|
||||||
* @param scale 统一缩放值
|
* @param scale 统一缩放值
|
||||||
*/
|
*/
|
||||||
void Node::setScale(float scale) {
|
void Node::setScale(float scale) { setScale(Vec2(scale, scale)); }
|
||||||
setScale(Vec2(scale, scale));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 设置节点缩放
|
* @brief 设置节点缩放
|
||||||
* @param x X轴缩放值
|
* @param x X轴缩放值
|
||||||
* @param y Y轴缩放值
|
* @param y Y轴缩放值
|
||||||
*/
|
*/
|
||||||
void Node::setScale(float x, float y) {
|
void Node::setScale(float x, float y) { setScale(Vec2(x, y)); }
|
||||||
setScale(Vec2(x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取节点缩放
|
* @brief 获取节点缩放
|
||||||
|
|
@ -317,7 +310,7 @@ Vec2 Node::getScale() const {
|
||||||
* @brief 设置节点锚点
|
* @brief 设置节点锚点
|
||||||
* @param anchor 锚点位置(0-1范围)
|
* @param anchor 锚点位置(0-1范围)
|
||||||
*/
|
*/
|
||||||
void Node::setAnchor(const Vec2& anchor) {
|
void Node::setAnchor(const Vec2 &anchor) {
|
||||||
if (transform_) {
|
if (transform_) {
|
||||||
transform_->setAnchor(anchor);
|
transform_->setAnchor(anchor);
|
||||||
}
|
}
|
||||||
|
|
@ -329,9 +322,7 @@ void Node::setAnchor(const Vec2& anchor) {
|
||||||
* @param x 锚点X坐标(0-1范围)
|
* @param x 锚点X坐标(0-1范围)
|
||||||
* @param y 锚点Y坐标(0-1范围)
|
* @param y 锚点Y坐标(0-1范围)
|
||||||
*/
|
*/
|
||||||
void Node::setAnchor(float x, float y) {
|
void Node::setAnchor(float x, float y) { setAnchor(Vec2(x, y)); }
|
||||||
setAnchor(Vec2(x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取节点锚点
|
* @brief 获取节点锚点
|
||||||
|
|
@ -348,7 +339,7 @@ Vec2 Node::getAnchor() const {
|
||||||
* @brief 设置节点斜切
|
* @brief 设置节点斜切
|
||||||
* @param skew 斜切角度向量
|
* @param skew 斜切角度向量
|
||||||
*/
|
*/
|
||||||
void Node::setSkew(const Vec2& skew) {
|
void Node::setSkew(const Vec2 &skew) {
|
||||||
if (transform_) {
|
if (transform_) {
|
||||||
transform_->setSkew(skew);
|
transform_->setSkew(skew);
|
||||||
}
|
}
|
||||||
|
|
@ -360,9 +351,7 @@ void Node::setSkew(const Vec2& skew) {
|
||||||
* @param x X轴斜切角度
|
* @param x X轴斜切角度
|
||||||
* @param y Y轴斜切角度
|
* @param y Y轴斜切角度
|
||||||
*/
|
*/
|
||||||
void Node::setSkew(float x, float y) {
|
void Node::setSkew(float x, float y) { setSkew(Vec2(x, y)); }
|
||||||
setSkew(Vec2(x, y));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取节点斜切
|
* @brief 获取节点斜切
|
||||||
|
|
@ -384,7 +373,7 @@ Vec2 Node::getSkew() const {
|
||||||
* @param localPos 本地坐标位置
|
* @param localPos 本地坐标位置
|
||||||
* @return 世界坐标位置
|
* @return 世界坐标位置
|
||||||
*/
|
*/
|
||||||
Vec2 Node::toWorld(const Vec2& localPos) const {
|
Vec2 Node::toWorld(const Vec2 &localPos) const {
|
||||||
if (transform_) {
|
if (transform_) {
|
||||||
return transform_->localToWorld(localPos);
|
return transform_->localToWorld(localPos);
|
||||||
}
|
}
|
||||||
|
|
@ -396,7 +385,7 @@ Vec2 Node::toWorld(const Vec2& localPos) const {
|
||||||
* @param worldPos 世界坐标位置
|
* @param worldPos 世界坐标位置
|
||||||
* @return 本地坐标位置
|
* @return 本地坐标位置
|
||||||
*/
|
*/
|
||||||
Vec2 Node::toLocal(const Vec2& worldPos) const {
|
Vec2 Node::toLocal(const Vec2 &worldPos) const {
|
||||||
if (transform_) {
|
if (transform_) {
|
||||||
return transform_->worldToLocal(worldPos);
|
return transform_->worldToLocal(worldPos);
|
||||||
}
|
}
|
||||||
|
|
@ -434,7 +423,7 @@ void Node::markTransformDirty() {
|
||||||
worldTransformDirty_ = true;
|
worldTransformDirty_ = true;
|
||||||
|
|
||||||
// 递归标记所有子节点
|
// 递归标记所有子节点
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
child->markTransformDirty();
|
child->markTransformDirty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -452,7 +441,7 @@ void Node::batchTransforms() {
|
||||||
worldTransformDirty_ = false;
|
worldTransformDirty_ = false;
|
||||||
|
|
||||||
// 递归更新子节点
|
// 递归更新子节点
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
child->batchTransforms();
|
child->batchTransforms();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -493,33 +482,25 @@ void Node::setOpacity(float opacity) {
|
||||||
* @brief 设置可见性
|
* @brief 设置可见性
|
||||||
* @param visible 是否可见
|
* @param visible 是否可见
|
||||||
*/
|
*/
|
||||||
void Node::setVisible(bool visible) {
|
void Node::setVisible(bool visible) { visible_ = visible; }
|
||||||
visible_ = visible;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 设置颜色
|
* @brief 设置颜色
|
||||||
* @param color RGB颜色值
|
* @param color RGB颜色值
|
||||||
*/
|
*/
|
||||||
void Node::setColor(const Color3B& color) {
|
void Node::setColor(const Color3B &color) { color_ = color; }
|
||||||
color_ = color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 设置水平翻转
|
* @brief 设置水平翻转
|
||||||
* @param flipX 是否水平翻转
|
* @param flipX 是否水平翻转
|
||||||
*/
|
*/
|
||||||
void Node::setFlipX(bool flipX) {
|
void Node::setFlipX(bool flipX) { flipX_ = flipX; }
|
||||||
flipX_ = flipX;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 设置垂直翻转
|
* @brief 设置垂直翻转
|
||||||
* @param flipY 是否垂直翻转
|
* @param flipY 是否垂直翻转
|
||||||
*/
|
*/
|
||||||
void Node::setFlipY(bool flipY) {
|
void Node::setFlipY(bool flipY) { flipY_ = flipY; }
|
||||||
flipY_ = flipY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 设置Z序
|
* @brief 设置Z序
|
||||||
|
|
@ -543,14 +524,14 @@ void Node::onEnter() {
|
||||||
running_ = true;
|
running_ = true;
|
||||||
|
|
||||||
// 初始化所有组件
|
// 初始化所有组件
|
||||||
for (auto& pair : components_) {
|
for (auto &pair : components_) {
|
||||||
if (!pair.second->isInitialized()) {
|
if (!pair.second->isInitialized()) {
|
||||||
pair.second->init();
|
pair.second->init();
|
||||||
pair.second->setInitialized(true);
|
pair.second->setInitialized(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
child->onEnter();
|
child->onEnter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -560,7 +541,7 @@ void Node::onEnter() {
|
||||||
*/
|
*/
|
||||||
void Node::onExit() {
|
void Node::onExit() {
|
||||||
running_ = false;
|
running_ = false;
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
child->onExit();
|
child->onExit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -573,14 +554,14 @@ void Node::onUpdate(float dt) {
|
||||||
onUpdateNode(dt);
|
onUpdateNode(dt);
|
||||||
|
|
||||||
// 更新所有启用的组件
|
// 更新所有启用的组件
|
||||||
for (auto& pair : components_) {
|
for (auto &pair : components_) {
|
||||||
if (pair.second->isEnabled()) {
|
if (pair.second->isEnabled()) {
|
||||||
pair.second->update(dt);
|
pair.second->update(dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新子节点
|
// 更新子节点
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
child->onUpdate(dt);
|
child->onUpdate(dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -589,29 +570,25 @@ void Node::onUpdate(float dt) {
|
||||||
* @brief 渲染回调
|
* @brief 渲染回调
|
||||||
* @param renderer 渲染后端引用
|
* @param renderer 渲染后端引用
|
||||||
*/
|
*/
|
||||||
void Node::onRender(RenderBackend& renderer) {
|
void Node::onRender(RenderBackend &renderer) {
|
||||||
if (!visible_)
|
if (!visible_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
renderer.pushTransform(getLocalTransform());
|
|
||||||
|
|
||||||
onDraw(renderer);
|
onDraw(renderer);
|
||||||
|
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
child->onRender(renderer);
|
child->onRender(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderer.popTransform();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 附加到场景时的回调
|
* @brief 附加到场景时的回调
|
||||||
* @param scene 所属场景指针
|
* @param scene 所属场景指针
|
||||||
*/
|
*/
|
||||||
void Node::onAttachToScene(Scene* scene) {
|
void Node::onAttachToScene(Scene *scene) {
|
||||||
scene_ = scene;
|
scene_ = scene;
|
||||||
|
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
child->onAttachToScene(scene);
|
child->onAttachToScene(scene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -621,7 +598,7 @@ void Node::onAttachToScene(Scene* scene) {
|
||||||
*/
|
*/
|
||||||
void Node::onDetachFromScene() {
|
void Node::onDetachFromScene() {
|
||||||
scene_ = nullptr;
|
scene_ = nullptr;
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
child->onDetachFromScene();
|
child->onDetachFromScene();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -639,15 +616,13 @@ Rect Node::getBounds() const {
|
||||||
* @brief 更新节点
|
* @brief 更新节点
|
||||||
* @param dt 帧间隔时间(秒)
|
* @param dt 帧间隔时间(秒)
|
||||||
*/
|
*/
|
||||||
void Node::update(float dt) {
|
void Node::update(float dt) { onUpdate(dt); }
|
||||||
onUpdate(dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 渲染节点
|
* @brief 渲染节点
|
||||||
* @param renderer 渲染后端引用
|
* @param renderer 渲染后端引用
|
||||||
*/
|
*/
|
||||||
void Node::render(RenderBackend& renderer) {
|
void Node::render(RenderBackend &renderer) {
|
||||||
if (childrenOrderDirty_) {
|
if (childrenOrderDirty_) {
|
||||||
sortChildren();
|
sortChildren();
|
||||||
}
|
}
|
||||||
|
|
@ -678,7 +653,7 @@ void Node::sortChildren() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::sort(children_.begin(), children_.end(),
|
std::sort(children_.begin(), children_.end(),
|
||||||
[](const Ptr<Node>& a, const Ptr<Node>& b) {
|
[](const Ptr<Node> &a, const Ptr<Node> &b) {
|
||||||
return a->getZOrder() < b->getZOrder();
|
return a->getZOrder() < b->getZOrder();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -691,7 +666,7 @@ void Node::sortChildren() {
|
||||||
* @param commands 渲染命令输出向量
|
* @param commands 渲染命令输出向量
|
||||||
* @param parentZOrder 父节点的Z序
|
* @param parentZOrder 父节点的Z序
|
||||||
*/
|
*/
|
||||||
void Node::collectRenderCommands(std::vector<RenderCommand>& commands,
|
void Node::collectRenderCommands(std::vector<RenderCommand> &commands,
|
||||||
int parentZOrder) {
|
int parentZOrder) {
|
||||||
if (!visible_)
|
if (!visible_)
|
||||||
return;
|
return;
|
||||||
|
|
@ -701,14 +676,14 @@ void Node::collectRenderCommands(std::vector<RenderCommand>& commands,
|
||||||
generateRenderCommand(commands, accumulatedZOrder);
|
generateRenderCommand(commands, accumulatedZOrder);
|
||||||
|
|
||||||
// 让组件也生成渲染命令
|
// 让组件也生成渲染命令
|
||||||
for (auto& pair : components_) {
|
for (auto &pair : components_) {
|
||||||
if (pair.second->isEnabled()) {
|
if (pair.second->isEnabled()) {
|
||||||
// 组件的渲染命令收集需要通过 RenderQueue
|
// 组件的渲染命令收集需要通过 RenderQueue
|
||||||
// 这里暂时跳过,使用 collectRenderCommandsToQueue 方法
|
// 这里暂时跳过,使用 collectRenderCommandsToQueue 方法
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
child->collectRenderCommands(commands, accumulatedZOrder);
|
child->collectRenderCommands(commands, accumulatedZOrder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -717,7 +692,7 @@ void Node::collectRenderCommands(std::vector<RenderCommand>& commands,
|
||||||
* @brief 收集渲染命令到队列
|
* @brief 收集渲染命令到队列
|
||||||
* @param queue 渲染队列引用
|
* @param queue 渲染队列引用
|
||||||
*/
|
*/
|
||||||
void Node::collectRenderCommandsToQueue(RenderQueue& queue) {
|
void Node::collectRenderCommandsToQueue(RenderQueue &queue) {
|
||||||
if (!visible_)
|
if (!visible_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -725,14 +700,14 @@ void Node::collectRenderCommandsToQueue(RenderQueue& queue) {
|
||||||
generateRenderCommandToQueue(queue);
|
generateRenderCommandToQueue(queue);
|
||||||
|
|
||||||
// 让组件也生成渲染命令
|
// 让组件也生成渲染命令
|
||||||
for (auto& pair : components_) {
|
for (auto &pair : components_) {
|
||||||
if (pair.second->isEnabled()) {
|
if (pair.second->isEnabled()) {
|
||||||
pair.second->collectRenderCommands(queue);
|
pair.second->collectRenderCommands(queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 递归收集子节点的渲染命令
|
// 递归收集子节点的渲染命令
|
||||||
for (auto& child : children_) {
|
for (auto &child : children_) {
|
||||||
child->collectRenderCommandsToQueue(queue);
|
child->collectRenderCommandsToQueue(queue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include <extra2d/core/service_locator.h>
|
#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_command.h>
|
||||||
#include <extra2d/render/core/render_queue.h>
|
#include <extra2d/render/core/render_queue.h>
|
||||||
#include <extra2d/scene/scene.h>
|
#include <extra2d/scene/scene.h>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <extra2d/app/application.h>
|
#include <extra2d/app/application.h>
|
||||||
#include <extra2d/core/service_locator.h>
|
#include <extra2d/core/service_locator.h>
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
#include <extra2d/render/core/render_backend.h>
|
||||||
#include <extra2d/graphics/core/render_command.h>
|
#include <extra2d/render/core/render_command.h>
|
||||||
#include <extra2d/platform/iinput.h>
|
#include <extra2d/platform/iinput.h>
|
||||||
#include <extra2d/scene/scene_manager.h>
|
#include <extra2d/scene/scene_manager.h>
|
||||||
#include <extra2d/scene/transition_box_scene.h>
|
#include <extra2d/scene/transition_box_scene.h>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
#include <extra2d/render/core/render_backend.h>
|
||||||
#include <extra2d/graphics/core/render_command.h>
|
#include <extra2d/render/core/render_command.h>
|
||||||
#include <extra2d/scene/shape_node.h>
|
#include <extra2d/scene/shape_node.h>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
|
@ -196,24 +196,18 @@ Ptr<ShapeNode> ShapeNode::createFilledPolygon(const std::vector<Vec2> &points,
|
||||||
* @brief 设置形状的所有顶点
|
* @brief 设置形状的所有顶点
|
||||||
* @param points 顶点坐标数组
|
* @param points 顶点坐标数组
|
||||||
*/
|
*/
|
||||||
void ShapeNode::setPoints(const std::vector<Vec2> &points) {
|
void ShapeNode::setPoints(const std::vector<Vec2> &points) { points_ = points; }
|
||||||
points_ = points;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 添加一个顶点到形状
|
* @brief 添加一个顶点到形状
|
||||||
* @param point 要添加的顶点坐标
|
* @param point 要添加的顶点坐标
|
||||||
*/
|
*/
|
||||||
void ShapeNode::addPoint(const Vec2 &point) {
|
void ShapeNode::addPoint(const Vec2 &point) { points_.push_back(point); }
|
||||||
points_.push_back(point);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 清除所有顶点
|
* @brief 清除所有顶点
|
||||||
*/
|
*/
|
||||||
void ShapeNode::clearPoints() {
|
void ShapeNode::clearPoints() { points_.clear(); }
|
||||||
points_.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 获取形状的边界矩形
|
* @brief 获取形状的边界矩形
|
||||||
|
|
@ -319,7 +313,7 @@ void ShapeNode::onDraw(RenderBackend &renderer) {
|
||||||
case ShapeType::Triangle:
|
case ShapeType::Triangle:
|
||||||
if (points_.size() >= 3) {
|
if (points_.size() >= 3) {
|
||||||
if (filled_) {
|
if (filled_) {
|
||||||
renderer.fillTriangle(points_[0], points_[1], points_[2], color_);
|
renderer.fillPolygon(points_.data(), 3, color_);
|
||||||
} else {
|
} else {
|
||||||
renderer.drawLine(points_[0], points_[1], color_, lineWidth_);
|
renderer.drawLine(points_[0], points_[1], color_, lineWidth_);
|
||||||
renderer.drawLine(points_[1], points_[2], color_, lineWidth_);
|
renderer.drawLine(points_[1], points_[2], color_, lineWidth_);
|
||||||
|
|
@ -331,9 +325,9 @@ void ShapeNode::onDraw(RenderBackend &renderer) {
|
||||||
case ShapeType::Polygon:
|
case ShapeType::Polygon:
|
||||||
if (!points_.empty()) {
|
if (!points_.empty()) {
|
||||||
if (filled_) {
|
if (filled_) {
|
||||||
renderer.fillPolygon(points_, color_);
|
renderer.fillPolygon(points_.data(), points_.size(), color_);
|
||||||
} else {
|
} else {
|
||||||
renderer.drawPolygon(points_, color_, lineWidth_);
|
renderer.drawPolygon(points_.data(), points_.size(), color_, lineWidth_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -354,71 +348,44 @@ void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2 offset = getPosition();
|
Vec2 offset = getPosition();
|
||||||
RenderCommand cmd;
|
|
||||||
cmd.layer = zOrder;
|
|
||||||
|
|
||||||
switch (shapeType_) {
|
switch (shapeType_) {
|
||||||
case ShapeType::Point:
|
case ShapeType::Point:
|
||||||
if (!points_.empty()) {
|
if (!points_.empty()) {
|
||||||
cmd.type = RenderCommandType::FilledCircle;
|
commands.push_back(RenderCommand::makeCircle(
|
||||||
cmd.data =
|
points_[0] + offset, lineWidth_ * 0.5f, color_, 8, true, zOrder));
|
||||||
CircleCommandData{points_[0] + offset, lineWidth_ * 0.5f, color_, 8, 0.0f, true};
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ShapeType::Line:
|
case ShapeType::Line:
|
||||||
if (points_.size() >= 2) {
|
if (points_.size() >= 2) {
|
||||||
cmd.type = RenderCommandType::Line;
|
commands.push_back(RenderCommand::makeLine(
|
||||||
cmd.data = LineCommandData{points_[0] + offset, points_[1] + offset, color_,
|
points_[0] + offset, points_[1] + offset, color_, lineWidth_, zOrder));
|
||||||
lineWidth_};
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ShapeType::Rect:
|
case ShapeType::Rect:
|
||||||
if (points_.size() >= 4) {
|
if (points_.size() >= 4) {
|
||||||
if (filled_) {
|
|
||||||
cmd.type = RenderCommandType::FilledRect;
|
|
||||||
Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x,
|
Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x,
|
||||||
points_[2].y - points_[0].y);
|
points_[2].y - points_[0].y);
|
||||||
cmd.data =
|
commands.push_back(RenderCommand::makeRect(
|
||||||
RectCommandData{Rect(rect.origin + offset, rect.size), color_, 0.0f, true};
|
Rect(rect.origin + offset, rect.size), color_, lineWidth_, filled_, zOrder));
|
||||||
} 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};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ShapeType::Circle:
|
case ShapeType::Circle:
|
||||||
if (points_.size() >= 2) {
|
if (points_.size() >= 2) {
|
||||||
float radius = points_[1].x;
|
float radius = points_[1].x;
|
||||||
if (filled_) {
|
commands.push_back(RenderCommand::makeCircle(
|
||||||
cmd.type = RenderCommandType::FilledCircle;
|
points_[0] + offset, radius, color_, segments_, filled_, zOrder));
|
||||||
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};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ShapeType::Triangle:
|
case ShapeType::Triangle:
|
||||||
if (points_.size() >= 3) {
|
if (points_.size() >= 3) {
|
||||||
Vec2 p1 = points_[0] + offset;
|
commands.push_back(RenderCommand::makeTriangle(
|
||||||
Vec2 p2 = points_[1] + offset;
|
points_[0] + offset, points_[1] + offset, points_[2] + offset,
|
||||||
Vec2 p3 = points_[2] + offset;
|
color_, filled_, zOrder));
|
||||||
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};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -429,19 +396,11 @@ void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
|
||||||
for (const auto &p : points_) {
|
for (const auto &p : points_) {
|
||||||
transformedPoints.push_back(p + offset);
|
transformedPoints.push_back(p + offset);
|
||||||
}
|
}
|
||||||
|
commands.push_back(RenderCommand::makePolygon(
|
||||||
if (filled_) {
|
transformedPoints, color_, filled_, zOrder));
|
||||||
cmd.type = RenderCommandType::FilledPolygon;
|
|
||||||
cmd.data = PolygonCommandData{transformedPoints, color_, 0.0f, true};
|
|
||||||
} else {
|
|
||||||
cmd.type = RenderCommandType::Polygon;
|
|
||||||
cmd.data = PolygonCommandData{transformedPoints, color_, lineWidth_, false};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
commands.push_back(std::move(cmd));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace extra2d
|
} // namespace extra2d
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
#include <extra2d/render/core/render_backend.h>
|
||||||
#include <extra2d/graphics/core/render_command.h>
|
#include <extra2d/render/core/render_command.h>
|
||||||
#include <extra2d/graphics/texture/texture.h>
|
|
||||||
#include <extra2d/scene/sprite.h>
|
#include <extra2d/scene/sprite.h>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
@ -168,8 +167,8 @@ void Sprite::onDraw(RenderBackend &renderer) {
|
||||||
// 从世界变换矩阵中提取旋转角度
|
// 从世界变换矩阵中提取旋转角度
|
||||||
float worldRotation = std::atan2(worldTransform[0][1], worldTransform[0][0]);
|
float worldRotation = std::atan2(worldTransform[0][1], worldTransform[0][0]);
|
||||||
|
|
||||||
renderer.drawSprite(*texture_, destRect, srcRect, color_, worldRotation,
|
renderer.drawSprite(texture_->getRHITexture(), destRect, srcRect, color_, worldRotation,
|
||||||
anchor);
|
flipX_, flipY_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -225,8 +224,8 @@ void Sprite::generateRenderCommand(std::vector<RenderCommand> &commands,
|
||||||
RenderCommand cmd;
|
RenderCommand cmd;
|
||||||
cmd.type = RenderCommandType::Sprite;
|
cmd.type = RenderCommandType::Sprite;
|
||||||
cmd.layer = zOrder;
|
cmd.layer = zOrder;
|
||||||
cmd.data = SpriteCommandData{texture_.get(), destRect, srcRect, color_,
|
cmd.data = SpriteRenderData{texture_->getRHITexture(), destRect, srcRect, color_,
|
||||||
worldRotation, anchor, 0};
|
worldRotation, anchor, rhi::BlendState::alphaBlend(), 0};
|
||||||
|
|
||||||
commands.push_back(std::move(cmd));
|
commands.push_back(std::move(cmd));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include <extra2d/scene/transition_box_scene.h>
|
#include <extra2d/scene/transition_box_scene.h>
|
||||||
#include <extra2d/app/application.h>
|
#include <extra2d/app/application.h>
|
||||||
#include <extra2d/core/color.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 <extra2d/platform/iwindow.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
@ -76,7 +76,8 @@ void TransitionBoxScene::renderContent(RenderBackend &renderer) {
|
||||||
|
|
||||||
glm::mat4 overlayVP =
|
glm::mat4 overlayVP =
|
||||||
glm::ortho(0.0f, windowWidth, windowHeight, 0.0f, -1.0f, 1.0f);
|
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) {
|
for (int idx = visible; idx < total; ++idx) {
|
||||||
int x = idx % div;
|
int x = idx % div;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include <extra2d/app/application.h>
|
#include <extra2d/app/application.h>
|
||||||
#include <extra2d/core/service_locator.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/platform/iwindow.h>
|
||||||
#include <extra2d/scene/transition_fade_scene.h>
|
#include <extra2d/scene/transition_fade_scene.h>
|
||||||
#include <extra2d/services/logger_service.h>
|
#include <extra2d/services/logger_service.h>
|
||||||
|
|
@ -75,7 +75,8 @@ void TransitionFadeScene::renderContent(RenderBackend &renderer) {
|
||||||
|
|
||||||
glm::mat4 overlayVP =
|
glm::mat4 overlayVP =
|
||||||
glm::ortho(0.0f, windowWidth, windowHeight, 0.0f, -1.0f, 1.0f);
|
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_;
|
Color maskColor = maskColor_;
|
||||||
maskColor.a = maskAlpha;
|
maskColor.a = maskAlpha;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
#include <extra2d/scene/transition_flip_scene.h>
|
#include <extra2d/scene/transition_flip_scene.h>
|
||||||
#include <extra2d/core/math_types.h>
|
#include <extra2d/core/math_types.h>
|
||||||
#include <extra2d/graphics/camera/camera.h>
|
#include <extra2d/render/camera/camera.h>
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
#include <extra2d/render/core/render_backend.h>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include <extra2d/scene/transition_scale_scene.h>
|
#include <extra2d/scene/transition_scale_scene.h>
|
||||||
#include <extra2d/graphics/camera/camera.h>
|
#include <extra2d/render/camera/camera.h>
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
#include <extra2d/render/core/render_backend.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include <extra2d/core/service_locator.h>
|
#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/scene/transition_scene.h>
|
||||||
#include <extra2d/services/logger_service.h>
|
#include <extra2d/services/logger_service.h>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#include <extra2d/scene/transition_slide_scene.h>
|
#include <extra2d/scene/transition_slide_scene.h>
|
||||||
#include <extra2d/graphics/camera/camera.h>
|
#include <extra2d/render/camera/camera.h>
|
||||||
#include <extra2d/graphics/core/render_backend.h>
|
#include <extra2d/render/core/render_backend.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace extra2d {
|
namespace extra2d {
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,13 @@ function define_extra2d_engine()
|
||||||
|
|
||||||
-- 渲染后端源文件
|
-- 渲染后端源文件
|
||||||
local render_backend = get_render_backend()
|
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
|
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")
|
add_defines("E2D_BACKEND_VULKAN")
|
||||||
else
|
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_files("Extra2D/src/glad/glad.c")
|
||||||
add_defines("E2D_BACKEND_OPENGL")
|
add_defines("E2D_BACKEND_OPENGL")
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue