refactor(render): 重构渲染模块结构,将图形相关代码迁移至render目录
- 将graphics目录重命名为render,调整相关头文件引用路径 - 添加RenderModule类作为应用模块集成渲染器 - 实现GLContext类管理OpenGL上下文状态 - 重构Camera和ViewportAdapter类,改进视口适配逻辑 - 统一渲染命令数据结构,优化形状节点渲染 - 更新构建脚本以适配新的目录结构
This commit is contained in:
parent
89d1612336
commit
1f2ed0942d
|
|
@ -13,8 +13,6 @@
|
|||
#include <extra2d/core/compression.h>
|
||||
#include <extra2d/core/aes_cipher.h>
|
||||
|
||||
// Config removed - app info now in Application class
|
||||
|
||||
// Platform
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
|
|
@ -23,17 +21,26 @@
|
|||
#include <extra2d/platform/backend_factory.h>
|
||||
#include <extra2d/platform/window_module.h>
|
||||
|
||||
// Graphics
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/texture/font.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_module.h>
|
||||
#include <extra2d/graphics/shader/shader_manager.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/graphics/core/render_target.h>
|
||||
#include <extra2d/graphics/camera/viewport_adapter.h>
|
||||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#include <extra2d/graphics/texture/texture_pool.h>
|
||||
// Render Core
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/render/core/render_context.h>
|
||||
#include <extra2d/render/core/render_queue.h>
|
||||
#include <extra2d/render/core/render_stats.h>
|
||||
#include <extra2d/render/core/render_module.h>
|
||||
#include <extra2d/render/core/backend_factory.h>
|
||||
|
||||
// Render Camera
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/camera/viewport_adapter.h>
|
||||
|
||||
// Render Batch
|
||||
#include <extra2d/render/batch/sprite_batcher.h>
|
||||
#include <extra2d/render/batch/shape_batcher.h>
|
||||
#include <extra2d/render/batch/text_batcher.h>
|
||||
|
||||
// Render Renderer
|
||||
#include <extra2d/render/renderer.h>
|
||||
|
||||
// RHI (Render Hardware Interface)
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
#pragma once
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief OpenGL 版本信息
|
||||
*/
|
||||
struct GLVersion {
|
||||
int major = 0;
|
||||
int minor = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief OpenGL 上下文管理类
|
||||
*
|
||||
* 单例模式,管理 OpenGL 上下文初始化和状态查询
|
||||
*/
|
||||
class GLContext {
|
||||
public:
|
||||
/**
|
||||
* @brief 获取单例实例
|
||||
*/
|
||||
static GLContext& get();
|
||||
|
||||
/**
|
||||
* @brief 初始化 OpenGL 上下文
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
bool init();
|
||||
|
||||
/**
|
||||
* @brief 关闭 OpenGL 上下文
|
||||
*/
|
||||
void shutdown();
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
*/
|
||||
bool isInitialized() const { return initialized_; }
|
||||
|
||||
// ========================================================================
|
||||
// 版本信息
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取 OpenGL 版本
|
||||
*/
|
||||
GLVersion getVersion() const { return version_; }
|
||||
|
||||
/**
|
||||
* @brief 获取版本字符串
|
||||
*/
|
||||
std::string getVersionString() const;
|
||||
|
||||
/**
|
||||
* @brief 获取渲染器名称
|
||||
*/
|
||||
const std::string& getRenderer() const { return renderer_; }
|
||||
|
||||
/**
|
||||
* @brief 获取供应商名称
|
||||
*/
|
||||
const std::string& getVendor() const { return vendor_; }
|
||||
|
||||
// ========================================================================
|
||||
// 能力查询
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取最大纹理尺寸
|
||||
*/
|
||||
int getMaxTextureSize() const { return maxTextureSize_; }
|
||||
|
||||
/**
|
||||
* @brief 获取最大纹理单元数
|
||||
*/
|
||||
int getMaxTextureUnits() const { return maxTextureUnits_; }
|
||||
|
||||
/**
|
||||
* @brief 获取最大顶点属性数
|
||||
*/
|
||||
int getMaxVertexAttribs() const { return maxVertexAttribs_; }
|
||||
|
||||
/**
|
||||
* @brief 获取最大 Uniform 缓冲区绑定数
|
||||
*/
|
||||
int getMaxUniformBufferBindings() const { return maxUniformBufferBindings_; }
|
||||
|
||||
/**
|
||||
* @brief 检查是否支持扩展
|
||||
*/
|
||||
bool hasExtension(const std::string& extension) const;
|
||||
|
||||
// ========================================================================
|
||||
// 状态管理
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 检查 OpenGL 错误
|
||||
*/
|
||||
bool checkError(const char* operation = nullptr);
|
||||
|
||||
/**
|
||||
* @brief 清除错误状态
|
||||
*/
|
||||
void clearErrors();
|
||||
|
||||
private:
|
||||
GLContext() = default;
|
||||
~GLContext() = default;
|
||||
GLContext(const GLContext&) = delete;
|
||||
GLContext& operator=(const GLContext&) = delete;
|
||||
|
||||
/**
|
||||
* @brief 查询 OpenGL 能力
|
||||
*/
|
||||
void queryCapabilities();
|
||||
|
||||
/**
|
||||
* @brief 解析版本字符串
|
||||
*/
|
||||
void parseVersion();
|
||||
|
||||
bool initialized_ = false;
|
||||
|
||||
GLVersion version_;
|
||||
std::string renderer_;
|
||||
std::string vendor_;
|
||||
std::string glslVersion_;
|
||||
|
||||
int maxTextureSize_ = 0;
|
||||
int maxTextureUnits_ = 0;
|
||||
int maxVertexAttribs_ = 0;
|
||||
int maxUniformBufferBindings_ = 0;
|
||||
|
||||
std::unordered_set<std::string> extensions_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,302 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/rhi/rhi_device.h>
|
||||
#include <extra2d/render/backends/opengl/gl_rhi_device.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <stack>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class IWindow;
|
||||
|
||||
/**
|
||||
* @brief OpenGL 渲染后端实现
|
||||
*
|
||||
* 实现 RenderBackend 接口,使用 OpenGL 作为底层图形 API
|
||||
*/
|
||||
class GLRenderBackend : public RenderBackend {
|
||||
public:
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
GLRenderBackend();
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
~GLRenderBackend() override;
|
||||
|
||||
// ========================================================================
|
||||
// 生命周期
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 初始化渲染后端
|
||||
* @param window 窗口接口
|
||||
* @param config 配置参数
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
bool init(IWindow *window, const RenderBackendConfig &config = {}) override;
|
||||
|
||||
/**
|
||||
* @brief 关闭渲染后端
|
||||
*/
|
||||
void shutdown() override;
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
*/
|
||||
bool isValid() const override;
|
||||
|
||||
// ========================================================================
|
||||
// 帧管理
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始帧渲染
|
||||
* @param clearColor 清屏颜色
|
||||
*/
|
||||
void beginFrame(const Color &clearColor = Colors::Black) override;
|
||||
|
||||
/**
|
||||
* @brief 结束帧渲染
|
||||
*/
|
||||
void endFrame() override;
|
||||
|
||||
/**
|
||||
* @brief 呈现帧
|
||||
*/
|
||||
void present() override;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染状态
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
*/
|
||||
void setViewport(int x, int y, int width, int height) override;
|
||||
|
||||
/**
|
||||
* @brief 设置裁剪区域
|
||||
*/
|
||||
void setScissor(int x, int y, int width, int height) override;
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用裁剪测试
|
||||
*/
|
||||
void setScissorEnabled(bool enabled) override;
|
||||
|
||||
/**
|
||||
* @brief 设置投影矩阵
|
||||
*/
|
||||
void setProjectionMatrix(const glm::mat4 &matrix) override;
|
||||
|
||||
/**
|
||||
* @brief 设置视图矩阵
|
||||
*/
|
||||
void setViewMatrix(const glm::mat4 &matrix) override;
|
||||
|
||||
/**
|
||||
* @brief 设置垂直同步
|
||||
*/
|
||||
void setVSync(bool enabled) override;
|
||||
|
||||
/**
|
||||
* @brief 获取垂直同步状态
|
||||
*/
|
||||
bool isVSyncEnabled() const override;
|
||||
|
||||
// ========================================================================
|
||||
// 精灵渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵
|
||||
*/
|
||||
void drawSprite(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect = Rect(0, 0, 1, 1),
|
||||
const Color &color = Colors::White,
|
||||
float rotation = 0.0f, bool flipX = false,
|
||||
bool flipY = false) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵(使用变换矩阵)
|
||||
*/
|
||||
void drawSprite(Ptr<rhi::RHITexture> texture,
|
||||
const glm::mat4 &transform,
|
||||
const Rect &srcRect = Rect(0, 0, 1, 1),
|
||||
const Color &color = Colors::White) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制九宫格精灵
|
||||
*/
|
||||
void draw9Slice(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect, const Vec2 &borderSize,
|
||||
const Color &color = Colors::White) override;
|
||||
|
||||
// ========================================================================
|
||||
// 文本渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制文本
|
||||
*/
|
||||
void drawText(const std::string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color = Colors::White) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制文本(UTF-32)
|
||||
*/
|
||||
void drawText(const std::u32string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color = Colors::White) override;
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸
|
||||
*/
|
||||
Vec2 measureText(const std::string &text, float fontSize) override;
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸(UTF-32)
|
||||
*/
|
||||
Vec2 measureText(const std::u32string &text, float fontSize) override;
|
||||
|
||||
// ========================================================================
|
||||
// 形状渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制矩形
|
||||
*/
|
||||
void drawRect(const Rect &rect, const Color &color,
|
||||
float lineWidth = 1.0f) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充矩形
|
||||
*/
|
||||
void fillRect(const Rect &rect, const Color &color) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制圆形
|
||||
*/
|
||||
void drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
float lineWidth = 1.0f, uint32_t segments = 32) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充圆形
|
||||
*/
|
||||
void fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
uint32_t segments = 32) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制线段
|
||||
*/
|
||||
void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
||||
float lineWidth = 1.0f) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制多边形
|
||||
*/
|
||||
void drawPolygon(const Vec2 *points, size_t count, const Color &color,
|
||||
float lineWidth = 1.0f) override;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充多边形
|
||||
*/
|
||||
void fillPolygon(const Vec2 *points, size_t count,
|
||||
const Color &color) override;
|
||||
|
||||
// ========================================================================
|
||||
// 批处理控制
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始精灵批处理
|
||||
*/
|
||||
void beginSpriteBatch() override;
|
||||
|
||||
/**
|
||||
* @brief 结束精灵批处理
|
||||
*/
|
||||
void endSpriteBatch() override;
|
||||
|
||||
/**
|
||||
* @brief 刷新当前批次
|
||||
*/
|
||||
void flush() override;
|
||||
|
||||
/**
|
||||
* @brief 设置渲染排序键
|
||||
*/
|
||||
void setSortKey(uint64_t key) override;
|
||||
|
||||
/**
|
||||
* @brief 设置渲染层
|
||||
*/
|
||||
void setLayer(int layer) override;
|
||||
|
||||
/**
|
||||
* @brief 设置混合模式
|
||||
*/
|
||||
void setBlendMode(rhi::BlendState blend) override;
|
||||
|
||||
// ========================================================================
|
||||
// 访问器
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取 RHI 设备
|
||||
*/
|
||||
rhi::RHIDevice *getDevice() const override;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口宽度
|
||||
*/
|
||||
int getWidth() const override;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口高度
|
||||
*/
|
||||
int getHeight() const override;
|
||||
|
||||
/**
|
||||
* @brief 获取渲染统计
|
||||
*/
|
||||
const RenderStats &getStats() const override;
|
||||
|
||||
/**
|
||||
* @brief 重置渲染统计
|
||||
*/
|
||||
void resetStats() override;
|
||||
|
||||
/**
|
||||
* @brief 获取图形 API 类型
|
||||
*/
|
||||
rhi::GraphicsAPI getAPI() const override;
|
||||
|
||||
/**
|
||||
* @brief 获取设备能力
|
||||
*/
|
||||
const rhi::DeviceCaps &getCaps() const override;
|
||||
|
||||
private:
|
||||
bool initialized_ = false;
|
||||
IWindow *window_ = nullptr;
|
||||
RenderBackendConfig config_;
|
||||
RenderStats stats_;
|
||||
|
||||
Ptr<rhi::RHIDevice> device_;
|
||||
glm::mat4 projectionMatrix_ = glm::mat4(1.0f);
|
||||
glm::mat4 viewMatrix_ = glm::mat4(1.0f);
|
||||
|
||||
int width_ = 0;
|
||||
int height_ = 0;
|
||||
|
||||
uint64_t sortKey_ = 0;
|
||||
int layer_ = 0;
|
||||
rhi::BlendState blendState_ = rhi::BlendState::alphaBlend();
|
||||
bool inBatch_ = false;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -3,9 +3,7 @@
|
|||
#include <extra2d/render/rhi/rhi_device.h>
|
||||
#include <extra2d/render/rhi/rhi_framebuffer.h>
|
||||
#include <glad/glad.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
@ -34,11 +32,11 @@ public:
|
|||
// 生命周期
|
||||
// ========================================================================
|
||||
|
||||
bool init(IWindow* window) override;
|
||||
bool init(IWindow *window) override;
|
||||
void shutdown() override;
|
||||
bool isValid() const override { return initialized_; }
|
||||
GraphicsAPI getAPI() const override { return GraphicsAPI::OpenGL; }
|
||||
const DeviceCaps& getCaps() const override { return caps_; }
|
||||
const DeviceCaps &getCaps() const override { return caps_; }
|
||||
|
||||
// ========================================================================
|
||||
// 帧管理
|
||||
|
|
@ -55,54 +53,63 @@ public:
|
|||
// 资源创建 - 缓冲区
|
||||
// ========================================================================
|
||||
|
||||
Ptr<RHIBuffer> createBuffer(const BufferDesc& desc) override;
|
||||
Ptr<RHIVertexBuffer> createVertexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
|
||||
const void* data = nullptr) override;
|
||||
Ptr<RHIIndexBuffer> createIndexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
|
||||
const void* data = nullptr) override;
|
||||
Ptr<RHIUniformBuffer> createUniformBuffer(size_t size, BufferUsage usage = BufferUsage::Dynamic) override;
|
||||
Ptr<RHIBuffer> createBuffer(const BufferDesc &desc) override;
|
||||
Ptr<RHIVertexBuffer>
|
||||
createVertexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
|
||||
const void *data = nullptr) override;
|
||||
Ptr<RHIIndexBuffer> createIndexBuffer(size_t size,
|
||||
BufferUsage usage = BufferUsage::Static,
|
||||
const void *data = nullptr) override;
|
||||
Ptr<RHIUniformBuffer>
|
||||
createUniformBuffer(size_t size,
|
||||
BufferUsage usage = BufferUsage::Dynamic) override;
|
||||
|
||||
// ========================================================================
|
||||
// 资源创建 - 纹理
|
||||
// ========================================================================
|
||||
|
||||
Ptr<RHITexture> createTexture(const TextureDesc& desc) override;
|
||||
Ptr<RHITexture> createTexture2D(uint32_t width, uint32_t height, Format format,
|
||||
const void* data = nullptr) override;
|
||||
Ptr<RHISampler> createSampler(const SamplerDesc& desc) override;
|
||||
Ptr<RHITextureView> createTextureView(Ptr<RHITexture> texture, const TextureViewDesc& desc) override;
|
||||
Ptr<RHITexture> createTexture(const TextureDesc &desc) override;
|
||||
Ptr<RHITexture> createTexture2D(uint32_t width, uint32_t height,
|
||||
Format format,
|
||||
const void *data = nullptr) override;
|
||||
Ptr<RHISampler> createSampler(const SamplerDesc &desc) override;
|
||||
Ptr<RHITextureView> createTextureView(Ptr<RHITexture> texture,
|
||||
const TextureViewDesc &desc) override;
|
||||
|
||||
// ========================================================================
|
||||
// 资源创建 - 着色器
|
||||
// ========================================================================
|
||||
|
||||
Ptr<RHIShader> createShader(const ShaderDesc& desc) override;
|
||||
Ptr<RHIShader> createShaderFromSource(const std::string& name,
|
||||
const std::string& vertexSource,
|
||||
const std::string& fragmentSource) override;
|
||||
Ptr<RHIShader> createShaderFromFile(const std::string& vertexPath,
|
||||
const std::string& fragmentPath) override;
|
||||
Ptr<RHIShader> createShader(const ShaderDesc &desc) override;
|
||||
Ptr<RHIShader>
|
||||
createShaderFromSource(const std::string &name,
|
||||
const std::string &vertexSource,
|
||||
const std::string &fragmentSource) override;
|
||||
Ptr<RHIShader> createShaderFromFile(const std::string &vertexPath,
|
||||
const std::string &fragmentPath) override;
|
||||
|
||||
// ========================================================================
|
||||
// 资源创建 - 管线
|
||||
// ========================================================================
|
||||
|
||||
Ptr<RHIPipeline> createPipeline(const PipelineDesc& desc, Ptr<RHIShader> shader) override;
|
||||
Ptr<RHIPipeline> createPipeline(const PipelineBuilder& builder) override;
|
||||
Ptr<RHIPipeline> createPipeline(const PipelineDesc &desc,
|
||||
Ptr<RHIShader> shader) override;
|
||||
Ptr<RHIPipeline> createPipeline(const PipelineBuilder &builder) override;
|
||||
|
||||
// ========================================================================
|
||||
// 资源创建 - 帧缓冲
|
||||
// ========================================================================
|
||||
|
||||
Ptr<RHIFramebuffer> createFramebuffer(const FramebufferDesc& desc) override;
|
||||
Ptr<RHIFramebuffer> createFramebuffer(const FramebufferBuilder& builder) override;
|
||||
Ptr<RHIFramebuffer> createFramebuffer(const FramebufferDesc &desc) override;
|
||||
Ptr<RHIFramebuffer>
|
||||
createFramebuffer(const FramebufferBuilder &builder) override;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染状态设置
|
||||
// ========================================================================
|
||||
|
||||
void setViewport(const Viewport& viewport) override;
|
||||
void setScissorRect(const ScissorRect& rect) override;
|
||||
void setViewport(const Viewport &viewport) override;
|
||||
void setScissorRect(const ScissorRect &rect) override;
|
||||
void setScissorEnabled(bool enabled) override;
|
||||
|
||||
// ========================================================================
|
||||
|
|
@ -111,9 +118,11 @@ public:
|
|||
|
||||
void setPipeline(Ptr<RHIPipeline> pipeline) override;
|
||||
void setShader(Ptr<RHIShader> shader) override;
|
||||
void setVertexBuffer(uint32_t slot, Ptr<RHIBuffer> buffer, uint32_t offset = 0) override;
|
||||
void setVertexBuffer(uint32_t slot, Ptr<RHIBuffer> buffer,
|
||||
uint32_t offset = 0) override;
|
||||
void setIndexBuffer(Ptr<RHIBuffer> buffer, IndexFormat format) override;
|
||||
void setTexture(uint32_t slot, Ptr<RHITexture> texture, Ptr<RHISampler> sampler = nullptr) override;
|
||||
void setTexture(uint32_t slot, Ptr<RHITexture> texture,
|
||||
Ptr<RHISampler> sampler = nullptr) override;
|
||||
void setUniformBuffer(uint32_t slot, Ptr<RHIBuffer> buffer) override;
|
||||
void setFramebuffer(Ptr<RHIFramebuffer> framebuffer) override;
|
||||
void setDefaultFramebuffer() override;
|
||||
|
|
@ -122,45 +131,47 @@ public:
|
|||
// 渲染命令 - Uniform 设置
|
||||
// ========================================================================
|
||||
|
||||
void setUniformFloat(const std::string& name, float value) override;
|
||||
void setUniformVec2(const std::string& name, const glm::vec2& value) override;
|
||||
void setUniformVec3(const std::string& name, const glm::vec3& value) override;
|
||||
void setUniformVec4(const std::string& name, const glm::vec4& value) override;
|
||||
void setUniformMat4(const std::string& name, const glm::mat4& value) override;
|
||||
void setUniformInt(const std::string& name, int value) override;
|
||||
void setUniformFloat(const std::string &name, float value) override;
|
||||
void setUniformVec2(const std::string &name, const glm::vec2 &value) override;
|
||||
void setUniformVec3(const std::string &name, const glm::vec3 &value) override;
|
||||
void setUniformVec4(const std::string &name, const glm::vec4 &value) override;
|
||||
void setUniformMat4(const std::string &name, const glm::mat4 &value) override;
|
||||
void setUniformInt(const std::string &name, int value) override;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染命令 - 绘制
|
||||
// ========================================================================
|
||||
|
||||
void draw(const DrawCommand& cmd) override;
|
||||
void drawIndexed(const DrawIndexedCommand& cmd) override;
|
||||
void draw(const DrawCommand &cmd) override;
|
||||
void drawIndexed(const DrawIndexedCommand &cmd) override;
|
||||
void drawIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) override;
|
||||
void drawIndexedIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) override;
|
||||
void 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 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;
|
||||
bool checkError() override;
|
||||
const std::string& getDebugName() const override { return debugName_; }
|
||||
void setDebugName(const std::string& name) override { debugName_ = name; }
|
||||
const std::string &getDebugName() const override { return debugName_; }
|
||||
void setDebugName(const std::string &name) override { debugName_ = name; }
|
||||
|
||||
private:
|
||||
bool initialized_ = false;
|
||||
bool vsyncEnabled_ = true;
|
||||
IWindow* window_ = nullptr;
|
||||
IWindow *window_ = nullptr;
|
||||
DeviceCaps caps_;
|
||||
DeviceStats stats_;
|
||||
std::string debugName_;
|
||||
|
|
@ -191,9 +202,9 @@ private:
|
|||
/**
|
||||
* @brief 应用管线状态
|
||||
*/
|
||||
void applyPipelineState(const BlendState& blend,
|
||||
const DepthStencilState& depthStencil,
|
||||
const RasterizerState& rasterizer);
|
||||
void applyPipelineState(const BlendState &blend,
|
||||
const DepthStencilState &depthStencil,
|
||||
const RasterizerState &rasterizer);
|
||||
};
|
||||
|
||||
} // namespace rhi
|
||||
|
|
|
|||
|
|
@ -0,0 +1,230 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class ViewportAdapter;
|
||||
|
||||
/**
|
||||
* @brief 相机类
|
||||
*
|
||||
* 2D 相机,支持平移、缩放、旋转和边界限制
|
||||
*/
|
||||
class Camera {
|
||||
public:
|
||||
Camera();
|
||||
Camera(float left, float right, float bottom, float top);
|
||||
~Camera() = default;
|
||||
|
||||
// ========================================================================
|
||||
// 视口设置
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
*/
|
||||
void setViewport(float left, float right, float bottom, float top);
|
||||
|
||||
/**
|
||||
* @brief 设置视口尺寸
|
||||
*/
|
||||
void setViewportSize(float width, float height);
|
||||
|
||||
/**
|
||||
* @brief 获取视口
|
||||
*/
|
||||
Rect getViewport() const;
|
||||
|
||||
/**
|
||||
* @brief 获取视口宽度
|
||||
*/
|
||||
float getViewportWidth() const { return right_ - left_; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口高度
|
||||
*/
|
||||
float getViewportHeight() const { return top_ - bottom_; }
|
||||
|
||||
// ========================================================================
|
||||
// 位置和变换
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置位置
|
||||
*/
|
||||
void setPos(const Vec2& position);
|
||||
void setPos(float x, float y);
|
||||
|
||||
/**
|
||||
* @brief 获取位置
|
||||
*/
|
||||
Vec2 getPosition() const { return position_; }
|
||||
|
||||
/**
|
||||
* @brief 移动相机
|
||||
*/
|
||||
void move(const Vec2& offset);
|
||||
void move(float x, float y);
|
||||
|
||||
/**
|
||||
* @brief 设置旋转角度(度)
|
||||
*/
|
||||
void setRotation(float degrees);
|
||||
|
||||
/**
|
||||
* @brief 获取旋转角度(度)
|
||||
*/
|
||||
float getRotation() const { return rotation_; }
|
||||
|
||||
/**
|
||||
* @brief 旋转相机
|
||||
*/
|
||||
void rotate(float degrees);
|
||||
|
||||
/**
|
||||
* @brief 设置缩放
|
||||
*/
|
||||
void setZoom(float zoom);
|
||||
|
||||
/**
|
||||
* @brief 获取缩放
|
||||
*/
|
||||
float getZoom() const { return zoom_; }
|
||||
|
||||
/**
|
||||
* @brief 缩放相机
|
||||
*/
|
||||
void zoomBy(float factor);
|
||||
|
||||
// ========================================================================
|
||||
// 边界限制
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置边界
|
||||
*/
|
||||
void setBounds(const Rect& bounds);
|
||||
|
||||
/**
|
||||
* @brief 清除边界
|
||||
*/
|
||||
void clearBounds();
|
||||
|
||||
/**
|
||||
* @brief 获取边界
|
||||
*/
|
||||
Rect getBounds() const { return bounds_; }
|
||||
|
||||
/**
|
||||
* @brief 是否有边界限制
|
||||
*/
|
||||
bool hasBounds() const { return hasBounds_; }
|
||||
|
||||
// ========================================================================
|
||||
// 矩阵
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取视图矩阵
|
||||
*/
|
||||
glm::mat4 getViewMatrix() const;
|
||||
|
||||
/**
|
||||
* @brief 获取投影矩阵
|
||||
*/
|
||||
glm::mat4 getProjectionMatrix() const;
|
||||
|
||||
/**
|
||||
* @brief 获取视图投影矩阵
|
||||
*/
|
||||
glm::mat4 getViewProjectionMatrix() const;
|
||||
|
||||
/**
|
||||
* @brief 更新矩阵
|
||||
*/
|
||||
void updateMatrices();
|
||||
|
||||
// ========================================================================
|
||||
// 坐标转换
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 屏幕坐标转世界坐标
|
||||
*/
|
||||
Vec2 screenToWorld(const Vec2& screenPos) const;
|
||||
|
||||
/**
|
||||
* @brief 世界坐标转屏幕坐标
|
||||
*/
|
||||
Vec2 worldToScreen(const Vec2& worldPos) const;
|
||||
|
||||
/**
|
||||
* @brief 注视目标
|
||||
*/
|
||||
void lookAt(const Vec2& target);
|
||||
|
||||
// ========================================================================
|
||||
// 视口适配器
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口适配器
|
||||
*/
|
||||
void setViewportAdapter(ViewportAdapter* adapter) { viewportAdapter_ = adapter; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口适配器
|
||||
*/
|
||||
ViewportAdapter* getViewportAdapter() const { return viewportAdapter_; }
|
||||
|
||||
/**
|
||||
* @brief 应用视口适配器
|
||||
*/
|
||||
void applyViewportAdapter();
|
||||
|
||||
// ========================================================================
|
||||
// 调试
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取调试名称
|
||||
*/
|
||||
const std::string& getDebugName() const { return debugName_; }
|
||||
|
||||
/**
|
||||
* @brief 设置调试名称
|
||||
*/
|
||||
void setDebugName(const std::string& name) { debugName_ = name; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 应用边界限制
|
||||
*/
|
||||
void applyBounds();
|
||||
|
||||
Vec2 position_;
|
||||
float rotation_;
|
||||
float zoom_;
|
||||
|
||||
float left_;
|
||||
float right_;
|
||||
float bottom_;
|
||||
float top_;
|
||||
|
||||
Rect bounds_;
|
||||
bool hasBounds_;
|
||||
|
||||
glm::mat4 viewMatrix_;
|
||||
glm::mat4 projectionMatrix_;
|
||||
glm::mat4 viewProjectionMatrix_;
|
||||
bool matricesDirty_;
|
||||
|
||||
ViewportAdapter* viewportAdapter_;
|
||||
std::string debugName_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,254 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 视口缩放模式
|
||||
*/
|
||||
enum class ViewportScaleMode {
|
||||
None, // 无缩放
|
||||
Letterbox, // 保持宽高比,黑边
|
||||
Crop, // 保持宽高比,裁剪
|
||||
Stretch, // 拉伸填充
|
||||
IntegerScale // 整数缩放
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 视口对齐方式
|
||||
*/
|
||||
enum class ViewportAlign {
|
||||
Center,
|
||||
TopLeft,
|
||||
TopCenter,
|
||||
TopRight,
|
||||
CenterLeft,
|
||||
CenterRight,
|
||||
BottomLeft,
|
||||
BottomCenter,
|
||||
BottomRight
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 视口配置
|
||||
*/
|
||||
struct ViewportConfig {
|
||||
float designWidth = 1280.0f;
|
||||
float designHeight = 720.0f;
|
||||
ViewportScaleMode scaleMode = ViewportScaleMode::Letterbox;
|
||||
ViewportAlign align = ViewportAlign::Center;
|
||||
bool integerScaleOnly = false;
|
||||
float minScale = 0.5f;
|
||||
float maxScale = 4.0f;
|
||||
|
||||
ViewportConfig() = default;
|
||||
|
||||
ViewportConfig(float width, float height,
|
||||
ViewportScaleMode mode = ViewportScaleMode::Letterbox)
|
||||
: designWidth(width), designHeight(height), scaleMode(mode) {}
|
||||
|
||||
/**
|
||||
* @brief 创建 HD (1280x720) 配置
|
||||
*/
|
||||
static ViewportConfig hd() {
|
||||
return ViewportConfig(1280.0f, 720.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建 Full HD (1920x1080) 配置
|
||||
*/
|
||||
static ViewportConfig fullHd() {
|
||||
return ViewportConfig(1920.0f, 1080.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 创建 4K (3840x2160) 配置
|
||||
*/
|
||||
static ViewportConfig uhd4k() {
|
||||
return ViewportConfig(3840.0f, 2160.0f);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 视口计算结果
|
||||
*/
|
||||
struct ViewportResult {
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
float width = 0.0f;
|
||||
float height = 0.0f;
|
||||
float scale = 1.0f;
|
||||
int offsetX = 0;
|
||||
int offsetY = 0;
|
||||
int screenWidth = 0;
|
||||
int screenHeight = 0;
|
||||
|
||||
ViewportResult() = default;
|
||||
|
||||
/**
|
||||
* @brief 获取视口矩形
|
||||
*/
|
||||
Rect getRect() const { return Rect(x, y, width, height); }
|
||||
|
||||
/**
|
||||
* @brief 获取缩放后的设计尺寸
|
||||
*/
|
||||
Size getScaledDesignSize() const { return Size(width / scale, height / scale); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 视口适配器
|
||||
*
|
||||
* 处理不同屏幕尺寸和宽高比的视口适配
|
||||
*/
|
||||
class ViewportAdapter {
|
||||
public:
|
||||
ViewportAdapter();
|
||||
explicit ViewportAdapter(const ViewportConfig& config);
|
||||
~ViewportAdapter() = default;
|
||||
|
||||
// ========================================================================
|
||||
// 配置
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置配置
|
||||
*/
|
||||
void setConfig(const ViewportConfig& config);
|
||||
|
||||
/**
|
||||
* @brief 获取配置
|
||||
*/
|
||||
const ViewportConfig& getConfig() const { return config_; }
|
||||
|
||||
/**
|
||||
* @brief 设置设计尺寸
|
||||
*/
|
||||
void setDesignSize(float width, float height);
|
||||
|
||||
/**
|
||||
* @brief 设置缩放模式
|
||||
*/
|
||||
void setScaleMode(ViewportScaleMode mode);
|
||||
|
||||
/**
|
||||
* @brief 设置对齐方式
|
||||
*/
|
||||
void setAlign(ViewportAlign align);
|
||||
|
||||
// ========================================================================
|
||||
// 更新
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 更新视口
|
||||
*/
|
||||
void update(int screenWidth, int screenHeight);
|
||||
|
||||
/**
|
||||
* @brief 获取结果
|
||||
*/
|
||||
const ViewportResult& getResult() const { return result_; }
|
||||
|
||||
// ========================================================================
|
||||
// 查询
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取设计宽度
|
||||
*/
|
||||
float getDesignWidth() const { return config_.designWidth; }
|
||||
|
||||
/**
|
||||
* @brief 获取设计高度
|
||||
*/
|
||||
float getDesignHeight() const { return config_.designHeight; }
|
||||
|
||||
/**
|
||||
* @brief 获取设计宽高比
|
||||
*/
|
||||
float getDesignAspectRatio() const;
|
||||
|
||||
/**
|
||||
* @brief 获取屏幕宽度
|
||||
*/
|
||||
int getScreenWidth() const { return result_.screenWidth; }
|
||||
|
||||
/**
|
||||
* @brief 获取屏幕高度
|
||||
*/
|
||||
int getScreenHeight() const { return result_.screenHeight; }
|
||||
|
||||
/**
|
||||
* @brief 获取屏幕宽高比
|
||||
*/
|
||||
float getScreenAspectRatio() const;
|
||||
|
||||
/**
|
||||
* @brief 获取当前缩放
|
||||
*/
|
||||
float getScale() const { return result_.scale; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口偏移 X
|
||||
*/
|
||||
int getOffsetX() const { return result_.offsetX; }
|
||||
|
||||
/**
|
||||
* @brief 获取视口偏移 Y
|
||||
*/
|
||||
int getOffsetY() const { return result_.offsetY; }
|
||||
|
||||
// ========================================================================
|
||||
// 坐标转换
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 屏幕坐标转设计坐标
|
||||
*/
|
||||
Vec2 screenToDesign(const Vec2& screenPos) const;
|
||||
|
||||
/**
|
||||
* @brief 设计坐标转屏幕坐标
|
||||
*/
|
||||
Vec2 designToScreen(const Vec2& designPos) const;
|
||||
|
||||
// ========================================================================
|
||||
// 调试
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取调试名称
|
||||
*/
|
||||
const std::string& getDebugName() const { return debugName_; }
|
||||
|
||||
/**
|
||||
* @brief 设置调试名称
|
||||
*/
|
||||
void setDebugName(const std::string& name) { debugName_ = name; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief 计算视口
|
||||
*/
|
||||
void calculateViewport();
|
||||
|
||||
/**
|
||||
* @brief 计算缩放
|
||||
*/
|
||||
float calculateScale() const;
|
||||
|
||||
/**
|
||||
* @brief 计算偏移
|
||||
*/
|
||||
void calculateOffset();
|
||||
|
||||
ViewportConfig config_;
|
||||
ViewportResult result_;
|
||||
std::string debugName_;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,182 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 渲染后端工厂
|
||||
*
|
||||
* 管理渲染后端的注册和创建
|
||||
* 支持多后端(OpenGL、Vulkan、DirectX 等)
|
||||
*/
|
||||
class BackendFactory {
|
||||
public:
|
||||
/**
|
||||
* @brief 后端创建函数类型
|
||||
*/
|
||||
using BackendFn = std::function<UniquePtr<RenderBackend>()>;
|
||||
|
||||
/**
|
||||
* @brief 后端注册信息
|
||||
*/
|
||||
struct BackendInfo {
|
||||
std::string name;
|
||||
BackendFn createFn;
|
||||
std::vector<std::string> compatibleWindowBackends;
|
||||
rhi::GraphicsAPI api;
|
||||
std::string description;
|
||||
int priority;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 注册渲染后端
|
||||
* @param name 后端名称(如 "opengl", "vulkan")
|
||||
* @param backend 后端创建函数
|
||||
* @param windowBackends 兼容的窗口后端列表
|
||||
* @param api 图形 API 类型
|
||||
* @param description 后端描述
|
||||
* @param priority 优先级(用于默认选择)
|
||||
*/
|
||||
static void reg(const std::string& name,
|
||||
BackendFn backend,
|
||||
const std::vector<std::string>& windowBackends = {},
|
||||
rhi::GraphicsAPI api = rhi::GraphicsAPI::OpenGL,
|
||||
const std::string& description = "",
|
||||
int priority = 0);
|
||||
|
||||
/**
|
||||
* @brief 注销渲染后端
|
||||
* @param name 后端名称
|
||||
*/
|
||||
static void unreg(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 创建渲染后端
|
||||
* @param name 后端名称
|
||||
* @return 后端实例,失败返回 nullptr
|
||||
*/
|
||||
static UniquePtr<RenderBackend> createBackend(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 创建默认渲染后端
|
||||
*
|
||||
* 按优先级选择最佳可用后端
|
||||
* @return 后端实例,失败返回 nullptr
|
||||
*/
|
||||
static UniquePtr<RenderBackend> createDefaultBackend();
|
||||
|
||||
/**
|
||||
* @brief 根据窗口后端创建兼容的渲染后端
|
||||
* @param windowBackend 窗口后端名称
|
||||
* @return 后端实例,失败返回 nullptr
|
||||
*/
|
||||
static UniquePtr<RenderBackend> createBackendForWindow(const std::string& windowBackend);
|
||||
|
||||
/**
|
||||
* @brief 根据图形 API 创建后端
|
||||
* @param api 图形 API 类型
|
||||
* @return 后端实例,失败返回 nullptr
|
||||
*/
|
||||
static UniquePtr<RenderBackend> createBackendForAPI(rhi::GraphicsAPI api);
|
||||
|
||||
/**
|
||||
* @brief 检查后端是否已注册
|
||||
* @param name 后端名称
|
||||
*/
|
||||
static bool hasBackend(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 获取所有已注册的后端名称
|
||||
*/
|
||||
static std::vector<std::string> getBackendNames();
|
||||
|
||||
/**
|
||||
* @brief 获取后端信息
|
||||
* @param name 后端名称
|
||||
* @return 后端信息,不存在返回 nullptr
|
||||
*/
|
||||
static const BackendInfo* getBackendInfo(const std::string& name);
|
||||
|
||||
/**
|
||||
* @brief 获取所有后端信息
|
||||
*/
|
||||
static std::vector<BackendInfo> getAllBackendInfos();
|
||||
|
||||
/**
|
||||
* @brief 获取兼容指定窗口后端的所有渲染后端
|
||||
* @param windowBackend 窗口后端名称
|
||||
*/
|
||||
static std::vector<std::string> getCompatibleBackends(const std::string& windowBackend);
|
||||
|
||||
/**
|
||||
* @brief 清除所有注册的后端
|
||||
*/
|
||||
static void clear();
|
||||
|
||||
/**
|
||||
* @brief 获取默认后端名称
|
||||
*/
|
||||
static std::string getDefaultBackendName();
|
||||
|
||||
/**
|
||||
* @brief 设置默认后端名称
|
||||
*/
|
||||
static void setDefaultBackendName(const std::string& name);
|
||||
|
||||
private:
|
||||
static std::unordered_map<std::string, BackendInfo>& getRegistry();
|
||||
static std::mutex& getMutex();
|
||||
static std::string& getDefaultName();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 后端自动注册器
|
||||
*
|
||||
* 用于静态初始化时自动注册后端
|
||||
*/
|
||||
class BackendRegistrar {
|
||||
public:
|
||||
BackendRegistrar(const std::string& name,
|
||||
BackendFactory::BackendFn backend,
|
||||
const std::vector<std::string>& windowBackends = {},
|
||||
rhi::GraphicsAPI api = rhi::GraphicsAPI::OpenGL,
|
||||
const std::string& description = "",
|
||||
int priority = 0) {
|
||||
BackendFactory::reg(name, backend, windowBackends, api, description, priority);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 渲染后端注册宏
|
||||
*
|
||||
* 使用方法:
|
||||
* E2D_REG_RENDER_BACKEND(opengl, GLRenderBackend, {"sdl2", "glfw"})
|
||||
*/
|
||||
#define E2D_REG_RENDER_BACKEND(name, BackendClass, windowBackends) \
|
||||
static ::extra2d::BackendRegistrar E2D_CONCAT(backend_reg_, name)( \
|
||||
#name, \
|
||||
[]() -> ::extra2d::UniquePtr<::extra2d::RenderBackend> { \
|
||||
return ::extra2d::makeUnique<BackendClass>(); \
|
||||
}, \
|
||||
windowBackends)
|
||||
|
||||
/**
|
||||
* @brief 渲染后端注册宏(带优先级)
|
||||
*/
|
||||
#define E2D_REG_RENDER_BACKEND_EX(name, BackendClass, windowBackends, api, desc, prio) \
|
||||
static ::extra2d::BackendRegistrar E2D_CONCAT(backend_reg_, name)( \
|
||||
#name, \
|
||||
[]() -> ::extra2d::UniquePtr<::extra2d::RenderBackend> { \
|
||||
return ::extra2d::makeUnique<BackendClass>(); \
|
||||
}, \
|
||||
windowBackends, api, desc, prio)
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,324 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/render/rhi/rhi_device.h>
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class IWindow;
|
||||
|
||||
/**
|
||||
* @brief 渲染统计信息
|
||||
*/
|
||||
struct RenderStats {
|
||||
uint32_t drawCalls = 0;
|
||||
uint32_t spriteCount = 0;
|
||||
uint32_t textCharCount = 0;
|
||||
uint32_t shapeCount = 0;
|
||||
uint32_t batchCount = 0;
|
||||
uint32_t textureBinds = 0;
|
||||
uint32_t shaderBinds = 0;
|
||||
|
||||
void reset() {
|
||||
drawCalls = 0;
|
||||
spriteCount = 0;
|
||||
textCharCount = 0;
|
||||
shapeCount = 0;
|
||||
batchCount = 0;
|
||||
textureBinds = 0;
|
||||
shaderBinds = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 渲染后端配置
|
||||
*/
|
||||
struct RenderBackendConfig {
|
||||
rhi::GraphicsAPI api = rhi::GraphicsAPI::OpenGL;
|
||||
bool vsync = true;
|
||||
uint32_t maxBatchSize = 10000;
|
||||
bool enableDebug = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 高层渲染后端接口
|
||||
*
|
||||
* 封装 RHI 层,提供游戏逻辑使用的简化渲染接口
|
||||
* 支持精灵、文本、形状等高层渲染功能
|
||||
*/
|
||||
class RenderBackend {
|
||||
public:
|
||||
virtual ~RenderBackend() = default;
|
||||
|
||||
// ========================================================================
|
||||
// 生命周期
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 初始化渲染后端
|
||||
* @param window 窗口接口
|
||||
* @param config 配置参数
|
||||
* @return 成功返回 true
|
||||
*/
|
||||
virtual bool init(IWindow *window,
|
||||
const RenderBackendConfig &config = {}) = 0;
|
||||
|
||||
/**
|
||||
* @brief 关闭渲染后端
|
||||
*/
|
||||
virtual void shutdown() = 0;
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
*/
|
||||
virtual bool isValid() const = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 帧管理
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始帧渲染
|
||||
* @param clearColor 清屏颜色
|
||||
*/
|
||||
virtual void beginFrame(const Color &clearColor = Colors::Black) = 0;
|
||||
|
||||
/**
|
||||
* @brief 结束帧渲染
|
||||
*/
|
||||
virtual void endFrame() = 0;
|
||||
|
||||
/**
|
||||
* @brief 呈现帧
|
||||
*/
|
||||
virtual void present() = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 渲染状态
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
*/
|
||||
virtual void setViewport(int x, int y, int width, int height) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置裁剪区域
|
||||
*/
|
||||
virtual void setScissor(int x, int y, int width, int height) = 0;
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用裁剪测试
|
||||
*/
|
||||
virtual void setScissorEnabled(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置投影矩阵
|
||||
*/
|
||||
virtual void setProjectionMatrix(const glm::mat4 &matrix) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置视图矩阵
|
||||
*/
|
||||
virtual void setViewMatrix(const glm::mat4 &matrix) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置垂直同步
|
||||
*/
|
||||
virtual void setVSync(bool enabled) = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取垂直同步状态
|
||||
*/
|
||||
virtual bool isVSyncEnabled() const = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 精灵渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵
|
||||
* @param texture 纹理
|
||||
* @param destRect 目标矩形
|
||||
* @param srcRect 源矩形(纹理坐标)
|
||||
* @param color 颜色调制
|
||||
* @param rotation 旋转角度(度)
|
||||
* @param flipX 水平翻转
|
||||
* @param flipY 垂直翻转
|
||||
*/
|
||||
virtual void drawSprite(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect = Rect(0, 0, 1, 1),
|
||||
const Color &color = Colors::White,
|
||||
float rotation = 0.0f, bool flipX = false,
|
||||
bool flipY = false) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵(使用变换矩阵)
|
||||
*/
|
||||
virtual void drawSprite(Ptr<rhi::RHITexture> texture,
|
||||
const glm::mat4 &transform,
|
||||
const Rect &srcRect = Rect(0, 0, 1, 1),
|
||||
const Color &color = Colors::White) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制九宫格精灵
|
||||
*/
|
||||
virtual void draw9Slice(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect, const Vec2 &borderSize,
|
||||
const Color &color = Colors::White) = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 文本渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制文本
|
||||
* @param text UTF-8 编码文本
|
||||
* @param position 位置
|
||||
* @param fontSize 字体大小
|
||||
* @param color 颜色
|
||||
*/
|
||||
virtual void drawText(const std::string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color = Colors::White) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制文本(UTF-32)
|
||||
*/
|
||||
virtual void drawText(const std::u32string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color = Colors::White) = 0;
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸
|
||||
*/
|
||||
virtual Vec2 measureText(const std::string &text, float fontSize) = 0;
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸(UTF-32)
|
||||
*/
|
||||
virtual Vec2 measureText(const std::u32string &text, float fontSize) = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 形状渲染
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制矩形
|
||||
*/
|
||||
virtual void drawRect(const Rect &rect, const Color &color,
|
||||
float lineWidth = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充矩形
|
||||
*/
|
||||
virtual void fillRect(const Rect &rect, const Color &color) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制圆形
|
||||
*/
|
||||
virtual void drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
float lineWidth = 1.0f, uint32_t segments = 32) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充圆形
|
||||
*/
|
||||
virtual void fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
uint32_t segments = 32) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制线段
|
||||
*/
|
||||
virtual void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
||||
float lineWidth = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制多边形
|
||||
*/
|
||||
virtual void drawPolygon(const Vec2 *points, size_t count, const Color &color,
|
||||
float lineWidth = 1.0f) = 0;
|
||||
|
||||
/**
|
||||
* @brief 绘制填充多边形
|
||||
*/
|
||||
virtual void fillPolygon(const Vec2 *points, size_t count,
|
||||
const Color &color) = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 批处理控制
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始精灵批处理
|
||||
*/
|
||||
virtual void beginSpriteBatch() = 0;
|
||||
|
||||
/**
|
||||
* @brief 结束精灵批处理
|
||||
*/
|
||||
virtual void endSpriteBatch() = 0;
|
||||
|
||||
/**
|
||||
* @brief 刷新当前批次
|
||||
*/
|
||||
virtual void flush() = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置渲染排序键
|
||||
*/
|
||||
virtual void setSortKey(uint64_t key) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置渲染层
|
||||
*/
|
||||
virtual void setLayer(int layer) = 0;
|
||||
|
||||
/**
|
||||
* @brief 设置混合模式
|
||||
*/
|
||||
virtual void setBlendMode(rhi::BlendState blend) = 0;
|
||||
|
||||
// ========================================================================
|
||||
// 访问器
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取 RHI 设备
|
||||
*/
|
||||
virtual rhi::RHIDevice *getDevice() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口宽度
|
||||
*/
|
||||
virtual int getWidth() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取窗口高度
|
||||
*/
|
||||
virtual int getHeight() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取渲染统计
|
||||
*/
|
||||
virtual const RenderStats &getStats() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 重置渲染统计
|
||||
*/
|
||||
virtual void resetStats() = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取图形 API 类型
|
||||
*/
|
||||
virtual rhi::GraphicsAPI getAPI() const = 0;
|
||||
|
||||
/**
|
||||
* @brief 获取设备能力
|
||||
*/
|
||||
virtual const rhi::DeviceCaps &getCaps() const = 0;
|
||||
};
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -30,6 +30,7 @@ enum class RenderCommandType : uint8_t {
|
|||
* @brief 形状类型枚举
|
||||
*/
|
||||
enum class ShapeType : uint8_t {
|
||||
Point,
|
||||
Line,
|
||||
Rect,
|
||||
FilledRect,
|
||||
|
|
|
|||
|
|
@ -3,48 +3,17 @@
|
|||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/core/types.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_queue.h>
|
||||
#include <extra2d/render/rhi/rhi_device.h>
|
||||
#include <extra2d/render/rhi/rhi_types.h>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
class IWindow;
|
||||
|
||||
/**
|
||||
* @brief 渲染统计信息
|
||||
*/
|
||||
struct RenderStats {
|
||||
uint32_t drawCalls;
|
||||
uint32_t batchCount;
|
||||
uint32_t vertexCount;
|
||||
uint32_t triangleCount;
|
||||
uint32_t spriteCount;
|
||||
uint32_t textCount;
|
||||
uint32_t shapeCount;
|
||||
float frameTime;
|
||||
float renderTime;
|
||||
|
||||
RenderStats()
|
||||
: drawCalls(0), batchCount(0), vertexCount(0), triangleCount(0),
|
||||
spriteCount(0), textCount(0), shapeCount(0), frameTime(0.0f), renderTime(0.0f) {}
|
||||
|
||||
void reset() {
|
||||
drawCalls = 0;
|
||||
batchCount = 0;
|
||||
vertexCount = 0;
|
||||
triangleCount = 0;
|
||||
spriteCount = 0;
|
||||
textCount = 0;
|
||||
shapeCount = 0;
|
||||
frameTime = 0.0f;
|
||||
renderTime = 0.0f;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 渲染上下文配置
|
||||
*/
|
||||
|
|
@ -56,11 +25,8 @@ struct RenderContextConfig {
|
|||
rhi::GraphicsAPI preferredAPI;
|
||||
|
||||
RenderContextConfig()
|
||||
: maxBatchSize(10000),
|
||||
enableBatching(true),
|
||||
enableScissor(true),
|
||||
enableStats(true),
|
||||
preferredAPI(rhi::GraphicsAPI::OpenGL) {}
|
||||
: maxBatchSize(10000), enableBatching(true), enableScissor(true),
|
||||
enableStats(true), preferredAPI(rhi::GraphicsAPI::OpenGL) {}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -73,14 +39,14 @@ public:
|
|||
static constexpr uint32_t DEFAULT_MAX_BATCH_SIZE = 10000;
|
||||
|
||||
RenderContext();
|
||||
explicit RenderContext(const RenderContextConfig& config);
|
||||
explicit RenderContext(const RenderContextConfig &config);
|
||||
~RenderContext();
|
||||
|
||||
/**
|
||||
* @brief 初始化渲染上下文
|
||||
*/
|
||||
bool init(IWindow* window);
|
||||
bool init(IWindow* window, rhi::GraphicsAPI api);
|
||||
bool init(IWindow *window);
|
||||
bool init(IWindow *window, rhi::GraphicsAPI api);
|
||||
|
||||
/**
|
||||
* @brief 关闭渲染上下文
|
||||
|
|
@ -110,20 +76,20 @@ public:
|
|||
/**
|
||||
* @brief 清除屏幕
|
||||
*/
|
||||
void clear(const Color& color = Colors::Black);
|
||||
void clear(const Color& color, float depth, uint8_t stencil = 0);
|
||||
void clear(const Color &color = Colors::Black);
|
||||
void clear(const Color &color, float depth, uint8_t stencil = 0);
|
||||
|
||||
/**
|
||||
* @brief 获取/设置视口
|
||||
*/
|
||||
void setViewport(const rhi::Viewport& viewport);
|
||||
void setViewport(const rhi::Viewport &viewport);
|
||||
void setViewport(float x, float y, float width, float height);
|
||||
rhi::Viewport getViewport() const;
|
||||
|
||||
/**
|
||||
* @brief 获取/设置裁剪区域
|
||||
*/
|
||||
void setScissorRect(const rhi::ScissorRect& rect);
|
||||
void setScissorRect(const rhi::ScissorRect &rect);
|
||||
void setScissorRect(int32_t x, int32_t y, uint32_t width, uint32_t height);
|
||||
void setScissorEnabled(bool enabled);
|
||||
rhi::ScissorRect getScissorRect() const;
|
||||
|
|
@ -131,7 +97,7 @@ public:
|
|||
/**
|
||||
* @brief 变换矩阵栈操作
|
||||
*/
|
||||
void pushTransform(const glm::mat4& transform);
|
||||
void pushTransform(const glm::mat4 &transform);
|
||||
void popTransform();
|
||||
void resetTransform();
|
||||
glm::mat4 getCurrentTransform() const;
|
||||
|
|
@ -139,16 +105,16 @@ public:
|
|||
/**
|
||||
* @brief 混合状态操作
|
||||
*/
|
||||
void setBlendState(const rhi::BlendState& blend);
|
||||
void setBlendState(const rhi::BlendState &blend);
|
||||
rhi::BlendState getBlendState() const;
|
||||
void pushBlendState(const rhi::BlendState& blend);
|
||||
void pushBlendState(const rhi::BlendState &blend);
|
||||
void popBlendState();
|
||||
|
||||
/**
|
||||
* @brief 渲染队列操作
|
||||
*/
|
||||
RenderQueue& getQueue() { return queue_; }
|
||||
const RenderQueue& getQueue() const { return queue_; }
|
||||
RenderQueue &getQueue() { return queue_; }
|
||||
const RenderQueue &getQueue() const { return queue_; }
|
||||
void clearQueue();
|
||||
|
||||
/**
|
||||
|
|
@ -164,19 +130,19 @@ public:
|
|||
/**
|
||||
* @brief 获取窗口
|
||||
*/
|
||||
IWindow* getWindow() const { return window_; }
|
||||
IWindow *getWindow() const { return window_; }
|
||||
|
||||
/**
|
||||
* @brief 获取统计信息
|
||||
*/
|
||||
const RenderStats& getStats() const { return stats_; }
|
||||
const RenderStats &getStats() const { return stats_; }
|
||||
void resetStats();
|
||||
|
||||
/**
|
||||
* @brief 获取配置
|
||||
*/
|
||||
const RenderContextConfig& getConfig() const { return config_; }
|
||||
void setConfig(const RenderContextConfig& config);
|
||||
const RenderContextConfig &getConfig() const { return config_; }
|
||||
void setConfig(const RenderContextConfig &config);
|
||||
|
||||
/**
|
||||
* @brief 获取帧缓冲尺寸
|
||||
|
|
@ -199,7 +165,7 @@ private:
|
|||
void initDefaultState();
|
||||
|
||||
Ptr<rhi::RHIDevice> device_;
|
||||
IWindow* window_;
|
||||
IWindow *window_;
|
||||
RenderQueue queue_;
|
||||
RenderStats stats_;
|
||||
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/types.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/components/transform_component.h>
|
||||
#include <memory>
|
||||
|
|
@ -31,7 +31,7 @@ public:
|
|||
* @param name 节点名称
|
||||
* @return 创建的节点智能指针
|
||||
*/
|
||||
static Ptr<Node> create(const std::string& name = "");
|
||||
static Ptr<Node> create(const std::string &name = "");
|
||||
|
||||
Node();
|
||||
virtual ~Node();
|
||||
|
|
@ -50,7 +50,7 @@ public:
|
|||
* @brief 批量添加子节点
|
||||
* @param children 子节点列表
|
||||
*/
|
||||
void addChildren(std::vector<Ptr<Node>>&& children);
|
||||
void addChildren(std::vector<Ptr<Node>> &&children);
|
||||
|
||||
/**
|
||||
* @brief 移除子节点
|
||||
|
|
@ -62,7 +62,7 @@ public:
|
|||
* @brief 通过名称移除子节点
|
||||
* @param name 子节点的名称
|
||||
*/
|
||||
void removeChildByName(const std::string& name);
|
||||
void removeChildByName(const std::string &name);
|
||||
|
||||
/**
|
||||
* @brief 从父节点分离
|
||||
|
|
@ -84,14 +84,14 @@ public:
|
|||
* @brief 获取所有子节点
|
||||
* @return 子节点列表的常量引用
|
||||
*/
|
||||
const std::vector<Ptr<Node>>& getChildren() const { return children_; }
|
||||
const std::vector<Ptr<Node>> &getChildren() const { return children_; }
|
||||
|
||||
/**
|
||||
* @brief 通过名称查找子节点
|
||||
* @param name 子节点的名称
|
||||
* @return 找到的子节点智能指针,未找到返回nullptr
|
||||
*/
|
||||
Ptr<Node> findChild(const std::string& name) const;
|
||||
Ptr<Node> findChild(const std::string &name) const;
|
||||
|
||||
/**
|
||||
* @brief 通过标签查找子节点
|
||||
|
|
@ -111,8 +111,7 @@ public:
|
|||
* @param args 构造函数参数
|
||||
* @return 创建的组件指针
|
||||
*/
|
||||
template<typename T, typename... Args>
|
||||
T* addComponent(Args&&... args) {
|
||||
template <typename T, typename... Args> T *addComponent(Args &&...args) {
|
||||
static_assert(std::is_base_of<Component, T>::value,
|
||||
"T must derive from Component");
|
||||
|
||||
|
|
@ -121,7 +120,7 @@ public:
|
|||
// 检查是否已存在相同类型的组件
|
||||
auto it = components_.find(typeId);
|
||||
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 组件类型
|
||||
* @return 组件指针,不存在返回nullptr
|
||||
*/
|
||||
template<typename T>
|
||||
T* getComponent() const {
|
||||
template <typename T> T *getComponent() const {
|
||||
static_assert(std::is_base_of<Component, T>::value,
|
||||
"T must derive from Component");
|
||||
|
||||
uint32_t typeId = T::getStaticTypeId();
|
||||
auto it = components_.find(typeId);
|
||||
if (it != components_.end()) {
|
||||
return static_cast<T*>(it->second.get());
|
||||
return static_cast<T *>(it->second.get());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -158,8 +156,7 @@ public:
|
|||
* @tparam T 组件类型
|
||||
* @return 如果存在返回true
|
||||
*/
|
||||
template<typename T>
|
||||
bool hasComponent() const {
|
||||
template <typename T> bool hasComponent() const {
|
||||
return getComponent<T>() != nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -167,8 +164,7 @@ public:
|
|||
* @brief 移除组件
|
||||
* @tparam T 组件类型
|
||||
*/
|
||||
template<typename T>
|
||||
void removeComponent() {
|
||||
template <typename T> void removeComponent() {
|
||||
static_assert(std::is_base_of<Component, T>::value,
|
||||
"T must derive from Component");
|
||||
|
||||
|
|
@ -186,7 +182,7 @@ public:
|
|||
* @brief 获取变换组件
|
||||
* @return 变换组件指针
|
||||
*/
|
||||
TransformComponent* getTransform() const { return transform_; }
|
||||
TransformComponent *getTransform() const { return transform_; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 变换属性(便捷方法,委托给TransformComponent)
|
||||
|
|
@ -196,7 +192,7 @@ public:
|
|||
* @brief 设置节点位置
|
||||
* @param pos 新的位置坐标
|
||||
*/
|
||||
void setPos(const Vec2& pos);
|
||||
void setPos(const Vec2 &pos);
|
||||
|
||||
/**
|
||||
* @brief 设置节点位置
|
||||
|
|
@ -227,7 +223,7 @@ public:
|
|||
* @brief 设置节点缩放
|
||||
* @param scale 缩放向量
|
||||
*/
|
||||
void setScale(const Vec2& scale);
|
||||
void setScale(const Vec2 &scale);
|
||||
|
||||
/**
|
||||
* @brief 设置节点统一缩放
|
||||
|
|
@ -252,7 +248,7 @@ public:
|
|||
* @brief 设置节点锚点
|
||||
* @param anchor 锚点位置(0-1范围)
|
||||
*/
|
||||
void setAnchor(const Vec2& anchor);
|
||||
void setAnchor(const Vec2 &anchor);
|
||||
|
||||
/**
|
||||
* @brief 设置节点锚点
|
||||
|
|
@ -271,7 +267,7 @@ public:
|
|||
* @brief 设置节点斜切
|
||||
* @param skew 斜切角度向量
|
||||
*/
|
||||
void setSkew(const Vec2& skew);
|
||||
void setSkew(const Vec2 &skew);
|
||||
|
||||
/**
|
||||
* @brief 设置节点斜切
|
||||
|
|
@ -295,14 +291,14 @@ public:
|
|||
* @param localPos 本地坐标位置
|
||||
* @return 世界坐标位置
|
||||
*/
|
||||
Vec2 toWorld(const Vec2& localPos) const;
|
||||
Vec2 toWorld(const Vec2 &localPos) const;
|
||||
|
||||
/**
|
||||
* @brief 将世界坐标转换为本地坐标
|
||||
* @param worldPos 世界坐标位置
|
||||
* @return 本地坐标位置
|
||||
*/
|
||||
Vec2 toLocal(const Vec2& worldPos) const;
|
||||
Vec2 toLocal(const Vec2 &worldPos) const;
|
||||
|
||||
/**
|
||||
* @brief 获取本地变换矩阵
|
||||
|
|
@ -364,7 +360,7 @@ public:
|
|||
* @brief 设置颜色
|
||||
* @param color RGB颜色
|
||||
*/
|
||||
void setColor(const Color3B& color);
|
||||
void setColor(const Color3B &color);
|
||||
|
||||
/**
|
||||
* @brief 获取颜色
|
||||
|
|
@ -412,13 +408,13 @@ public:
|
|||
* @brief 设置名称
|
||||
* @param name 节点名称
|
||||
*/
|
||||
void setName(const std::string& name) { name_ = name; }
|
||||
void setName(const std::string &name) { name_ = name; }
|
||||
|
||||
/**
|
||||
* @brief 获取名称
|
||||
* @return 节点名称
|
||||
*/
|
||||
const std::string& getName() const { return name_; }
|
||||
const std::string &getName() const { return name_; }
|
||||
|
||||
/**
|
||||
* @brief 设置标签
|
||||
|
|
@ -456,13 +452,13 @@ public:
|
|||
* @brief 渲染回调
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
virtual void onRender(RenderBackend& renderer);
|
||||
virtual void onRender(RenderBackend &renderer);
|
||||
|
||||
/**
|
||||
* @brief 附加到场景时的回调
|
||||
* @param scene 所属场景指针
|
||||
*/
|
||||
virtual void onAttachToScene(Scene* scene);
|
||||
virtual void onAttachToScene(Scene *scene);
|
||||
|
||||
/**
|
||||
* @brief 从场景分离时的回调
|
||||
|
|
@ -487,7 +483,7 @@ public:
|
|||
* @brief 获取事件分发器
|
||||
* @return 事件分发器引用
|
||||
*/
|
||||
EventDispatcher& getEventDispatcher() { return eventDispatcher_; }
|
||||
EventDispatcher &getEventDispatcher() { return eventDispatcher_; }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 内部方法
|
||||
|
|
@ -503,7 +499,7 @@ public:
|
|||
* @brief 渲染节点
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
void render(RenderBackend& renderer);
|
||||
void render(RenderBackend &renderer);
|
||||
|
||||
/**
|
||||
* @brief 对子节点排序
|
||||
|
|
@ -520,28 +516,28 @@ public:
|
|||
* @brief 获取所属场景
|
||||
* @return 所属场景指针
|
||||
*/
|
||||
Scene* getScene() const { return scene_; }
|
||||
Scene *getScene() const { return scene_; }
|
||||
|
||||
/**
|
||||
* @brief 收集渲染命令
|
||||
* @param commands 渲染命令输出向量
|
||||
* @param parentZOrder 父节点的Z序
|
||||
*/
|
||||
virtual void collectRenderCommands(std::vector<RenderCommand>& commands,
|
||||
virtual void collectRenderCommands(std::vector<RenderCommand> &commands,
|
||||
int parentZOrder = 0);
|
||||
|
||||
/**
|
||||
* @brief 收集渲染命令到队列
|
||||
* @param queue 渲染队列引用
|
||||
*/
|
||||
virtual void collectRenderCommandsToQueue(RenderQueue& queue);
|
||||
virtual void collectRenderCommandsToQueue(RenderQueue &queue);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief 绘制回调(子类重写)
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
virtual void onDraw(RenderBackend& renderer) {}
|
||||
virtual void onDraw(RenderBackend &renderer) {}
|
||||
|
||||
/**
|
||||
* @brief 节点更新回调(子类重写)
|
||||
|
|
@ -554,14 +550,14 @@ protected:
|
|||
* @param commands 渲染命令输出向量
|
||||
* @param zOrder Z序
|
||||
*/
|
||||
virtual void generateRenderCommand(std::vector<RenderCommand>& commands,
|
||||
virtual void generateRenderCommand(std::vector<RenderCommand> &commands,
|
||||
int zOrder) {}
|
||||
|
||||
/**
|
||||
* @brief 生成渲染命令到队列(子类重写)
|
||||
* @param queue 渲染队列引用
|
||||
*/
|
||||
virtual void generateRenderCommandToQueue(RenderQueue& queue) { (void)queue; }
|
||||
virtual void generateRenderCommandToQueue(RenderQueue &queue) { (void)queue; }
|
||||
|
||||
private:
|
||||
// ==========================================================================
|
||||
|
|
@ -588,7 +584,7 @@ private:
|
|||
WeakPtr<Node> parent_;
|
||||
|
||||
// 6. 变换组件(内置)
|
||||
TransformComponent* transform_ = nullptr;
|
||||
TransformComponent *transform_ = nullptr;
|
||||
|
||||
// 7. 浮点属性
|
||||
float opacity_ = 1.0f;
|
||||
|
|
@ -605,7 +601,7 @@ private:
|
|||
bool flipY_ = false;
|
||||
|
||||
// 11. 场景指针
|
||||
Scene* scene_ = nullptr;
|
||||
Scene *scene_ = nullptr;
|
||||
|
||||
// 12. 布尔标志(打包在一起)
|
||||
mutable bool transformDirty_ = true;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ public:
|
|||
* @brief 设置背景颜色
|
||||
* @param color 背景颜色
|
||||
*/
|
||||
void setBackgroundColor(const Color& color) { backgroundColor_ = color; }
|
||||
void setBackgroundColor(const Color &color) { backgroundColor_ = color; }
|
||||
|
||||
/**
|
||||
* @brief 获取背景颜色
|
||||
|
|
@ -55,7 +55,7 @@ public:
|
|||
* @brief 获取活动相机
|
||||
* @return 活动相机指针(优先返回设置的相机,否则返回默认相机)
|
||||
*/
|
||||
Camera* getActiveCamera() const {
|
||||
Camera *getActiveCamera() const {
|
||||
return camera_ ? camera_.get() : defaultCamera_.get();
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ public:
|
|||
* @brief 设置视口大小
|
||||
* @param size 视口尺寸结构体
|
||||
*/
|
||||
void setViewportSize(const Size& size);
|
||||
void setViewportSize(const Size &size);
|
||||
|
||||
/**
|
||||
* @brief 获取视口大小
|
||||
|
|
@ -122,13 +122,13 @@ public:
|
|||
* @brief 渲染场景
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
void renderScene(RenderBackend& renderer);
|
||||
void renderScene(RenderBackend &renderer);
|
||||
|
||||
/**
|
||||
* @brief 渲染场景内容
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
virtual void renderContent(RenderBackend& renderer);
|
||||
virtual void renderContent(RenderBackend &renderer);
|
||||
|
||||
/**
|
||||
* @brief 更新场景
|
||||
|
|
@ -141,14 +141,14 @@ public:
|
|||
* @param commands 渲染命令输出向量
|
||||
* @param parentZOrder 父节点的Z序
|
||||
*/
|
||||
void collectRenderCommands(std::vector<RenderCommand>& commands,
|
||||
void collectRenderCommands(std::vector<RenderCommand> &commands,
|
||||
int parentZOrder = 0) override;
|
||||
|
||||
/**
|
||||
* @brief 收集渲染命令到队列
|
||||
* @param queue 渲染队列引用
|
||||
*/
|
||||
void collectRenderCommandsToQueue(RenderQueue& queue) override;
|
||||
void collectRenderCommandsToQueue(RenderQueue &queue) override;
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// 静态创建方法
|
||||
|
|
|
|||
|
|
@ -2,16 +2,12 @@
|
|||
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
#include <vector>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
// ============================================================================
|
||||
// 形状类型
|
||||
// ============================================================================
|
||||
enum class ShapeType { Point, Line, Rect, Circle, Triangle, Polygon };
|
||||
|
||||
// ============================================================================
|
||||
// 形状节点 - 用于绘制几何形状
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/resources/texture.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
#include <extra2d/core/service_interface.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/camera/viewport_adapter.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/camera/viewport_adapter.h>
|
||||
#include <functional>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/registry.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_module.h>
|
||||
#include <extra2d/graphics/memory/vram_manager.h>
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <extra2d/platform/input_module.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/platform/window_module.h>
|
||||
#include <extra2d/render/camera/viewport_adapter.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_module.h>
|
||||
#include <extra2d/render/renderer.h>
|
||||
#include <extra2d/services/camera_service.h>
|
||||
#include <extra2d/services/event_service.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <extra2d/services/scene_service.h>
|
||||
#include <extra2d/services/timer_service.h>
|
||||
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
static double getTimeSeconds() {
|
||||
|
|
@ -81,9 +81,9 @@ void Application::configureCameraService() {
|
|||
static_cast<float>(win->height()), 0);
|
||||
|
||||
ViewportConfig vpConfig;
|
||||
vpConfig.logicWidth = static_cast<float>(win->width());
|
||||
vpConfig.logicHeight = static_cast<float>(win->height());
|
||||
vpConfig.mode = ViewportMode::AspectRatio;
|
||||
vpConfig.designWidth = static_cast<float>(win->width());
|
||||
vpConfig.designHeight = static_cast<float>(win->height());
|
||||
vpConfig.scaleMode = ViewportScaleMode::Letterbox;
|
||||
cameraService->setViewportConfig(vpConfig);
|
||||
cameraService->updateViewport(win->width(), win->height());
|
||||
|
||||
|
|
@ -97,8 +97,6 @@ void Application::shutdown() {
|
|||
if (!initialized_)
|
||||
return;
|
||||
|
||||
VRAMMgr::get().printStats();
|
||||
|
||||
ServiceLocator::instance().shutdownAll();
|
||||
ServiceLocator::instance().clear();
|
||||
Registry::instance().shutdown();
|
||||
|
|
@ -176,8 +174,7 @@ void Application::mainLoop() {
|
|||
|
||||
// 帧率限制
|
||||
auto *renderMod = get<RenderModule>();
|
||||
if (renderMod && renderMod->renderer()) {
|
||||
// 这里可以添加帧率限制逻辑
|
||||
if (renderMod && renderMod->getRenderer()) {
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -192,29 +189,28 @@ void Application::update() {
|
|||
|
||||
void Application::render() {
|
||||
auto *renderMod = get<RenderModule>();
|
||||
if (!renderMod || !renderMod->renderer())
|
||||
if (!renderMod || !renderMod->getRenderer())
|
||||
return;
|
||||
|
||||
auto *renderer = renderMod->renderer();
|
||||
auto *renderer = renderMod->getRenderer();
|
||||
auto *winMod = get<WindowModule>();
|
||||
if (!winMod || !winMod->win())
|
||||
return;
|
||||
|
||||
auto cameraService = ServiceLocator::instance().getService<ICameraService>();
|
||||
if (cameraService) {
|
||||
const auto &vp = cameraService->getViewportResult().viewport;
|
||||
const auto &vpResult = cameraService->getViewportResult();
|
||||
renderer->setViewport(
|
||||
static_cast<int>(vp.origin.x), static_cast<int>(vp.origin.y),
|
||||
static_cast<int>(vp.size.width), static_cast<int>(vp.size.height));
|
||||
renderer->setViewProjection(cameraService->getViewProjectionMatrix());
|
||||
vpResult.offsetX, vpResult.offsetY,
|
||||
static_cast<int>(vpResult.width), static_cast<int>(vpResult.height));
|
||||
} else {
|
||||
renderer->setViewport(0, 0, winMod->win()->width(),
|
||||
winMod->win()->height());
|
||||
}
|
||||
|
||||
auto sceneService = ServiceLocator::instance().getService<ISceneService>();
|
||||
if (sceneService) {
|
||||
sceneService->render(*renderer);
|
||||
if (sceneService && renderer->getBackend()) {
|
||||
sceneService->render(*renderer->getBackend());
|
||||
}
|
||||
|
||||
winMod->win()->swap();
|
||||
|
|
@ -227,7 +223,7 @@ IWindow *Application::window() {
|
|||
|
||||
RenderBackend *Application::renderer() {
|
||||
auto *renderMod = get<RenderModule>();
|
||||
return renderMod ? renderMod->renderer() : nullptr;
|
||||
return renderMod ? (renderMod->getRenderer() ? renderMod->getRenderer()->getBackend() : nullptr) : nullptr;
|
||||
}
|
||||
|
||||
IInput *Application::input() {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,128 @@
|
|||
#include <extra2d/render/backends/opengl/gl_context.h>
|
||||
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
GLContext& GLContext::get() {
|
||||
static GLContext instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool GLContext::init() {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!gladLoadGL()) {
|
||||
E2D_LOG_ERROR("Failed to load OpenGL functions");
|
||||
return false;
|
||||
}
|
||||
|
||||
parseVersion();
|
||||
queryCapabilities();
|
||||
|
||||
initialized_ = true;
|
||||
|
||||
E2D_LOG_INFO("OpenGL Context initialized");
|
||||
E2D_LOG_INFO(" Version: {}.{}", version_.major, version_.minor);
|
||||
E2D_LOG_INFO(" Renderer: {}", renderer_);
|
||||
E2D_LOG_INFO(" Vendor: {}", vendor_);
|
||||
E2D_LOG_INFO(" GLSL: {}", glslVersion_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext::shutdown() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
extensions_.clear();
|
||||
initialized_ = false;
|
||||
|
||||
E2D_LOG_INFO("OpenGL Context shutdown");
|
||||
}
|
||||
|
||||
std::string GLContext::getVersionString() const {
|
||||
std::ostringstream oss;
|
||||
oss << version_.major << "." << version_.minor;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
bool GLContext::hasExtension(const std::string& extension) const {
|
||||
return extensions_.find(extension) != extensions_.end();
|
||||
}
|
||||
|
||||
bool GLContext::checkError(const char* operation) {
|
||||
GLenum error = glGetError();
|
||||
if (error != GL_NO_ERROR) {
|
||||
if (operation) {
|
||||
E2D_LOG_ERROR("OpenGL error during {}: 0x{:X}", operation, error);
|
||||
} else {
|
||||
E2D_LOG_ERROR("OpenGL error: 0x{:X}", error);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLContext::clearErrors() {
|
||||
while (glGetError() != GL_NO_ERROR) {
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::queryCapabilities() {
|
||||
const char* rendererStr = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
|
||||
const char* vendorStr = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
|
||||
const char* glslStr = reinterpret_cast<const char*>(glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
|
||||
renderer_ = rendererStr ? rendererStr : "Unknown";
|
||||
vendor_ = vendorStr ? vendorStr : "Unknown";
|
||||
glslVersion_ = glslStr ? glslStr : "Unknown";
|
||||
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize_);
|
||||
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits_);
|
||||
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs_);
|
||||
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &maxUniformBufferBindings_);
|
||||
|
||||
GLint numExtensions = 0;
|
||||
glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions);
|
||||
for (GLint i = 0; i < numExtensions; ++i) {
|
||||
const char* ext = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
|
||||
if (ext) {
|
||||
extensions_.insert(ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLContext::parseVersion() {
|
||||
const char* versionStr = reinterpret_cast<const char*>(glGetString(GL_VERSION));
|
||||
if (!versionStr) {
|
||||
version_ = {4, 5};
|
||||
return;
|
||||
}
|
||||
|
||||
int major = 0, minor = 0;
|
||||
const char* ptr = versionStr;
|
||||
|
||||
while (*ptr && (*ptr < '0' || *ptr > '9')) {
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (*ptr) {
|
||||
major = std::atoi(ptr);
|
||||
while (*ptr && *ptr != '.') {
|
||||
ptr++;
|
||||
}
|
||||
if (*ptr == '.') {
|
||||
ptr++;
|
||||
minor = std::atoi(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
version_ = {major, minor};
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,521 @@
|
|||
#include <extra2d/render/backends/opengl/gl_render_backend.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <cmath>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
/**
|
||||
* @brief 构造函数
|
||||
*/
|
||||
GLRenderBackend::GLRenderBackend()
|
||||
: initialized_(false)
|
||||
, window_(nullptr)
|
||||
, config_()
|
||||
, stats_()
|
||||
, device_(nullptr)
|
||||
, projectionMatrix_(1.0f)
|
||||
, viewMatrix_(1.0f)
|
||||
, width_(0)
|
||||
, height_(0)
|
||||
, sortKey_(0)
|
||||
, layer_(0)
|
||||
, blendState_(rhi::BlendState::alphaBlend())
|
||||
, inBatch_(false) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 析构函数
|
||||
*/
|
||||
GLRenderBackend::~GLRenderBackend() {
|
||||
shutdown();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 生命周期
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 初始化渲染后端
|
||||
*/
|
||||
bool GLRenderBackend::init(IWindow *window, const RenderBackendConfig &config) {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
window_ = window;
|
||||
config_ = config;
|
||||
width_ = window->width();
|
||||
height_ = window->height();
|
||||
|
||||
device_ = rhi::RHIDevice::create(rhi::GraphicsAPI::OpenGL);
|
||||
if (!device_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!device_->init(window)) {
|
||||
device_.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
projectionMatrix_ = glm::ortho(0.0f, static_cast<float>(width_),
|
||||
static_cast<float>(height_), 0.0f,
|
||||
-1.0f, 1.0f);
|
||||
viewMatrix_ = glm::mat4(1.0f);
|
||||
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 关闭渲染后端
|
||||
*/
|
||||
void GLRenderBackend::shutdown() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (device_) {
|
||||
device_->shutdown();
|
||||
device_.reset();
|
||||
}
|
||||
|
||||
window_ = nullptr;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
initialized_ = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 检查是否已初始化
|
||||
*/
|
||||
bool GLRenderBackend::isValid() const {
|
||||
return initialized_ && device_ && device_->isValid();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 帧管理
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始帧渲染
|
||||
*/
|
||||
void GLRenderBackend::beginFrame(const Color &clearColor) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.reset();
|
||||
device_->beginFrame();
|
||||
device_->resetStats();
|
||||
|
||||
rhi::ColorValue cv(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
|
||||
device_->clearColor(cv);
|
||||
|
||||
device_->setViewport(rhi::Viewport(0.0f, 0.0f,
|
||||
static_cast<float>(width_),
|
||||
static_cast<float>(height_)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 结束帧渲染
|
||||
*/
|
||||
void GLRenderBackend::endFrame() {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (inBatch_) {
|
||||
endSpriteBatch();
|
||||
}
|
||||
|
||||
device_->endFrame();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 呈现帧
|
||||
*/
|
||||
void GLRenderBackend::present() {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_->present();
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 渲染状态
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 设置视口
|
||||
*/
|
||||
void GLRenderBackend::setViewport(int x, int y, int width, int height) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_->setViewport(rhi::Viewport(
|
||||
static_cast<float>(x),
|
||||
static_cast<float>(y),
|
||||
static_cast<float>(width),
|
||||
static_cast<float>(height)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置裁剪区域
|
||||
*/
|
||||
void GLRenderBackend::setScissor(int x, int y, int width, int height) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_->setScissorRect(rhi::ScissorRect(x, y,
|
||||
static_cast<uint32_t>(width),
|
||||
static_cast<uint32_t>(height)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启用/禁用裁剪测试
|
||||
*/
|
||||
void GLRenderBackend::setScissorEnabled(bool enabled) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_->setScissorEnabled(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置投影矩阵
|
||||
*/
|
||||
void GLRenderBackend::setProjectionMatrix(const glm::mat4 &matrix) {
|
||||
projectionMatrix_ = matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置视图矩阵
|
||||
*/
|
||||
void GLRenderBackend::setViewMatrix(const glm::mat4 &matrix) {
|
||||
viewMatrix_ = matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置垂直同步
|
||||
*/
|
||||
void GLRenderBackend::setVSync(bool enabled) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
device_->setVSync(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取垂直同步状态
|
||||
*/
|
||||
bool GLRenderBackend::isVSyncEnabled() const {
|
||||
return isValid() ? device_->isVSyncEnabled() : false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 精灵渲染
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵
|
||||
*/
|
||||
void GLRenderBackend::drawSprite(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect, const Color &color,
|
||||
float rotation, bool flipX, bool flipY) {
|
||||
if (!isValid() || !texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.spriteCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制精灵(使用变换矩阵)
|
||||
*/
|
||||
void GLRenderBackend::drawSprite(Ptr<rhi::RHITexture> texture,
|
||||
const glm::mat4 &transform,
|
||||
const Rect &srcRect, const Color &color) {
|
||||
if (!isValid() || !texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.spriteCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制九宫格精灵
|
||||
*/
|
||||
void GLRenderBackend::draw9Slice(Ptr<rhi::RHITexture> texture, const Rect &destRect,
|
||||
const Rect &srcRect, const Vec2 &borderSize,
|
||||
const Color &color) {
|
||||
if (!isValid() || !texture) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.spriteCount += 9;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 文本渲染
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制文本
|
||||
*/
|
||||
void GLRenderBackend::drawText(const std::string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color) {
|
||||
if (!isValid() || text.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.textCharCount += static_cast<uint32_t>(text.length());
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制文本(UTF-32)
|
||||
*/
|
||||
void GLRenderBackend::drawText(const std::u32string &text, const Vec2 &position,
|
||||
float fontSize, const Color &color) {
|
||||
if (!isValid() || text.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.textCharCount += static_cast<uint32_t>(text.length());
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸
|
||||
*/
|
||||
Vec2 GLRenderBackend::measureText(const std::string &text, float fontSize) {
|
||||
float width = static_cast<float>(text.length()) * fontSize * 0.6f;
|
||||
return Vec2(width, fontSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 测量文本尺寸(UTF-32)
|
||||
*/
|
||||
Vec2 GLRenderBackend::measureText(const std::u32string &text, float fontSize) {
|
||||
float width = static_cast<float>(text.length()) * fontSize * 0.6f;
|
||||
return Vec2(width, fontSize);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 形状渲染
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 绘制矩形
|
||||
*/
|
||||
void GLRenderBackend::drawRect(const Rect &rect, const Color &color, float lineWidth) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制填充矩形
|
||||
*/
|
||||
void GLRenderBackend::fillRect(const Rect &rect, const Color &color) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制圆形
|
||||
*/
|
||||
void GLRenderBackend::drawCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
float lineWidth, uint32_t segments) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制填充圆形
|
||||
*/
|
||||
void GLRenderBackend::fillCircle(const Vec2 ¢er, float radius, const Color &color,
|
||||
uint32_t segments) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制线段
|
||||
*/
|
||||
void GLRenderBackend::drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
|
||||
float lineWidth) {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制多边形
|
||||
*/
|
||||
void GLRenderBackend::drawPolygon(const Vec2 *points, size_t count, const Color &color,
|
||||
float lineWidth) {
|
||||
if (!isValid() || !points || count < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 绘制填充多边形
|
||||
*/
|
||||
void GLRenderBackend::fillPolygon(const Vec2 *points, size_t count, const Color &color) {
|
||||
if (!isValid() || !points || count < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.shapeCount++;
|
||||
stats_.drawCalls++;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 批处理控制
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 开始精灵批处理
|
||||
*/
|
||||
void GLRenderBackend::beginSpriteBatch() {
|
||||
inBatch_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 结束精灵批处理
|
||||
*/
|
||||
void GLRenderBackend::endSpriteBatch() {
|
||||
if (!inBatch_) {
|
||||
return;
|
||||
}
|
||||
|
||||
flush();
|
||||
inBatch_ = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 刷新当前批次
|
||||
*/
|
||||
void GLRenderBackend::flush() {
|
||||
if (!isValid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
stats_.batchCount++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置渲染排序键
|
||||
*/
|
||||
void GLRenderBackend::setSortKey(uint64_t key) {
|
||||
sortKey_ = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置渲染层
|
||||
*/
|
||||
void GLRenderBackend::setLayer(int layer) {
|
||||
layer_ = layer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 设置混合模式
|
||||
*/
|
||||
void GLRenderBackend::setBlendMode(rhi::BlendState blend) {
|
||||
blendState_ = blend;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// 访问器
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* @brief 获取 RHI 设备
|
||||
*/
|
||||
rhi::RHIDevice *GLRenderBackend::getDevice() const {
|
||||
return device_.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取窗口宽度
|
||||
*/
|
||||
int GLRenderBackend::getWidth() const {
|
||||
return width_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取窗口高度
|
||||
*/
|
||||
int GLRenderBackend::getHeight() const {
|
||||
return height_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取渲染统计
|
||||
*/
|
||||
const RenderStats &GLRenderBackend::getStats() const {
|
||||
return stats_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重置渲染统计
|
||||
*/
|
||||
void GLRenderBackend::resetStats() {
|
||||
stats_.reset();
|
||||
if (device_) {
|
||||
device_->resetStats();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取图形 API 类型
|
||||
*/
|
||||
rhi::GraphicsAPI GLRenderBackend::getAPI() const {
|
||||
return rhi::GraphicsAPI::OpenGL;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取设备能力
|
||||
*/
|
||||
const rhi::DeviceCaps &GLRenderBackend::getCaps() const {
|
||||
static rhi::DeviceCaps empty;
|
||||
return device_ ? device_->getCaps() : empty;
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
#include <extra2d/render/backends/opengl/gl_rhi_texture.h>
|
||||
#include <extra2d/render/backends/opengl/gl_rhi_shader.h>
|
||||
#include <extra2d/render/backends/opengl/gl_rhi_pipeline.h>
|
||||
#include <extra2d/graphics/backends/opengl/gl_context.h>
|
||||
#include <extra2d/render/backends/opengl/gl_context.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <fstream>
|
||||
|
|
|
|||
|
|
@ -1,27 +1,23 @@
|
|||
#include <cmath>
|
||||
#include <extra2d/render/batch/shape_batcher.h>
|
||||
#include <extra2d/resources/shader_manager.h>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <cmath>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
ShapeBatcher::ShapeBatcher()
|
||||
: device_(nullptr), shader_(nullptr), pipeline_(nullptr), linePipeline_(nullptr),
|
||||
vertexBuffer_(nullptr), indexBuffer_(nullptr), uniformBuffer_(nullptr),
|
||||
viewProj_(1.0f), currentBlend_(rhi::BlendState::alphaBlend()),
|
||||
currentVertexIndex_(0), currentIndexIndex_(0),
|
||||
drawCallCount_(0), shapeCount_(0), batchCount_(0),
|
||||
initialized_(false), inBatch_(false) {
|
||||
}
|
||||
: device_(nullptr), shader_(nullptr), pipeline_(nullptr),
|
||||
linePipeline_(nullptr), vertexBuffer_(nullptr), indexBuffer_(nullptr),
|
||||
uniformBuffer_(nullptr), viewProj_(1.0f),
|
||||
currentBlend_(rhi::BlendState::alphaBlend()), currentVertexIndex_(0),
|
||||
currentIndexIndex_(0), drawCallCount_(0), shapeCount_(0), batchCount_(0),
|
||||
initialized_(false), inBatch_(false) {}
|
||||
|
||||
ShapeBatcher::ShapeBatcher(const ShapeBatcherConfig& config)
|
||||
: ShapeBatcher() {
|
||||
ShapeBatcher::ShapeBatcher(const ShapeBatcherConfig &config) : ShapeBatcher() {
|
||||
config_ = config;
|
||||
}
|
||||
|
||||
ShapeBatcher::~ShapeBatcher() {
|
||||
shutdown();
|
||||
}
|
||||
ShapeBatcher::~ShapeBatcher() { shutdown(); }
|
||||
|
||||
bool ShapeBatcher::init(Ptr<rhi::RHIDevice> device) {
|
||||
if (initialized_) {
|
||||
|
|
@ -73,11 +69,9 @@ void ShapeBatcher::shutdown() {
|
|||
inBatch_ = false;
|
||||
}
|
||||
|
||||
void ShapeBatcher::begin() {
|
||||
begin(viewProj_);
|
||||
}
|
||||
void ShapeBatcher::begin() { begin(viewProj_); }
|
||||
|
||||
void ShapeBatcher::begin(const glm::mat4& viewProj) {
|
||||
void ShapeBatcher::begin(const glm::mat4 &viewProj) {
|
||||
if (!initialized_ || inBatch_) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -109,8 +103,8 @@ void ShapeBatcher::end() {
|
|||
inBatch_ = false;
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawLine(const Vec2& start, const Vec2& end,
|
||||
const Color& color, float width) {
|
||||
void ShapeBatcher::drawLine(const Vec2 &start, const Vec2 &end,
|
||||
const Color &color, float width) {
|
||||
if (!initialized_ || !inBatch_) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -124,8 +118,8 @@ void ShapeBatcher::drawLine(const Vec2& start, const Vec2& end,
|
|||
shapeCount_++;
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawLines(const std::vector<Vec2>& points,
|
||||
const Color& color, float width) {
|
||||
void ShapeBatcher::drawLines(const std::vector<Vec2> &points,
|
||||
const Color &color, float width) {
|
||||
if (!initialized_ || !inBatch_ || points.size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -135,8 +129,8 @@ void ShapeBatcher::drawLines(const std::vector<Vec2>& points,
|
|||
}
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawPolyline(const std::vector<Vec2>& points,
|
||||
const Color& color, float width) {
|
||||
void ShapeBatcher::drawPolyline(const std::vector<Vec2> &points,
|
||||
const Color &color, float width) {
|
||||
if (!initialized_ || !inBatch_ || points.size() < 2) {
|
||||
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_) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -162,15 +156,19 @@ void ShapeBatcher::drawRect(const Rect& rect, const Color& color, float 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_) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 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);
|
||||
uint32_t i1 =
|
||||
addVertex(Vec2(rect.origin.x + rect.size.width, rect.origin.y), 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(i1);
|
||||
|
|
@ -182,8 +180,8 @@ void ShapeBatcher::drawFilledRect(const Rect& rect, const Color& color) {
|
|||
shapeCount_++;
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawCircle(const Vec2& center, float radius,
|
||||
const Color& color, int segments, float width) {
|
||||
void ShapeBatcher::drawCircle(const Vec2 ¢er, float radius,
|
||||
const Color &color, int segments, float width) {
|
||||
if (!initialized_ || !inBatch_ || radius <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -198,8 +196,8 @@ void ShapeBatcher::drawCircle(const Vec2& center, float radius,
|
|||
}
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawFilledCircle(const Vec2& center, float radius,
|
||||
const Color& color, int segments) {
|
||||
void ShapeBatcher::drawFilledCircle(const Vec2 ¢er, float radius,
|
||||
const Color &color, int segments) {
|
||||
if (!initialized_ || !inBatch_ || radius <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -222,8 +220,8 @@ void ShapeBatcher::drawFilledCircle(const Vec2& center, float radius,
|
|||
shapeCount_++;
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawEllipse(const Vec2& center, float radiusX, float radiusY,
|
||||
const Color& color, int segments, float width) {
|
||||
void ShapeBatcher::drawEllipse(const Vec2 ¢er, float radiusX, float radiusY,
|
||||
const Color &color, int segments, float width) {
|
||||
if (!initialized_ || !inBatch_ || radiusX <= 0.0f || radiusY <= 0.0f) {
|
||||
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,
|
||||
const Color& color, int segments) {
|
||||
void ShapeBatcher::drawFilledEllipse(const Vec2 ¢er, float radiusX,
|
||||
float radiusY, const Color &color,
|
||||
int segments) {
|
||||
if (!initialized_ || !inBatch_ || radiusX <= 0.0f || radiusY <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -262,8 +261,8 @@ void ShapeBatcher::drawFilledEllipse(const Vec2& center, float radiusX, float ra
|
|||
shapeCount_++;
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3,
|
||||
const Color& color, float width) {
|
||||
void ShapeBatcher::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
|
||||
const Color &color, float width) {
|
||||
if (!initialized_ || !inBatch_) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -273,8 +272,8 @@ void ShapeBatcher::drawTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3,
|
|||
drawLine(p3, p1, color, width);
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawFilledTriangle(const Vec2& p1, const Vec2& p2, const Vec2& p3,
|
||||
const Color& color) {
|
||||
void ShapeBatcher::drawFilledTriangle(const Vec2 &p1, const Vec2 &p2,
|
||||
const Vec2 &p3, const Color &color) {
|
||||
if (!initialized_ || !inBatch_) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -290,8 +289,8 @@ void ShapeBatcher::drawFilledTriangle(const Vec2& p1, const Vec2& p2, const Vec2
|
|||
shapeCount_++;
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawPolygon(const std::vector<Vec2>& points,
|
||||
const Color& color, float width) {
|
||||
void ShapeBatcher::drawPolygon(const std::vector<Vec2> &points,
|
||||
const Color &color, float width) {
|
||||
if (!initialized_ || !inBatch_ || points.size() < 3) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -302,8 +301,8 @@ void ShapeBatcher::drawPolygon(const std::vector<Vec2>& points,
|
|||
}
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawFilledPolygon(const std::vector<Vec2>& points,
|
||||
const Color& color) {
|
||||
void ShapeBatcher::drawFilledPolygon(const std::vector<Vec2> &points,
|
||||
const Color &color) {
|
||||
if (!initialized_ || !inBatch_ || points.size() < 3) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -322,9 +321,9 @@ void ShapeBatcher::drawFilledPolygon(const std::vector<Vec2>& points,
|
|||
shapeCount_++;
|
||||
}
|
||||
|
||||
void ShapeBatcher::drawArc(const Vec2& center, float radius,
|
||||
float startAngle, float endAngle,
|
||||
const Color& color, int segments, float width) {
|
||||
void ShapeBatcher::drawArc(const Vec2 ¢er, float radius, float startAngle,
|
||||
float endAngle, const Color &color, int segments,
|
||||
float width) {
|
||||
if (!initialized_ || !inBatch_ || radius <= 0.0f) {
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& data = std::get<ShapeRenderData>(command.data);
|
||||
const auto &data = std::get<ShapeRenderData>(command.data);
|
||||
|
||||
switch (data.shapeType) {
|
||||
case ShapeType::Line:
|
||||
|
|
@ -375,7 +374,8 @@ void ShapeBatcher::draw(const RenderCommand& command) {
|
|||
break;
|
||||
case ShapeType::Circle:
|
||||
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;
|
||||
case ShapeType::FilledCircle:
|
||||
|
|
@ -385,13 +385,14 @@ void ShapeBatcher::draw(const RenderCommand& command) {
|
|||
break;
|
||||
case ShapeType::Triangle:
|
||||
if (data.points.size() >= 3) {
|
||||
drawTriangle(data.points[0], data.points[1], data.points[2],
|
||||
data.color, data.lineWidth);
|
||||
drawTriangle(data.points[0], data.points[1], data.points[2], data.color,
|
||||
data.lineWidth);
|
||||
}
|
||||
break;
|
||||
case ShapeType::FilledTriangle:
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -413,16 +414,14 @@ void ShapeBatcher::resetStats() {
|
|||
batchCount_ = 0;
|
||||
}
|
||||
|
||||
void ShapeBatcher::setConfig(const ShapeBatcherConfig& config) {
|
||||
void ShapeBatcher::setConfig(const ShapeBatcherConfig &config) {
|
||||
config_ = config;
|
||||
}
|
||||
|
||||
void ShapeBatcher::setShader(Ptr<rhi::RHIShader> shader) {
|
||||
shader_ = shader;
|
||||
}
|
||||
void ShapeBatcher::setShader(Ptr<rhi::RHIShader> shader) { shader_ = shader; }
|
||||
|
||||
bool ShapeBatcher::createShader() {
|
||||
ShaderManager& shaderManager = ShaderManager::getInstance();
|
||||
ShaderManager &shaderManager = ShaderManager::getInstance();
|
||||
|
||||
auto shaderHandle = shaderManager.getBuiltin("shape");
|
||||
if (!shaderHandle) {
|
||||
|
|
@ -442,9 +441,12 @@ bool ShapeBatcher::createPipeline() {
|
|||
builder.setShader(shader_)
|
||||
.setBlendState(rhi::BlendState::alphaBlend())
|
||||
.setPrimitiveType(rhi::PrimitiveType::Triangles)
|
||||
.addVertexAttribute(rhi::VertexAttribute(0, rhi::Format::RG32_FLOAT, 0, 0))
|
||||
.addVertexAttribute(rhi::VertexAttribute(1, rhi::Format::RGBA32_FLOAT, 8, 0))
|
||||
.addVertexBufferBinding(rhi::VertexBufferBinding(0, sizeof(ShapeVertex), 0));
|
||||
.addVertexAttribute(
|
||||
rhi::VertexAttribute(0, rhi::Format::RG32_FLOAT, 0, 0))
|
||||
.addVertexAttribute(
|
||||
rhi::VertexAttribute(1, rhi::Format::RGBA32_FLOAT, 8, 0))
|
||||
.addVertexBufferBinding(
|
||||
rhi::VertexBufferBinding(0, sizeof(ShapeVertex), 0));
|
||||
|
||||
pipeline_ = device_->createPipeline(builder);
|
||||
if (!pipeline_) {
|
||||
|
|
@ -455,9 +457,12 @@ bool ShapeBatcher::createPipeline() {
|
|||
lineBuilder.setShader(shader_)
|
||||
.setBlendState(rhi::BlendState::alphaBlend())
|
||||
.setPrimitiveType(rhi::PrimitiveType::Lines)
|
||||
.addVertexAttribute(rhi::VertexAttribute(0, rhi::Format::RG32_FLOAT, 0, 0))
|
||||
.addVertexAttribute(rhi::VertexAttribute(1, rhi::Format::RGBA32_FLOAT, 8, 0))
|
||||
.addVertexBufferBinding(rhi::VertexBufferBinding(0, sizeof(ShapeVertex), 0));
|
||||
.addVertexAttribute(
|
||||
rhi::VertexAttribute(0, rhi::Format::RG32_FLOAT, 0, 0))
|
||||
.addVertexAttribute(
|
||||
rhi::VertexAttribute(1, rhi::Format::RGBA32_FLOAT, 8, 0))
|
||||
.addVertexBufferBinding(
|
||||
rhi::VertexBufferBinding(0, sizeof(ShapeVertex), 0));
|
||||
|
||||
linePipeline_ = device_->createPipeline(lineBuilder);
|
||||
return linePipeline_ != nullptr;
|
||||
|
|
@ -467,12 +472,14 @@ bool ShapeBatcher::createBuffers() {
|
|||
size_t vertexBufferSize = config_.maxBatchSize * 4 * sizeof(ShapeVertex);
|
||||
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_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
indexBuffer_ = device_->createIndexBuffer(indexBufferSize, rhi::BufferUsage::Dynamic);
|
||||
indexBuffer_ =
|
||||
device_->createIndexBuffer(indexBufferSize, rhi::BufferUsage::Dynamic);
|
||||
if (!indexBuffer_) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -485,16 +492,18 @@ bool ShapeBatcher::createBuffers() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void ShapeBatcher::flushBatch(rhi::PrimitiveType primitiveType, float lineWidth) {
|
||||
void ShapeBatcher::flushBatch(rhi::PrimitiveType primitiveType,
|
||||
float lineWidth) {
|
||||
if (vertices_.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
vertexBuffer_->setData(vertices_.data(), vertices_.size() * sizeof(ShapeVertex));
|
||||
vertexBuffer_->setData(vertices_.data(),
|
||||
vertices_.size() * sizeof(ShapeVertex));
|
||||
uniformBuffer_->setValue(viewProj_);
|
||||
|
||||
Ptr<rhi::RHIPipeline> activePipeline = (primitiveType == rhi::PrimitiveType::Lines)
|
||||
? linePipeline_ : pipeline_;
|
||||
Ptr<rhi::RHIPipeline> activePipeline =
|
||||
(primitiveType == rhi::PrimitiveType::Lines) ? linePipeline_ : pipeline_;
|
||||
|
||||
device_->setPipeline(activePipeline);
|
||||
device_->setShader(shader_);
|
||||
|
|
@ -519,7 +528,7 @@ void ShapeBatcher::flushBatch(rhi::PrimitiveType primitiveType, float lineWidth)
|
|||
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));
|
||||
return currentVertexIndex_++;
|
||||
}
|
||||
|
|
@ -529,12 +538,14 @@ void ShapeBatcher::addIndex(uint32_t index) {
|
|||
currentIndexIndex_++;
|
||||
}
|
||||
|
||||
void ShapeBatcher::generateCircleVertices(const Vec2& center, float radius,
|
||||
int segments, std::vector<Vec2>& vertices) const {
|
||||
void ShapeBatcher::generateCircleVertices(const Vec2 ¢er, float radius,
|
||||
int segments,
|
||||
std::vector<Vec2> &vertices) const {
|
||||
vertices.clear();
|
||||
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) {
|
||||
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,
|
||||
int segments, std::vector<Vec2>& vertices) const {
|
||||
void ShapeBatcher::generateEllipseVertices(const Vec2 ¢er, float radiusX,
|
||||
float radiusY, int segments,
|
||||
std::vector<Vec2> &vertices) const {
|
||||
vertices.clear();
|
||||
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) {
|
||||
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();
|
||||
|
||||
stats_.spriteCount = queueStats.spriteCommands;
|
||||
stats_.textCount = queueStats.textCommands;
|
||||
stats_.textCharCount = queueStats.textCommands;
|
||||
stats_.shapeCount = queueStats.shapeCommands;
|
||||
|
||||
stats_.batchCount = queueStats.batchCount;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
#include <extra2d/platform/window_module.h>
|
||||
#include <extra2d/render/core/render_module.h>
|
||||
#include <extra2d/render/renderer.h>
|
||||
|
||||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <typeindex>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
RenderModule::RenderModule() : initialized_(false) {}
|
||||
|
||||
RenderModule::RenderModule(const RenderModuleConfig &config)
|
||||
: config_(config), initialized_(false) {}
|
||||
|
||||
RenderModule::~RenderModule() { shutdown(); }
|
||||
|
||||
bool RenderModule::init() {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!app_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IWindow *window = nullptr;
|
||||
|
||||
renderer_ = Renderer::create();
|
||||
|
||||
if (!renderer_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RendererConfig rendererConfig;
|
||||
rendererConfig.api = config_.api;
|
||||
rendererConfig.vsync = config_.vsync;
|
||||
rendererConfig.maxBatchSize = config_.maxBatchSize;
|
||||
rendererConfig.enableDebug = config_.enableDebug;
|
||||
rendererConfig.viewportConfig =
|
||||
ViewportConfig(config_.designWidth, config_.designHeight);
|
||||
|
||||
renderer_->setConfig(rendererConfig);
|
||||
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void RenderModule::shutdown() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderer_.reset();
|
||||
initialized_ = false;
|
||||
}
|
||||
|
||||
std::vector<std::type_index> RenderModule::deps() const {
|
||||
return {std::type_index(typeid(class WindowModule))};
|
||||
}
|
||||
|
||||
void RenderModule::setConfig(const RenderModuleConfig &config) {
|
||||
config_ = config;
|
||||
|
||||
if (renderer_ && initialized_) {
|
||||
RendererConfig rendererConfig;
|
||||
rendererConfig.api = config_.api;
|
||||
rendererConfig.vsync = config_.vsync;
|
||||
rendererConfig.maxBatchSize = config_.maxBatchSize;
|
||||
rendererConfig.enableDebug = config_.enableDebug;
|
||||
rendererConfig.viewportConfig =
|
||||
ViewportConfig(config_.designWidth, config_.designHeight);
|
||||
renderer_->setConfig(rendererConfig);
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<RenderModule> RenderModule::create(const RenderModuleConfig &config) {
|
||||
return makePtr<RenderModule>(config);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -0,0 +1,349 @@
|
|||
#include <extra2d/render/renderer.h>
|
||||
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/render/core/backend_factory.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/scene/scene.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
Renderer::Renderer()
|
||||
: window_(nullptr), width_(0), height_(0), initialized_(false) {}
|
||||
|
||||
Renderer::Renderer(const RendererConfig &config)
|
||||
: window_(nullptr), config_(config), width_(0), height_(0),
|
||||
initialized_(false) {}
|
||||
|
||||
Renderer::~Renderer() { shutdown(); }
|
||||
|
||||
bool Renderer::init() { return initialized_; }
|
||||
|
||||
bool Renderer::init(IWindow *window) { return init(window, config_); }
|
||||
|
||||
bool Renderer::init(IWindow *window, const RendererConfig &config) {
|
||||
if (initialized_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
window_ = window;
|
||||
config_ = config;
|
||||
width_ = window->width();
|
||||
height_ = window->height();
|
||||
|
||||
viewportAdapter_.setConfig(config.viewportConfig);
|
||||
viewportAdapter_.update(width_, height_);
|
||||
|
||||
RenderBackendConfig backendConfig;
|
||||
backendConfig.api = config.api;
|
||||
backendConfig.vsync = config.vsync;
|
||||
backendConfig.maxBatchSize = config.maxBatchSize;
|
||||
backendConfig.enableDebug = config.enableDebug;
|
||||
|
||||
backend_ = BackendFactory::createBackendForAPI(config.api);
|
||||
if (!backend_ || !backend_->init(window, backendConfig)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RenderContextConfig contextConfig;
|
||||
contextConfig.maxBatchSize = config.maxBatchSize;
|
||||
contextConfig.preferredAPI = config.api;
|
||||
|
||||
context_ = makeUnique<RenderContext>(contextConfig);
|
||||
if (!context_->init(window, config.api)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!createBatchers()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
createDefaultCamera();
|
||||
|
||||
initialized_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::shutdown() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
textBatcher_.reset();
|
||||
shapeBatcher_.reset();
|
||||
spriteBatcher_.reset();
|
||||
context_.reset();
|
||||
backend_.reset();
|
||||
|
||||
activeCamera_.reset();
|
||||
defaultCamera_.reset();
|
||||
|
||||
window_ = nullptr;
|
||||
width_ = 0;
|
||||
height_ = 0;
|
||||
initialized_ = false;
|
||||
}
|
||||
|
||||
void Renderer::beginFrame(const Color &clearColor) {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (backend_) {
|
||||
backend_->beginFrame(clearColor);
|
||||
}
|
||||
|
||||
if (context_) {
|
||||
context_->beginFrame();
|
||||
context_->clear(clearColor);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::endFrame() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (spriteBatcher_) {
|
||||
spriteBatcher_->end();
|
||||
}
|
||||
if (shapeBatcher_) {
|
||||
shapeBatcher_->end();
|
||||
}
|
||||
if (textBatcher_) {
|
||||
textBatcher_->end();
|
||||
}
|
||||
|
||||
if (context_) {
|
||||
context_->endFrame();
|
||||
}
|
||||
|
||||
if (backend_) {
|
||||
backend_->endFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::present() {
|
||||
if (!initialized_) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (backend_) {
|
||||
backend_->present();
|
||||
}
|
||||
|
||||
if (context_) {
|
||||
context_->present();
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::renderScene(Scene *scene) {
|
||||
if (!initialized_ || !scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
Camera *camera = activeCamera_ ? activeCamera_.get() : defaultCamera_.get();
|
||||
if (!camera) {
|
||||
camera = scene->getActiveCamera();
|
||||
}
|
||||
|
||||
renderScene(scene, camera);
|
||||
}
|
||||
|
||||
void Renderer::renderScene(Scene *scene, Camera *camera) {
|
||||
if (!initialized_ || !scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!camera) {
|
||||
camera = defaultCamera_.get();
|
||||
}
|
||||
|
||||
if (camera) {
|
||||
camera->setViewportAdapter(&viewportAdapter_);
|
||||
camera->applyViewportAdapter();
|
||||
}
|
||||
|
||||
applyCameraTransform(camera);
|
||||
|
||||
scene->renderScene(*backend_);
|
||||
}
|
||||
|
||||
void Renderer::setActiveCamera(Ptr<Camera> camera) { activeCamera_ = camera; }
|
||||
|
||||
Ptr<Camera> Renderer::getActiveCamera() const {
|
||||
return activeCamera_ ? activeCamera_ : defaultCamera_;
|
||||
}
|
||||
|
||||
void Renderer::setViewport(int x, int y, int width, int height) {
|
||||
if (context_) {
|
||||
context_->setViewport(x, y, width, height);
|
||||
}
|
||||
if (backend_) {
|
||||
backend_->setViewport(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::setScissor(int x, int y, int width, int height) {
|
||||
if (context_) {
|
||||
context_->setScissorRect(x, y, width, height);
|
||||
}
|
||||
if (backend_) {
|
||||
backend_->setScissor(x, y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::setScissorEnabled(bool enabled) {
|
||||
if (context_) {
|
||||
context_->setScissorEnabled(enabled);
|
||||
}
|
||||
if (backend_) {
|
||||
backend_->setScissorEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::setVSync(bool enabled) {
|
||||
if (context_) {
|
||||
context_->setVSync(enabled);
|
||||
}
|
||||
if (backend_) {
|
||||
backend_->setVSync(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
bool Renderer::isVSyncEnabled() const {
|
||||
if (backend_) {
|
||||
return backend_->isVSyncEnabled();
|
||||
}
|
||||
if (context_) {
|
||||
return context_->isVSyncEnabled();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
rhi::RHIDevice *Renderer::getDevice() const {
|
||||
if (backend_) {
|
||||
return backend_->getDevice();
|
||||
}
|
||||
if (context_) {
|
||||
return context_->getDevice().get();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const RenderStats &Renderer::getStats() const {
|
||||
if (backend_) {
|
||||
return backend_->getStats();
|
||||
}
|
||||
if (context_) {
|
||||
return context_->getStats();
|
||||
}
|
||||
static RenderStats empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
void Renderer::resetStats() {
|
||||
if (backend_) {
|
||||
backend_->resetStats();
|
||||
}
|
||||
if (context_) {
|
||||
context_->resetStats();
|
||||
}
|
||||
if (spriteBatcher_) {
|
||||
spriteBatcher_->resetStats();
|
||||
}
|
||||
if (shapeBatcher_) {
|
||||
shapeBatcher_->resetStats();
|
||||
}
|
||||
if (textBatcher_) {
|
||||
textBatcher_->resetStats();
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::setConfig(const RendererConfig &config) {
|
||||
config_ = config;
|
||||
viewportAdapter_.setConfig(config.viewportConfig);
|
||||
updateViewportAdapter();
|
||||
}
|
||||
|
||||
bool Renderer::createBatchers() {
|
||||
auto device = getDevice();
|
||||
if (!device) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto devicePtr = context_ ? context_->getDevice() : nullptr;
|
||||
if (!devicePtr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SpriteBatcherConfig spriteConfig;
|
||||
spriteConfig.maxBatchSize = config_.maxBatchSize;
|
||||
spriteBatcher_ = makeUnique<SpriteBatcher>(spriteConfig);
|
||||
if (!spriteBatcher_->init(devicePtr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ShapeBatcherConfig shapeConfig;
|
||||
shapeConfig.maxBatchSize = config_.maxBatchSize / 2;
|
||||
shapeBatcher_ = makeUnique<ShapeBatcher>(shapeConfig);
|
||||
if (!shapeBatcher_->init(devicePtr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TextBatcherConfig textConfig;
|
||||
textConfig.maxBatchSize = config_.maxBatchSize / 2;
|
||||
textBatcher_ = makeUnique<TextBatcher>(textConfig);
|
||||
if (!textBatcher_->init(devicePtr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::createDefaultCamera() {
|
||||
float designWidth = viewportAdapter_.getDesignWidth();
|
||||
float designHeight = viewportAdapter_.getDesignHeight();
|
||||
|
||||
defaultCamera_ = makePtr<Camera>();
|
||||
defaultCamera_->setViewport(0, designWidth, 0, designHeight);
|
||||
defaultCamera_->setViewportAdapter(&viewportAdapter_);
|
||||
defaultCamera_->setDebugName("DefaultCamera");
|
||||
}
|
||||
|
||||
void Renderer::updateViewportAdapter() {
|
||||
viewportAdapter_.update(width_, height_);
|
||||
}
|
||||
|
||||
void Renderer::applyCameraTransform(Camera *camera) {
|
||||
if (!camera) {
|
||||
return;
|
||||
}
|
||||
|
||||
camera->updateMatrices();
|
||||
glm::mat4 viewProj = camera->getViewProjectionMatrix();
|
||||
|
||||
if (spriteBatcher_) {
|
||||
spriteBatcher_->setViewProjection(viewProj);
|
||||
}
|
||||
if (shapeBatcher_) {
|
||||
shapeBatcher_->setViewProjection(viewProj);
|
||||
}
|
||||
if (textBatcher_) {
|
||||
textBatcher_->setViewProjection(viewProj);
|
||||
}
|
||||
|
||||
if (backend_) {
|
||||
backend_->setProjectionMatrix(camera->getProjectionMatrix());
|
||||
backend_->setViewMatrix(camera->getViewMatrix());
|
||||
}
|
||||
}
|
||||
|
||||
Ptr<Renderer> Renderer::create(const RendererConfig &config) {
|
||||
return makePtr<Renderer>(config);
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/scene/node.h>
|
||||
|
|
@ -13,7 +12,7 @@ namespace extra2d {
|
|||
* @param name 节点名称
|
||||
* @return 创建的节点智能指针
|
||||
*/
|
||||
Ptr<Node> Node::create(const std::string& name) {
|
||||
Ptr<Node> Node::create(const std::string &name) {
|
||||
auto node = makePtr<Node>();
|
||||
node->setName(name);
|
||||
return node;
|
||||
|
|
@ -41,7 +40,7 @@ Node::~Node() {
|
|||
clearChildren();
|
||||
|
||||
// 销毁所有组件
|
||||
for (auto& pair : components_) {
|
||||
for (auto &pair : components_) {
|
||||
pair.second->destroy();
|
||||
pair.second->setNode(nullptr);
|
||||
}
|
||||
|
|
@ -86,13 +85,13 @@ void Node::addChild(Ptr<Node> child) {
|
|||
* @brief 批量添加子节点
|
||||
* @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();
|
||||
if (newSize > children_.capacity()) {
|
||||
children_.reserve(newSize);
|
||||
}
|
||||
|
||||
for (auto& child : children) {
|
||||
for (auto &child : children) {
|
||||
if (!child || child.get() == this) {
|
||||
continue;
|
||||
}
|
||||
|
|
@ -151,7 +150,7 @@ void Node::removeChild(Ptr<Node> child) {
|
|||
* @brief 通过名称移除子节点
|
||||
* @param name 子节点的名称
|
||||
*/
|
||||
void Node::removeChildByName(const std::string& name) {
|
||||
void Node::removeChildByName(const std::string &name) {
|
||||
auto child = findChild(name);
|
||||
if (child) {
|
||||
removeChild(child);
|
||||
|
|
@ -167,7 +166,7 @@ void Node::detach() {
|
|||
Ptr<Node> self;
|
||||
try {
|
||||
self = shared_from_this();
|
||||
} catch (const std::bad_weak_ptr&) {
|
||||
} catch (const std::bad_weak_ptr &) {
|
||||
parent_.reset();
|
||||
return;
|
||||
}
|
||||
|
|
@ -179,7 +178,7 @@ void Node::detach() {
|
|||
* @brief 清除所有子节点
|
||||
*/
|
||||
void Node::clearChildren() {
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
if (running_) {
|
||||
child->onDetachFromScene();
|
||||
child->onExit();
|
||||
|
|
@ -196,7 +195,7 @@ void Node::clearChildren() {
|
|||
* @param name 子节点的名称
|
||||
* @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);
|
||||
if (it != nameIndex_.end()) {
|
||||
return it->second.lock();
|
||||
|
|
@ -225,7 +224,7 @@ Ptr<Node> Node::findChildByTag(int tag) const {
|
|||
* @brief 设置节点位置
|
||||
* @param pos 新的位置坐标
|
||||
*/
|
||||
void Node::setPos(const Vec2& pos) {
|
||||
void Node::setPos(const Vec2 &pos) {
|
||||
if (transform_) {
|
||||
transform_->setPosition(pos);
|
||||
}
|
||||
|
|
@ -237,9 +236,7 @@ void Node::setPos(const Vec2& pos) {
|
|||
* @param x X坐标
|
||||
* @param y Y坐标
|
||||
*/
|
||||
void Node::setPos(float x, float y) {
|
||||
setPos(Vec2(x, y));
|
||||
}
|
||||
void Node::setPos(float x, float y) { setPos(Vec2(x, y)); }
|
||||
|
||||
/**
|
||||
* @brief 获取节点位置
|
||||
|
|
@ -278,7 +275,7 @@ float Node::getRotation() const {
|
|||
* @brief 设置节点缩放
|
||||
* @param scale 缩放向量
|
||||
*/
|
||||
void Node::setScale(const Vec2& scale) {
|
||||
void Node::setScale(const Vec2 &scale) {
|
||||
if (transform_) {
|
||||
transform_->setScale(scale);
|
||||
}
|
||||
|
|
@ -289,18 +286,14 @@ void Node::setScale(const Vec2& scale) {
|
|||
* @brief 设置节点统一缩放
|
||||
* @param scale 统一缩放值
|
||||
*/
|
||||
void Node::setScale(float scale) {
|
||||
setScale(Vec2(scale, scale));
|
||||
}
|
||||
void Node::setScale(float scale) { setScale(Vec2(scale, scale)); }
|
||||
|
||||
/**
|
||||
* @brief 设置节点缩放
|
||||
* @param x X轴缩放值
|
||||
* @param y Y轴缩放值
|
||||
*/
|
||||
void Node::setScale(float x, float y) {
|
||||
setScale(Vec2(x, y));
|
||||
}
|
||||
void Node::setScale(float x, float y) { setScale(Vec2(x, y)); }
|
||||
|
||||
/**
|
||||
* @brief 获取节点缩放
|
||||
|
|
@ -317,7 +310,7 @@ Vec2 Node::getScale() const {
|
|||
* @brief 设置节点锚点
|
||||
* @param anchor 锚点位置(0-1范围)
|
||||
*/
|
||||
void Node::setAnchor(const Vec2& anchor) {
|
||||
void Node::setAnchor(const Vec2 &anchor) {
|
||||
if (transform_) {
|
||||
transform_->setAnchor(anchor);
|
||||
}
|
||||
|
|
@ -329,9 +322,7 @@ void Node::setAnchor(const Vec2& anchor) {
|
|||
* @param x 锚点X坐标(0-1范围)
|
||||
* @param y 锚点Y坐标(0-1范围)
|
||||
*/
|
||||
void Node::setAnchor(float x, float y) {
|
||||
setAnchor(Vec2(x, y));
|
||||
}
|
||||
void Node::setAnchor(float x, float y) { setAnchor(Vec2(x, y)); }
|
||||
|
||||
/**
|
||||
* @brief 获取节点锚点
|
||||
|
|
@ -348,7 +339,7 @@ Vec2 Node::getAnchor() const {
|
|||
* @brief 设置节点斜切
|
||||
* @param skew 斜切角度向量
|
||||
*/
|
||||
void Node::setSkew(const Vec2& skew) {
|
||||
void Node::setSkew(const Vec2 &skew) {
|
||||
if (transform_) {
|
||||
transform_->setSkew(skew);
|
||||
}
|
||||
|
|
@ -360,9 +351,7 @@ void Node::setSkew(const Vec2& skew) {
|
|||
* @param x X轴斜切角度
|
||||
* @param y Y轴斜切角度
|
||||
*/
|
||||
void Node::setSkew(float x, float y) {
|
||||
setSkew(Vec2(x, y));
|
||||
}
|
||||
void Node::setSkew(float x, float y) { setSkew(Vec2(x, y)); }
|
||||
|
||||
/**
|
||||
* @brief 获取节点斜切
|
||||
|
|
@ -384,7 +373,7 @@ Vec2 Node::getSkew() const {
|
|||
* @param localPos 本地坐标位置
|
||||
* @return 世界坐标位置
|
||||
*/
|
||||
Vec2 Node::toWorld(const Vec2& localPos) const {
|
||||
Vec2 Node::toWorld(const Vec2 &localPos) const {
|
||||
if (transform_) {
|
||||
return transform_->localToWorld(localPos);
|
||||
}
|
||||
|
|
@ -396,7 +385,7 @@ Vec2 Node::toWorld(const Vec2& localPos) const {
|
|||
* @param worldPos 世界坐标位置
|
||||
* @return 本地坐标位置
|
||||
*/
|
||||
Vec2 Node::toLocal(const Vec2& worldPos) const {
|
||||
Vec2 Node::toLocal(const Vec2 &worldPos) const {
|
||||
if (transform_) {
|
||||
return transform_->worldToLocal(worldPos);
|
||||
}
|
||||
|
|
@ -434,7 +423,7 @@ void Node::markTransformDirty() {
|
|||
worldTransformDirty_ = true;
|
||||
|
||||
// 递归标记所有子节点
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
child->markTransformDirty();
|
||||
}
|
||||
}
|
||||
|
|
@ -452,7 +441,7 @@ void Node::batchTransforms() {
|
|||
worldTransformDirty_ = false;
|
||||
|
||||
// 递归更新子节点
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
child->batchTransforms();
|
||||
}
|
||||
}
|
||||
|
|
@ -493,33 +482,25 @@ void Node::setOpacity(float opacity) {
|
|||
* @brief 设置可见性
|
||||
* @param visible 是否可见
|
||||
*/
|
||||
void Node::setVisible(bool visible) {
|
||||
visible_ = visible;
|
||||
}
|
||||
void Node::setVisible(bool visible) { visible_ = visible; }
|
||||
|
||||
/**
|
||||
* @brief 设置颜色
|
||||
* @param color RGB颜色值
|
||||
*/
|
||||
void Node::setColor(const Color3B& color) {
|
||||
color_ = color;
|
||||
}
|
||||
void Node::setColor(const Color3B &color) { color_ = color; }
|
||||
|
||||
/**
|
||||
* @brief 设置水平翻转
|
||||
* @param flipX 是否水平翻转
|
||||
*/
|
||||
void Node::setFlipX(bool flipX) {
|
||||
flipX_ = flipX;
|
||||
}
|
||||
void Node::setFlipX(bool flipX) { flipX_ = flipX; }
|
||||
|
||||
/**
|
||||
* @brief 设置垂直翻转
|
||||
* @param flipY 是否垂直翻转
|
||||
*/
|
||||
void Node::setFlipY(bool flipY) {
|
||||
flipY_ = flipY;
|
||||
}
|
||||
void Node::setFlipY(bool flipY) { flipY_ = flipY; }
|
||||
|
||||
/**
|
||||
* @brief 设置Z序
|
||||
|
|
@ -543,14 +524,14 @@ void Node::onEnter() {
|
|||
running_ = true;
|
||||
|
||||
// 初始化所有组件
|
||||
for (auto& pair : components_) {
|
||||
for (auto &pair : components_) {
|
||||
if (!pair.second->isInitialized()) {
|
||||
pair.second->init();
|
||||
pair.second->setInitialized(true);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
child->onEnter();
|
||||
}
|
||||
}
|
||||
|
|
@ -560,7 +541,7 @@ void Node::onEnter() {
|
|||
*/
|
||||
void Node::onExit() {
|
||||
running_ = false;
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
child->onExit();
|
||||
}
|
||||
}
|
||||
|
|
@ -573,14 +554,14 @@ void Node::onUpdate(float dt) {
|
|||
onUpdateNode(dt);
|
||||
|
||||
// 更新所有启用的组件
|
||||
for (auto& pair : components_) {
|
||||
for (auto &pair : components_) {
|
||||
if (pair.second->isEnabled()) {
|
||||
pair.second->update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新子节点
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
child->onUpdate(dt);
|
||||
}
|
||||
}
|
||||
|
|
@ -589,29 +570,25 @@ void Node::onUpdate(float dt) {
|
|||
* @brief 渲染回调
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
void Node::onRender(RenderBackend& renderer) {
|
||||
void Node::onRender(RenderBackend &renderer) {
|
||||
if (!visible_)
|
||||
return;
|
||||
|
||||
renderer.pushTransform(getLocalTransform());
|
||||
|
||||
onDraw(renderer);
|
||||
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
child->onRender(renderer);
|
||||
}
|
||||
|
||||
renderer.popTransform();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 附加到场景时的回调
|
||||
* @param scene 所属场景指针
|
||||
*/
|
||||
void Node::onAttachToScene(Scene* scene) {
|
||||
void Node::onAttachToScene(Scene *scene) {
|
||||
scene_ = scene;
|
||||
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
child->onAttachToScene(scene);
|
||||
}
|
||||
}
|
||||
|
|
@ -621,7 +598,7 @@ void Node::onAttachToScene(Scene* scene) {
|
|||
*/
|
||||
void Node::onDetachFromScene() {
|
||||
scene_ = nullptr;
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
child->onDetachFromScene();
|
||||
}
|
||||
}
|
||||
|
|
@ -639,15 +616,13 @@ Rect Node::getBounds() const {
|
|||
* @brief 更新节点
|
||||
* @param dt 帧间隔时间(秒)
|
||||
*/
|
||||
void Node::update(float dt) {
|
||||
onUpdate(dt);
|
||||
}
|
||||
void Node::update(float dt) { onUpdate(dt); }
|
||||
|
||||
/**
|
||||
* @brief 渲染节点
|
||||
* @param renderer 渲染后端引用
|
||||
*/
|
||||
void Node::render(RenderBackend& renderer) {
|
||||
void Node::render(RenderBackend &renderer) {
|
||||
if (childrenOrderDirty_) {
|
||||
sortChildren();
|
||||
}
|
||||
|
|
@ -678,7 +653,7 @@ void Node::sortChildren() {
|
|||
}
|
||||
} else {
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
|
@ -691,7 +666,7 @@ void Node::sortChildren() {
|
|||
* @param commands 渲染命令输出向量
|
||||
* @param parentZOrder 父节点的Z序
|
||||
*/
|
||||
void Node::collectRenderCommands(std::vector<RenderCommand>& commands,
|
||||
void Node::collectRenderCommands(std::vector<RenderCommand> &commands,
|
||||
int parentZOrder) {
|
||||
if (!visible_)
|
||||
return;
|
||||
|
|
@ -701,14 +676,14 @@ void Node::collectRenderCommands(std::vector<RenderCommand>& commands,
|
|||
generateRenderCommand(commands, accumulatedZOrder);
|
||||
|
||||
// 让组件也生成渲染命令
|
||||
for (auto& pair : components_) {
|
||||
for (auto &pair : components_) {
|
||||
if (pair.second->isEnabled()) {
|
||||
// 组件的渲染命令收集需要通过 RenderQueue
|
||||
// 这里暂时跳过,使用 collectRenderCommandsToQueue 方法
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
child->collectRenderCommands(commands, accumulatedZOrder);
|
||||
}
|
||||
}
|
||||
|
|
@ -717,7 +692,7 @@ void Node::collectRenderCommands(std::vector<RenderCommand>& commands,
|
|||
* @brief 收集渲染命令到队列
|
||||
* @param queue 渲染队列引用
|
||||
*/
|
||||
void Node::collectRenderCommandsToQueue(RenderQueue& queue) {
|
||||
void Node::collectRenderCommandsToQueue(RenderQueue &queue) {
|
||||
if (!visible_)
|
||||
return;
|
||||
|
||||
|
|
@ -725,14 +700,14 @@ void Node::collectRenderCommandsToQueue(RenderQueue& queue) {
|
|||
generateRenderCommandToQueue(queue);
|
||||
|
||||
// 让组件也生成渲染命令
|
||||
for (auto& pair : components_) {
|
||||
for (auto &pair : components_) {
|
||||
if (pair.second->isEnabled()) {
|
||||
pair.second->collectRenderCommands(queue);
|
||||
}
|
||||
}
|
||||
|
||||
// 递归收集子节点的渲染命令
|
||||
for (auto& child : children_) {
|
||||
for (auto &child : children_) {
|
||||
child->collectRenderCommandsToQueue(queue);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/render/core/render_queue.h>
|
||||
#include <extra2d/scene/scene.h>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#include <algorithm>
|
||||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_command.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/platform/iinput.h>
|
||||
#include <extra2d/scene/scene_manager.h>
|
||||
#include <extra2d/scene/transition_box_scene.h>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_command.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/scene/shape_node.h>
|
||||
#include <limits>
|
||||
|
||||
|
|
@ -196,24 +196,18 @@ Ptr<ShapeNode> ShapeNode::createFilledPolygon(const std::vector<Vec2> &points,
|
|||
* @brief 设置形状的所有顶点
|
||||
* @param points 顶点坐标数组
|
||||
*/
|
||||
void ShapeNode::setPoints(const std::vector<Vec2> &points) {
|
||||
points_ = points;
|
||||
}
|
||||
void ShapeNode::setPoints(const std::vector<Vec2> &points) { points_ = points; }
|
||||
|
||||
/**
|
||||
* @brief 添加一个顶点到形状
|
||||
* @param point 要添加的顶点坐标
|
||||
*/
|
||||
void ShapeNode::addPoint(const Vec2 &point) {
|
||||
points_.push_back(point);
|
||||
}
|
||||
void ShapeNode::addPoint(const Vec2 &point) { points_.push_back(point); }
|
||||
|
||||
/**
|
||||
* @brief 清除所有顶点
|
||||
*/
|
||||
void ShapeNode::clearPoints() {
|
||||
points_.clear();
|
||||
}
|
||||
void ShapeNode::clearPoints() { points_.clear(); }
|
||||
|
||||
/**
|
||||
* @brief 获取形状的边界矩形
|
||||
|
|
@ -319,7 +313,7 @@ void ShapeNode::onDraw(RenderBackend &renderer) {
|
|||
case ShapeType::Triangle:
|
||||
if (points_.size() >= 3) {
|
||||
if (filled_) {
|
||||
renderer.fillTriangle(points_[0], points_[1], points_[2], color_);
|
||||
renderer.fillPolygon(points_.data(), 3, color_);
|
||||
} else {
|
||||
renderer.drawLine(points_[0], points_[1], color_, lineWidth_);
|
||||
renderer.drawLine(points_[1], points_[2], color_, lineWidth_);
|
||||
|
|
@ -331,9 +325,9 @@ void ShapeNode::onDraw(RenderBackend &renderer) {
|
|||
case ShapeType::Polygon:
|
||||
if (!points_.empty()) {
|
||||
if (filled_) {
|
||||
renderer.fillPolygon(points_, color_);
|
||||
renderer.fillPolygon(points_.data(), points_.size(), color_);
|
||||
} else {
|
||||
renderer.drawPolygon(points_, color_, lineWidth_);
|
||||
renderer.drawPolygon(points_.data(), points_.size(), color_, lineWidth_);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -354,71 +348,44 @@ void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
|
|||
}
|
||||
|
||||
Vec2 offset = getPosition();
|
||||
RenderCommand cmd;
|
||||
cmd.layer = zOrder;
|
||||
|
||||
switch (shapeType_) {
|
||||
case ShapeType::Point:
|
||||
if (!points_.empty()) {
|
||||
cmd.type = RenderCommandType::FilledCircle;
|
||||
cmd.data =
|
||||
CircleCommandData{points_[0] + offset, lineWidth_ * 0.5f, color_, 8, 0.0f, true};
|
||||
commands.push_back(RenderCommand::makeCircle(
|
||||
points_[0] + offset, lineWidth_ * 0.5f, color_, 8, true, zOrder));
|
||||
}
|
||||
break;
|
||||
|
||||
case ShapeType::Line:
|
||||
if (points_.size() >= 2) {
|
||||
cmd.type = RenderCommandType::Line;
|
||||
cmd.data = LineCommandData{points_[0] + offset, points_[1] + offset, color_,
|
||||
lineWidth_};
|
||||
commands.push_back(RenderCommand::makeLine(
|
||||
points_[0] + offset, points_[1] + offset, color_, lineWidth_, zOrder));
|
||||
}
|
||||
break;
|
||||
|
||||
case ShapeType::Rect:
|
||||
if (points_.size() >= 4) {
|
||||
if (filled_) {
|
||||
cmd.type = RenderCommandType::FilledRect;
|
||||
Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x,
|
||||
points_[2].y - points_[0].y);
|
||||
cmd.data =
|
||||
RectCommandData{Rect(rect.origin + offset, rect.size), color_, 0.0f, true};
|
||||
} else {
|
||||
cmd.type = RenderCommandType::Rect;
|
||||
Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x,
|
||||
points_[2].y - points_[0].y);
|
||||
cmd.data =
|
||||
RectCommandData{Rect(rect.origin + offset, rect.size), color_, lineWidth_, false};
|
||||
}
|
||||
commands.push_back(RenderCommand::makeRect(
|
||||
Rect(rect.origin + offset, rect.size), color_, lineWidth_, filled_, zOrder));
|
||||
}
|
||||
break;
|
||||
|
||||
case ShapeType::Circle:
|
||||
if (points_.size() >= 2) {
|
||||
float radius = points_[1].x;
|
||||
if (filled_) {
|
||||
cmd.type = RenderCommandType::FilledCircle;
|
||||
cmd.data =
|
||||
CircleCommandData{points_[0] + offset, radius, color_, segments_, 0.0f, true};
|
||||
} else {
|
||||
cmd.type = RenderCommandType::Circle;
|
||||
cmd.data = CircleCommandData{points_[0] + offset, radius, color_, segments_,
|
||||
lineWidth_, false};
|
||||
}
|
||||
commands.push_back(RenderCommand::makeCircle(
|
||||
points_[0] + offset, radius, color_, segments_, filled_, zOrder));
|
||||
}
|
||||
break;
|
||||
|
||||
case ShapeType::Triangle:
|
||||
if (points_.size() >= 3) {
|
||||
Vec2 p1 = points_[0] + offset;
|
||||
Vec2 p2 = points_[1] + offset;
|
||||
Vec2 p3 = points_[2] + offset;
|
||||
if (filled_) {
|
||||
cmd.type = RenderCommandType::FilledTriangle;
|
||||
cmd.data = TriangleCommandData{p1, p2, p3, color_, 0.0f, true};
|
||||
} else {
|
||||
cmd.type = RenderCommandType::Triangle;
|
||||
cmd.data = TriangleCommandData{p1, p2, p3, color_, lineWidth_, false};
|
||||
}
|
||||
commands.push_back(RenderCommand::makeTriangle(
|
||||
points_[0] + offset, points_[1] + offset, points_[2] + offset,
|
||||
color_, filled_, zOrder));
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -429,19 +396,11 @@ void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
|
|||
for (const auto &p : points_) {
|
||||
transformedPoints.push_back(p + offset);
|
||||
}
|
||||
|
||||
if (filled_) {
|
||||
cmd.type = RenderCommandType::FilledPolygon;
|
||||
cmd.data = PolygonCommandData{transformedPoints, color_, 0.0f, true};
|
||||
} else {
|
||||
cmd.type = RenderCommandType::Polygon;
|
||||
cmd.data = PolygonCommandData{transformedPoints, color_, lineWidth_, false};
|
||||
}
|
||||
commands.push_back(RenderCommand::makePolygon(
|
||||
transformedPoints, color_, filled_, zOrder));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
commands.push_back(std::move(cmd));
|
||||
}
|
||||
|
||||
} // namespace extra2d
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/graphics/core/render_command.h>
|
||||
#include <extra2d/graphics/texture/texture.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_command.h>
|
||||
#include <extra2d/scene/sprite.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
@ -168,8 +167,8 @@ void Sprite::onDraw(RenderBackend &renderer) {
|
|||
// 从世界变换矩阵中提取旋转角度
|
||||
float worldRotation = std::atan2(worldTransform[0][1], worldTransform[0][0]);
|
||||
|
||||
renderer.drawSprite(*texture_, destRect, srcRect, color_, worldRotation,
|
||||
anchor);
|
||||
renderer.drawSprite(texture_->getRHITexture(), destRect, srcRect, color_, worldRotation,
|
||||
flipX_, flipY_);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -225,8 +224,8 @@ void Sprite::generateRenderCommand(std::vector<RenderCommand> &commands,
|
|||
RenderCommand cmd;
|
||||
cmd.type = RenderCommandType::Sprite;
|
||||
cmd.layer = zOrder;
|
||||
cmd.data = SpriteCommandData{texture_.get(), destRect, srcRect, color_,
|
||||
worldRotation, anchor, 0};
|
||||
cmd.data = SpriteRenderData{texture_->getRHITexture(), destRect, srcRect, color_,
|
||||
worldRotation, anchor, rhi::BlendState::alphaBlend(), 0};
|
||||
|
||||
commands.push_back(std::move(cmd));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <extra2d/scene/transition_box_scene.h>
|
||||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/color.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <algorithm>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
|
@ -76,7 +76,8 @@ void TransitionBoxScene::renderContent(RenderBackend &renderer) {
|
|||
|
||||
glm::mat4 overlayVP =
|
||||
glm::ortho(0.0f, windowWidth, windowHeight, 0.0f, -1.0f, 1.0f);
|
||||
renderer.setViewProjection(overlayVP);
|
||||
renderer.setProjectionMatrix(overlayVP);
|
||||
renderer.setViewMatrix(glm::mat4(1.0f));
|
||||
|
||||
for (int idx = visible; idx < total; ++idx) {
|
||||
int x = idx % div;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <extra2d/app/application.h>
|
||||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/platform/iwindow.h>
|
||||
#include <extra2d/scene/transition_fade_scene.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
|
@ -75,7 +75,8 @@ void TransitionFadeScene::renderContent(RenderBackend &renderer) {
|
|||
|
||||
glm::mat4 overlayVP =
|
||||
glm::ortho(0.0f, windowWidth, windowHeight, 0.0f, -1.0f, 1.0f);
|
||||
renderer.setViewProjection(overlayVP);
|
||||
renderer.setProjectionMatrix(overlayVP);
|
||||
renderer.setViewMatrix(glm::mat4(1.0f));
|
||||
|
||||
Color maskColor = maskColor_;
|
||||
maskColor.a = maskAlpha;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <extra2d/scene/transition_flip_scene.h>
|
||||
#include <extra2d/core/math_types.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
|
||||
namespace extra2d {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <extra2d/scene/transition_scale_scene.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include <extra2d/core/service_locator.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <extra2d/scene/transition_scene.h>
|
||||
#include <extra2d/services/logger_service.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include <extra2d/scene/transition_slide_scene.h>
|
||||
#include <extra2d/graphics/camera/camera.h>
|
||||
#include <extra2d/graphics/core/render_backend.h>
|
||||
#include <extra2d/render/camera/camera.h>
|
||||
#include <extra2d/render/core/render_backend.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace extra2d {
|
||||
|
|
|
|||
|
|
@ -34,13 +34,13 @@ function define_extra2d_engine()
|
|||
|
||||
-- 渲染后端源文件
|
||||
local render_backend = get_render_backend()
|
||||
-- 图形后端工厂(始终编译)
|
||||
add_files("Extra2D/src/graphics/backends/backend_factory.cpp")
|
||||
-- 渲染后端工厂
|
||||
add_files("Extra2D/src/render/core/backend_factory.cpp")
|
||||
if render_backend == "vulkan" then
|
||||
add_files("Extra2D/src/graphics/backends/vulkan/*.cpp")
|
||||
add_files("Extra2D/src/render/backends/vulkan/*.cpp")
|
||||
add_defines("E2D_BACKEND_VULKAN")
|
||||
else
|
||||
add_files("Extra2D/src/graphics/backends/opengl/*.cpp")
|
||||
add_files("Extra2D/src/render/backends/opengl/*.cpp")
|
||||
add_files("Extra2D/src/glad/glad.c")
|
||||
add_defines("E2D_BACKEND_OPENGL")
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue