refactor(渲染器): 将RenderBackend重命名为Renderer并重构相关代码

重构渲染器接口命名,将RenderBackend统一更名为Renderer,同时更新所有相关文件和文档引用。此变更旨在提供更简洁清晰的接口命名,并保持代码一致性。

- 重命名RenderBackend类为Renderer
- 更新所有相关文件中的类型引用和文档
- 保持原有功能不变,仅进行命名和结构调整
- 修复因重命名导致的编译错误和警告
This commit is contained in:
ChestnutYueyue 2026-02-20 15:04:21 +08:00
parent b34df8bdd1
commit 9e911db53c
40 changed files with 749 additions and 914 deletions

View File

@ -9,7 +9,7 @@
namespace extra2d { namespace extra2d {
class GLFWWindow; class GLFWWindow;
class RenderBackend; class Renderer;
class WindowModule; class WindowModule;
class RenderModule; class RenderModule;
@ -91,7 +91,7 @@ public:
* @brief * @brief
* @return * @return
*/ */
RenderBackend *renderer(); Renderer *renderer();
/** /**
* @brief * @brief

View File

@ -20,10 +20,10 @@
// Graphics // Graphics
#include <extra2d/graphics/camera/camera.h> #include <extra2d/graphics/camera/camera.h>
#include <extra2d/graphics/camera/viewport_adapter.h> #include <extra2d/graphics/camera/viewport_adapter.h>
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_module.h> #include <extra2d/graphics/core/render_module.h>
#include <extra2d/graphics/core/render_target.h> #include <extra2d/graphics/core/render_target.h>
#include <extra2d/graphics/memory/vram_manager.h> #include <extra2d/graphics/memory/vram_manager.h>
#include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/graphics/shader/shader_manager.h> #include <extra2d/graphics/shader/shader_manager.h>
#include <extra2d/graphics/texture/font.h> #include <extra2d/graphics/texture/font.h>
#include <extra2d/graphics/texture/texture.h> #include <extra2d/graphics/texture/texture.h>

View File

@ -1,125 +0,0 @@
#pragma once
#include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/resources/pipeline.h>
#include <glm/mat4x4.hpp>
namespace extra2d {
// 前向声明
class GLFWWindow;
class Texture;
class FontAtlas;
class Shader;
// BlendMode 定义在 pipeline.h 中
// ============================================================================
// 渲染后端抽象接口
// ============================================================================
class RenderBackend {
public:
virtual ~RenderBackend() = default;
// ------------------------------------------------------------------------
// 生命周期
// ------------------------------------------------------------------------
virtual bool init(GLFWWindow* window) = 0;
virtual void shutdown() = 0;
// ------------------------------------------------------------------------
// 帧管理
// ------------------------------------------------------------------------
virtual void beginFrame(const Color &clearColor) = 0;
virtual void endFrame() = 0;
virtual void setViewport(int x, int y, int width, int height) = 0;
virtual void setVSync(bool enabled) = 0;
// ------------------------------------------------------------------------
// 状态设置
// ------------------------------------------------------------------------
virtual void setBlendMode(BlendMode mode) = 0;
virtual void setViewProjection(const glm::mat4 &matrix) = 0;
// ------------------------------------------------------------------------
// 变换矩阵栈
// ------------------------------------------------------------------------
virtual void pushTransform(const glm::mat4 &transform) = 0;
virtual void popTransform() = 0;
virtual glm::mat4 getCurrentTransform() const = 0;
// ------------------------------------------------------------------------
// 纹理
// ------------------------------------------------------------------------
virtual Ptr<Texture> createTexture(int width, int height,
const uint8_t *pixels, int channels) = 0;
virtual Ptr<Texture> loadTexture(const std::string &filepath) = 0;
// ------------------------------------------------------------------------
// 精灵批渲染
// ------------------------------------------------------------------------
/**
* @brief
* @note drawSprite/drawText
*/
virtual void beginSpriteBatch() = 0;
virtual void drawSprite(const Texture &texture, const Rect &destRect,
const Rect &srcRect, const Color &tint,
float rotation, const Vec2 &anchor) = 0;
virtual void drawSprite(const Texture &texture, const Vec2 &position,
const Color &tint) = 0;
virtual void endSpriteBatch() = 0;
/**
* @brief
* @note
*/
virtual void flush() = 0;
// ------------------------------------------------------------------------
// 形状渲染
// ------------------------------------------------------------------------
virtual void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
float width = 1.0f) = 0;
virtual void drawRect(const Rect &rect, const Color &color,
float width = 1.0f) = 0;
virtual void fillRect(const Rect &rect, const Color &color) = 0;
virtual void drawCircle(const Vec2 &center, float radius, const Color &color,
int segments = 32, float width = 1.0f) = 0;
virtual void fillCircle(const Vec2 &center, float radius, const Color &color,
int segments = 32) = 0;
virtual void drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color, float width = 1.0f) = 0;
virtual void fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color) = 0;
virtual void drawPolygon(const std::vector<Vec2> &points, const Color &color,
float width = 1.0f) = 0;
virtual void fillPolygon(const std::vector<Vec2> &points,
const Color &color) = 0;
// ------------------------------------------------------------------------
// 文字渲染
// ------------------------------------------------------------------------
virtual Ptr<FontAtlas> createFontAtlas(const std::string &filepath,
int fontSize, bool useSDF = false) = 0;
virtual void drawText(const FontAtlas &font, const std::string &text,
const Vec2 &position, const Color &color) = 0;
virtual void drawText(const FontAtlas &font, const std::string &text, float x,
float y, const Color &color) = 0;
// ------------------------------------------------------------------------
// 统计信息
// ------------------------------------------------------------------------
struct Stats {
uint32_t drawCalls = 0;
uint32_t triangleCount = 0;
uint32_t textureBinds = 0;
uint32_t shaderBinds = 0;
};
virtual Stats getStats() const = 0;
virtual void resetStats() = 0;
};
} // namespace extra2d

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <extra2d/core/module.h> #include <extra2d/core/module.h>
#include <extra2d/graphics/core/render_backend.h> #include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/platform/window_module.h> #include <extra2d/platform/window_module.h>
#include <functional> #include <functional>
#include <typeindex> #include <typeindex>
@ -12,67 +12,62 @@ namespace extra2d {
* @brief * @brief
*/ */
struct RenderCfg { struct RenderCfg {
int targetFPS; int targetFPS;
bool vsync; bool vsync;
int multisamples; int multisamples;
int priority; int priority;
RenderCfg() RenderCfg() : targetFPS(60), vsync(true), multisamples(0), priority(10) {}
: targetFPS(60)
, vsync(true)
, multisamples(0)
, priority(10)
{}
}; };
/** /**
* @brief * @brief
* OpenGL * OpenGL
*/ */
class RenderModule : public Module { class RenderModule : public Module {
public: public:
/** /**
* @brief Lambda * @brief Lambda
* @param configFn * @param configFn
*/ */
explicit RenderModule(std::function<void(RenderCfg&)> configFn); explicit RenderModule(std::function<void(RenderCfg &)> configFn);
/** /**
* @brief * @brief
*/ */
~RenderModule() override; ~RenderModule() override;
bool init() override; bool init() override;
void shutdown() override; void shutdown() override;
bool ok() const override { return initialized_; } bool ok() const override { return initialized_; }
const char* name() const override { return "render"; } const char *name() const override { return "render"; }
int priority() const override { return cfg_.priority; } int priority() const override { return cfg_.priority; }
/** /**
* @brief * @brief
* @return * @return
*/ */
std::vector<std::type_index> deps() const override { std::vector<std::type_index> deps() const override {
return {std::type_index(typeid(WindowModule))}; return {std::type_index(typeid(WindowModule))};
} }
/** /**
* @brief * @brief
* RenderModule OpenGL 线 * RenderModule OpenGL 线
* @return false * @return false
*/ */
bool allowParallelInit() const override { return false; } bool allowParallelInit() const override { return false; }
/** /**
* @brief * @brief
* @return * @return
*/ */
RenderBackend* renderer() const { return renderer_.get(); } Renderer *renderer() const { return renderer_.get(); }
private: private:
RenderCfg cfg_; RenderCfg cfg_;
UniquePtr<RenderBackend> renderer_; UniquePtr<Renderer> renderer_;
bool initialized_ = false; bool initialized_ = false;
}; };
} // namespace extra2d } // namespace extra2d

View File

@ -1,132 +1,111 @@
#pragma once #pragma once
#include <extra2d/graphics/core/render_backend.h> #include <extra2d/core/color.h>
#include <extra2d/core/math_types.h>
#include <extra2d/core/types.h>
#include <extra2d/graphics/opengl/gl_buffer.h> #include <extra2d/graphics/opengl/gl_buffer.h>
#include <extra2d/graphics/opengl/gl_framebuffer.h> #include <extra2d/graphics/opengl/gl_framebuffer.h>
#include <extra2d/graphics/opengl/gl_pipeline.h> #include <extra2d/graphics/opengl/gl_pipeline.h>
#include <extra2d/graphics/opengl/gl_sprite_batch.h> #include <extra2d/graphics/opengl/gl_sprite_batch.h>
#include <extra2d/graphics/resources/pipeline.h>
#include <extra2d/graphics/shader/shader_interface.h> #include <extra2d/graphics/shader/shader_interface.h>
#include <array> #include <array>
#include <glad/glad.h> #include <glad/glad.h>
#include <glm/mat4x4.hpp>
#include <vector> #include <vector>
namespace extra2d { namespace extra2d {
// 前向声明
class GLFWWindow; class GLFWWindow;
class GLContext; class GLContext;
class GLFramebuffer; class GLFramebuffer;
class FontAtlas;
// ============================================================================ /**
// OpenGL 渲染器实现 * @brief
// ============================================================================ */
class GLRenderer : public RenderBackend { struct RenderStats {
uint32_t drawCalls = 0;
uint32_t triangleCount = 0;
uint32_t textureBinds = 0;
uint32_t shaderBinds = 0;
};
/**
* @brief OpenGL
*/
class Renderer {
public: public:
GLRenderer(); Renderer();
~GLRenderer() override; ~Renderer();
// RenderBackend 接口实现 bool init(GLFWWindow *window);
bool init(GLFWWindow *window) override; void shutdown();
void shutdown() override;
void beginFrame(const Color &clearColor) override; void beginFrame(const Color &clearColor);
void endFrame() override; void endFrame();
void setViewport(int x, int y, int width, int height) override; void setViewport(int x, int y, int width, int height);
void setVSync(bool enabled) override; void setVSync(bool enabled);
void setBlendMode(BlendMode mode) override; void setBlendMode(BlendMode mode);
void setViewProjection(const glm::mat4 &matrix) override; void setViewProjection(const glm::mat4 &matrix);
// 变换矩阵栈 void pushTransform(const glm::mat4 &transform);
void pushTransform(const glm::mat4 &transform) override; void popTransform();
void popTransform() override; glm::mat4 getCurrentTransform() const;
glm::mat4 getCurrentTransform() const override;
Ptr<Texture> createTexture(int width, int height, const uint8_t *pixels, Ptr<Texture> createTexture(int width, int height, const uint8_t *pixels,
int channels) override; int channels);
Ptr<Texture> loadTexture(const std::string &filepath) override; Ptr<Texture> loadTexture(const std::string &filepath);
void beginSpriteBatch() override; void beginSpriteBatch();
void drawSprite(const Texture &texture, const Rect &destRect, void drawSprite(const Texture &texture, const Rect &destRect,
const Rect &srcRect, const Color &tint, float rotation, const Rect &srcRect, const Color &tint, float rotation,
const Vec2 &anchor) override; const Vec2 &anchor);
void drawSprite(const Texture &texture, const Vec2 &position, void drawSprite(const Texture &texture, const Vec2 &position,
const Color &tint) override; const Color &tint);
void endSpriteBatch() override; void endSpriteBatch();
void flush() override; void flush();
void drawLine(const Vec2 &start, const Vec2 &end, const Color &color, void drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
float width) override; float width = 1.0f);
void drawRect(const Rect &rect, const Color &color, float width) override; void drawRect(const Rect &rect, const Color &color, float width = 1.0f);
void fillRect(const Rect &rect, const Color &color) override; void fillRect(const Rect &rect, const Color &color);
void drawCircle(const Vec2 &center, float radius, const Color &color, void drawCircle(const Vec2 &center, float radius, const Color &color,
int segments, float width) override; int segments = 32, float width = 1.0f);
void fillCircle(const Vec2 &center, float radius, const Color &color, void fillCircle(const Vec2 &center, float radius, const Color &color,
int segments) override; int segments = 32);
void drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, void drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color, float width) override; const Color &color, float width = 1.0f);
void fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, void fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color) override; const Color &color);
void drawPolygon(const std::vector<Vec2> &points, const Color &color, void drawPolygon(const std::vector<Vec2> &points, const Color &color,
float width) override; float width = 1.0f);
void fillPolygon(const std::vector<Vec2> &points, void fillPolygon(const std::vector<Vec2> &points, const Color &color);
const Color &color) override;
Ptr<FontAtlas> createFontAtlas(const std::string &filepath, int fontSize, Ptr<FontAtlas> createFontAtlas(const std::string &filepath, int fontSize,
bool useSDF = false) override; bool useSDF = false);
void drawText(const FontAtlas &font, const std::string &text, void drawText(const FontAtlas &font, const std::string &text,
const Vec2 &position, const Color &color) override; const Vec2 &position, const Color &color);
void drawText(const FontAtlas &font, const std::string &text, float x, void drawText(const FontAtlas &font, const std::string &text, float x,
float y, const Color &color) override; float y, const Color &color);
Stats getStats() const override { return stats_; } RenderStats getStats() const { return stats_; }
void resetStats() override; void resetStats();
// GLFramebuffer 相关方法
/**
* @brief
* @param desc
* @return
*/
Ptr<GLFramebuffer> createFramebuffer(const FramebufferDesc &desc); Ptr<GLFramebuffer> createFramebuffer(const FramebufferDesc &desc);
/**
* @brief
* @param framebuffer nullptr
*/
void bindFramebuffer(GLFramebuffer *framebuffer); void bindFramebuffer(GLFramebuffer *framebuffer);
/**
* @brief
*/
void unbindFramebuffer(); void unbindFramebuffer();
/**
* @brief
* @return
*/
Ptr<GLFramebuffer> getDefaultFramebuffer() const; Ptr<GLFramebuffer> getDefaultFramebuffer() const;
/**
* @brief
* @param color
* @param clearColor
* @param clearDepth
* @param clearStencil
*/
void clearFramebuffer(const Color &color, bool clearColor = true, void clearFramebuffer(const Color &color, bool clearColor = true,
bool clearDepth = true, bool clearStencil = false); bool clearDepth = true, bool clearStencil = false);
private: private:
// 形状批处理常量
static constexpr size_t MAX_CIRCLE_SEGMENTS = 128; static constexpr size_t MAX_CIRCLE_SEGMENTS = 128;
static constexpr size_t MAX_SHAPE_VERTICES = 8192; // 最大形状顶点数 static constexpr size_t MAX_SHAPE_VERTICES = 8192;
static constexpr size_t MAX_LINE_VERTICES = 16384; // 最大线条顶点数 static constexpr size_t MAX_LINE_VERTICES = 16384;
// 形状顶点结构(包含颜色)
struct ShapeVertex { struct ShapeVertex {
float x, y; float x, y;
float r, g, b, a; float r, g, b, a;
@ -135,45 +114,40 @@ private:
GLFWWindow *window_; GLFWWindow *window_;
GLSpriteBatch spriteBatch_; GLSpriteBatch spriteBatch_;
Ptr<IShader> shapeShader_; Ptr<IShader> shapeShader_;
Ptr<IShader> sdfFontShader_; // SDF字体专用着色器 Ptr<IShader> sdfFontShader_;
GLuint shapeVao_; // 形状 VAO手动管理用于顶点属性配置 GLuint shapeVao_;
GLBuffer shapeBuffer_; // 形状 VBO使用 GLBuffer 管理) GLBuffer shapeBuffer_;
GLuint lineVao_; // 线条 VAO手动管理用于顶点属性配置 GLuint lineVao_;
GLBuffer lineBuffer_; // 线条 VBO使用 GLBuffer 管理) GLBuffer lineBuffer_;
glm::mat4 viewProjection_; glm::mat4 viewProjection_;
std::vector<glm::mat4> transformStack_; std::vector<glm::mat4> transformStack_;
Stats stats_; RenderStats stats_;
bool vsync_; bool vsync_;
// 形状批处理缓冲区(预分配,避免每帧内存分配)
std::array<ShapeVertex, MAX_SHAPE_VERTICES> shapeVertexCache_; std::array<ShapeVertex, MAX_SHAPE_VERTICES> shapeVertexCache_;
size_t shapeVertexCount_ = 0; size_t shapeVertexCount_ = 0;
GLenum currentShapeMode_ = GL_TRIANGLES; GLenum currentShapeMode_ = GL_TRIANGLES;
// 线条批处理缓冲区
std::array<ShapeVertex, MAX_LINE_VERTICES> lineVertexCache_; std::array<ShapeVertex, MAX_LINE_VERTICES> lineVertexCache_;
size_t lineVertexCount_ = 0; size_t lineVertexCount_ = 0;
float currentLineWidth_ = 1.0f; float currentLineWidth_ = 1.0f;
// OpenGL 管线状态管理
GLPipeline pipeline_; GLPipeline pipeline_;
// 自动批处理状态 bool batchActive_ = false;
bool batchActive_ = false; // 批处理是否激活 bool autoBatchEnabled_ = true;
bool autoBatchEnabled_ = true; // 是否启用自动批处理 const Texture *currentBatchTexture_ = nullptr;
const Texture *currentBatchTexture_ = nullptr; // 当前批处理的纹理 std::vector<SpriteData> pendingSprites_;
std::vector<SpriteData> pendingSprites_; // 待提交的精灵 static constexpr size_t MAX_BATCH_SPRITES = 1000;
static constexpr size_t MAX_BATCH_SPRITES = 1000; // 最大批处理精灵数
// 帧缓冲管理 mutable Ptr<GLFramebuffer> defaultFramebuffer_;
mutable Ptr<GLFramebuffer> defaultFramebuffer_; // 默认帧缓冲(延迟创建) GLFramebuffer *currentFramebuffer_ = nullptr;
GLFramebuffer *currentFramebuffer_ = nullptr; // 当前绑定的帧缓冲
void initShapeRendering(); void initShapeRendering();
void ensureBatchActive(); // 确保批处理已激活 void ensureBatchActive();
void submitPendingSprites(); // 提交待处理的精灵 void submitPendingSprites();
void flushShapeBatch(); void flushShapeBatch();
void flushLineBatch(); void flushLineBatch();
void addShapeVertex(float x, float y, const Color &color); void addShapeVertex(float x, float y, const Color &color);

View File

@ -13,12 +13,10 @@
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
namespace extra2d { namespace extra2d {
// 前向声明
class Scene; class Scene;
class RenderBackend; class Renderer;
// ============================================================================ // ============================================================================
// 纹理加载选项 // 纹理加载选项

View File

@ -4,16 +4,15 @@
#include <extra2d/core/math_types.h> #include <extra2d/core/math_types.h>
#include <extra2d/core/types.h> #include <extra2d/core/types.h>
#include <extra2d/event/event_dispatcher.h> #include <extra2d/event/event_dispatcher.h>
#include <extra2d/graphics/core/render_backend.h> #include <extra2d/graphics/opengl/gl_renderer.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
namespace extra2d { namespace extra2d {
// 前向声明
class Scene; class Scene;
class RenderBackend; class Renderer;
struct RenderCommand; struct RenderCommand;
// ============================================================================ // ============================================================================
@ -137,7 +136,7 @@ public:
virtual void onEnter(); virtual void onEnter();
virtual void onExit(); virtual void onExit();
virtual void onUpdate(float dt); virtual void onUpdate(float dt);
virtual void onRender(RenderBackend &renderer); virtual void onRender(Renderer &renderer);
virtual void onAttachToScene(Scene *scene); virtual void onAttachToScene(Scene *scene);
virtual void onDetachFromScene(); virtual void onDetachFromScene();
@ -155,7 +154,7 @@ public:
// 内部方法 // 内部方法
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void update(float dt); void update(float dt);
void render(RenderBackend &renderer); void render(Renderer &renderer);
void sortChildren(); void sortChildren();
bool isRunning() const { return running_; } bool isRunning() const { return running_; }
@ -167,7 +166,7 @@ public:
protected: protected:
// 子类重写 // 子类重写
virtual void onDraw(RenderBackend &renderer) {} virtual void onDraw(Renderer &renderer) {}
virtual void onUpdateNode(float dt) {} virtual void onUpdateNode(float dt) {}
virtual void generateRenderCommand(std::vector<RenderCommand> &commands, virtual void generateRenderCommand(std::vector<RenderCommand> &commands,
int zOrder) {}; int zOrder) {};

View File

@ -54,11 +54,11 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 渲染和更新 // 渲染和更新
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void renderScene(RenderBackend &renderer); void renderScene(Renderer &renderer);
virtual void renderContent(RenderBackend &renderer); virtual void renderContent(Renderer &renderer);
void updateScene(float dt); void updateScene(float dt);
void collectRenderCommands(std::vector<RenderCommand> &commands, void collectRenderCommands(std::vector<RenderCommand> &commands,
int parentZOrder = 0) override; int parentZOrder = 0) override;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 静态创建方法 // 静态创建方法

View File

@ -102,7 +102,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);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -143,7 +143,8 @@ private:
* @param inScene * @param inScene
* @return * @return
*/ */
Ptr<TransitionScene> createTransitionScene(TransitionType type, float duration, Ptr<TransitionScene> createTransitionScene(TransitionType type,
float duration,
Ptr<Scene> inScene); Ptr<Scene> inScene);
/** /**

View File

@ -88,7 +88,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

@ -25,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;
private: private:

View File

@ -44,7 +44,7 @@ protected:
* @brief * @brief
* *
*/ */
void renderContent(RenderBackend &renderer) override; void renderContent(Renderer &renderer) override;
private: private:
/** /**
@ -52,8 +52,8 @@ private:
*/ */
void hideOutShowIn(); void hideOutShowIn();
Color maskColor_; // 遮罩颜色 Color maskColor_; // 遮罩颜色
bool hasSwitched_ = false; // 是否已经切换场景 bool hasSwitched_ = false; // 是否已经切换场景
}; };
} // namespace extra2d } // namespace extra2d

View File

@ -28,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

@ -23,7 +23,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

@ -63,7 +63,9 @@ public:
/** /**
* @brief * @brief
*/ */
void setFinishCallback(FinishCallback callback) { finishCallback_ = callback; } void setFinishCallback(FinishCallback callback) {
finishCallback_ = callback;
}
/** /**
* @brief * @brief
@ -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
@ -136,11 +138,11 @@ protected:
bool isFinished_ = false; bool isFinished_ = false;
bool isCancelled_ = false; bool isCancelled_ = false;
Ptr<Scene> inScene_; // 要进入的场景 Ptr<Scene> inScene_; // 要进入的场景
Ptr<Scene> outScene_; // 要退出的场景 Ptr<Scene> outScene_; // 要退出的场景
FinishCallback finishCallback_; FinishCallback finishCallback_;
FinishCallback cancelCallback_; // 取消回调 FinishCallback cancelCallback_; // 取消回调
friend class SceneManager; friend class SceneManager;
}; };

View File

@ -26,7 +26,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

@ -2,6 +2,7 @@
#include <extra2d/core/service_interface.h> #include <extra2d/core/service_interface.h>
#include <extra2d/core/service_locator.h> #include <extra2d/core/service_locator.h>
#include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/scene/scene_manager.h> #include <extra2d/scene/scene_manager.h>
namespace extra2d { namespace extra2d {
@ -12,33 +13,34 @@ namespace extra2d {
*/ */
class ISceneService : public IService { class ISceneService : public IService {
public: public:
virtual ~ISceneService() = default; virtual ~ISceneService() = default;
virtual void runWithScene(Ptr<Scene> scene) = 0; virtual void runWithScene(Ptr<Scene> scene) = 0;
virtual void replaceScene(Ptr<Scene> scene) = 0; virtual void replaceScene(Ptr<Scene> scene) = 0;
virtual void pushScene(Ptr<Scene> scene) = 0; virtual void pushScene(Ptr<Scene> scene) = 0;
virtual void popScene() = 0; virtual void popScene() = 0;
virtual void popToRootScene() = 0; virtual void popToRootScene() = 0;
virtual void popToScene(const std::string& name) = 0; virtual void popToScene(const std::string &name) = 0;
virtual Ptr<Scene> getCurrentScene() const = 0; virtual Ptr<Scene> getCurrentScene() const = 0;
virtual Ptr<Scene> getPreviousScene() const = 0; virtual Ptr<Scene> getPreviousScene() const = 0;
virtual Ptr<Scene> getRootScene() const = 0; virtual Ptr<Scene> getRootScene() const = 0;
virtual Ptr<Scene> getSceneByName(const std::string& name) const = 0; virtual Ptr<Scene> getSceneByName(const std::string &name) const = 0;
virtual size_t getSceneCount() const = 0; virtual size_t getSceneCount() const = 0;
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;
virtual void setTransitionCallback(SceneManager::TransitionCallback callback) = 0; virtual void
setTransitionCallback(SceneManager::TransitionCallback callback) = 0;
virtual void end() = 0; virtual void end() = 0;
virtual void purgeCachedScenes() = 0; virtual void purgeCachedScenes() = 0;
virtual void enterScene(Ptr<Scene> scene) = 0; virtual void enterScene(Ptr<Scene> scene) = 0;
}; };
/** /**
@ -47,49 +49,50 @@ public:
*/ */
class SceneService : public ISceneService { class SceneService : public ISceneService {
public: public:
SceneService(); SceneService();
~SceneService() override = default; ~SceneService() override = default;
ServiceInfo getServiceInfo() const override; ServiceInfo getServiceInfo() const override;
bool initialize() override; bool initialize() override;
void shutdown() override; void shutdown() override;
void update(float deltaTime) override; void update(float deltaTime) override;
void runWithScene(Ptr<Scene> scene) override; void runWithScene(Ptr<Scene> scene) override;
void replaceScene(Ptr<Scene> scene) override; void replaceScene(Ptr<Scene> scene) override;
void pushScene(Ptr<Scene> scene) override; void pushScene(Ptr<Scene> scene) override;
void popScene() override; void popScene() override;
void popToRootScene() override; void popToRootScene() override;
void popToScene(const std::string& name) override; void popToScene(const std::string &name) override;
Ptr<Scene> getCurrentScene() const override; Ptr<Scene> getCurrentScene() const override;
Ptr<Scene> getPreviousScene() const override; Ptr<Scene> getPreviousScene() const override;
Ptr<Scene> getRootScene() const override; Ptr<Scene> getRootScene() const override;
Ptr<Scene> getSceneByName(const std::string& name) const override; Ptr<Scene> getSceneByName(const std::string &name) const override;
size_t getSceneCount() const override; size_t getSceneCount() const override;
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;
void setTransitionCallback(SceneManager::TransitionCallback callback) override; void
setTransitionCallback(SceneManager::TransitionCallback callback) override;
void end() override; void end() override;
void purgeCachedScenes() override; void purgeCachedScenes() override;
void enterScene(Ptr<Scene> scene) override; void enterScene(Ptr<Scene> scene) override;
SceneManager& getManager() { return manager_; } SceneManager &getManager() { return manager_; }
const SceneManager& getManager() const { return manager_; } const SceneManager &getManager() const { return manager_; }
private: private:
SceneManager manager_; SceneManager manager_;
// 服务注册元数据 // 服务注册元数据
E2D_AUTO_REGISTER_SERVICE(ISceneService, SceneService); E2D_AUTO_REGISTER_SERVICE(ISceneService, SceneService);
}; };
} } // namespace extra2d

View File

@ -1,8 +1,8 @@
#include <extra2d/app/application.h> #include <extra2d/app/application.h>
#include <extra2d/core/registry.h> #include <extra2d/core/registry.h>
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_module.h> #include <extra2d/graphics/core/render_module.h>
#include <extra2d/graphics/memory/vram_manager.h> #include <extra2d/graphics/memory/vram_manager.h>
#include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/platform/glfw/glfw_window.h> #include <extra2d/platform/glfw/glfw_window.h>
#include <extra2d/platform/window_module.h> #include <extra2d/platform/window_module.h>
#include <extra2d/services/camera_service.h> #include <extra2d/services/camera_service.h>
@ -11,7 +11,6 @@
#include <extra2d/services/scene_service.h> #include <extra2d/services/scene_service.h>
#include <extra2d/services/timer_service.h> #include <extra2d/services/timer_service.h>
namespace extra2d { namespace extra2d {
static double getTimeSeconds() { static double getTimeSeconds() {
@ -179,9 +178,7 @@ void Application::mainLoop() {
} }
} }
void Application::update() { void Application::update() { ServiceLocator::instance().updateAll(deltaTime_); }
ServiceLocator::instance().updateAll(deltaTime_);
}
void Application::render() { void Application::render() {
auto *renderMod = get<RenderModule>(); auto *renderMod = get<RenderModule>();
@ -218,7 +215,7 @@ GLFWWindow *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->renderer() : nullptr; return renderMod ? renderMod->renderer() : nullptr;
} }

View File

@ -38,7 +38,7 @@ bool RenderModule::init() {
} }
E2D_LOG_INFO("正在创建 OpenGL 渲染后端"); E2D_LOG_INFO("正在创建 OpenGL 渲染后端");
renderer_ = makeUnique<GLRenderer>(); renderer_ = makeUnique<Renderer>();
if (!renderer_) { if (!renderer_) {
E2D_LOG_ERROR("创建渲染后端失败"); E2D_LOG_ERROR("创建渲染后端失败");

View File

@ -13,7 +13,6 @@
#include <extra2d/services/logger_service.h> #include <extra2d/services/logger_service.h>
#include <vector> #include <vector>
namespace extra2d { namespace extra2d {
// VBO 初始大小(用于 VRAM 跟踪) // VBO 初始大小(用于 VRAM 跟踪)
@ -22,7 +21,7 @@ static constexpr size_t SHAPE_VBO_SIZE = 1024 * sizeof(float);
/** /**
* @brief OpenGL渲染器成员变量 * @brief OpenGL渲染器成员变量
*/ */
GLRenderer::GLRenderer() Renderer::Renderer()
: window_(nullptr), shapeVao_(0), lineVao_(0), vsync_(true), : window_(nullptr), shapeVao_(0), lineVao_(0), vsync_(true),
shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES), shapeVertexCount_(0), currentShapeMode_(GL_TRIANGLES),
lineVertexCount_(0), currentLineWidth_(1.0f) { lineVertexCount_(0), currentLineWidth_(1.0f) {
@ -38,14 +37,14 @@ GLRenderer::GLRenderer()
/** /**
* @brief shutdown释放资源 * @brief shutdown释放资源
*/ */
GLRenderer::~GLRenderer() { shutdown(); } Renderer::~Renderer() { shutdown(); }
/** /**
* @brief OpenGL渲染器 * @brief OpenGL渲染器
* @param window * @param window
* @return truefalse * @return truefalse
*/ */
bool GLRenderer::init(GLFWWindow *window) { bool Renderer::init(GLFWWindow *window) {
window_ = window; window_ = window;
// 初始化 OpenGL 上下文Switch 平台已通过 SDL2 + EGL 初始化GLContext // 初始化 OpenGL 上下文Switch 平台已通过 SDL2 + EGL 初始化GLContext
@ -89,7 +88,7 @@ bool GLRenderer::init(GLFWWindow *window) {
/** /**
* @brief GPU资源 * @brief GPU资源
*/ */
void GLRenderer::shutdown() { void Renderer::shutdown() {
// 标记 GPU 上下文为无效 // 标记 GPU 上下文为无效
// 这会在销毁 OpenGL 上下文之前通知所有 GPU 资源 // 这会在销毁 OpenGL 上下文之前通知所有 GPU 资源
GPUContext::get().markInvalid(); GPUContext::get().markInvalid();
@ -118,7 +117,7 @@ void GLRenderer::shutdown() {
* @brief * @brief
* @param clearColor * @param clearColor
*/ */
void GLRenderer::beginFrame(const Color &clearColor) { void Renderer::beginFrame(const Color &clearColor) {
// 应用管线状态 // 应用管线状态
pipeline_.applyAllStates(); pipeline_.applyAllStates();
@ -130,7 +129,7 @@ void GLRenderer::beginFrame(const Color &clearColor) {
/** /**
* @brief * @brief
*/ */
void GLRenderer::endFrame() { void Renderer::endFrame() {
// 刷新所有待处理的精灵批次(自动批处理) // 刷新所有待处理的精灵批次(自动批处理)
if (autoBatchEnabled_ && batchActive_) { if (autoBatchEnabled_ && batchActive_) {
flush(); flush();
@ -148,7 +147,7 @@ void GLRenderer::endFrame() {
* @param width * @param width
* @param height * @param height
*/ */
void GLRenderer::setViewport(int x, int y, int width, int height) { void Renderer::setViewport(int x, int y, int width, int height) {
// 使用 GLPipeline 管理视口状态 // 使用 GLPipeline 管理视口状态
pipeline_.setViewport(x, y, width, height); pipeline_.setViewport(x, y, width, height);
} }
@ -157,7 +156,7 @@ void GLRenderer::setViewport(int x, int y, int width, int height) {
* @brief * @brief
* @param enabled true启用垂直同步false禁用 * @param enabled true启用垂直同步false禁用
*/ */
void GLRenderer::setVSync(bool enabled) { void Renderer::setVSync(bool enabled) {
vsync_ = enabled; vsync_ = enabled;
// 通过窗口接口设置垂直同步 // 通过窗口接口设置垂直同步
if (window_) { if (window_) {
@ -169,7 +168,7 @@ void GLRenderer::setVSync(bool enabled) {
* @brief * @brief
* @param mode * @param mode
*/ */
void GLRenderer::setBlendMode(BlendMode mode) { void Renderer::setBlendMode(BlendMode mode) {
// 使用 GLPipeline 管理混合状态 // 使用 GLPipeline 管理混合状态
pipeline_.setBlendMode(mode); pipeline_.setBlendMode(mode);
} }
@ -178,7 +177,7 @@ void GLRenderer::setBlendMode(BlendMode mode) {
* @brief * @brief
* @param matrix 4x4视图投影矩阵 * @param matrix 4x4视图投影矩阵
*/ */
void GLRenderer::setViewProjection(const glm::mat4 &matrix) { void Renderer::setViewProjection(const glm::mat4 &matrix) {
viewProjection_ = matrix; viewProjection_ = matrix;
} }
@ -186,7 +185,7 @@ void GLRenderer::setViewProjection(const glm::mat4 &matrix) {
* @brief * @brief
* @param transform * @param transform
*/ */
void GLRenderer::pushTransform(const glm::mat4 &transform) { void Renderer::pushTransform(const glm::mat4 &transform) {
if (transformStack_.empty()) { if (transformStack_.empty()) {
transformStack_.push_back(transform); transformStack_.push_back(transform);
} else { } else {
@ -197,7 +196,7 @@ void GLRenderer::pushTransform(const glm::mat4 &transform) {
/** /**
* @brief * @brief
*/ */
void GLRenderer::popTransform() { void Renderer::popTransform() {
if (!transformStack_.empty()) { if (!transformStack_.empty()) {
transformStack_.pop_back(); transformStack_.pop_back();
} }
@ -207,7 +206,7 @@ void GLRenderer::popTransform() {
* @brief * @brief
* @return * @return
*/ */
glm::mat4 GLRenderer::getCurrentTransform() const { glm::mat4 Renderer::getCurrentTransform() const {
if (transformStack_.empty()) { if (transformStack_.empty()) {
return glm::mat4(1.0f); return glm::mat4(1.0f);
} }
@ -222,8 +221,8 @@ glm::mat4 GLRenderer::getCurrentTransform() const {
* @param channels * @param channels
* @return * @return
*/ */
Ptr<Texture> GLRenderer::createTexture(int width, int height, Ptr<Texture> Renderer::createTexture(int width, int height,
const uint8_t *pixels, int channels) { const uint8_t *pixels, int channels) {
return makePtr<GLTexture>(width, height, pixels, channels); return makePtr<GLTexture>(width, height, pixels, channels);
} }
@ -232,14 +231,14 @@ Ptr<Texture> GLRenderer::createTexture(int width, int height,
* @param filepath * @param filepath
* @return * @return
*/ */
Ptr<Texture> GLRenderer::loadTexture(const std::string &filepath) { Ptr<Texture> Renderer::loadTexture(const std::string &filepath) {
return makePtr<GLTexture>(filepath); return makePtr<GLTexture>(filepath);
} }
/** /**
* @brief 使 * @brief 使
*/ */
void GLRenderer::ensureBatchActive() { void Renderer::ensureBatchActive() {
if (!batchActive_) { if (!batchActive_) {
spriteBatch_.begin(viewProjection_); spriteBatch_.begin(viewProjection_);
batchActive_ = true; batchActive_ = true;
@ -251,7 +250,7 @@ void GLRenderer::ensureBatchActive() {
/** /**
* @brief 使 * @brief 使
*/ */
void GLRenderer::submitPendingSprites() { void Renderer::submitPendingSprites() {
if (pendingSprites_.empty()) { if (pendingSprites_.empty()) {
return; return;
} }
@ -266,7 +265,7 @@ void GLRenderer::submitPendingSprites() {
* @brief * @brief
* @note drawSprite/drawText * @note drawSprite/drawText
*/ */
void GLRenderer::beginSpriteBatch() { void Renderer::beginSpriteBatch() {
// 如果自动批处理已激活,先提交 // 如果自动批处理已激活,先提交
if (autoBatchEnabled_ && batchActive_) { if (autoBatchEnabled_ && batchActive_) {
flush(); flush();
@ -286,9 +285,9 @@ void GLRenderer::beginSpriteBatch() {
* @param rotation * @param rotation
* @param anchor 0-1 * @param anchor 0-1
*/ */
void GLRenderer::drawSprite(const Texture &texture, const Rect &destRect, void Renderer::drawSprite(const Texture &texture, const Rect &destRect,
const Rect &srcRect, const Color &tint, const Rect &srcRect, const Color &tint,
float rotation, const Vec2 &anchor) { float rotation, const Vec2 &anchor) {
// 自动批处理模式 // 自动批处理模式
if (autoBatchEnabled_) { if (autoBatchEnabled_) {
ensureBatchActive(); ensureBatchActive();
@ -356,8 +355,8 @@ void GLRenderer::drawSprite(const Texture &texture, const Rect &destRect,
* @param position * @param position
* @param tint * @param tint
*/ */
void GLRenderer::drawSprite(const Texture &texture, const Vec2 &position, void Renderer::drawSprite(const Texture &texture, const Vec2 &position,
const Color &tint) { const Color &tint) {
Rect destRect(position.x, position.y, static_cast<float>(texture.getWidth()), Rect destRect(position.x, position.y, static_cast<float>(texture.getWidth()),
static_cast<float>(texture.getHeight())); static_cast<float>(texture.getHeight()));
Rect srcRect(0, 0, static_cast<float>(texture.getWidth()), Rect srcRect(0, 0, static_cast<float>(texture.getWidth()),
@ -369,7 +368,7 @@ void GLRenderer::drawSprite(const Texture &texture, const Vec2 &position,
* @brief * @brief
* @note * @note
*/ */
void GLRenderer::endSpriteBatch() { void Renderer::endSpriteBatch() {
if (autoBatchEnabled_) { if (autoBatchEnabled_) {
// 自动模式下,只是标记批处理结束 // 自动模式下,只是标记批处理结束
flush(); flush();
@ -386,7 +385,7 @@ void GLRenderer::endSpriteBatch() {
* @brief * @brief
* @note * @note
*/ */
void GLRenderer::flush() { void Renderer::flush() {
if (autoBatchEnabled_ && batchActive_) { if (autoBatchEnabled_ && batchActive_) {
submitPendingSprites(); submitPendingSprites();
spriteBatch_.end(); spriteBatch_.end();
@ -403,8 +402,8 @@ void GLRenderer::flush() {
* @param color 线 * @param color 线
* @param width 线 * @param width 线
*/ */
void GLRenderer::drawLine(const Vec2 &start, const Vec2 &end, void Renderer::drawLine(const Vec2 &start, const Vec2 &end, const Color &color,
const Color &color, float width) { float width) {
// 如果线宽改变,需要先刷新线条批次 // 如果线宽改变,需要先刷新线条批次
if (width != currentLineWidth_) { if (width != currentLineWidth_) {
flushLineBatch(); flushLineBatch();
@ -416,7 +415,7 @@ void GLRenderer::drawLine(const Vec2 &start, const Vec2 &end,
addLineVertex(end.x, end.y, color); addLineVertex(end.x, end.y, color);
} }
void GLRenderer::drawRect(const Rect &rect, const Color &color, float width) { void Renderer::drawRect(const Rect &rect, const Color &color, float width) {
// 如果线宽改变,需要先刷新线条批次 // 如果线宽改变,需要先刷新线条批次
if (width != currentLineWidth_) { if (width != currentLineWidth_) {
flushLineBatch(); flushLineBatch();
@ -448,7 +447,7 @@ void GLRenderer::drawRect(const Rect &rect, const Color &color, float width) {
* @param rect * @param rect
* @param color * @param color
*/ */
void GLRenderer::fillRect(const Rect &rect, const Color &color) { void Renderer::fillRect(const Rect &rect, const Color &color) {
// 提交当前批次(如果模式不同) // 提交当前批次(如果模式不同)
submitShapeBatch(GL_TRIANGLES); submitShapeBatch(GL_TRIANGLES);
@ -477,8 +476,8 @@ void GLRenderer::fillRect(const Rect &rect, const Color &color) {
* @param segments * @param segments
* @param width 线 * @param width 线
*/ */
void GLRenderer::drawCircle(const Vec2 &center, float radius, void Renderer::drawCircle(const Vec2 &center, float radius, const Color &color,
const Color &color, int segments, float width) { int segments, float width) {
// 限制段数不超过缓存大小 // 限制段数不超过缓存大小
if (segments > static_cast<int>(MAX_CIRCLE_SEGMENTS)) { if (segments > static_cast<int>(MAX_CIRCLE_SEGMENTS)) {
segments = static_cast<int>(MAX_CIRCLE_SEGMENTS); segments = static_cast<int>(MAX_CIRCLE_SEGMENTS);
@ -511,8 +510,8 @@ void GLRenderer::drawCircle(const Vec2 &center, float radius,
* @param color * @param color
* @param segments * @param segments
*/ */
void GLRenderer::fillCircle(const Vec2 &center, float radius, void Renderer::fillCircle(const Vec2 &center, float radius, const Color &color,
const Color &color, int segments) { int segments) {
// 限制段数不超过缓存大小 // 限制段数不超过缓存大小
if (segments > static_cast<int>(MAX_CIRCLE_SEGMENTS)) { if (segments > static_cast<int>(MAX_CIRCLE_SEGMENTS)) {
segments = static_cast<int>(MAX_CIRCLE_SEGMENTS); segments = static_cast<int>(MAX_CIRCLE_SEGMENTS);
@ -546,8 +545,8 @@ void GLRenderer::fillCircle(const Vec2 &center, float radius,
* @param color * @param color
* @param width 线 * @param width 线
*/ */
void GLRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, void Renderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color, float width) { const Color &color, float width) {
drawLine(p1, p2, color, width); drawLine(p1, p2, color, width);
drawLine(p2, p3, color, width); drawLine(p2, p3, color, width);
drawLine(p3, p1, color, width); drawLine(p3, p1, color, width);
@ -560,8 +559,8 @@ void GLRenderer::drawTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
* @param p3 * @param p3
* @param color * @param color
*/ */
void GLRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3, void Renderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
const Color &color) { const Color &color) {
submitShapeBatch(GL_TRIANGLES); submitShapeBatch(GL_TRIANGLES);
addShapeVertex(p1.x, p1.y, color); addShapeVertex(p1.x, p1.y, color);
@ -575,8 +574,8 @@ void GLRenderer::fillTriangle(const Vec2 &p1, const Vec2 &p2, const Vec2 &p3,
* @param color * @param color
* @param width 线 * @param width 线
*/ */
void GLRenderer::drawPolygon(const std::vector<Vec2> &points, void Renderer::drawPolygon(const std::vector<Vec2> &points, const Color &color,
const Color &color, float width) { float width) {
if (points.size() < 2) if (points.size() < 2)
return; return;
@ -600,8 +599,8 @@ void GLRenderer::drawPolygon(const std::vector<Vec2> &points,
* @param points * @param points
* @param color * @param color
*/ */
void GLRenderer::fillPolygon(const std::vector<Vec2> &points, void Renderer::fillPolygon(const std::vector<Vec2> &points,
const Color &color) { const Color &color) {
if (points.size() < 3) if (points.size() < 3)
return; return;
@ -623,8 +622,8 @@ void GLRenderer::fillPolygon(const std::vector<Vec2> &points,
* @param useSDF 使SDF渲染 * @param useSDF 使SDF渲染
* @return * @return
*/ */
Ptr<FontAtlas> GLRenderer::createFontAtlas(const std::string &filepath, Ptr<FontAtlas> Renderer::createFontAtlas(const std::string &filepath,
int fontSize, bool useSDF) { int fontSize, bool useSDF) {
return makePtr<GLFontAtlas>(filepath, fontSize, useSDF); return makePtr<GLFontAtlas>(filepath, fontSize, useSDF);
} }
@ -635,8 +634,8 @@ Ptr<FontAtlas> GLRenderer::createFontAtlas(const std::string &filepath,
* @param position * @param position
* @param color * @param color
*/ */
void GLRenderer::drawText(const FontAtlas &font, const std::string &text, void Renderer::drawText(const FontAtlas &font, const std::string &text,
const Vec2 &position, const Color &color) { const Vec2 &position, const Color &color) {
drawText(font, text, position.x, position.y, color); drawText(font, text, position.x, position.y, color);
} }
@ -648,8 +647,8 @@ void GLRenderer::drawText(const FontAtlas &font, const std::string &text,
* @param y Y坐标 * @param y Y坐标
* @param color * @param color
*/ */
void GLRenderer::drawText(const FontAtlas &font, const std::string &text, void Renderer::drawText(const FontAtlas &font, const std::string &text, float x,
float x, float y, const Color &color) { float y, const Color &color) {
float cursorX = x; float cursorX = x;
float cursorY = y; float cursorY = y;
float baselineY = cursorY + font.getAscent(); float baselineY = cursorY + font.getAscent();
@ -789,12 +788,12 @@ void GLRenderer::drawText(const FontAtlas &font, const std::string &text,
/** /**
* @brief * @brief
*/ */
void GLRenderer::resetStats() { stats_ = Stats{}; } void Renderer::resetStats() { stats_ = RenderStats{}; }
/** /**
* @brief OpenGL资源VAOVBO * @brief OpenGL资源VAOVBO
*/ */
void GLRenderer::initShapeRendering() { void Renderer::initShapeRendering() {
// 从ShaderManager获取形状着色器 // 从ShaderManager获取形状着色器
shapeShader_ = ShaderManager::getInstance().getBuiltin("shape"); shapeShader_ = ShaderManager::getInstance().getBuiltin("shape");
if (!shapeShader_) { if (!shapeShader_) {
@ -871,7 +870,7 @@ void GLRenderer::initShapeRendering() {
* @param y Y坐标 * @param y Y坐标
* @param color * @param color
*/ */
void GLRenderer::addShapeVertex(float x, float y, const Color &color) { void Renderer::addShapeVertex(float x, float y, const Color &color) {
if (shapeVertexCount_ >= MAX_SHAPE_VERTICES) { if (shapeVertexCount_ >= MAX_SHAPE_VERTICES) {
flushShapeBatch(); flushShapeBatch();
} }
@ -896,7 +895,7 @@ void GLRenderer::addShapeVertex(float x, float y, const Color &color) {
* @param y Y坐标 * @param y Y坐标
* @param color * @param color
*/ */
void GLRenderer::addLineVertex(float x, float y, const Color &color) { void Renderer::addLineVertex(float x, float y, const Color &color) {
if (lineVertexCount_ >= MAX_LINE_VERTICES) { if (lineVertexCount_ >= MAX_LINE_VERTICES) {
flushLineBatch(); flushLineBatch();
} }
@ -919,7 +918,7 @@ void GLRenderer::addLineVertex(float x, float y, const Color &color) {
* @brief * @brief
* @param mode OpenGL绘制模式 * @param mode OpenGL绘制模式
*/ */
void GLRenderer::submitShapeBatch(GLenum mode) { void Renderer::submitShapeBatch(GLenum mode) {
if (shapeVertexCount_ == 0) if (shapeVertexCount_ == 0)
return; return;
@ -933,7 +932,7 @@ void GLRenderer::submitShapeBatch(GLenum mode) {
/** /**
* @brief OpenGL绘制调用 * @brief OpenGL绘制调用
*/ */
void GLRenderer::flushShapeBatch() { void Renderer::flushShapeBatch() {
if (shapeVertexCount_ == 0) if (shapeVertexCount_ == 0)
return; return;
@ -966,7 +965,7 @@ void GLRenderer::flushShapeBatch() {
/** /**
* @brief 线OpenGL绘制调用 * @brief 线OpenGL绘制调用
*/ */
void GLRenderer::flushLineBatch() { void Renderer::flushLineBatch() {
if (lineVertexCount_ == 0) if (lineVertexCount_ == 0)
return; return;
@ -1004,7 +1003,7 @@ void GLRenderer::flushLineBatch() {
* @param desc * @param desc
* @return * @return
*/ */
Ptr<GLFramebuffer> GLRenderer::createFramebuffer(const FramebufferDesc &desc) { Ptr<GLFramebuffer> Renderer::createFramebuffer(const FramebufferDesc &desc) {
auto framebuffer = makePtr<GLFramebuffer>(); auto framebuffer = makePtr<GLFramebuffer>();
if (!framebuffer->init(desc)) { if (!framebuffer->init(desc)) {
E2D_LOG_ERROR("创建帧缓冲区失败"); E2D_LOG_ERROR("创建帧缓冲区失败");
@ -1017,7 +1016,7 @@ Ptr<GLFramebuffer> GLRenderer::createFramebuffer(const FramebufferDesc &desc) {
* @brief * @brief
* @param framebuffer nullptr * @param framebuffer nullptr
*/ */
void GLRenderer::bindFramebuffer(GLFramebuffer *framebuffer) { void Renderer::bindFramebuffer(GLFramebuffer *framebuffer) {
// 先刷新所有待处理的渲染批次 // 先刷新所有待处理的渲染批次
flush(); flush();
flushShapeBatch(); flushShapeBatch();
@ -1039,13 +1038,13 @@ void GLRenderer::bindFramebuffer(GLFramebuffer *framebuffer) {
/** /**
* @brief * @brief
*/ */
void GLRenderer::unbindFramebuffer() { bindFramebuffer(nullptr); } void Renderer::unbindFramebuffer() { bindFramebuffer(nullptr); }
/** /**
* @brief * @brief
* @return * @return
*/ */
Ptr<GLFramebuffer> GLRenderer::getDefaultFramebuffer() const { Ptr<GLFramebuffer> Renderer::getDefaultFramebuffer() const {
if (!defaultFramebuffer_) { if (!defaultFramebuffer_) {
// 延迟创建默认帧缓冲对象代表系统默认帧缓冲ID 为 0 // 延迟创建默认帧缓冲对象代表系统默认帧缓冲ID 为 0
defaultFramebuffer_ = makePtr<GLFramebuffer>(); defaultFramebuffer_ = makePtr<GLFramebuffer>();
@ -1061,8 +1060,8 @@ Ptr<GLFramebuffer> GLRenderer::getDefaultFramebuffer() const {
* @param clearDepth * @param clearDepth
* @param clearStencil * @param clearStencil
*/ */
void GLRenderer::clearFramebuffer(const Color &color, bool clearColor, void Renderer::clearFramebuffer(const Color &color, bool clearColor,
bool clearDepth, bool clearStencil) { bool clearDepth, bool clearStencil) {
GLbitfield mask = 0; GLbitfield mask = 0;
if (clearColor) { if (clearColor) {

View File

@ -1,5 +1,5 @@
#include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/graphics/texture/texture_pool.h> #include <extra2d/graphics/texture/texture_pool.h>
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/scene/scene.h> #include <extra2d/scene/scene.h>
#include <algorithm> #include <algorithm>
@ -17,13 +17,8 @@ namespace extra2d {
* *
*/ */
TexturePool::TexturePool() TexturePool::TexturePool()
: scene_(nullptr) : scene_(nullptr), maxMemoryUsage_(0), currentMemoryUsage_(0),
, maxMemoryUsage_(0) cacheHits_(0), cacheMisses_(0), evictionCount_(0) {}
, currentMemoryUsage_(0)
, cacheHits_(0)
, cacheMisses_(0)
, evictionCount_(0) {
}
/** /**
* @brief * @brief
@ -32,14 +27,10 @@ TexturePool::TexturePool()
* *
* *
*/ */
TexturePool::TexturePool(Scene* scene, size_t maxMemoryUsage) TexturePool::TexturePool(Scene *scene, size_t maxMemoryUsage)
: scene_(scene) : scene_(scene), maxMemoryUsage_(maxMemoryUsage), currentMemoryUsage_(0),
, maxMemoryUsage_(maxMemoryUsage) cacheHits_(0), cacheMisses_(0), evictionCount_(0) {
, currentMemoryUsage_(0) E2D_LOG_INFO("TexturePool 已创建,最大内存: {} 字节", maxMemoryUsage);
, cacheHits_(0)
, cacheMisses_(0)
, evictionCount_(0) {
E2D_LOG_INFO("TexturePool 已创建,最大内存: {} 字节", maxMemoryUsage);
} }
/** /**
@ -49,10 +40,10 @@ TexturePool::TexturePool(Scene* scene, size_t maxMemoryUsage)
* *
* *
*/ */
void TexturePool::init(Scene* scene, size_t maxMemoryUsage) { void TexturePool::init(Scene *scene, size_t maxMemoryUsage) {
scene_ = scene; scene_ = scene;
maxMemoryUsage_ = maxMemoryUsage; maxMemoryUsage_ = maxMemoryUsage;
E2D_LOG_INFO("TexturePool 已初始化,最大内存: {} 字节", maxMemoryUsage); E2D_LOG_INFO("TexturePool 已初始化,最大内存: {} 字节", maxMemoryUsage);
} }
/** /**
@ -61,8 +52,8 @@ void TexturePool::init(Scene* scene, size_t maxMemoryUsage) {
* *
*/ */
TexturePool::~TexturePool() { TexturePool::~TexturePool() {
clear(); clear();
E2D_LOG_INFO("TexturePool 已销毁"); E2D_LOG_INFO("TexturePool 已销毁");
} }
// ============================================================================ // ============================================================================
@ -77,8 +68,9 @@ TexturePool::~TexturePool() {
* *
* *
*/ */
TextureRef TexturePool::load(const std::string& path, const TextureLoadOptions& options) { TextureRef TexturePool::load(const std::string &path,
return load(path, Rect::Zero(), options); const TextureLoadOptions &options) {
return load(path, Rect::Zero(), options);
} }
/** /**
@ -90,75 +82,76 @@ TextureRef TexturePool::load(const std::string& path, const TextureLoadOptions&
* *
* *
*/ */
TextureRef TexturePool::load(const std::string& path, const Rect& region, TextureRef TexturePool::load(const std::string &path, const Rect &region,
const TextureLoadOptions& options) { const TextureLoadOptions &options) {
TextureKey key(path, region); TextureKey key(path, region);
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
// 检查缓存 // 检查缓存
auto it = cache_.find(key); auto it = cache_.find(key);
if (it != cache_.end()) { if (it != cache_.end()) {
// 缓存命中 // 缓存命中
it->second.touch(); it->second.touch();
it->second.refCount.fetch_add(1, std::memory_order_relaxed); it->second.refCount.fetch_add(1, std::memory_order_relaxed);
cacheHits_.fetch_add(1, std::memory_order_relaxed); cacheHits_.fetch_add(1, std::memory_order_relaxed);
E2D_LOG_DEBUG("纹理缓存命中: {}", path); E2D_LOG_DEBUG("纹理缓存命中: {}", path);
return TextureRef(it->second.texture, &it->second, &mutex_); return TextureRef(it->second.texture, &it->second, &mutex_);
} }
// 缓存未命中 // 缓存未命中
cacheMisses_.fetch_add(1, std::memory_order_relaxed); cacheMisses_.fetch_add(1, std::memory_order_relaxed);
// 获取渲染后端 // 获取渲染后端
RenderBackend* backend = nullptr; Renderer *backend = nullptr;
if (scene_) { if (scene_) {
// 假设 Scene 有获取 RenderBackend 的方法 // 假设 Scene 有获取 Renderer 的方法
// 这里需要根据实际接口调整 // 这里需要根据实际接口调整
backend = nullptr; // TODO: 从 Scene 获取 RenderBackend backend = nullptr; // TODO: 从 Scene 获取 Renderer
} }
if (!backend) {
E2D_LOG_ERROR("TexturePool: 渲染后端不可用");
return TextureRef();
}
// 加载纹理
Ptr<Texture> texture = backend->loadTexture(path);
if (!texture) {
E2D_LOG_ERROR("TexturePool: 加载纹理失败: {}", path);
return TextureRef();
}
// 计算内存大小
size_t memorySize = calculateTextureMemory(texture.get());
// 检查内存限制
if (maxMemoryUsage_ > 0 && currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
// 尝试淘汰
evictLRU(currentMemoryUsage_ + memorySize - maxMemoryUsage_);
// 再次检查
if (currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
E2D_LOG_WARN("TexturePool: 内存限制超出,无法加载纹理: {}", path);
return TextureRef();
}
}
// 创建缓存条目
auto result = cache_.emplace(key, TexturePoolEntry(nullptr, key, 0));
if (result.second) {
result.first->second.texture = texture;
result.first->second.memorySize = memorySize;
result.first->second.refCount.store(1, std::memory_order_relaxed);
result.first->second.touch();
currentMemoryUsage_ += memorySize;
E2D_LOG_INFO("TexturePool: 已加载纹理: {} ({} 字节)", path, memorySize);
return TextureRef(texture, &result.first->second, &mutex_);
}
if (!backend) {
E2D_LOG_ERROR("TexturePool: 渲染后端不可用");
return TextureRef(); return TextureRef();
}
// 加载纹理
Ptr<Texture> texture = backend->loadTexture(path);
if (!texture) {
E2D_LOG_ERROR("TexturePool: 加载纹理失败: {}", path);
return TextureRef();
}
// 计算内存大小
size_t memorySize = calculateTextureMemory(texture.get());
// 检查内存限制
if (maxMemoryUsage_ > 0 &&
currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
// 尝试淘汰
evictLRU(currentMemoryUsage_ + memorySize - maxMemoryUsage_);
// 再次检查
if (currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
E2D_LOG_WARN("TexturePool: 内存限制超出,无法加载纹理: {}", path);
return TextureRef();
}
}
// 创建缓存条目
auto result = cache_.emplace(key, TexturePoolEntry(nullptr, key, 0));
if (result.second) {
result.first->second.texture = texture;
result.first->second.memorySize = memorySize;
result.first->second.refCount.store(1, std::memory_order_relaxed);
result.first->second.touch();
currentMemoryUsage_ += memorySize;
E2D_LOG_INFO("TexturePool: 已加载纹理: {} ({} 字节)", path, memorySize);
return TextureRef(texture, &result.first->second, &mutex_);
}
return TextureRef();
} }
/** /**
@ -172,67 +165,70 @@ TextureRef TexturePool::load(const std::string& path, const Rect& region,
* *
* *
*/ */
TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int height, TextureRef TexturePool::loadFromMemory(const uint8_t *data, int width,
int channels, const std::string& key) { int height, int channels,
TextureKey textureKey(key); const std::string &key) {
TextureKey textureKey(key);
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
// 检查缓存 // 检查缓存
auto it = cache_.find(textureKey); auto it = cache_.find(textureKey);
if (it != cache_.end()) { if (it != cache_.end()) {
it->second.touch(); it->second.touch();
it->second.refCount.fetch_add(1, std::memory_order_relaxed); it->second.refCount.fetch_add(1, std::memory_order_relaxed);
cacheHits_.fetch_add(1, std::memory_order_relaxed); cacheHits_.fetch_add(1, std::memory_order_relaxed);
return TextureRef(it->second.texture, &it->second, &mutex_); return TextureRef(it->second.texture, &it->second, &mutex_);
} }
cacheMisses_.fetch_add(1, std::memory_order_relaxed); cacheMisses_.fetch_add(1, std::memory_order_relaxed);
// 获取渲染后端 // 获取渲染后端
RenderBackend* backend = nullptr; Renderer *backend = nullptr;
if (scene_) { if (scene_) {
backend = nullptr; // TODO: 从 Scene 获取 RenderBackend backend = nullptr; // TODO: 从 Scene 获取 Renderer
} }
if (!backend) {
E2D_LOG_ERROR("TexturePool: 渲染后端不可用");
return TextureRef();
}
// 创建纹理
Ptr<Texture> texture = backend->createTexture(width, height, data, channels);
if (!texture) {
E2D_LOG_ERROR("TexturePool: 从内存创建纹理失败");
return TextureRef();
}
// 计算内存大小
size_t memorySize = calculateTextureMemory(texture.get());
// 检查内存限制
if (maxMemoryUsage_ > 0 && currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
evictLRU(currentMemoryUsage_ + memorySize - maxMemoryUsage_);
if (currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
E2D_LOG_WARN("TexturePool: 内存限制超出");
return TextureRef();
}
}
// 创建缓存条目
auto result = cache_.emplace(textureKey, TexturePoolEntry(nullptr, textureKey, 0));
if (result.second) {
result.first->second.texture = texture;
result.first->second.memorySize = memorySize;
result.first->second.refCount.store(1, std::memory_order_relaxed);
result.first->second.touch();
currentMemoryUsage_ += memorySize;
E2D_LOG_INFO("TexturePool: 已从内存创建纹理 ({} 字节)", memorySize);
return TextureRef(texture, &result.first->second, &mutex_);
}
if (!backend) {
E2D_LOG_ERROR("TexturePool: 渲染后端不可用");
return TextureRef(); return TextureRef();
}
// 创建纹理
Ptr<Texture> texture = backend->createTexture(width, height, data, channels);
if (!texture) {
E2D_LOG_ERROR("TexturePool: 从内存创建纹理失败");
return TextureRef();
}
// 计算内存大小
size_t memorySize = calculateTextureMemory(texture.get());
// 检查内存限制
if (maxMemoryUsage_ > 0 &&
currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
evictLRU(currentMemoryUsage_ + memorySize - maxMemoryUsage_);
if (currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
E2D_LOG_WARN("TexturePool: 内存限制超出");
return TextureRef();
}
}
// 创建缓存条目
auto result =
cache_.emplace(textureKey, TexturePoolEntry(nullptr, textureKey, 0));
if (result.second) {
result.first->second.texture = texture;
result.first->second.memorySize = memorySize;
result.first->second.refCount.store(1, std::memory_order_relaxed);
result.first->second.touch();
currentMemoryUsage_ += memorySize;
E2D_LOG_INFO("TexturePool: 已从内存创建纹理 ({} 字节)", memorySize);
return TextureRef(texture, &result.first->second, &mutex_);
}
return TextureRef();
} }
/** /**
@ -243,8 +239,9 @@ TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int heigh
* *
* *
*/ */
TextureRef TexturePool::getOrLoad(const std::string& path, const TextureLoadOptions& options) { TextureRef TexturePool::getOrLoad(const std::string &path,
return getOrLoad(path, Rect::Zero(), options); const TextureLoadOptions &options) {
return getOrLoad(path, Rect::Zero(), options);
} }
/** /**
@ -256,65 +253,66 @@ TextureRef TexturePool::getOrLoad(const std::string& path, const TextureLoadOpti
* *
* *
*/ */
TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region, TextureRef TexturePool::getOrLoad(const std::string &path, const Rect &region,
const TextureLoadOptions& options) { const TextureLoadOptions &options) {
TextureKey key(path, region); TextureKey key(path, region);
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
// 检查缓存 // 检查缓存
auto it = cache_.find(key); auto it = cache_.find(key);
if (it != cache_.end()) { if (it != cache_.end()) {
it->second.touch(); it->second.touch();
it->second.refCount.fetch_add(1, std::memory_order_relaxed); it->second.refCount.fetch_add(1, std::memory_order_relaxed);
cacheHits_.fetch_add(1, std::memory_order_relaxed); cacheHits_.fetch_add(1, std::memory_order_relaxed);
return TextureRef(it->second.texture, &it->second, &mutex_); return TextureRef(it->second.texture, &it->second, &mutex_);
} }
// 释放锁后调用 load // 释放锁后调用 load
// 注意:这里需要重新设计以避免死锁 // 注意:这里需要重新设计以避免死锁
// 简化处理:直接在这里加载 // 简化处理:直接在这里加载
cacheMisses_.fetch_add(1, std::memory_order_relaxed); cacheMisses_.fetch_add(1, std::memory_order_relaxed);
RenderBackend* backend = nullptr; Renderer *backend = nullptr;
if (scene_) { if (scene_) {
backend = nullptr; // TODO: 从 Scene 获取 RenderBackend backend = nullptr; // TODO: 从 Scene 获取 Renderer
} }
if (!backend) {
E2D_LOG_ERROR("TexturePool: 渲染后端不可用");
return TextureRef();
}
Ptr<Texture> texture = backend->loadTexture(path);
if (!texture) {
E2D_LOG_ERROR("TexturePool: 加载纹理失败: {}", path);
return TextureRef();
}
size_t memorySize = calculateTextureMemory(texture.get());
if (maxMemoryUsage_ > 0 && currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
evictLRU(currentMemoryUsage_ + memorySize - maxMemoryUsage_);
if (currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
E2D_LOG_WARN("TexturePool: 内存限制超出");
return TextureRef();
}
}
auto result = cache_.emplace(key, TexturePoolEntry(nullptr, key, 0));
if (result.second) {
result.first->second.texture = texture;
result.first->second.memorySize = memorySize;
result.first->second.refCount.store(1, std::memory_order_relaxed);
result.first->second.touch();
currentMemoryUsage_ += memorySize;
return TextureRef(texture, &result.first->second, &mutex_);
}
if (!backend) {
E2D_LOG_ERROR("TexturePool: 渲染后端不可用");
return TextureRef(); return TextureRef();
}
Ptr<Texture> texture = backend->loadTexture(path);
if (!texture) {
E2D_LOG_ERROR("TexturePool: 加载纹理失败: {}", path);
return TextureRef();
}
size_t memorySize = calculateTextureMemory(texture.get());
if (maxMemoryUsage_ > 0 &&
currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
evictLRU(currentMemoryUsage_ + memorySize - maxMemoryUsage_);
if (currentMemoryUsage_ + memorySize > maxMemoryUsage_) {
E2D_LOG_WARN("TexturePool: 内存限制超出");
return TextureRef();
}
}
auto result = cache_.emplace(key, TexturePoolEntry(nullptr, key, 0));
if (result.second) {
result.first->second.texture = texture;
result.first->second.memorySize = memorySize;
result.first->second.refCount.store(1, std::memory_order_relaxed);
result.first->second.touch();
currentMemoryUsage_ += memorySize;
return TextureRef(texture, &result.first->second, &mutex_);
}
return TextureRef();
} }
// ============================================================================ // ============================================================================
@ -328,16 +326,16 @@ TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region,
* *
* *
*/ */
bool TexturePool::addRef(const TextureKey& key) { bool TexturePool::addRef(const TextureKey &key) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
auto it = cache_.find(key); auto it = cache_.find(key);
if (it != cache_.end()) { if (it != cache_.end()) {
it->second.touch(); it->second.touch();
it->second.refCount.fetch_add(1, std::memory_order_relaxed); it->second.refCount.fetch_add(1, std::memory_order_relaxed);
return true; return true;
} }
return false; return false;
} }
/** /**
@ -347,15 +345,16 @@ bool TexturePool::addRef(const TextureKey& key) {
* *
* *
*/ */
uint32_t TexturePool::release(const TextureKey& key) { uint32_t TexturePool::release(const TextureKey &key) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
auto it = cache_.find(key); auto it = cache_.find(key);
if (it != cache_.end()) { if (it != cache_.end()) {
uint32_t count = it->second.refCount.fetch_sub(1, std::memory_order_relaxed); uint32_t count =
return count > 0 ? count - 1 : 0; it->second.refCount.fetch_sub(1, std::memory_order_relaxed);
} return count > 0 ? count - 1 : 0;
return 0; }
return 0;
} }
/** /**
@ -365,14 +364,14 @@ uint32_t TexturePool::release(const TextureKey& key) {
* *
* *
*/ */
uint32_t TexturePool::getRefCount(const TextureKey& key) const { uint32_t TexturePool::getRefCount(const TextureKey &key) const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
auto it = cache_.find(key); auto it = cache_.find(key);
if (it != cache_.end()) { if (it != cache_.end()) {
return it->second.refCount.load(std::memory_order_relaxed); return it->second.refCount.load(std::memory_order_relaxed);
} }
return 0; return 0;
} }
// ============================================================================ // ============================================================================
@ -386,9 +385,9 @@ uint32_t TexturePool::getRefCount(const TextureKey& key) const {
* *
* *
*/ */
bool TexturePool::isCached(const TextureKey& key) const { bool TexturePool::isCached(const TextureKey &key) const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
return cache_.find(key) != cache_.end(); return cache_.find(key) != cache_.end();
} }
/** /**
@ -398,17 +397,17 @@ bool TexturePool::isCached(const TextureKey& key) const {
* *
* *
*/ */
bool TexturePool::removeFromCache(const TextureKey& key) { bool TexturePool::removeFromCache(const TextureKey &key) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
auto it = cache_.find(key); auto it = cache_.find(key);
if (it != cache_.end()) { if (it != cache_.end()) {
currentMemoryUsage_ -= it->second.memorySize; currentMemoryUsage_ -= it->second.memorySize;
cache_.erase(it); cache_.erase(it);
E2D_LOG_DEBUG("TexturePool: 已从缓存移除纹理"); E2D_LOG_DEBUG("TexturePool: 已从缓存移除纹理");
return true; return true;
} }
return false; return false;
} }
/** /**
@ -418,24 +417,24 @@ bool TexturePool::removeFromCache(const TextureKey& key) {
* 0 * 0
*/ */
size_t TexturePool::collectGarbage() { size_t TexturePool::collectGarbage() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
size_t removed = 0; size_t removed = 0;
for (auto it = cache_.begin(); it != cache_.end(); ) { for (auto it = cache_.begin(); it != cache_.end();) {
if (it->second.refCount.load(std::memory_order_relaxed) == 0) { if (it->second.refCount.load(std::memory_order_relaxed) == 0) {
currentMemoryUsage_ -= it->second.memorySize; currentMemoryUsage_ -= it->second.memorySize;
it = cache_.erase(it); it = cache_.erase(it);
++removed; ++removed;
} else { } else {
++it; ++it;
}
} }
}
if (removed > 0) { if (removed > 0) {
E2D_LOG_INFO("TexturePool: 垃圾回收 {} 个纹理", removed); E2D_LOG_INFO("TexturePool: 垃圾回收 {} 个纹理", removed);
} }
return removed; return removed;
} }
/** /**
@ -444,12 +443,12 @@ size_t TexturePool::collectGarbage() {
* *
*/ */
void TexturePool::clear() { void TexturePool::clear() {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
cache_.clear(); cache_.clear();
currentMemoryUsage_ = 0; currentMemoryUsage_ = 0;
E2D_LOG_INFO("TexturePool: 已清除所有纹理"); E2D_LOG_INFO("TexturePool: 已清除所有纹理");
} }
// ============================================================================ // ============================================================================
@ -463,8 +462,8 @@ void TexturePool::clear() {
* 使 * 使
*/ */
size_t TexturePool::getMemoryUsage() const { size_t TexturePool::getMemoryUsage() const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
return currentMemoryUsage_; return currentMemoryUsage_;
} }
/** /**
@ -474,15 +473,15 @@ size_t TexturePool::getMemoryUsage() const {
* 使 * 使
*/ */
void TexturePool::setMaxMemoryUsage(size_t maxMemory) { void TexturePool::setMaxMemoryUsage(size_t maxMemory) {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
maxMemoryUsage_ = maxMemory; maxMemoryUsage_ = maxMemory;
// 如果当前内存超过新的限制,执行淘汰 // 如果当前内存超过新的限制,执行淘汰
if (maxMemoryUsage_ > 0 && currentMemoryUsage_ > maxMemoryUsage_) { if (maxMemoryUsage_ > 0 && currentMemoryUsage_ > maxMemoryUsage_) {
evictLRU(maxMemoryUsage_); evictLRU(maxMemoryUsage_);
} }
E2D_LOG_INFO("TexturePool: 最大内存设置为 {} 字节", maxMemory); E2D_LOG_INFO("TexturePool: 最大内存设置为 {} 字节", maxMemory);
} }
/** /**
@ -493,49 +492,49 @@ void TexturePool::setMaxMemoryUsage(size_t maxMemory) {
* LRU算法淘汰最少使用的纹理以达到目标内存使用量 * LRU算法淘汰最少使用的纹理以达到目标内存使用量
*/ */
size_t TexturePool::evictLRU(size_t targetMemory) { size_t TexturePool::evictLRU(size_t targetMemory) {
// 注意:调用者应该已持有锁 // 注意:调用者应该已持有锁
if (cache_.empty()) { if (cache_.empty()) {
return 0; return 0;
}
// 收集所有条目并按最后访问时间排序
std::vector<std::pair<TextureKey, uint64_t>> entries;
entries.reserve(cache_.size());
for (const auto &pair : cache_) {
// 只淘汰引用计数为 0 的纹理
if (pair.second.refCount.load(std::memory_order_relaxed) == 0) {
entries.emplace_back(pair.first, pair.second.lastAccessTime);
}
}
// 按访问时间升序排序(最旧的在前)
std::sort(entries.begin(), entries.end(),
[](const auto &a, const auto &b) { return a.second < b.second; });
size_t evicted = 0;
size_t target = targetMemory > 0 ? targetMemory : 0;
for (const auto &entry : entries) {
if (targetMemory > 0 && currentMemoryUsage_ <= target) {
break;
} }
// 收集所有条目并按最后访问时间排序 auto it = cache_.find(entry.first);
std::vector<std::pair<TextureKey, uint64_t>> entries; if (it != cache_.end()) {
entries.reserve(cache_.size()); currentMemoryUsage_ -= it->second.memorySize;
cache_.erase(it);
for (const auto& pair : cache_) { ++evicted;
// 只淘汰引用计数为 0 的纹理
if (pair.second.refCount.load(std::memory_order_relaxed) == 0) {
entries.emplace_back(pair.first, pair.second.lastAccessTime);
}
} }
}
// 按访问时间升序排序(最旧的在前) if (evicted > 0) {
std::sort(entries.begin(), entries.end(), evictionCount_.fetch_add(evicted, std::memory_order_relaxed);
[](const auto& a, const auto& b) { return a.second < b.second; }); E2D_LOG_INFO("TexturePool: LRU 淘汰 {} 个纹理", evicted);
}
size_t evicted = 0; return evicted;
size_t target = targetMemory > 0 ? targetMemory : 0;
for (const auto& entry : entries) {
if (targetMemory > 0 && currentMemoryUsage_ <= target) {
break;
}
auto it = cache_.find(entry.first);
if (it != cache_.end()) {
currentMemoryUsage_ -= it->second.memorySize;
cache_.erase(it);
++evicted;
}
}
if (evicted > 0) {
evictionCount_.fetch_add(evicted, std::memory_order_relaxed);
E2D_LOG_INFO("TexturePool: LRU 淘汰 {} 个纹理", evicted);
}
return evicted;
} }
// ============================================================================ // ============================================================================
@ -549,17 +548,17 @@ size_t TexturePool::evictLRU(size_t targetMemory) {
* 使 * 使
*/ */
TexturePool::Stats TexturePool::getStats() const { TexturePool::Stats TexturePool::getStats() const {
std::lock_guard<std::mutex> lock(mutex_); std::lock_guard<std::mutex> lock(mutex_);
Stats stats; Stats stats;
stats.textureCount = cache_.size(); stats.textureCount = cache_.size();
stats.memoryUsage = currentMemoryUsage_; stats.memoryUsage = currentMemoryUsage_;
stats.maxMemoryUsage = maxMemoryUsage_; stats.maxMemoryUsage = maxMemoryUsage_;
stats.cacheHits = cacheHits_.load(std::memory_order_relaxed); stats.cacheHits = cacheHits_.load(std::memory_order_relaxed);
stats.cacheMisses = cacheMisses_.load(std::memory_order_relaxed); stats.cacheMisses = cacheMisses_.load(std::memory_order_relaxed);
stats.evictionCount = evictionCount_.load(std::memory_order_relaxed); stats.evictionCount = evictionCount_.load(std::memory_order_relaxed);
return stats; return stats;
} }
/** /**
@ -568,9 +567,9 @@ TexturePool::Stats TexturePool::getStats() const {
* *
*/ */
void TexturePool::resetStats() { void TexturePool::resetStats() {
cacheHits_.store(0, std::memory_order_relaxed); cacheHits_.store(0, std::memory_order_relaxed);
cacheMisses_.store(0, std::memory_order_relaxed); cacheMisses_.store(0, std::memory_order_relaxed);
evictionCount_.store(0, std::memory_order_relaxed); evictionCount_.store(0, std::memory_order_relaxed);
} }
// ============================================================================ // ============================================================================
@ -584,48 +583,48 @@ void TexturePool::resetStats() {
* *
* *
*/ */
size_t TexturePool::calculateTextureMemory(const Texture* texture) { size_t TexturePool::calculateTextureMemory(const Texture *texture) {
if (!texture) { if (!texture) {
return 0; return 0;
} }
int width = texture->getWidth(); int width = texture->getWidth();
int height = texture->getHeight(); int height = texture->getHeight();
int channels = texture->getChannels(); int channels = texture->getChannels();
// 基础内存计算 // 基础内存计算
size_t baseSize = static_cast<size_t>(width) * height * channels; size_t baseSize = static_cast<size_t>(width) * height * channels;
// 根据像素格式调整 // 根据像素格式调整
PixelFormat format = texture->getFormat(); PixelFormat format = texture->getFormat();
switch (format) { switch (format) {
case PixelFormat::RGB16F: case PixelFormat::RGB16F:
case PixelFormat::RGBA16F: case PixelFormat::RGBA16F:
baseSize *= 2; // 半精度浮点 baseSize *= 2; // 半精度浮点
break; break;
case PixelFormat::RGB32F: case PixelFormat::RGB32F:
case PixelFormat::RGBA32F: case PixelFormat::RGBA32F:
baseSize *= 4; // 全精度浮点 baseSize *= 4; // 全精度浮点
break; break;
case PixelFormat::Depth16: case PixelFormat::Depth16:
baseSize = static_cast<size_t>(width) * height * 2; baseSize = static_cast<size_t>(width) * height * 2;
break; break;
case PixelFormat::Depth24: case PixelFormat::Depth24:
case PixelFormat::Depth24Stencil8: case PixelFormat::Depth24Stencil8:
baseSize = static_cast<size_t>(width) * height * 4; baseSize = static_cast<size_t>(width) * height * 4;
break; break;
case PixelFormat::Depth32F: case PixelFormat::Depth32F:
baseSize = static_cast<size_t>(width) * height * 4; baseSize = static_cast<size_t>(width) * height * 4;
break; break;
default: default:
break; break;
} }
// 考虑 Mipmaps大约增加 33% 内存) // 考虑 Mipmaps大约增加 33% 内存)
// 注意:这里假设生成了 mipmaps实际应该根据 TextureLoadOptions 判断 // 注意:这里假设生成了 mipmaps实际应该根据 TextureLoadOptions 判断
// baseSize = baseSize * 4 / 3; // baseSize = baseSize * 4 / 3;
return baseSize; return baseSize;
} }
/** /**
@ -635,7 +634,7 @@ size_t TexturePool::calculateTextureMemory(const Texture* texture) {
* 使 * 使
*/ */
bool TexturePool::needsEviction() const { bool TexturePool::needsEviction() const {
return maxMemoryUsage_ > 0 && currentMemoryUsage_ > maxMemoryUsage_; return maxMemoryUsage_ > 0 && currentMemoryUsage_ > maxMemoryUsage_;
} }
/** /**
@ -644,9 +643,9 @@ bool TexturePool::needsEviction() const {
* 使LRU淘汰 * 使LRU淘汰
*/ */
void TexturePool::tryAutoEvict() { void TexturePool::tryAutoEvict() {
if (needsEviction()) { if (needsEviction()) {
evictLRU(maxMemoryUsage_); evictLRU(maxMemoryUsage_);
} }
} }
} // namespace extra2d } // namespace extra2d

View File

@ -511,12 +511,12 @@ 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;
@ -579,7 +579,7 @@ void Node::update(float dt) { onUpdate(dt); }
* *
* onRender进行渲染 * onRender进行渲染
*/ */
void Node::render(RenderBackend &renderer) { void Node::render(Renderer &renderer) {
if (childrenOrderDirty_) { if (childrenOrderDirty_) {
sortChildren(); sortChildren();
} }

View File

@ -1,8 +1,9 @@
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_command.h> #include <extra2d/graphics/core/render_command.h>
#include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/scene/scene.h> #include <extra2d/scene/scene.h>
#include <extra2d/services/logger_service.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
/** /**
@ -48,7 +49,7 @@ void Scene::setViewportSize(const Size &size) {
* *
* *
*/ */
void Scene::renderScene(RenderBackend &renderer) { void Scene::renderScene(Renderer &renderer) {
if (!isVisible()) if (!isVisible())
return; return;
@ -65,7 +66,7 @@ void Scene::renderScene(RenderBackend &renderer) {
* *
* Application CameraService * Application CameraService
*/ */
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/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_command.h> #include <extra2d/graphics/core/render_command.h>
#include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/platform/keys.h> #include <extra2d/platform/keys.h>
#include <extra2d/scene/scene_manager.h> #include <extra2d/scene/scene_manager.h>
#include <extra2d/scene/transition_box_scene.h> #include <extra2d/scene/transition_box_scene.h>
@ -13,6 +13,7 @@
#include <extra2d/services/event_service.h> #include <extra2d/services/event_service.h>
#include <extra2d/services/logger_service.h> #include <extra2d/services/logger_service.h>
namespace extra2d { namespace extra2d {
namespace { namespace {
@ -89,32 +90,36 @@ void SceneManager::setupEventListeners() {
return; return;
} }
mouseMoveListener_ = eventService->addListener(EventType::MouseMoved, [this](Event &e) { mouseMoveListener_ =
auto &mouseEvent = std::get<MouseMoveEvent>(e.data); eventService->addListener(EventType::MouseMoved, [this](Event &e) {
mousePos_ = mouseEvent.position; auto &mouseEvent = std::get<MouseMoveEvent>(e.data);
mouseDelta_ = mouseEvent.delta; mousePos_ = mouseEvent.position;
}); mouseDelta_ = mouseEvent.delta;
});
mousePressListener_ = eventService->addListener(EventType::MouseButtonPressed, [this](Event &e) { mousePressListener_ = eventService->addListener(
auto &mouseEvent = std::get<MouseButtonEvent>(e.data); EventType::MouseButtonPressed, [this](Event &e) {
if (mouseEvent.button == static_cast<int>(Mouse::Left)) { auto &mouseEvent = std::get<MouseButtonEvent>(e.data);
mouseLeftPressed_ = true; if (mouseEvent.button == static_cast<int>(Mouse::Left)) {
mouseLeftDown_ = true; mouseLeftPressed_ = true;
} mouseLeftDown_ = true;
}); }
});
mouseReleaseListener_ = eventService->addListener(EventType::MouseButtonReleased, [this](Event &e) { mouseReleaseListener_ = eventService->addListener(
auto &mouseEvent = std::get<MouseButtonEvent>(e.data); EventType::MouseButtonReleased, [this](Event &e) {
if (mouseEvent.button == static_cast<int>(Mouse::Left)) { auto &mouseEvent = std::get<MouseButtonEvent>(e.data);
mouseLeftReleased_ = true; if (mouseEvent.button == static_cast<int>(Mouse::Left)) {
mouseLeftDown_ = false; mouseLeftReleased_ = true;
} mouseLeftDown_ = false;
}); }
});
scrollListener_ = eventService->addListener(EventType::MouseScrolled, [this](Event &e) { scrollListener_ =
auto &scrollEvent = std::get<MouseScrollEvent>(e.data); eventService->addListener(EventType::MouseScrolled, [this](Event &e) {
scrollDelta_ = scrollEvent.offset.y; auto &scrollEvent = std::get<MouseScrollEvent>(e.data);
}); scrollDelta_ = scrollEvent.offset.y;
});
} }
/** /**
@ -610,7 +615,7 @@ void SceneManager::update(float dt) {
* *
* 使 * 使
*/ */
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,10 +1,11 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_command.h> #include <extra2d/graphics/core/render_command.h>
#include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/scene/shape_node.h> #include <extra2d/scene/shape_node.h>
#include <limits> #include <limits>
namespace extra2d { namespace extra2d {
/** /**
@ -196,24 +197,18 @@ Ptr<ShapeNode> ShapeNode::createFilledPolygon(const std::vector<Vec2> &points,
* @brief * @brief
* @param points * @param points
*/ */
void ShapeNode::setPoints(const std::vector<Vec2> &points) { void ShapeNode::setPoints(const std::vector<Vec2> &points) { points_ = points; }
points_ = points;
}
/** /**
* @brief * @brief
* @param point * @param point
*/ */
void ShapeNode::addPoint(const Vec2 &point) { void ShapeNode::addPoint(const Vec2 &point) { points_.push_back(point); }
points_.push_back(point);
}
/** /**
* @brief * @brief
*/ */
void ShapeNode::clearPoints() { void ShapeNode::clearPoints() { points_.clear(); }
points_.clear();
}
/** /**
* @brief * @brief
@ -271,7 +266,7 @@ Rect ShapeNode::getBounds() const {
* Node::onRender pushTransform * Node::onRender pushTransform
* 使 * 使
*/ */
void ShapeNode::onDraw(RenderBackend &renderer) { void ShapeNode::onDraw(Renderer &renderer) {
if (points_.empty()) { if (points_.empty()) {
return; return;
} }
@ -361,16 +356,16 @@ void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
case ShapeType::Point: case ShapeType::Point:
if (!points_.empty()) { if (!points_.empty()) {
cmd.type = RenderCommandType::FilledCircle; cmd.type = RenderCommandType::FilledCircle;
cmd.data = cmd.data = CircleCommandData{
CircleCommandData{points_[0] + offset, lineWidth_ * 0.5f, color_, 8, 0.0f, true}; points_[0] + offset, lineWidth_ * 0.5f, color_, 8, 0.0f, true};
} }
break; break;
case ShapeType::Line: case ShapeType::Line:
if (points_.size() >= 2) { if (points_.size() >= 2) {
cmd.type = RenderCommandType::Line; cmd.type = RenderCommandType::Line;
cmd.data = LineCommandData{points_[0] + offset, points_[1] + offset, color_, cmd.data = LineCommandData{points_[0] + offset, points_[1] + offset,
lineWidth_}; color_, lineWidth_};
} }
break; break;
@ -380,14 +375,14 @@ void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
cmd.type = RenderCommandType::FilledRect; cmd.type = RenderCommandType::FilledRect;
Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x, Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x,
points_[2].y - points_[0].y); points_[2].y - points_[0].y);
cmd.data = cmd.data = RectCommandData{Rect(rect.origin + offset, rect.size),
RectCommandData{Rect(rect.origin + offset, rect.size), color_, 0.0f, true}; color_, 0.0f, true};
} else { } else {
cmd.type = RenderCommandType::Rect; cmd.type = RenderCommandType::Rect;
Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x, Rect rect(points_[0].x, points_[0].y, points_[2].x - points_[0].x,
points_[2].y - points_[0].y); points_[2].y - points_[0].y);
cmd.data = cmd.data = RectCommandData{Rect(rect.origin + offset, rect.size),
RectCommandData{Rect(rect.origin + offset, rect.size), color_, lineWidth_, false}; color_, lineWidth_, false};
} }
} }
break; break;
@ -397,12 +392,12 @@ void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
float radius = points_[1].x; float radius = points_[1].x;
if (filled_) { if (filled_) {
cmd.type = RenderCommandType::FilledCircle; cmd.type = RenderCommandType::FilledCircle;
cmd.data = cmd.data = CircleCommandData{points_[0] + offset, radius, color_,
CircleCommandData{points_[0] + offset, radius, color_, segments_, 0.0f, true}; segments_, 0.0f, true};
} else { } else {
cmd.type = RenderCommandType::Circle; cmd.type = RenderCommandType::Circle;
cmd.data = CircleCommandData{points_[0] + offset, radius, color_, segments_, cmd.data = CircleCommandData{points_[0] + offset, radius, color_,
lineWidth_, false}; segments_, lineWidth_, false};
} }
} }
break; break;
@ -435,7 +430,8 @@ void ShapeNode::generateRenderCommand(std::vector<RenderCommand> &commands,
cmd.data = PolygonCommandData{transformedPoints, color_, 0.0f, true}; cmd.data = PolygonCommandData{transformedPoints, color_, 0.0f, true};
} else { } else {
cmd.type = RenderCommandType::Polygon; cmd.type = RenderCommandType::Polygon;
cmd.data = PolygonCommandData{transformedPoints, color_, lineWidth_, false}; cmd.data =
PolygonCommandData{transformedPoints, color_, lineWidth_, false};
} }
} }
break; break;

View File

@ -1,7 +1,7 @@
#include <algorithm> #include <algorithm>
#include <cmath> #include <cmath>
#include <extra2d/graphics/core/render_backend.h>
#include <extra2d/graphics/core/render_command.h> #include <extra2d/graphics/core/render_command.h>
#include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/graphics/texture/texture.h> #include <extra2d/graphics/texture/texture.h>
#include <extra2d/scene/sprite.h> #include <extra2d/scene/sprite.h>
@ -127,7 +127,7 @@ Rect Sprite::getBounds() const {
* *
* 使 * 使
*/ */
void Sprite::onDraw(RenderBackend &renderer) { void Sprite::onDraw(Renderer &renderer) {
if (!texture_ || !texture_->isValid()) { if (!texture_ || !texture_->isValid()) {
return; return;
} }
@ -151,7 +151,7 @@ void Sprite::onDraw(RenderBackend &renderer) {
auto anchor = getAnchor(); auto anchor = getAnchor();
// 锚点由 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
@ -204,7 +204,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,11 +1,12 @@
#include <extra2d/scene/transition_box_scene.h> #include <algorithm>
#include <extra2d/app/application.h> #include <extra2d/app/application.h>
#include <extra2d/core/color.h> #include <extra2d/core/color.h>
#include <extra2d/graphics/core/render_backend.h> #include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/platform/glfw/glfw_window.h> #include <extra2d/platform/glfw/glfw_window.h>
#include <algorithm> #include <extra2d/scene/transition_box_scene.h>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
namespace extra2d { namespace extra2d {
/** /**
@ -25,9 +26,8 @@ TransitionBoxScene::TransitionBoxScene(float duration, Ptr<Scene> inScene,
* @param divisions * @param divisions
* @return * @return
*/ */
Ptr<TransitionBoxScene> TransitionBoxScene::create(float duration, Ptr<TransitionBoxScene>
Ptr<Scene> inScene, TransitionBoxScene::create(float duration, Ptr<Scene> inScene, int divisions) {
int divisions) {
return makePtr<TransitionBoxScene>(duration, inScene, divisions); return makePtr<TransitionBoxScene>(duration, inScene, divisions);
} }
@ -36,8 +36,7 @@ Ptr<TransitionBoxScene> TransitionBoxScene::create(float duration,
* *
* *
*/ */
void TransitionBoxScene::onTransitionStart() { void TransitionBoxScene::onTransitionStart() {}
}
/** /**
* @brief * @brief
@ -53,7 +52,7 @@ void TransitionBoxScene::updateTransition(float dt) {
* *
* *
*/ */
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/graphics/core/render_backend.h> #include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/platform/glfw/glfw_window.h> #include <extra2d/platform/glfw/glfw_window.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,8 @@
#include <extra2d/scene/transition_flip_scene.h>
#include <extra2d/core/math_types.h> #include <extra2d/core/math_types.h>
#include <extra2d/graphics/camera/camera.h> #include <extra2d/graphics/camera/camera.h>
#include <extra2d/graphics/core/render_backend.h> #include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/scene/transition_flip_scene.h>
namespace extra2d { namespace extra2d {
@ -22,9 +23,8 @@ TransitionFlipScene::TransitionFlipScene(float duration, Ptr<Scene> inScene,
* @param axis * @param axis
* @return * @return
*/ */
Ptr<TransitionFlipScene> TransitionFlipScene::create(float duration, Ptr<TransitionFlipScene>
Ptr<Scene> inScene, TransitionFlipScene::create(float duration, Ptr<Scene> inScene, Axis axis) {
Axis axis) {
return makePtr<TransitionFlipScene>(duration, inScene, axis); return makePtr<TransitionFlipScene>(duration, inScene, axis);
} }
@ -33,8 +33,7 @@ Ptr<TransitionFlipScene> TransitionFlipScene::create(float duration,
* *
* *
*/ */
void TransitionFlipScene::onTransitionStart() { void TransitionFlipScene::onTransitionStart() {}
}
/** /**
* @brief * @brief
@ -50,9 +49,10 @@ void TransitionFlipScene::updateTransition(float dt) {
* *
* *
*/ */
void TransitionFlipScene::renderContent(RenderBackend &renderer) { void TransitionFlipScene::renderContent(Renderer &renderer) {
float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_ float easeProgress = progress_ < 0.5f
: -1.0f + (4.0f - 2.0f * progress_) * progress_; ? 2.0f * progress_ * progress_
: -1.0f + (4.0f - 2.0f * progress_) * progress_;
float angle = easeProgress * PI_F; float angle = easeProgress * PI_F;
@ -103,7 +103,6 @@ void TransitionFlipScene::renderContent(RenderBackend &renderer) {
} }
} }
} }
} }
} // namespace extra2d } // namespace extra2d

View File

@ -1,7 +1,8 @@
#include <extra2d/scene/transition_scale_scene.h>
#include <extra2d/graphics/camera/camera.h>
#include <extra2d/graphics/core/render_backend.h>
#include <algorithm> #include <algorithm>
#include <extra2d/graphics/camera/camera.h>
#include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/scene/transition_scale_scene.h>
namespace extra2d { namespace extra2d {
@ -29,8 +30,7 @@ Ptr<TransitionScaleScene> TransitionScaleScene::create(float duration,
* *
* *
*/ */
void TransitionScaleScene::onTransitionStart() { void TransitionScaleScene::onTransitionStart() {}
}
/** /**
* @brief * @brief
@ -46,9 +46,10 @@ void TransitionScaleScene::updateTransition(float dt) {
* *
* *
*/ */
void TransitionScaleScene::renderContent(RenderBackend &renderer) { void TransitionScaleScene::renderContent(Renderer &renderer) {
float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_ float easeProgress = progress_ < 0.5f
: -1.0f + (4.0f - 2.0f * progress_) * progress_; ? 2.0f * progress_ * progress_
: -1.0f + (4.0f - 2.0f * progress_) * progress_;
if (outScene_) { if (outScene_) {
float scale = std::max(0.01f, 1.0f - easeProgress); float scale = std::max(0.01f, 1.0f - easeProgress);
@ -83,7 +84,6 @@ void TransitionScaleScene::renderContent(RenderBackend &renderer) {
camera->setZoom(originalZoom); camera->setZoom(originalZoom);
} }
} }
} }
} // namespace extra2d } // namespace extra2d

View File

@ -1,5 +1,5 @@
#include <extra2d/core/service_locator.h> #include <extra2d/core/service_locator.h>
#include <extra2d/graphics/core/render_backend.h> #include <extra2d/graphics/opengl/gl_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>
@ -119,7 +119,7 @@ void TransitionScene::cancel(bool immediate) {
* *
* 退 * 退
*/ */
void TransitionScene::renderContent(RenderBackend &renderer) { void TransitionScene::renderContent(Renderer &renderer) {
drawOutScene(renderer); drawOutScene(renderer);
drawInScene(renderer); drawInScene(renderer);
} }
@ -128,7 +128,7 @@ void TransitionScene::renderContent(RenderBackend &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);
} }
@ -138,7 +138,7 @@ 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,7 +1,8 @@
#include <extra2d/scene/transition_slide_scene.h>
#include <extra2d/graphics/camera/camera.h>
#include <extra2d/graphics/core/render_backend.h>
#include <algorithm> #include <algorithm>
#include <extra2d/graphics/camera/camera.h>
#include <extra2d/graphics/opengl/gl_renderer.h>
#include <extra2d/scene/transition_slide_scene.h>
namespace extra2d { namespace extra2d {
@ -22,8 +23,9 @@ TransitionSlideScene::TransitionSlideScene(float duration, Ptr<Scene> inScene,
* @param direction * @param direction
* @return * @return
*/ */
Ptr<TransitionSlideScene> TransitionSlideScene::create( Ptr<TransitionSlideScene>
float duration, Ptr<Scene> inScene, TransitionDirection direction) { TransitionSlideScene::create(float duration, Ptr<Scene> inScene,
TransitionDirection direction) {
return makePtr<TransitionSlideScene>(duration, inScene, direction); return makePtr<TransitionSlideScene>(duration, inScene, direction);
} }
@ -32,8 +34,7 @@ Ptr<TransitionSlideScene> TransitionSlideScene::create(
* *
* *
*/ */
void TransitionSlideScene::onTransitionStart() { void TransitionSlideScene::onTransitionStart() {}
}
/** /**
* @brief * @brief
@ -49,7 +50,7 @@ void TransitionSlideScene::updateTransition(float dt) {
* *
* *
*/ */
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;
@ -67,8 +68,9 @@ void TransitionSlideScene::renderContent(RenderBackend &renderer) {
} }
} }
float easeProgress = progress_ < 0.5f ? 2.0f * progress_ * progress_ float easeProgress = progress_ < 0.5f
: -1.0f + (4.0f - 2.0f * progress_) * progress_; ? 2.0f * progress_ * progress_
: -1.0f + (4.0f - 2.0f * progress_) * progress_;
if (outScene_) { if (outScene_) {
float offsetX = 0.0f; float offsetX = 0.0f;
@ -135,7 +137,6 @@ void TransitionSlideScene::renderContent(RenderBackend &renderer) {
camera->setPos(originalPos); camera->setPos(originalPos);
} }
} }
} }
} // namespace extra2d } // namespace extra2d

View File

@ -68,9 +68,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);
}
void SceneService::collectRenderCommands(std::vector<RenderCommand> &commands) { void SceneService::collectRenderCommands(std::vector<RenderCommand> &commands) {
manager_.collectRenderCommands(commands); manager_.collectRenderCommands(commands);

View File

@ -96,7 +96,7 @@ flowchart TB
subgraph Graphics["Graphics (图形系统)"] subgraph Graphics["Graphics (图形系统)"]
direction TB direction TB
RESOURCES[Resources<br/>资源抽象层] RESOURCES[Resources<br/>资源抽象层]
BACKEND[RenderBackend<br/>渲染后端] BACKEND[Renderer<br/>渲染后端]
BATCH[Batch Layer<br/>批处理层] BATCH[Batch Layer<br/>批处理层]
GL[OpenGL Backend<br/>OpenGL 后端] GL[OpenGL Backend<br/>OpenGL 后端]
VK[Vulkan Backend<br/>Vulkan 后端] VK[Vulkan Backend<br/>Vulkan 后端]

View File

@ -229,9 +229,9 @@ cameraService->setZoom(2.0f);
### 渲染后端接口 ### 渲染后端接口
```cpp ```cpp
class RenderBackend { class Renderer {
public: public:
virtual ~RenderBackend() = default; virtual ~Renderer() = default;
// 生命周期 // 生命周期
virtual bool init(IWindow* window) = 0; virtual bool init(IWindow* window) = 0;
@ -276,7 +276,7 @@ public:
virtual void drawText(const FontAtlas &font, const std::string &text, const Vec2 &position, const Color &color) = 0; virtual void drawText(const FontAtlas &font, const std::string &text, const Vec2 &position, const Color &color) = 0;
// 工厂方法 // 工厂方法
static UniquePtr<RenderBackend> create(BackendType type); static UniquePtr<Renderer> create(BackendType type);
}; };
``` ```
@ -407,7 +407,7 @@ public:
virtual void onEnter(); virtual void onEnter();
virtual void onExit(); virtual void onExit();
virtual void onUpdate(float dt); virtual void onUpdate(float dt);
virtual void onRender(RenderBackend& renderer); virtual void onRender(Renderer& renderer);
}; };
``` ```

View File

@ -90,7 +90,7 @@ public:
* @brief * @brief
* @param renderer * @param renderer
*/ */
void onRender(RenderBackend &renderer) override { Scene::onRender(renderer); } void onRender(Renderer &renderer) override { Scene::onRender(renderer); }
}; };
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -107,9 +107,7 @@ int main(int argc, char *argv[]) {
cfg.priority = 0; cfg.priority = 0;
}); });
app.use<RenderModule>([](auto &cfg) { app.use<RenderModule>([](auto &cfg) { cfg.priority = 10; });
cfg.priority = 10;
});
std::cout << "Initializing application..." << std::endl; std::cout << "Initializing application..." << std::endl;
if (!app.init()) { if (!app.init()) {

View File

@ -29,7 +29,7 @@ public:
time_ = 0.0f; time_ = 0.0f;
} }
} }
void onRender(RenderBackend &renderer) override { Scene::onRender(renderer); } void onRender(Renderer &renderer) override { Scene::onRender(renderer); }
private: private:
float time_ = 0.0f; float time_ = 0.0f;
@ -44,9 +44,7 @@ int main(int argc, char *argv[]) {
cfg.w = 800; cfg.w = 800;
cfg.h = 600; cfg.h = 600;
}); });
app.use<RenderModule>([](auto &cfg) { app.use<RenderModule>([](auto &cfg) { cfg.priority = 10; });
cfg.priority = 10;
});
app.use<HelloModule>([](auto &cfg) { app.use<HelloModule>([](auto &cfg) {
cfg.greeting = "Hello from custom module!"; cfg.greeting = "Hello from custom module!";
cfg.repeatCount = 3; cfg.repeatCount = 3;

View File

@ -2,7 +2,7 @@
* @file main.cpp * @file main.cpp
* @brief Extra2D * @brief Extra2D
* *
* 使 RenderBackend * 使 Renderer
* OpenGL * OpenGL
*/ */
@ -40,14 +40,14 @@ public:
void onExit() override { texture_.reset(); } void onExit() override { texture_.reset(); }
void onRender(RenderBackend &renderer) override { void onRender(Renderer &renderer) override {
Scene::onRender(renderer); Scene::onRender(renderer);
if (!texture_) { if (!texture_) {
return; return;
} }
// 使用 RenderBackend 的抽象接口绘制图片 // 使用 Renderer 的抽象接口绘制图片
// 不依赖任何特定后端(如 OpenGL // 不依赖任何特定后端(如 OpenGL
// 自动批处理:无需手动调用 begin/endSpriteBatch // 自动批处理:无需手动调用 begin/endSpriteBatch
@ -70,7 +70,7 @@ public:
float x = (windowWidth - displayWidth) * 0.5f; float x = (windowWidth - displayWidth) * 0.5f;
float y = (windowHeight - displayHeight) * 0.5f; float y = (windowHeight - displayHeight) * 0.5f;
// 使用 RenderBackend 的 drawSprite 方法绘制图片 // 使用 Renderer 的 drawSprite 方法绘制图片
// 参数:纹理、目标矩形、源矩形、颜色、旋转角度、锚点 // 参数:纹理、目标矩形、源矩形、颜色、旋转角度、锚点
Rect destRect(x, y, displayWidth, displayHeight); Rect destRect(x, y, displayWidth, displayHeight);
Rect srcRect(0, 0, imgWidth, imgHeight); Rect srcRect(0, 0, imgWidth, imgHeight);
@ -80,11 +80,11 @@ public:
// 注意:无需手动调用 renderer.endSpriteBatch(),帧结束时会自动刷新 // 注意:无需手动调用 renderer.endSpriteBatch(),帧结束时会自动刷新
} }
void setRenderer(RenderBackend *renderer) { renderer_ = renderer; } void setRenderer(Renderer *renderer) { renderer_ = renderer; }
private: private:
Ptr<Texture> texture_; Ptr<Texture> texture_;
RenderBackend *renderer_ = nullptr; Renderer *renderer_ = nullptr;
}; };
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -103,9 +103,7 @@ int main(int argc, char *argv[]) {
cfg.priority = 0; cfg.priority = 0;
}); });
app.use<RenderModule>([](auto &cfg) { app.use<RenderModule>([](auto &cfg) { cfg.priority = 10; });
cfg.priority = 10;
});
if (!app.init()) { if (!app.init()) {
std::cerr << "Failed to initialize application!" << std::endl; std::cerr << "Failed to initialize application!" << std::endl;
@ -127,7 +125,7 @@ int main(int argc, char *argv[]) {
} }
// 获取渲染器 // 获取渲染器
RenderBackend *renderer = app.renderer(); Renderer *renderer = app.renderer();
// 创建并配置场景 // 创建并配置场景
auto scene = makeShared<ImageDisplayScene>(); auto scene = makeShared<ImageDisplayScene>();

View File

@ -2,7 +2,7 @@
* @file main.cpp * @file main.cpp
* @brief Extra2D * @brief Extra2D
* *
* 使 RenderBackend * 使 Renderer
* OpenGL * OpenGL
*/ */
@ -40,7 +40,7 @@ public:
void onExit() override { font_.reset(); } void onExit() override { font_.reset(); }
void onRender(RenderBackend &renderer) override { void onRender(Renderer &renderer) override {
Scene::onRender(renderer); Scene::onRender(renderer);
if (!font_) { if (!font_) {
@ -85,21 +85,21 @@ public:
Color(0.5f, 0.5f, 0.5f, 1.0f)); Color(0.5f, 0.5f, 0.5f, 1.0f));
} }
void setRenderer(RenderBackend *renderer) { renderer_ = renderer; } void setRenderer(Renderer *renderer) { renderer_ = renderer; }
private: private:
void renderText(RenderBackend &renderer, const std::string &text, float x, void renderText(Renderer &renderer, const std::string &text, float x, float y,
float y, const Color &color) { const Color &color) {
if (!font_) { if (!font_) {
return; return;
} }
// 使用 RenderBackend 的 drawText 方法 // 使用 Renderer 的 drawText 方法
renderer.drawText(*font_, text, Vec2(x, y), color); renderer.drawText(*font_, text, Vec2(x, y), color);
} }
Ptr<FontAtlas> font_; Ptr<FontAtlas> font_;
RenderBackend *renderer_ = nullptr; Renderer *renderer_ = nullptr;
}; };
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@ -139,7 +139,7 @@ int main(int argc, char *argv[]) {
} }
// 获取渲染器 // 获取渲染器
RenderBackend *renderer = app.renderer(); Renderer *renderer = app.renderer();
// 创建并配置场景 // 创建并配置场景
auto scene = makeShared<TextRenderingScene>(); auto scene = makeShared<TextRenderingScene>();