refactor(render): 移除RenderBackend并重构渲染系统

将RenderBackend相关代码移除,重构渲染系统使用Renderer类
更新所有相关引用和接口,移除backend_factory和render_backend
调整SDL2和GLFW窗口实现,不再直接处理OpenGL上下文
优化GLRHIDevice以支持多种窗口后端创建OpenGL上下文
This commit is contained in:
ChestnutYueyue 2026-02-20 03:35:14 +08:00
parent d681f63905
commit 0999644a71
44 changed files with 1224 additions and 2497 deletions

View File

@ -10,7 +10,7 @@ namespace extra2d {
class IWindow; class IWindow;
class IInput; class IInput;
class RenderBackend; class Renderer;
class WindowModule; class WindowModule;
class RenderModule; class RenderModule;
class InputModule; class InputModule;
@ -93,7 +93,7 @@ public:
* @brief * @brief
* @return * @return
*/ */
RenderBackend *renderer(); Renderer *renderer();
/** /**
* @brief * @brief

View File

@ -22,13 +22,10 @@
#include <extra2d/platform/window_module.h> #include <extra2d/platform/window_module.h>
// Render Core // Render Core
#include <extra2d/render/core/render_backend.h>
#include <extra2d/render/core/render_command.h> #include <extra2d/render/core/render_command.h>
#include <extra2d/render/core/render_context.h> #include <extra2d/render/core/render_context.h>
#include <extra2d/render/core/render_queue.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/render_module.h>
#include <extra2d/render/core/backend_factory.h>
// Render Camera // Render Camera
#include <extra2d/render/camera/camera.h> #include <extra2d/render/camera/camera.h>

View File

@ -1,302 +0,0 @@
#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 &center, float radius, const Color &color,
float lineWidth = 1.0f, uint32_t segments = 32) override;
/**
* @brief
*/
void fillCircle(const Vec2 &center, 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

View File

@ -11,6 +11,15 @@ class IWindow;
namespace rhi { namespace rhi {
/**
* @brief OpenGL
*/
enum class GLContextType {
None,
GLFW,
SDL2
};
/** /**
* @brief OpenGL RHI * @brief OpenGL RHI
* *
@ -176,6 +185,12 @@ private:
DeviceStats stats_; DeviceStats stats_;
std::string debugName_; std::string debugName_;
// OpenGL 上下文相关
GLContextType contextType_ = GLContextType::None;
void *glfwWindow_ = nullptr;
void *sdlWindow_ = nullptr;
void *glContext_ = nullptr;
// 当前绑定的资源 // 当前绑定的资源
Ptr<RHIPipeline> currentPipeline_; Ptr<RHIPipeline> currentPipeline_;
Ptr<RHIShader> currentShader_; Ptr<RHIShader> currentShader_;
@ -205,6 +220,16 @@ private:
void applyPipelineState(const BlendState &blend, void applyPipelineState(const BlendState &blend,
const DepthStencilState &depthStencil, const DepthStencilState &depthStencil,
const RasterizerState &rasterizer); const RasterizerState &rasterizer);
/**
* @brief GLFW
*/
bool initGLFWContext();
/**
* @brief SDL2
*/
bool initSDL2Context();
}; };
} // namespace rhi } // namespace rhi

View File

@ -1,182 +0,0 @@
#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
*
*
* OpenGLVulkanDirectX
*/
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

View File

@ -1,324 +0,0 @@
#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 &center, float radius, const Color &color,
float lineWidth = 1.0f, uint32_t segments = 32) = 0;
/**
* @brief
*/
virtual void fillCircle(const Vec2 &center, 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

View File

@ -3,7 +3,6 @@
#include <extra2d/core/color.h> #include <extra2d/core/color.h>
#include <extra2d/core/math_types.h> #include <extra2d/core/math_types.h>
#include <extra2d/core/types.h> #include <extra2d/core/types.h>
#include <extra2d/render/core/render_backend.h>
#include <extra2d/render/core/render_queue.h> #include <extra2d/render/core/render_queue.h>
#include <extra2d/render/rhi/rhi_device.h> #include <extra2d/render/rhi/rhi_device.h>
#include <extra2d/render/rhi/rhi_types.h> #include <extra2d/render/rhi/rhi_types.h>
@ -132,12 +131,6 @@ public:
*/ */
IWindow *getWindow() const { return window_; } IWindow *getWindow() const { return window_; }
/**
* @brief
*/
const RenderStats &getStats() const { return stats_; }
void resetStats();
/** /**
* @brief * @brief
*/ */
@ -167,7 +160,6 @@ private:
Ptr<rhi::RHIDevice> device_; Ptr<rhi::RHIDevice> device_;
IWindow *window_; IWindow *window_;
RenderQueue queue_; RenderQueue queue_;
RenderStats stats_;
RenderContextConfig config_; RenderContextConfig config_;
std::stack<glm::mat4> transformStack_; std::stack<glm::mat4> transformStack_;

View File

@ -2,7 +2,6 @@
#include <extra2d/core/module.h> #include <extra2d/core/module.h>
#include <extra2d/core/types.h> #include <extra2d/core/types.h>
#include <extra2d/render/core/render_backend.h>
#include <extra2d/render/rhi/rhi_types.h> #include <extra2d/render/rhi/rhi_types.h>
#include <functional> #include <functional>

View File

@ -1,22 +1,46 @@
#pragma once #pragma once
#include <extra2d/core/color.h> #include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/module.h> #include <extra2d/core/module.h>
#include <extra2d/core/types.h> #include <extra2d/core/types.h>
#include <extra2d/render/batch/shape_batcher.h>
#include <extra2d/render/batch/sprite_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/camera.h>
#include <extra2d/render/camera/viewport_adapter.h> #include <extra2d/render/camera/viewport_adapter.h>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/core/render_queue.h>
#include <extra2d/render/core/render_context.h> #include <extra2d/render/rhi/rhi_device.h>
#include <extra2d/render/rhi/rhi_types.h> #include <extra2d/render/rhi/rhi_types.h>
#include <glm/mat4x4.hpp>
#include <string>
namespace extra2d { namespace extra2d {
class IWindow; class IWindow;
class Scene; class Scene;
/**
* @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 * @brief
*/ */
@ -42,7 +66,7 @@ struct RendererConfig {
/** /**
* @brief * @brief
* *
* * RHI
* 使 * 使
*/ */
class Renderer : public Module { class Renderer : public Module {
@ -105,6 +129,7 @@ public:
/** /**
* @brief * @brief
* @param clearColor
*/ */
void beginFrame(const Color &clearColor = Colors::Black); void beginFrame(const Color &clearColor = Colors::Black);
@ -127,10 +152,188 @@ public:
*/ */
void renderScene(Scene *scene); void renderScene(Scene *scene);
// ========================================================================
// 渲染状态
// ========================================================================
/** /**
* @brief * @brief
*/ */
void renderScene(Scene *scene, Camera *camera); 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 setProjectionMatrix(const glm::mat4 &matrix);
/**
* @brief
*/
void setViewMatrix(const glm::mat4 &matrix);
/**
* @brief
*/
void setVSync(bool enabled);
/**
* @brief
*/
bool isVSyncEnabled() const;
// ========================================================================
// 精灵渲染
// ========================================================================
/**
* @brief
* @param texture
* @param destRect
* @param srcRect
* @param color
* @param rotation
* @param flipX
* @param flipY
*/
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);
/**
* @brief 使
*/
void drawSprite(Ptr<rhi::RHITexture> texture,
const glm::mat4 &transform,
const Rect &srcRect = Rect(0, 0, 1, 1),
const Color &color = Colors::White);
/**
* @brief
*/
void draw9Slice(Ptr<rhi::RHITexture> texture, const Rect &destRect,
const Rect &srcRect, const Vec2 &borderSize,
const Color &color = Colors::White);
// ========================================================================
// 文本渲染
// ========================================================================
/**
* @brief
* @param text UTF-8
* @param position
* @param fontSize
* @param color
*/
void drawText(const std::string &text, const Vec2 &position,
float fontSize, const Color &color = Colors::White);
/**
* @brief UTF-32
*/
void drawText(const std::u32string &text, const Vec2 &position,
float fontSize, const Color &color = Colors::White);
/**
* @brief
*/
Vec2 measureText(const std::string &text, float fontSize);
/**
* @brief UTF-32
*/
Vec2 measureText(const std::u32string &text, float fontSize);
// ========================================================================
// 形状渲染
// ========================================================================
/**
* @brief
*/
void drawRect(const Rect &rect, const Color &color,
float lineWidth = 1.0f);
/**
* @brief
*/
void fillRect(const Rect &rect, const Color &color);
/**
* @brief
*/
void drawCircle(const Vec2 &center, float radius, const Color &color,
float lineWidth = 1.0f, uint32_t segments = 32);
/**
* @brief
*/
void fillCircle(const Vec2 &center, float radius, const Color &color,
uint32_t segments = 32);
/**
* @brief 线
*/
void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
float lineWidth = 1.0f);
/**
* @brief
*/
void drawPolygon(const Vec2 *points, size_t count, const Color &color,
float lineWidth = 1.0f);
/**
* @brief
*/
void fillPolygon(const Vec2 *points, size_t count,
const Color &color);
// ========================================================================
// 批处理控制
// ========================================================================
/**
* @brief
*/
void beginSpriteBatch();
/**
* @brief
*/
void endSpriteBatch();
/**
* @brief
*/
void flush();
/**
* @brief
*/
void setSortKey(uint64_t key);
/**
* @brief
*/
void setLayer(int layer);
/**
* @brief
*/
void setBlendMode(rhi::BlendState blend);
// ======================================================================== // ========================================================================
// 相机系统 // 相机系统
@ -162,71 +365,23 @@ public:
const ViewportAdapter &getViewportAdapter() const { return viewportAdapter_; } const ViewportAdapter &getViewportAdapter() const { return viewportAdapter_; }
// ======================================================================== // ========================================================================
// 渲染状态 // RHI 设备访问
// ======================================================================== // ========================================================================
/**
* @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 * @brief RHI
*/ */
rhi::RHIDevice *getDevice() const; rhi::RHIDevice *getDevice() const { return device_.get(); }
/**
* @brief API
*/
rhi::GraphicsAPI getAPI() const;
/**
* @brief
*/
const rhi::DeviceCaps &getCaps() const;
// ======================================================================== // ========================================================================
// 统计信息 // 统计信息
@ -285,11 +440,6 @@ public:
static Ptr<Renderer> create(const RendererConfig &config = {}); static Ptr<Renderer> create(const RendererConfig &config = {});
private: private:
/**
* @brief
*/
bool createBatchers();
/** /**
* @brief * @brief
*/ */
@ -300,27 +450,29 @@ private:
*/ */
void updateViewportAdapter(); void updateViewportAdapter();
/**
* @brief
*/
void applyCameraTransform(Camera *camera);
IWindow *window_; IWindow *window_;
RendererConfig config_; RendererConfig config_;
UniquePtr<RenderContext> context_; Ptr<rhi::RHIDevice> device_;
UniquePtr<RenderBackend> backend_;
UniquePtr<SpriteBatcher> spriteBatcher_; UniquePtr<SpriteBatcher> spriteBatcher_;
UniquePtr<ShapeBatcher> shapeBatcher_; UniquePtr<RenderQueue> renderQueue_;
UniquePtr<TextBatcher> textBatcher_;
ViewportAdapter viewportAdapter_; ViewportAdapter viewportAdapter_;
Ptr<Camera> activeCamera_; Ptr<Camera> activeCamera_;
Ptr<Camera> defaultCamera_; Ptr<Camera> defaultCamera_;
glm::mat4 projectionMatrix_;
glm::mat4 viewMatrix_;
int width_; int width_;
int height_; int height_;
bool initialized_; bool initialized_;
RenderStats stats_;
uint64_t sortKey_;
int layer_;
rhi::BlendState blendState_;
bool inBatch_;
}; };
} // namespace extra2d } // namespace extra2d

View File

@ -9,7 +9,6 @@
#include <extra2d/render/rhi/rhi_types.h> #include <extra2d/render/rhi/rhi_types.h>
#include <glm/mat4x4.hpp> #include <glm/mat4x4.hpp>
#include <string> #include <string>
#include <vector>
namespace extra2d { namespace extra2d {
@ -21,39 +20,39 @@ namespace rhi {
* @brief RHI * @brief RHI
*/ */
struct DeviceCaps { struct DeviceCaps {
GraphicsAPI api = GraphicsAPI::OpenGL; GraphicsAPI api = GraphicsAPI::OpenGL;
std::string apiVersion; std::string apiVersion;
std::string deviceName; std::string deviceName;
std::string vendorName; std::string vendorName;
uint32_t maxTextureSize = 0; uint32_t maxTextureSize = 0;
uint32_t maxTextureUnits = 0; uint32_t maxTextureUnits = 0;
uint32_t maxVertexAttributes = 0; uint32_t maxVertexAttributes = 0;
uint32_t maxUniformBufferBindings = 0; uint32_t maxUniformBufferBindings = 0;
uint32_t maxColorAttachments = 0; uint32_t maxColorAttachments = 0;
float maxAnisotropy = 1.0f; float maxAnisotropy = 1.0f;
bool supportsCompute = false; bool supportsCompute = false;
bool supportsGeometry = false; bool supportsGeometry = false;
bool supportsTessellation = false; bool supportsTessellation = false;
bool supportsInstancing = false; bool supportsInstancing = false;
bool supportsIndirectDraw = false; bool supportsIndirectDraw = false;
bool supportsMultiDrawIndirect = false; bool supportsMultiDrawIndirect = false;
bool supportsPersistentMapping = false; bool supportsPersistentMapping = false;
bool supportsBindlessTextures = false; bool supportsBindlessTextures = false;
}; };
/** /**
* @brief RHI * @brief RHI
*/ */
struct DeviceStats { struct DeviceStats {
uint32_t drawCalls = 0; uint32_t drawCalls = 0;
uint32_t triangleCount = 0; uint32_t triangleCount = 0;
uint32_t vertexCount = 0; uint32_t vertexCount = 0;
uint32_t textureBinds = 0; uint32_t textureBinds = 0;
uint32_t shaderBinds = 0; uint32_t shaderBinds = 0;
uint32_t bufferBinds = 0; uint32_t bufferBinds = 0;
uint32_t framebufferBinds = 0; uint32_t framebufferBinds = 0;
uint64_t textureMemory = 0; uint64_t textureMemory = 0;
uint64_t bufferMemory = 0; uint64_t bufferMemory = 0;
}; };
/** /**
@ -64,390 +63,409 @@ struct DeviceStats {
*/ */
class RHIDevice { class RHIDevice {
public: public:
virtual ~RHIDevice() = default; virtual ~RHIDevice() = default;
// ======================================================================== // ========================================================================
// 生命周期 // 生命周期
// ======================================================================== // ========================================================================
/** /**
* @brief * @brief
* @param window * @param window
* @return true * @return true
*/ */
virtual bool init(IWindow* window) = 0; virtual bool init(IWindow *window) = 0;
/** /**
* @brief * @brief
*/ */
virtual void shutdown() = 0; virtual void shutdown() = 0;
/** /**
* @brief * @brief
*/ */
virtual bool isValid() const = 0; virtual bool isValid() const = 0;
/** /**
* @brief API * @brief API
*/ */
virtual GraphicsAPI getAPI() const = 0; virtual GraphicsAPI getAPI() const = 0;
/** /**
* @brief * @brief
*/ */
virtual const DeviceCaps& getCaps() const = 0; virtual const DeviceCaps &getCaps() const = 0;
// ======================================================================== // ========================================================================
// 帧管理 // 帧管理
// ======================================================================== // ========================================================================
/** /**
* @brief * @brief
*/ */
virtual void beginFrame() = 0; virtual void beginFrame() = 0;
/** /**
* @brief * @brief
*/ */
virtual void endFrame() = 0; virtual void endFrame() = 0;
/** /**
* @brief * @brief
*/ */
virtual void present() = 0; virtual void present() = 0;
/** /**
* @brief * @brief
*/ */
virtual void setVSync(bool enabled) = 0; virtual void setVSync(bool enabled) = 0;
/** /**
* @brief * @brief
*/ */
virtual bool isVSyncEnabled() const = 0; virtual bool isVSyncEnabled() const = 0;
/** /**
* @brief * @brief
*/ */
virtual void setDefaultFramebufferSize(uint32_t width, uint32_t height) = 0; virtual void setDefaultFramebufferSize(uint32_t width, uint32_t height) = 0;
// ======================================================================== // ========================================================================
// 资源创建 - 缓冲区 // 资源创建 - 缓冲区
// ======================================================================== // ========================================================================
/** /**
* @brief * @brief
*/ */
virtual Ptr<RHIBuffer> createBuffer(const BufferDesc& desc) = 0; virtual Ptr<RHIBuffer> createBuffer(const BufferDesc &desc) = 0;
/** /**
* @brief * @brief
*/ */
virtual Ptr<RHIVertexBuffer> createVertexBuffer(size_t size, BufferUsage usage = BufferUsage::Static, virtual Ptr<RHIVertexBuffer>
const void* data = nullptr) = 0; createVertexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
const void *data = nullptr) = 0;
/**
* @brief /**
*/ * @brief
virtual Ptr<RHIIndexBuffer> createIndexBuffer(size_t size, BufferUsage usage = BufferUsage::Static, */
const void* data = nullptr) = 0; virtual Ptr<RHIIndexBuffer>
createIndexBuffer(size_t size, BufferUsage usage = BufferUsage::Static,
/** const void *data = nullptr) = 0;
* @brief Uniform
*/ /**
virtual Ptr<RHIUniformBuffer> createUniformBuffer(size_t size, BufferUsage usage = BufferUsage::Dynamic) = 0; * @brief Uniform
*/
// ======================================================================== virtual Ptr<RHIUniformBuffer>
// 资源创建 - 纹理 createUniformBuffer(size_t size,
// ======================================================================== BufferUsage usage = BufferUsage::Dynamic) = 0;
/** // ========================================================================
* @brief // 资源创建 - 纹理
*/ // ========================================================================
virtual Ptr<RHITexture> createTexture(const TextureDesc& desc) = 0;
/**
/** * @brief
* @brief 2D */
*/ virtual Ptr<RHITexture> createTexture(const TextureDesc &desc) = 0;
virtual Ptr<RHITexture> createTexture2D(uint32_t width, uint32_t height, Format format,
const void* data = nullptr) = 0; /**
* @brief 2D
/** */
* @brief virtual Ptr<RHITexture> createTexture2D(uint32_t width, uint32_t height,
*/ Format format,
virtual Ptr<RHISampler> createSampler(const SamplerDesc& desc) = 0; const void *data = nullptr) = 0;
/** /**
* @brief * @brief
*/ */
virtual Ptr<RHITextureView> createTextureView(Ptr<RHITexture> texture, virtual Ptr<RHISampler> createSampler(const SamplerDesc &desc) = 0;
const TextureViewDesc& desc) = 0;
/**
// ======================================================================== * @brief
// 资源创建 - 着色器 */
// ======================================================================== virtual Ptr<RHITextureView>
createTextureView(Ptr<RHITexture> texture, const TextureViewDesc &desc) = 0;
/**
* @brief // ========================================================================
*/ // 资源创建 - 着色器
virtual Ptr<RHIShader> createShader(const ShaderDesc& desc) = 0; // ========================================================================
/** /**
* @brief * @brief
*/ */
virtual Ptr<RHIShader> createShaderFromSource(const std::string& name, virtual Ptr<RHIShader> createShader(const ShaderDesc &desc) = 0;
const std::string& vertexSource,
const std::string& fragmentSource) = 0; /**
* @brief
/** */
* @brief virtual Ptr<RHIShader>
*/ createShaderFromSource(const std::string &name,
virtual Ptr<RHIShader> createShaderFromFile(const std::string& vertexPath, const std::string &vertexSource,
const std::string& fragmentPath) = 0; const std::string &fragmentSource) = 0;
// ======================================================================== /**
// 资源创建 - 管线 * @brief
// ======================================================================== */
virtual Ptr<RHIShader>
/** createShaderFromFile(const std::string &vertexPath,
* @brief 线 const std::string &fragmentPath) = 0;
*/
virtual Ptr<RHIPipeline> createPipeline(const PipelineDesc& desc, Ptr<RHIShader> shader) = 0; // ========================================================================
// 资源创建 - 管线
/** // ========================================================================
* @brief 使线
*/ /**
virtual Ptr<RHIPipeline> createPipeline(const PipelineBuilder& builder) = 0; * @brief 线
*/
// ======================================================================== virtual Ptr<RHIPipeline> createPipeline(const PipelineDesc &desc,
// 资源创建 - 帧缓冲 Ptr<RHIShader> shader) = 0;
// ========================================================================
/**
/** * @brief 使线
* @brief */
*/ virtual Ptr<RHIPipeline> createPipeline(const PipelineBuilder &builder) = 0;
virtual Ptr<RHIFramebuffer> createFramebuffer(const FramebufferDesc& desc) = 0;
// ========================================================================
/** // 资源创建 - 帧缓冲
* @brief 使 // ========================================================================
*/
virtual Ptr<RHIFramebuffer> createFramebuffer(const FramebufferBuilder& builder) = 0; /**
* @brief
// ======================================================================== */
// 渲染状态设置 virtual Ptr<RHIFramebuffer>
// ======================================================================== createFramebuffer(const FramebufferDesc &desc) = 0;
/** /**
* @brief * @brief 使
*/ */
virtual void setViewport(const Viewport& viewport) = 0; virtual Ptr<RHIFramebuffer>
createFramebuffer(const FramebufferBuilder &builder) = 0;
/**
* @brief // ========================================================================
*/ // 渲染状态设置
void setViewport(float x, float y, float width, float height, // ========================================================================
float minDepth = 0.0f, float maxDepth = 1.0f) {
setViewport(Viewport(x, y, width, height, minDepth, maxDepth)); /**
} * @brief
*/
/** virtual void setViewport(const Viewport &viewport) = 0;
* @brief
*/ /**
virtual void setScissorRect(const ScissorRect& rect) = 0; * @brief
*/
/** void setViewport(float x, float y, float width, float height,
* @brief float minDepth = 0.0f, float maxDepth = 1.0f) {
*/ setViewport(Viewport(x, y, width, height, minDepth, maxDepth));
void setScissorRect(int32_t x, int32_t y, uint32_t width, uint32_t height) { }
setScissorRect(ScissorRect(x, y, width, height));
} /**
* @brief
/** */
* @brief / virtual void setScissorRect(const ScissorRect &rect) = 0;
*/
virtual void setScissorEnabled(bool enabled) = 0; /**
* @brief
// ======================================================================== */
// 渲染命令 - 绑定资源 void setScissorRect(int32_t x, int32_t y, uint32_t width, uint32_t height) {
// ======================================================================== setScissorRect(ScissorRect(x, y, width, height));
}
/**
* @brief 线 /**
*/ * @brief /
virtual void setPipeline(Ptr<RHIPipeline> pipeline) = 0; */
virtual void setScissorEnabled(bool enabled) = 0;
/**
* @brief // ========================================================================
*/ // 渲染命令 - 绑定资源
virtual void setShader(Ptr<RHIShader> shader) = 0; // ========================================================================
/** /**
* @brief * @brief 线
*/ */
virtual void setVertexBuffer(uint32_t slot, Ptr<RHIBuffer> buffer, uint32_t offset = 0) = 0; virtual void setPipeline(Ptr<RHIPipeline> pipeline) = 0;
/** /**
* @brief * @brief
*/ */
virtual void setIndexBuffer(Ptr<RHIBuffer> buffer, IndexFormat format) = 0; virtual void setShader(Ptr<RHIShader> shader) = 0;
/** /**
* @brief * @brief
*/ */
virtual void setTexture(uint32_t slot, Ptr<RHITexture> texture, Ptr<RHISampler> sampler = nullptr) = 0; virtual void setVertexBuffer(uint32_t slot, Ptr<RHIBuffer> buffer,
uint32_t offset = 0) = 0;
/**
* @brief Uniform /**
*/ * @brief
virtual void setUniformBuffer(uint32_t slot, Ptr<RHIBuffer> buffer) = 0; */
virtual void setIndexBuffer(Ptr<RHIBuffer> buffer, IndexFormat format) = 0;
/**
* @brief /**
*/ * @brief
virtual void setFramebuffer(Ptr<RHIFramebuffer> framebuffer) = 0; */
virtual void setTexture(uint32_t slot, Ptr<RHITexture> texture,
/** Ptr<RHISampler> sampler = nullptr) = 0;
* @brief
*/ /**
virtual void setDefaultFramebuffer() = 0; * @brief Uniform
*/
// ======================================================================== virtual void setUniformBuffer(uint32_t slot, Ptr<RHIBuffer> buffer) = 0;
// 渲染命令 - Uniform 设置
// ======================================================================== /**
* @brief
/** */
* @brief Uniform virtual void setFramebuffer(Ptr<RHIFramebuffer> framebuffer) = 0;
*/
virtual void setUniformFloat(const std::string& name, float value) = 0; /**
* @brief
/** */
* @brief Uniform virtual void setDefaultFramebuffer() = 0;
*/
virtual void setUniformVec2(const std::string& name, const glm::vec2& value) = 0; // ========================================================================
virtual void setUniformVec3(const std::string& name, const glm::vec3& value) = 0; // 渲染命令 - Uniform 设置
virtual void setUniformVec4(const std::string& name, const glm::vec4& value) = 0; // ========================================================================
/** /**
* @brief Uniform * @brief Uniform
*/ */
virtual void setUniformMat4(const std::string& name, const glm::mat4& value) = 0; virtual void setUniformFloat(const std::string &name, float value) = 0;
/** /**
* @brief Uniform * @brief Uniform
*/ */
virtual void setUniformInt(const std::string& name, int value) = 0; virtual void setUniformVec2(const std::string &name,
const glm::vec2 &value) = 0;
// ======================================================================== virtual void setUniformVec3(const std::string &name,
// 渲染命令 - 绘制 const glm::vec3 &value) = 0;
// ======================================================================== virtual void setUniformVec4(const std::string &name,
const glm::vec4 &value) = 0;
/**
* @brief /**
*/ * @brief Uniform
virtual void draw(const DrawCommand& cmd) = 0; */
virtual void setUniformMat4(const std::string &name,
/** const glm::mat4 &value) = 0;
* @brief
*/ /**
void draw(uint32_t vertexCount, uint32_t firstVertex = 0, uint32_t instanceCount = 1) { * @brief Uniform
DrawCommand cmd; */
cmd.vertexCount = vertexCount; virtual void setUniformInt(const std::string &name, int value) = 0;
cmd.firstVertex = firstVertex;
cmd.instanceCount = instanceCount; // ========================================================================
draw(cmd); // 渲染命令 - 绘制
} // ========================================================================
/** /**
* @brief * @brief
*/ */
virtual void drawIndexed(const DrawIndexedCommand& cmd) = 0; virtual void draw(const DrawCommand &cmd) = 0;
/** /**
* @brief * @brief
*/ */
void drawIndexed(uint32_t indexCount, uint32_t firstIndex = 0, int32_t vertexOffset = 0, void draw(uint32_t vertexCount, uint32_t firstVertex = 0,
uint32_t instanceCount = 1) { uint32_t instanceCount = 1) {
DrawIndexedCommand cmd; DrawCommand cmd;
cmd.indexCount = indexCount; cmd.vertexCount = vertexCount;
cmd.firstIndex = firstIndex; cmd.firstVertex = firstVertex;
cmd.vertexOffset = vertexOffset; cmd.instanceCount = instanceCount;
cmd.instanceCount = instanceCount; draw(cmd);
drawIndexed(cmd); }
}
/**
/** * @brief
* @brief */
*/ virtual void drawIndexed(const DrawIndexedCommand &cmd) = 0;
virtual void drawIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) = 0;
/**
/** * @brief
* @brief */
*/ void drawIndexed(uint32_t indexCount, uint32_t firstIndex = 0,
virtual void drawIndexedIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) = 0; int32_t vertexOffset = 0, uint32_t instanceCount = 1) {
DrawIndexedCommand cmd;
// ======================================================================== cmd.indexCount = indexCount;
// 渲染命令 - 清除 cmd.firstIndex = firstIndex;
// ======================================================================== cmd.vertexOffset = vertexOffset;
cmd.instanceCount = instanceCount;
/** drawIndexed(cmd);
* @brief }
*/
virtual void clearColor(const ColorValue& color) = 0; /**
* @brief
/** */
* @brief virtual void drawIndirect(Ptr<RHIBuffer> indirectBuffer, size_t offset) = 0;
*/
virtual void clearDepth(float depth = 1.0f) = 0; /**
* @brief
/** */
* @brief virtual void drawIndexedIndirect(Ptr<RHIBuffer> indirectBuffer,
*/ size_t offset) = 0;
virtual void clearStencil(uint8_t stencil = 0) = 0;
// ========================================================================
/** // 渲染命令 - 清除
* @brief // ========================================================================
*/
virtual void clear(const ColorValue& color, float depth = 1.0f, uint8_t stencil = 0) = 0; /**
* @brief
// ======================================================================== */
// 统计与调试 virtual void clearColor(const ColorValue &color) = 0;
// ========================================================================
/**
/** * @brief
* @brief */
*/ virtual void clearDepth(float depth = 1.0f) = 0;
virtual const DeviceStats& getStats() const = 0;
/**
/** * @brief
* @brief */
*/ virtual void clearStencil(uint8_t stencil = 0) = 0;
virtual void resetStats() = 0;
/**
/** * @brief
* @brief */
*/ virtual void clear(const ColorValue &color, float depth = 1.0f,
virtual bool checkError() = 0; uint8_t stencil = 0) = 0;
/** // ========================================================================
* @brief // 统计与调试
*/ // ========================================================================
virtual const std::string& getDebugName() const = 0;
/**
/** * @brief
* @brief */
*/ virtual const DeviceStats &getStats() const = 0;
virtual void setDebugName(const std::string& name) = 0;
/**
// ======================================================================== * @brief
// 静态工厂方法 */
// ======================================================================== virtual void resetStats() = 0;
/** /**
* @brief RHI * @brief
* @param api API */
* @return virtual bool checkError() = 0;
*/
static Ptr<RHIDevice> create(GraphicsAPI api); /**
* @brief
*/
virtual const std::string &getDebugName() const = 0;
/**
* @brief
*/
virtual void setDebugName(const std::string &name) = 0;
// ========================================================================
// 静态工厂方法
// ========================================================================
/**
* @brief RHI
* @param api API
* @return
*/
static Ptr<RHIDevice> create(GraphicsAPI api);
}; };
/** /**
@ -455,26 +473,26 @@ public:
*/ */
class RHIDeviceScope { class RHIDeviceScope {
public: public:
explicit RHIDeviceScope(Ptr<RHIDevice> device) : device_(device) { explicit RHIDeviceScope(Ptr<RHIDevice> device) : device_(device) {
if (device_) { if (device_) {
device_->beginFrame(); device_->beginFrame();
}
} }
}
~RHIDeviceScope() { ~RHIDeviceScope() {
if (device_) { if (device_) {
device_->endFrame(); device_->endFrame();
}
} }
}
RHIDeviceScope(const RHIDeviceScope&) = delete; RHIDeviceScope(const RHIDeviceScope &) = delete;
RHIDeviceScope& operator=(const RHIDeviceScope&) = delete; RHIDeviceScope &operator=(const RHIDeviceScope &) = delete;
RHIDevice* operator->() { return device_.get(); } RHIDevice *operator->() { return device_.get(); }
RHIDevice* get() { return device_.get(); } RHIDevice *get() { return device_.get(); }
private: private:
Ptr<RHIDevice> device_; Ptr<RHIDevice> device_;
}; };
} // namespace rhi } // namespace rhi

View File

@ -4,7 +4,7 @@
#include <extra2d/core/math_types.h> #include <extra2d/core/math_types.h>
#include <extra2d/core/types.h> #include <extra2d/core/types.h>
#include <extra2d/event/event_dispatcher.h> #include <extra2d/event/event_dispatcher.h>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
#include <extra2d/scene/component.h> #include <extra2d/scene/component.h>
#include <extra2d/scene/components/transform_component.h> #include <extra2d/scene/components/transform_component.h>
#include <memory> #include <memory>
@ -15,7 +15,7 @@
namespace extra2d { namespace extra2d {
class Scene; class Scene;
class RenderBackend; class Renderer;
struct RenderCommand; struct RenderCommand;
class RenderQueue; class RenderQueue;
@ -450,9 +450,9 @@ public:
/** /**
* @brief * @brief
* @param renderer * @param renderer
*/ */
virtual void onRender(RenderBackend &renderer); virtual void onRender(Renderer &renderer);
/** /**
* @brief * @brief
@ -497,9 +497,9 @@ public:
/** /**
* @brief * @brief
* @param renderer * @param renderer
*/ */
void render(RenderBackend &renderer); void render(Renderer &renderer);
/** /**
* @brief * @brief
@ -535,9 +535,9 @@ public:
protected: protected:
/** /**
* @brief * @brief
* @param renderer * @param renderer
*/ */
virtual void onDraw(RenderBackend &renderer) {} virtual void onDraw(Renderer &renderer) {}
/** /**
* @brief * @brief

View File

@ -8,6 +8,7 @@
namespace extra2d { namespace extra2d {
class RenderQueue; class RenderQueue;
class Renderer;
/** /**
* @brief - * @brief -
@ -120,15 +121,15 @@ public:
/** /**
* @brief * @brief
* @param renderer * @param renderer
*/ */
void renderScene(RenderBackend &renderer); void renderScene(Renderer &renderer);
/** /**
* @brief * @brief
* @param renderer * @param renderer
*/ */
virtual void renderContent(RenderBackend &renderer); virtual void renderContent(Renderer &renderer);
/** /**
* @brief * @brief

View File

@ -14,6 +14,7 @@ namespace extra2d {
struct RenderCommand; struct RenderCommand;
class TransitionScene; class TransitionScene;
enum class TransitionType; enum class TransitionType;
class Renderer;
/** /**
* @brief - * @brief -
@ -102,7 +103,7 @@ public:
// 更新和渲染 // 更新和渲染
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void update(float dt); void update(float dt);
void render(RenderBackend &renderer); void render(Renderer &renderer);
void collectRenderCommands(std::vector<RenderCommand> &commands); void collectRenderCommands(std::vector<RenderCommand> &commands);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -84,7 +84,7 @@ public:
Rect getBounds() const override; Rect getBounds() const override;
protected: protected:
void onDraw(RenderBackend &renderer) override; void onDraw(Renderer &renderer) override;
void generateRenderCommand(std::vector<RenderCommand> &commands, void generateRenderCommand(std::vector<RenderCommand> &commands,
int zOrder) override; int zOrder) override;

View File

@ -40,7 +40,7 @@ public:
Rect getBounds() const override; Rect getBounds() const override;
protected: protected:
void onDraw(RenderBackend &renderer) override; void onDraw(Renderer &renderer) override;
void generateRenderCommand(std::vector<RenderCommand> &commands, void generateRenderCommand(std::vector<RenderCommand> &commands,
int zOrder) override; int zOrder) override;

View File

@ -4,6 +4,8 @@
namespace extra2d { namespace extra2d {
class Renderer;
// ============================================================================ // ============================================================================
// 方块/马赛克过渡场景 // 方块/马赛克过渡场景
// 实现原理: // 实现原理:
@ -25,7 +27,7 @@ public:
protected: protected:
void onTransitionStart() override; void onTransitionStart() override;
void renderContent(RenderBackend &renderer) override; void renderContent(Renderer &renderer) override;
void updateTransition(float dt) override; void updateTransition(float dt) override;
private: private:

View File

@ -5,6 +5,8 @@
namespace extra2d { namespace extra2d {
class Renderer;
// ============================================================================ // ============================================================================
// 淡入淡出过渡场景 // 淡入淡出过渡场景
// 实现原理: // 实现原理:
@ -44,7 +46,7 @@ protected:
* @brief * @brief
* *
*/ */
void renderContent(RenderBackend &renderer) override; void renderContent(Renderer &renderer) override;
private: private:
/** /**

View File

@ -4,6 +4,8 @@
namespace extra2d { namespace extra2d {
class Renderer;
// ============================================================================ // ============================================================================
// 翻页过渡场景 // 翻页过渡场景
// 实现原理: // 实现原理:
@ -28,7 +30,7 @@ public:
protected: protected:
void onTransitionStart() override; void onTransitionStart() override;
void renderContent(RenderBackend &renderer) override; void renderContent(Renderer &renderer) override;
void updateTransition(float dt) override; void updateTransition(float dt) override;
private: private:

View File

@ -4,6 +4,8 @@
namespace extra2d { namespace extra2d {
class Renderer;
// ============================================================================ // ============================================================================
// 缩放过渡场景 // 缩放过渡场景
// 实现原理: // 实现原理:
@ -23,7 +25,7 @@ public:
protected: protected:
void onTransitionStart() override; void onTransitionStart() override;
void renderContent(RenderBackend &renderer) override; void renderContent(Renderer &renderer) override;
void updateTransition(float dt) override; void updateTransition(float dt) override;
}; };

View File

@ -5,6 +5,8 @@
namespace extra2d { namespace extra2d {
class Renderer;
// ============================================================================ // ============================================================================
// 过渡方向 // 过渡方向
// ============================================================================ // ============================================================================
@ -99,7 +101,7 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 渲染 - 在 TransitionScene 上渲染新旧两个子场景 // 渲染 - 在 TransitionScene 上渲染新旧两个子场景
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void renderContent(RenderBackend &renderer) override; void renderContent(Renderer &renderer) override;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 生命周期 // 生命周期
@ -117,12 +119,12 @@ protected:
/** /**
* @brief * @brief
*/ */
virtual void drawOutScene(RenderBackend &renderer); virtual void drawOutScene(Renderer &renderer);
/** /**
* @brief * @brief
*/ */
virtual void drawInScene(RenderBackend &renderer); virtual void drawInScene(Renderer &renderer);
/** /**
* @brief * @brief

View File

@ -4,6 +4,8 @@
namespace extra2d { namespace extra2d {
class Renderer;
// ============================================================================ // ============================================================================
// 滑动过渡场景 // 滑动过渡场景
// 实现原理: // 实现原理:
@ -26,7 +28,7 @@ public:
protected: protected:
void onTransitionStart() override; void onTransitionStart() override;
void renderContent(RenderBackend &renderer) override; void renderContent(Renderer &renderer) override;
void updateTransition(float dt) override; void updateTransition(float dt) override;
private: private:

View File

@ -6,6 +6,8 @@
namespace extra2d { namespace extra2d {
class Renderer;
/** /**
* @brief * @brief
* 便Mock * 便Mock
@ -30,7 +32,7 @@ public:
virtual bool isEmpty() const = 0; virtual bool isEmpty() const = 0;
virtual bool hasScene(const std::string& name) const = 0; virtual bool hasScene(const std::string& name) const = 0;
virtual void render(RenderBackend& renderer) = 0; virtual void render(Renderer& renderer) = 0;
virtual void collectRenderCommands(std::vector<RenderCommand>& commands) = 0; virtual void collectRenderCommands(std::vector<RenderCommand>& commands) = 0;
virtual bool isTransitioning() const = 0; virtual bool isTransitioning() const = 0;
@ -72,7 +74,7 @@ public:
bool isEmpty() const override; bool isEmpty() const override;
bool hasScene(const std::string& name) const override; bool hasScene(const std::string& name) const override;
void render(RenderBackend& renderer) override; void render(Renderer& renderer) override;
void collectRenderCommands(std::vector<RenderCommand>& commands) override; void collectRenderCommands(std::vector<RenderCommand>& commands) override;
bool isTransitioning() const override; bool isTransitioning() const override;

View File

@ -5,7 +5,6 @@
#include <extra2d/platform/iwindow.h> #include <extra2d/platform/iwindow.h>
#include <extra2d/platform/window_module.h> #include <extra2d/platform/window_module.h>
#include <extra2d/render/camera/viewport_adapter.h> #include <extra2d/render/camera/viewport_adapter.h>
#include <extra2d/render/core/render_backend.h>
#include <extra2d/render/core/render_module.h> #include <extra2d/render/core/render_module.h>
#include <extra2d/render/renderer.h> #include <extra2d/render/renderer.h>
#include <extra2d/services/camera_service.h> #include <extra2d/services/camera_service.h>
@ -209,8 +208,8 @@ void Application::render() {
} }
auto sceneService = ServiceLocator::instance().getService<ISceneService>(); auto sceneService = ServiceLocator::instance().getService<ISceneService>();
if (sceneService && renderer->getBackend()) { if (sceneService) {
sceneService->render(*renderer->getBackend()); sceneService->render(*renderer);
} }
winMod->win()->swap(); winMod->win()->swap();
@ -221,9 +220,9 @@ IWindow *Application::window() {
return winMod ? winMod->win() : nullptr; return winMod ? winMod->win() : nullptr;
} }
RenderBackend *Application::renderer() { Renderer *Application::renderer() {
auto *renderMod = get<RenderModule>(); auto *renderMod = get<RenderModule>();
return renderMod ? (renderMod->getRenderer() ? renderMod->getRenderer()->getBackend() : nullptr) : nullptr; return renderMod ? renderMod->getRenderer() : nullptr;
} }
IInput *Application::input() { IInput *Application::input() {

View File

@ -5,7 +5,6 @@
#include <extra2d/platform/keys.h> #include <extra2d/platform/keys.h>
#include <extra2d/services/event_service.h> #include <extra2d/services/event_service.h>
#include <extra2d/services/logger_service.h> #include <extra2d/services/logger_service.h>
#include <glad/glad.h>
namespace extra2d { namespace extra2d {
@ -19,10 +18,6 @@ bool GLFWWindow::create(const std::string &title, int width, int height,
return false; return false;
} }
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE); glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_DEPTH_BITS, 24); glfwWindowHint(GLFW_DEPTH_BITS, 24);
glfwWindowHint(GLFW_STENCIL_BITS, 8); glfwWindowHint(GLFW_STENCIL_BITS, 8);
@ -65,17 +60,6 @@ bool GLFWWindow::create(const std::string &title, int width, int height,
} }
#endif #endif
glfwMakeContextCurrent(glfwWindow_);
if (!gladLoadGLES2Loader((GLADloadproc)glfwGetProcAddress)) {
E2D_LOG_ERROR("初始化 GLAD GLES2 失败");
glfwDestroyWindow(glfwWindow_);
glfwWindow_ = nullptr;
deinitGLFW();
return false;
}
glfwSwapInterval(vsync ? 1 : 0);
vsync_ = vsync; vsync_ = vsync;
glfwGetWindowSize(glfwWindow_, &width_, &height_); glfwGetWindowSize(glfwWindow_, &width_, &height_);
@ -194,10 +178,7 @@ void GLFWWindow::setFullscreen(bool fs) {
} }
void GLFWWindow::setVSync(bool vsync) { void GLFWWindow::setVSync(bool vsync) {
if (glfwWindow_) { vsync_ = vsync;
glfwSwapInterval(vsync ? 1 : 0);
vsync_ = vsync;
}
} }
void GLFWWindow::setVisible(bool visible) { void GLFWWindow::setVisible(bool visible) {

View File

@ -5,7 +5,6 @@
#include <extra2d/platform/keys.h> #include <extra2d/platform/keys.h>
#include <extra2d/services/event_service.h> #include <extra2d/services/event_service.h>
#include <extra2d/services/logger_service.h> #include <extra2d/services/logger_service.h>
#include <glad/glad.h>
namespace extra2d { namespace extra2d {
@ -24,20 +23,12 @@ bool SDL2Window::create(const std::string &title, int width, int height,
return false; return false;
} }
Uint32 flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE; Uint32 flags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE;
#ifdef __SWITCH__ #ifdef __SWITCH__
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
#endif #endif
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
sdlWindow_ = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED, sdlWindow_ = SDL_CreateWindow(title.c_str(), SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED, width, height, flags); SDL_WINDOWPOS_CENTERED, width, height, flags);
@ -47,27 +38,6 @@ bool SDL2Window::create(const std::string &title, int width, int height,
return false; return false;
} }
glContext_ = SDL_GL_CreateContext(sdlWindow_);
if (!glContext_) {
E2D_LOG_ERROR("创建 OpenGL 上下文失败: {}", SDL_GetError());
SDL_DestroyWindow(sdlWindow_);
sdlWindow_ = nullptr;
deinitSDL();
return false;
}
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
E2D_LOG_ERROR("初始化 GLAD 失败");
SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr;
SDL_DestroyWindow(sdlWindow_);
sdlWindow_ = nullptr;
deinitSDL();
return false;
}
SDL_GL_SetSwapInterval(vsync ? 1 : 0);
SDL_GetWindowSize(sdlWindow_, &width_, &height_); SDL_GetWindowSize(sdlWindow_, &width_, &height_);
fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; fullscreen_ = (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
vsync_ = vsync; vsync_ = vsync;
@ -81,7 +51,6 @@ bool SDL2Window::create(const std::string &title, int width, int height,
input_->init(); input_->init();
E2D_LOG_INFO("SDL2 窗口创建成功: {}x{}", width_, height_); E2D_LOG_INFO("SDL2 窗口创建成功: {}x{}", width_, height_);
E2D_LOG_INFO(" 平台: OpenGL ES 3.2");
return true; return true;
} }
@ -95,11 +64,6 @@ void SDL2Window::destroy() {
deinitCursors(); deinitCursors();
#endif #endif
if (glContext_) {
SDL_GL_DeleteContext(glContext_);
glContext_ = nullptr;
}
if (sdlWindow_) { if (sdlWindow_) {
SDL_DestroyWindow(sdlWindow_); SDL_DestroyWindow(sdlWindow_);
sdlWindow_ = nullptr; sdlWindow_ = nullptr;
@ -123,9 +87,6 @@ void SDL2Window::poll() {
} }
void SDL2Window::swap() { void SDL2Window::swap() {
if (sdlWindow_ && glContext_) {
SDL_GL_SwapWindow(sdlWindow_);
}
} }
bool SDL2Window::shouldClose() const { return shouldClose_; } bool SDL2Window::shouldClose() const { return shouldClose_; }
@ -169,10 +130,7 @@ void SDL2Window::setFullscreen(bool fs) {
} }
void SDL2Window::setVSync(bool vsync) { void SDL2Window::setVSync(bool vsync) {
if (glContext_) { vsync_ = vsync;
SDL_GL_SetSwapInterval(vsync ? 1 : 0);
vsync_ = vsync;
}
} }
void SDL2Window::setVisible(bool visible) { void SDL2Window::setVisible(bool visible) {
@ -313,10 +271,8 @@ void SDL2Window::deinitCursors() {
void SDL2Window::updateContentScale() { void SDL2Window::updateContentScale() {
if (sdlWindow_) { if (sdlWindow_) {
SDL_GetWindowSize(sdlWindow_, &width_, &height_); SDL_GetWindowSize(sdlWindow_, &width_, &height_);
int dw, dh; scaleX_ = 1.0f;
SDL_GL_GetDrawableSize(sdlWindow_, &dw, &dh); scaleY_ = 1.0f;
scaleX_ = dw > 0 ? static_cast<float>(dw) / width_ : 1.0f;
scaleY_ = dh > 0 ? static_cast<float>(dh) / height_ : 1.0f;
} }
} }

View File

@ -60,11 +60,6 @@ public:
*/ */
SDL_Window* sdlWindow() const { return sdlWindow_; } SDL_Window* sdlWindow() const { return sdlWindow_; }
/**
* @brief OpenGL
*/
SDL_GLContext glContext() const { return glContext_; }
private: private:
bool initSDL(); bool initSDL();
void deinitSDL(); void deinitSDL();
@ -75,7 +70,6 @@ private:
Key sdlScancodeToKey(int scancode); Key sdlScancodeToKey(int scancode);
SDL_Window* sdlWindow_ = nullptr; SDL_Window* sdlWindow_ = nullptr;
SDL_GLContext glContext_ = nullptr;
SDL_Cursor* sdlCursors_[7] = {}; SDL_Cursor* sdlCursors_[7] = {};
int currentCursor_ = 0; int currentCursor_ = 0;

View File

@ -1,521 +0,0 @@
#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 &center, float radius, const Color &color,
float lineWidth, uint32_t segments) {
if (!isValid()) {
return;
}
stats_.shapeCount++;
stats_.drawCalls++;
}
/**
* @brief
*/
void GLRenderBackend::fillCircle(const Vec2 &center, 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

View File

@ -6,6 +6,15 @@
#include <extra2d/render/backends/opengl/gl_context.h> #include <extra2d/render/backends/opengl/gl_context.h>
#include <extra2d/services/logger_service.h> #include <extra2d/services/logger_service.h>
#include <extra2d/platform/iwindow.h> #include <extra2d/platform/iwindow.h>
#ifdef E2D_BACKEND_GLFW
#include <GLFW/glfw3.h>
#endif
#ifdef E2D_BACKEND_SDL2
#include <SDL.h>
#endif
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
@ -28,10 +37,35 @@ bool GLRHIDevice::init(IWindow* window) {
} }
window_ = window; window_ = window;
if (!window_) {
E2D_LOG_ERROR("窗口不能为空");
return false;
}
// 初始化 OpenGL 上下文 // 尝试识别窗口类型并创建 OpenGL 上下文
if (!GLContext::get().init()) { void* nativeHandle = window_->native();
E2D_LOG_ERROR("初始化 OpenGL 上下文失败"); if (!nativeHandle) {
E2D_LOG_ERROR("无法获取原生窗口句柄");
return false;
}
// 首先尝试 GLFW 窗口(通过动态类型检查或已知的窗口类)
// 注意:这里我们需要通过某种方式识别窗口类型
// 由于没有 RTTI 信息,我们尝试两种方式
bool contextCreated = false;
// 先尝试 GLFW
if (initGLFWContext()) {
contextCreated = true;
}
// 如果 GLFW 失败,尝试 SDL2
else if (initSDL2Context()) {
contextCreated = true;
}
if (!contextCreated) {
E2D_LOG_ERROR("无法创建 OpenGL 上下文");
return false; return false;
} }
@ -62,12 +96,108 @@ void GLRHIDevice::shutdown() {
currentShader_.reset(); currentShader_.reset();
currentFramebuffer_.reset(); currentFramebuffer_.reset();
// 销毁 OpenGL 上下文
#ifdef E2D_BACKEND_SDL2
if (contextType_ == GLContextType::SDL2 && glContext_) {
SDL_GL_DeleteContext(static_cast<SDL_GLContext>(glContext_));
}
#endif
GLContext::get().shutdown(); GLContext::get().shutdown();
initialized_ = false; initialized_ = false;
contextType_ = GLContextType::None;
glfwWindow_ = nullptr;
sdlWindow_ = nullptr;
glContext_ = nullptr;
E2D_LOG_INFO("OpenGL RHI 设备已关闭"); E2D_LOG_INFO("OpenGL RHI 设备已关闭");
} }
bool GLRHIDevice::initGLFWContext() {
#ifdef E2D_BACKEND_GLFW
// 尝试将窗口句柄作为 GLFWwindow 使用
GLFWwindow* glfwWin = static_cast<GLFWwindow*>(window_->native());
if (!glfwWin) {
return false;
}
// 设置 OpenGL 上下文属性
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_DOUBLEBUFFER, GLFW_TRUE);
glfwWindowHint(GLFW_DEPTH_BITS, 24);
glfwWindowHint(GLFW_STENCIL_BITS, 8);
// 对于 GLFW我们需要重新创建带上下文的窗口
// 或者尝试使用当前窗口创建上下文
// 这里我们假设窗口已经存在,但没有 OpenGL 上下文
// 实际上GLFW 窗口创建时必须指定 API
// 所以我们需要一个不同的方法
// 这里我们简化处理,尝试直接使用 gladLoadGLLoader
glfwMakeContextCurrent(glfwWin);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
E2D_LOG_ERROR("初始化 GLAD 失败 (GLFW)");
return false;
}
glfwSwapInterval(window_->vsync() ? 1 : 0);
contextType_ = GLContextType::GLFW;
glfwWindow_ = glfwWin;
E2D_LOG_INFO("GLFW OpenGL 上下文创建成功");
return true;
#else
return false;
#endif
}
bool GLRHIDevice::initSDL2Context() {
#ifdef E2D_BACKEND_SDL2
// 尝试将窗口句柄作为 SDL_Window 使用
SDL_Window* sdlWin = static_cast<SDL_Window*>(window_->native());
if (!sdlWin) {
return false;
}
// 设置 OpenGL 属性
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 5);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
// 创建 OpenGL 上下文
SDL_GLContext context = SDL_GL_CreateContext(sdlWin);
if (!context) {
E2D_LOG_ERROR("创建 OpenGL 上下文失败 (SDL2): {}", SDL_GetError());
return false;
}
// 初始化 GLAD
if (!gladLoadGLLoader((GLADloadproc)SDL_GL_GetProcAddress)) {
E2D_LOG_ERROR("初始化 GLAD 失败 (SDL2)");
SDL_GL_DeleteContext(context);
return false;
}
SDL_GL_SetSwapInterval(window_->vsync() ? 1 : 0);
contextType_ = GLContextType::SDL2;
sdlWindow_ = sdlWin;
glContext_ = context;
E2D_LOG_INFO("SDL2 OpenGL 上下文创建成功");
return true;
#else
return false;
#endif
}
void GLRHIDevice::initCaps() { void GLRHIDevice::initCaps() {
caps_.api = GraphicsAPI::OpenGL; caps_.api = GraphicsAPI::OpenGL;
caps_.apiVersion = GLContext::get().getVersionString(); caps_.apiVersion = GLContext::get().getVersionString();
@ -124,16 +254,30 @@ void GLRHIDevice::endFrame() {
} }
void GLRHIDevice::present() { void GLRHIDevice::present() {
if (window_) { #ifdef E2D_BACKEND_GLFW
window_->swap(); if (contextType_ == GLContextType::GLFW && glfwWindow_) {
glfwSwapBuffers(static_cast<GLFWwindow*>(glfwWindow_));
} }
#endif
#ifdef E2D_BACKEND_SDL2
if (contextType_ == GLContextType::SDL2 && sdlWindow_) {
SDL_GL_SwapWindow(static_cast<SDL_Window*>(sdlWindow_));
}
#endif
} }
void GLRHIDevice::setVSync(bool enabled) { void GLRHIDevice::setVSync(bool enabled) {
vsyncEnabled_ = enabled; vsyncEnabled_ = enabled;
if (window_) { #ifdef E2D_BACKEND_GLFW
window_->setVSync(enabled); if (contextType_ == GLContextType::GLFW) {
glfwSwapInterval(enabled ? 1 : 0);
} }
#endif
#ifdef E2D_BACKEND_SDL2
if (contextType_ == GLContextType::SDL2) {
SDL_GL_SetSwapInterval(enabled ? 1 : 0);
}
#endif
} }
void GLRHIDevice::setDefaultFramebufferSize(uint32_t width, uint32_t height) { void GLRHIDevice::setDefaultFramebufferSize(uint32_t width, uint32_t height) {

View File

@ -1,262 +0,0 @@
#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

View File

@ -7,7 +7,6 @@ RenderContext::RenderContext()
: device_(nullptr), : device_(nullptr),
window_(nullptr), window_(nullptr),
queue_(), queue_(),
stats_(),
config_(), config_(),
currentBlend_(rhi::BlendState::alphaBlend()), currentBlend_(rhi::BlendState::alphaBlend()),
viewport_(), viewport_(),
@ -23,7 +22,6 @@ RenderContext::RenderContext(const RenderContextConfig& config)
: device_(nullptr), : device_(nullptr),
window_(nullptr), window_(nullptr),
queue_(), queue_(),
stats_(),
config_(config), config_(config),
currentBlend_(rhi::BlendState::alphaBlend()), currentBlend_(rhi::BlendState::alphaBlend()),
viewport_(), viewport_(),
@ -100,7 +98,6 @@ void RenderContext::beginFrame() {
return; return;
} }
stats_.reset();
device_->beginFrame(); device_->beginFrame();
device_->resetStats(); device_->resetStats();
@ -244,13 +241,6 @@ void RenderContext::flushQueue() {
const auto& commands = queue_.getCommands(); const auto& commands = queue_.getCommands();
const RenderQueueStats& queueStats = queue_.getStats(); const RenderQueueStats& queueStats = queue_.getStats();
stats_.spriteCount = queueStats.spriteCommands;
stats_.textCharCount = queueStats.textCommands;
stats_.shapeCount = queueStats.shapeCommands;
stats_.batchCount = queueStats.batchCount;
stats_.drawCalls = queueStats.drawCalls;
queue_.clear(); queue_.clear();
} }
@ -282,11 +272,4 @@ void RenderContext::initDefaultState() {
scissorEnabled_ = false; scissorEnabled_ = false;
} }
void RenderContext::resetStats() {
stats_.reset();
if (device_) {
device_->resetStats();
}
}
} // namespace extra2d } // namespace extra2d

View File

@ -1,19 +1,24 @@
#include <extra2d/render/renderer.h> #include <extra2d/render/renderer.h>
#include <extra2d/platform/iwindow.h> #include <extra2d/platform/iwindow.h>
#include <extra2d/render/core/backend_factory.h>
#include <extra2d/render/core/render_backend.h>
#include <extra2d/resources/shader_manager.h> #include <extra2d/resources/shader_manager.h>
#include <extra2d/scene/scene.h> #include <extra2d/scene/scene.h>
#include <glm/gtc/matrix_transform.hpp>
#include <cmath>
namespace extra2d { namespace extra2d {
Renderer::Renderer() Renderer::Renderer()
: window_(nullptr), width_(0), height_(0), initialized_(false) {} : window_(nullptr), config_(), width_(0), height_(0), initialized_(false),
projectionMatrix_(1.0f), viewMatrix_(1.0f), stats_(),
sortKey_(0), layer_(0), blendState_(rhi::BlendState::alphaBlend()),
inBatch_(false) {}
Renderer::Renderer(const RendererConfig &config) Renderer::Renderer(const RendererConfig &config)
: window_(nullptr), config_(config), width_(0), height_(0), : window_(nullptr), config_(config), width_(0), height_(0), initialized_(false),
initialized_(false) {} projectionMatrix_(1.0f), viewMatrix_(1.0f), stats_(),
sortKey_(0), layer_(0), blendState_(rhi::BlendState::alphaBlend()),
inBatch_(false) {}
Renderer::~Renderer() { shutdown(); } Renderer::~Renderer() { shutdown(); }
@ -38,36 +43,24 @@ bool Renderer::init(IWindow *window, const RendererConfig &config) {
viewportAdapter_.setConfig(config.viewportConfig); viewportAdapter_.setConfig(config.viewportConfig);
viewportAdapter_.update(width_, height_); viewportAdapter_.update(width_, height_);
RenderBackendConfig backendConfig; device_ = rhi::RHIDevice::create(config.api);
backendConfig.api = config.api; if (!device_ || !device_->init(window)) {
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; return false;
} }
RenderContextConfig contextConfig; spriteBatcher_ = makeUnique<SpriteBatcher>();
contextConfig.maxBatchSize = config.maxBatchSize; SpriteBatcherConfig batcherConfig;
contextConfig.preferredAPI = config.api; batcherConfig.maxBatchSize = config.maxBatchSize;
if (!spriteBatcher_->init(device_)) {
context_ = makeUnique<RenderContext>(contextConfig);
if (!context_->init(window, config.api)) {
return false; return false;
} }
auto& shaderManager = ShaderManager::getInstance(); renderQueue_ = makeUnique<RenderQueue>();
if (!shaderManager.isInitialized()) {
if (!shaderManager.init(context_->getDevice(), "shaders")) {
return false;
}
}
if (!createBatchers()) { projectionMatrix_ = glm::ortho(0.0f, static_cast<float>(width_),
return false; static_cast<float>(height_), 0.0f,
} -1.0f, 1.0f);
viewMatrix_ = glm::mat4(1.0f);
createDefaultCamera(); createDefaultCamera();
@ -80,11 +73,19 @@ void Renderer::shutdown() {
return; return;
} }
textBatcher_.reset(); if (spriteBatcher_) {
shapeBatcher_.reset(); spriteBatcher_->shutdown();
spriteBatcher_.reset(); spriteBatcher_.reset();
context_.reset(); }
backend_.reset();
if (renderQueue_) {
renderQueue_.reset();
}
if (device_) {
device_->shutdown();
device_.reset();
}
activeCamera_.reset(); activeCamera_.reset();
defaultCamera_.reset(); defaultCamera_.reset();
@ -96,88 +97,271 @@ void Renderer::shutdown() {
} }
void Renderer::beginFrame(const Color &clearColor) { void Renderer::beginFrame(const Color &clearColor) {
if (!initialized_) { if (!initialized_ || !device_) {
return; return;
} }
if (backend_) { stats_.reset();
backend_->beginFrame(clearColor); device_->beginFrame();
} device_->resetStats();
if (context_) { rhi::ColorValue cv(clearColor.r, clearColor.g, clearColor.b, clearColor.a);
context_->beginFrame(); device_->clearColor(cv);
context_->clear(clearColor);
} device_->setViewport(rhi::Viewport(0.0f, 0.0f,
static_cast<float>(width_),
static_cast<float>(height_)));
} }
void Renderer::endFrame() { void Renderer::endFrame() {
if (!initialized_) { if (!initialized_ || !device_) {
return; return;
} }
if (spriteBatcher_) { if (inBatch_) {
spriteBatcher_->end(); endSpriteBatch();
}
if (shapeBatcher_) {
shapeBatcher_->end();
}
if (textBatcher_) {
textBatcher_->end();
} }
if (context_) { device_->endFrame();
context_->endFrame();
}
if (backend_) {
backend_->endFrame();
}
} }
void Renderer::present() { void Renderer::present() {
if (!initialized_) { if (!initialized_ || !device_) {
return; return;
} }
if (backend_) { device_->present();
backend_->present();
}
if (context_) {
context_->present();
}
} }
void Renderer::renderScene(Scene *scene) { void Renderer::renderScene(Scene *scene) {
if (!initialized_ || !scene) { if (!initialized_ || !scene) {
return; return;
} }
Camera *camera = activeCamera_ ? activeCamera_.get() : defaultCamera_.get();
if (!camera) {
camera = scene->getActiveCamera();
}
renderScene(scene, camera);
} }
void Renderer::renderScene(Scene *scene, Camera *camera) { void Renderer::setViewport(int x, int y, int width, int height) {
if (!initialized_ || !scene) { if (!device_) {
return; return;
} }
if (!camera) { device_->setViewport(rhi::Viewport(
camera = defaultCamera_.get(); static_cast<float>(x),
static_cast<float>(y),
static_cast<float>(width),
static_cast<float>(height)));
}
void Renderer::setScissor(int x, int y, int width, int height) {
if (!device_) {
return;
} }
if (camera) { device_->setScissorRect(rhi::ScissorRect(x, y,
camera->setViewportAdapter(&viewportAdapter_); static_cast<uint32_t>(width),
camera->applyViewportAdapter(); static_cast<uint32_t>(height)));
}
void Renderer::setScissorEnabled(bool enabled) {
if (!device_) {
return;
} }
applyCameraTransform(camera); device_->setScissorEnabled(enabled);
}
scene->renderScene(*backend_); void Renderer::setProjectionMatrix(const glm::mat4 &matrix) {
projectionMatrix_ = matrix;
}
void Renderer::setViewMatrix(const glm::mat4 &matrix) {
viewMatrix_ = matrix;
}
void Renderer::setVSync(bool enabled) {
if (!device_) {
return;
}
device_->setVSync(enabled);
}
bool Renderer::isVSyncEnabled() const {
if (!device_) {
return false;
}
return device_->isVSyncEnabled();
}
void Renderer::drawSprite(Ptr<rhi::RHITexture> texture, const Rect &destRect,
const Rect &srcRect, const Color &color,
float rotation, bool flipX, bool flipY) {
if (!initialized_ || !texture || !spriteBatcher_) {
return;
}
stats_.spriteCount++;
if (!inBatch_) {
beginSpriteBatch();
}
Vec2 anchor(0.5f, 0.5f);
spriteBatcher_->draw(texture, destRect, srcRect, color, rotation, anchor, blendState_);
}
void Renderer::drawSprite(Ptr<rhi::RHITexture> texture,
const glm::mat4 &transform,
const Rect &srcRect, const Color &color) {
if (!initialized_ || !texture || !spriteBatcher_) {
return;
}
stats_.spriteCount++;
if (!inBatch_) {
beginSpriteBatch();
}
spriteBatcher_->draw(texture, srcRect, transform, color, blendState_);
}
void Renderer::draw9Slice(Ptr<rhi::RHITexture> texture, const Rect &destRect,
const Rect &srcRect, const Vec2 &borderSize,
const Color &color) {
if (!initialized_ || !texture) {
return;
}
stats_.spriteCount += 9;
}
void Renderer::drawText(const std::string &text, const Vec2 &position,
float fontSize, const Color &color) {
if (!initialized_ || text.empty()) {
return;
}
stats_.textCharCount += static_cast<uint32_t>(text.length());
}
void Renderer::drawText(const std::u32string &text, const Vec2 &position,
float fontSize, const Color &color) {
if (!initialized_ || text.empty()) {
return;
}
stats_.textCharCount += static_cast<uint32_t>(text.length());
}
Vec2 Renderer::measureText(const std::string &text, float fontSize) {
float width = static_cast<float>(text.length()) * fontSize * 0.6f;
return Vec2(width, fontSize);
}
Vec2 Renderer::measureText(const std::u32string &text, float fontSize) {
float width = static_cast<float>(text.length()) * fontSize * 0.6f;
return Vec2(width, fontSize);
}
void Renderer::drawRect(const Rect &rect, const Color &color, float lineWidth) {
if (!initialized_) {
return;
}
stats_.shapeCount++;
}
void Renderer::fillRect(const Rect &rect, const Color &color) {
if (!initialized_) {
return;
}
stats_.shapeCount++;
}
void Renderer::drawCircle(const Vec2 &center, float radius, const Color &color,
float lineWidth, uint32_t segments) {
if (!initialized_) {
return;
}
stats_.shapeCount++;
}
void Renderer::fillCircle(const Vec2 &center, float radius, const Color &color,
uint32_t segments) {
if (!initialized_) {
return;
}
stats_.shapeCount++;
}
void Renderer::drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
float lineWidth) {
if (!initialized_) {
return;
}
stats_.shapeCount++;
}
void Renderer::drawPolygon(const Vec2 *points, size_t count, const Color &color,
float lineWidth) {
if (!initialized_ || !points || count < 3) {
return;
}
stats_.shapeCount++;
}
void Renderer::fillPolygon(const Vec2 *points, size_t count,
const Color &color) {
if (!initialized_ || !points || count < 3) {
return;
}
stats_.shapeCount++;
}
void Renderer::beginSpriteBatch() {
if (!initialized_ || !spriteBatcher_ || inBatch_) {
return;
}
inBatch_ = true;
spriteBatcher_->begin(projectionMatrix_ * viewMatrix_);
}
void Renderer::endSpriteBatch() {
if (!initialized_ || !spriteBatcher_ || !inBatch_) {
return;
}
spriteBatcher_->end();
inBatch_ = false;
stats_.batchCount++;
stats_.drawCalls += spriteBatcher_->getDrawCallCount();
}
void Renderer::flush() {
if (!initialized_ || !spriteBatcher_) {
return;
}
stats_.batchCount++;
}
void Renderer::setSortKey(uint64_t key) {
sortKey_ = key;
}
void Renderer::setLayer(int layer) {
layer_ = layer;
}
void Renderer::setBlendMode(rhi::BlendState blend) {
blendState_ = blend;
} }
void Renderer::setActiveCamera(Ptr<Camera> camera) { activeCamera_ = camera; } void Renderer::setActiveCamera(Ptr<Camera> camera) { activeCamera_ = camera; }
@ -186,88 +370,26 @@ Ptr<Camera> Renderer::getActiveCamera() const {
return activeCamera_ ? activeCamera_ : defaultCamera_; return activeCamera_ ? activeCamera_ : defaultCamera_;
} }
void Renderer::setViewport(int x, int y, int width, int height) { rhi::GraphicsAPI Renderer::getAPI() const {
if (context_) { if (!device_) {
context_->setViewport(x, y, width, height); return rhi::GraphicsAPI::OpenGL;
}
if (backend_) {
backend_->setViewport(x, y, width, height);
} }
return device_->getAPI();
} }
void Renderer::setScissor(int x, int y, int width, int height) { const rhi::DeviceCaps &Renderer::getCaps() const {
if (context_) { static rhi::DeviceCaps empty;
context_->setScissorRect(x, y, width, height); return device_ ? device_->getCaps() : empty;
}
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 { const RenderStats &Renderer::getStats() const {
if (backend_) { return stats_;
return backend_->getStats();
}
if (context_) {
return context_->getStats();
}
static RenderStats empty;
return empty;
} }
void Renderer::resetStats() { void Renderer::resetStats() {
if (backend_) { stats_.reset();
backend_->resetStats(); if (device_) {
} device_->resetStats();
if (context_) {
context_->resetStats();
}
if (spriteBatcher_) {
spriteBatcher_->resetStats();
}
if (shapeBatcher_) {
shapeBatcher_->resetStats();
}
if (textBatcher_) {
textBatcher_->resetStats();
} }
} }
@ -277,41 +399,6 @@ void Renderer::setConfig(const RendererConfig &config) {
updateViewportAdapter(); 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() { void Renderer::createDefaultCamera() {
float designWidth = viewportAdapter_.getDesignWidth(); float designWidth = viewportAdapter_.getDesignWidth();
float designHeight = viewportAdapter_.getDesignHeight(); float designHeight = viewportAdapter_.getDesignHeight();
@ -326,30 +413,6 @@ void Renderer::updateViewportAdapter() {
viewportAdapter_.update(width_, height_); 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) { Ptr<Renderer> Renderer::create(const RendererConfig &config) {
return makePtr<Renderer>(config); return makePtr<Renderer>(config);
} }

View File

@ -568,9 +568,9 @@ void Node::onUpdate(float dt) {
/** /**
* @brief * @brief
* @param renderer * @param renderer
*/ */
void Node::onRender(RenderBackend &renderer) { void Node::onRender(Renderer &renderer) {
if (!visible_) if (!visible_)
return; return;
@ -620,9 +620,9 @@ void Node::update(float dt) { onUpdate(dt); }
/** /**
* @brief * @brief
* @param renderer * @param renderer
*/ */
void Node::render(RenderBackend &renderer) { void Node::render(Renderer &renderer) {
if (childrenOrderDirty_) { if (childrenOrderDirty_) {
sortChildren(); sortChildren();
} }

View File

@ -1,5 +1,5 @@
#include <extra2d/core/service_locator.h> #include <extra2d/core/service_locator.h>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
#include <extra2d/render/core/render_command.h> #include <extra2d/render/core/render_command.h>
#include <extra2d/render/core/render_queue.h> #include <extra2d/render/core/render_queue.h>
#include <extra2d/scene/scene.h> #include <extra2d/scene/scene.h>
@ -46,11 +46,11 @@ void Scene::setViewportSize(const Size &size) {
/** /**
* @brief * @brief
* @param renderer * @param renderer
* *
* *
*/ */
void Scene::renderScene(RenderBackend &renderer) { void Scene::renderScene(Renderer &renderer) {
if (!isVisible()) if (!isVisible())
return; return;
@ -61,11 +61,11 @@ void Scene::renderScene(RenderBackend &renderer) {
/** /**
* @brief * @brief
* @param renderer * @param renderer
* *
* *
*/ */
void Scene::renderContent(RenderBackend &renderer) { void Scene::renderContent(Renderer &renderer) {
if (!isVisible()) if (!isVisible())
return; return;

View File

@ -1,7 +1,7 @@
#include <algorithm> #include <algorithm>
#include <extra2d/app/application.h> #include <extra2d/app/application.h>
#include <extra2d/core/service_locator.h> #include <extra2d/core/service_locator.h>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
#include <extra2d/render/core/render_command.h> #include <extra2d/render/core/render_command.h>
#include <extra2d/platform/iinput.h> #include <extra2d/platform/iinput.h>
#include <extra2d/scene/scene_manager.h> #include <extra2d/scene/scene_manager.h>
@ -565,11 +565,11 @@ void SceneManager::update(float dt) {
/** /**
* @brief * @brief
* @param renderer * @param renderer
* *
* 使 * 使
*/ */
void SceneManager::render(RenderBackend &renderer) { void SceneManager::render(Renderer &renderer) {
Color clearColor = Colors::Black; Color clearColor = Colors::Black;
if (!sceneStack_.empty()) { if (!sceneStack_.empty()) {
clearColor = sceneStack_.top()->getBackgroundColor(); clearColor = sceneStack_.top()->getBackgroundColor();

View File

@ -1,6 +1,6 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
#include <extra2d/render/core/render_command.h> #include <extra2d/render/core/render_command.h>
#include <extra2d/scene/shape_node.h> #include <extra2d/scene/shape_node.h>
#include <limits> #include <limits>
@ -259,13 +259,13 @@ Rect ShapeNode::getBounds() const {
/** /**
* @brief * @brief
* @param renderer * @param renderer
* *
* *
* Node::onRender pushTransform * Node::onRender pushTransform
* 使 * 使
*/ */
void ShapeNode::onDraw(RenderBackend &renderer) { void ShapeNode::onDraw(Renderer &renderer) {
if (points_.empty()) { if (points_.empty()) {
return; return;
} }

View File

@ -1,6 +1,6 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
#include <extra2d/render/core/render_command.h> #include <extra2d/render/core/render_command.h>
#include <extra2d/scene/sprite.h> #include <extra2d/scene/sprite.h>
@ -122,11 +122,11 @@ Rect Sprite::getBounds() const {
/** /**
* @brief * @brief
* @param renderer * @param renderer
* *
* 使 * 使
*/ */
void Sprite::onDraw(RenderBackend &renderer) { void Sprite::onDraw(Renderer &renderer) {
if (!texture_ || !texture_->isValid()) { if (!texture_ || !texture_->isValid()) {
return; return;
} }
@ -148,7 +148,7 @@ void Sprite::onDraw(RenderBackend &renderer) {
float worldScaleY = float worldScaleY =
glm::length(glm::vec2(worldTransform[1][0], worldTransform[1][1])); glm::length(glm::vec2(worldTransform[1][0], worldTransform[1][1]));
// 锚点由 RenderBackend 在绘制时处理,这里只传递位置和尺寸 // 锚点由 Renderer 在绘制时处理,这里只传递位置和尺寸
Rect destRect(worldX, worldY, width * worldScaleX, height * worldScaleY); Rect destRect(worldX, worldY, width * worldScaleX, height * worldScaleY);
// Adjust source rect for flipping // Adjust source rect for flipping
@ -201,7 +201,7 @@ void Sprite::generateRenderCommand(std::vector<RenderCommand> &commands,
auto anchor = getAnchor(); auto anchor = getAnchor();
// 锚点由 RenderBackend 在绘制时处理,这里只传递位置和尺寸 // 锚点由 Renderer 在绘制时处理,这里只传递位置和尺寸
Rect destRect(worldX, worldY, width * worldScaleX, height * worldScaleY); Rect destRect(worldX, worldY, width * worldScaleX, height * worldScaleY);
// 调整源矩形(翻转) // 调整源矩形(翻转)

View File

@ -1,7 +1,7 @@
#include <extra2d/scene/transition_box_scene.h> #include <extra2d/scene/transition_box_scene.h>
#include <extra2d/app/application.h> #include <extra2d/app/application.h>
#include <extra2d/core/color.h> #include <extra2d/core/color.h>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
#include <extra2d/platform/iwindow.h> #include <extra2d/platform/iwindow.h>
#include <algorithm> #include <algorithm>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
@ -49,11 +49,11 @@ void TransitionBoxScene::updateTransition(float dt) {
/** /**
* @brief * @brief
* @param renderer * @param renderer
* *
* *
*/ */
void TransitionBoxScene::renderContent(RenderBackend &renderer) { void TransitionBoxScene::renderContent(Renderer &renderer) {
auto &app = Application::get(); auto &app = Application::get();
float windowWidth = static_cast<float>(app.window()->width()); float windowWidth = static_cast<float>(app.window()->width());
float windowHeight = static_cast<float>(app.window()->height()); float windowHeight = static_cast<float>(app.window()->height());

View File

@ -1,6 +1,6 @@
#include <extra2d/app/application.h> #include <extra2d/app/application.h>
#include <extra2d/core/service_locator.h> #include <extra2d/core/service_locator.h>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
#include <extra2d/platform/iwindow.h> #include <extra2d/platform/iwindow.h>
#include <extra2d/scene/transition_fade_scene.h> #include <extra2d/scene/transition_fade_scene.h>
#include <extra2d/services/logger_service.h> #include <extra2d/services/logger_service.h>
@ -50,7 +50,7 @@ void TransitionFadeScene::updateTransition(float dt) {
} }
} }
void TransitionFadeScene::renderContent(RenderBackend &renderer) { void TransitionFadeScene::renderContent(Renderer &renderer) {
auto &app = Application::get(); auto &app = Application::get();
float windowWidth = static_cast<float>(app.window()->width()); float windowWidth = static_cast<float>(app.window()->width());
float windowHeight = static_cast<float>(app.window()->height()); float windowHeight = static_cast<float>(app.window()->height());

View File

@ -1,7 +1,7 @@
#include <extra2d/scene/transition_flip_scene.h> #include <extra2d/scene/transition_flip_scene.h>
#include <extra2d/core/math_types.h> #include <extra2d/core/math_types.h>
#include <extra2d/render/camera/camera.h> #include <extra2d/render/camera/camera.h>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
namespace extra2d { namespace extra2d {
@ -46,11 +46,11 @@ void TransitionFlipScene::updateTransition(float dt) {
/** /**
* @brief * @brief
* @param renderer * @param renderer
* *
* *
*/ */
void TransitionFlipScene::renderContent(RenderBackend &renderer) { void TransitionFlipScene::renderContent(Renderer &renderer) {
float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_ float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_
: -1.0f + (4.0f - 2.0f * progress_) * progress_; : -1.0f + (4.0f - 2.0f * progress_) * progress_;

View File

@ -1,6 +1,6 @@
#include <extra2d/scene/transition_scale_scene.h> #include <extra2d/scene/transition_scale_scene.h>
#include <extra2d/render/camera/camera.h> #include <extra2d/render/camera/camera.h>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
#include <algorithm> #include <algorithm>
namespace extra2d { namespace extra2d {
@ -42,11 +42,11 @@ void TransitionScaleScene::updateTransition(float dt) {
/** /**
* @brief * @brief
* @param renderer * @param renderer
* *
* *
*/ */
void TransitionScaleScene::renderContent(RenderBackend &renderer) { void TransitionScaleScene::renderContent(Renderer &renderer) {
float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_ float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_
: -1.0f + (4.0f - 2.0f * progress_) * progress_; : -1.0f + (4.0f - 2.0f * progress_) * progress_;

View File

@ -1,5 +1,5 @@
#include <extra2d/core/service_locator.h> #include <extra2d/core/service_locator.h>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
#include <extra2d/scene/transition_scene.h> #include <extra2d/scene/transition_scene.h>
#include <extra2d/services/logger_service.h> #include <extra2d/services/logger_service.h>
@ -115,20 +115,20 @@ void TransitionScene::cancel(bool immediate) {
/** /**
* @brief * @brief
* @param renderer * @param renderer
* *
* 退 * 退
*/ */
void TransitionScene::renderContent(RenderBackend &renderer) { void TransitionScene::renderContent(Renderer &renderer) {
drawOutScene(renderer); drawOutScene(renderer);
drawInScene(renderer); drawInScene(renderer);
} }
/** /**
* @brief 退 * @brief 退
* @param renderer * @param renderer
*/ */
void TransitionScene::drawOutScene(RenderBackend &renderer) { void TransitionScene::drawOutScene(Renderer &renderer) {
if (outScene_) { if (outScene_) {
outScene_->renderContent(renderer); outScene_->renderContent(renderer);
} }
@ -136,9 +136,9 @@ void TransitionScene::drawOutScene(RenderBackend &renderer) {
/** /**
* @brief * @brief
* @param renderer * @param renderer
*/ */
void TransitionScene::drawInScene(RenderBackend &renderer) { void TransitionScene::drawInScene(Renderer &renderer) {
if (inScene_) { if (inScene_) {
inScene_->renderContent(renderer); inScene_->renderContent(renderer);
} }

View File

@ -1,6 +1,6 @@
#include <extra2d/scene/transition_slide_scene.h> #include <extra2d/scene/transition_slide_scene.h>
#include <extra2d/render/camera/camera.h> #include <extra2d/render/camera/camera.h>
#include <extra2d/render/core/render_backend.h> #include <extra2d/render/renderer.h>
#include <algorithm> #include <algorithm>
namespace extra2d { namespace extra2d {
@ -45,11 +45,11 @@ void TransitionSlideScene::updateTransition(float dt) {
/** /**
* @brief * @brief
* @param renderer * @param renderer
* *
* *
*/ */
void TransitionSlideScene::renderContent(RenderBackend &renderer) { void TransitionSlideScene::renderContent(Renderer &renderer) {
float screenWidth = 800.0f; float screenWidth = 800.0f;
float screenHeight = 600.0f; float screenHeight = 600.0f;

View File

@ -1,4 +1,5 @@
#include <extra2d/services/scene_service.h> #include <extra2d/services/scene_service.h>
#include <extra2d/render/renderer.h>
namespace extra2d { namespace extra2d {
@ -68,7 +69,7 @@ bool SceneService::hasScene(const std::string &name) const {
return manager_.hasScene(name); return manager_.hasScene(name);
} }
void SceneService::render(RenderBackend &renderer) { void SceneService::render(Renderer &renderer) {
manager_.render(renderer); manager_.render(renderer);
} }

View File

@ -34,8 +34,6 @@ function define_extra2d_engine()
-- 渲染后端源文件 -- 渲染后端源文件
local render_backend = get_render_backend() local render_backend = get_render_backend()
-- 渲染后端工厂
add_files("Extra2D/src/render/core/backend_factory.cpp")
if render_backend == "vulkan" then if render_backend == "vulkan" then
add_files("Extra2D/src/render/backends/vulkan/*.cpp") add_files("Extra2D/src/render/backends/vulkan/*.cpp")
add_defines("E2D_BACKEND_VULKAN") add_defines("E2D_BACKEND_VULKAN")