From cba2a5eb313b38251625114bf9320392c1d9f2a2 Mon Sep 17 00:00:00 2001 From: ChestnutYueyue <952134128@qq.com> Date: Sun, 15 Feb 2026 15:21:31 +0800 Subject: [PATCH] =?UTF-8?q?refactor(graphics):=20=E5=B0=86Ptr=E6=9B=BF?= =?UTF-8?q?=E6=8D=A2=E4=B8=BASharedPtr=E4=BB=A5=E7=BB=9F=E4=B8=80=E6=99=BA?= =?UTF-8?q?=E8=83=BD=E6=8C=87=E9=92=88=E4=BD=BF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将代码中的Ptr统一替换为SharedPtr,主要涉及纹理、渲染目标、精灵等图形相关类。修改包括: 1. 纹理创建和加载接口 2. 渲染目标与纹理的关联 3. 精灵节点的纹理引用 4. 纹理池的条目管理 同时更新文档说明智能指针类型选择策略 --- .../extra2d/graphics/opengl/gl_renderer.h | 6 +- .../extra2d/graphics/opengl/gl_texture.h | 2 +- .../include/extra2d/graphics/render_backend.h | 13 +- .../include/extra2d/graphics/render_target.h | 10 +- .../include/extra2d/graphics/texture_atlas.h | 4 +- .../include/extra2d/graphics/texture_pool.h | 12 +- Extra2D/include/extra2d/scene/sprite.h | 12 +- Extra2D/src/graphics/opengl/gl_renderer.cpp | 17 +-- Extra2D/src/graphics/opengl/gl_texture.cpp | 4 +- Extra2D/src/graphics/render_target.cpp | 2 +- Extra2D/src/graphics/texture_atlas.cpp | 2 +- Extra2D/src/graphics/texture_pool.cpp | 6 +- Extra2D/src/scene/sprite.cpp | 8 +- docs/module_system.md | 128 +++++++++++++++++- 14 files changed, 171 insertions(+), 55 deletions(-) diff --git a/Extra2D/include/extra2d/graphics/opengl/gl_renderer.h b/Extra2D/include/extra2d/graphics/opengl/gl_renderer.h index e0964ce..7bdf22b 100644 --- a/Extra2D/include/extra2d/graphics/opengl/gl_renderer.h +++ b/Extra2D/include/extra2d/graphics/opengl/gl_renderer.h @@ -37,9 +37,9 @@ public: void popTransform() override; glm::mat4 getCurrentTransform() const override; - Ptr createTexture(int width, int height, const uint8_t *pixels, + SharedPtr createTexture(int width, int height, const uint8_t *pixels, int channels) override; - Ptr loadTexture(const std::string &filepath) override; + SharedPtr loadTexture(const std::string &filepath) override; void beginSpriteBatch() override; void drawSprite(const Texture &texture, const Rect &destRect, @@ -66,7 +66,7 @@ public: void fillPolygon(const std::vector &points, const Color &color) override; - Ptr createFontAtlas(const std::string &filepath, int fontSize, + SharedPtr createFontAtlas(const std::string &filepath, int fontSize, bool useSDF = false) override; void drawText(const FontAtlas &font, const std::string &text, const Vec2 &position, const Color &color) override; diff --git a/Extra2D/include/extra2d/graphics/opengl/gl_texture.h b/Extra2D/include/extra2d/graphics/opengl/gl_texture.h index 8d559a7..c55006f 100644 --- a/Extra2D/include/extra2d/graphics/opengl/gl_texture.h +++ b/Extra2D/include/extra2d/graphics/opengl/gl_texture.h @@ -31,7 +31,7 @@ public: void setWrap(bool repeat) override; // 从参数创建纹理的工厂方法 - static Ptr create(int width, int height, PixelFormat format); + static SharedPtr create(int width, int height, PixelFormat format); // 加载压缩纹理(KTX/DDS 格式) bool loadCompressed(const std::string& filepath); diff --git a/Extra2D/include/extra2d/graphics/render_backend.h b/Extra2D/include/extra2d/graphics/render_backend.h index 895f439..bb67d5e 100644 --- a/Extra2D/include/extra2d/graphics/render_backend.h +++ b/Extra2D/include/extra2d/graphics/render_backend.h @@ -44,7 +44,7 @@ public: // ------------------------------------------------------------------------ // 生命周期 // ------------------------------------------------------------------------ - virtual bool init(IWindow* window) = 0; + virtual bool init(IWindow *window) = 0; virtual void shutdown() = 0; // ------------------------------------------------------------------------ @@ -71,9 +71,9 @@ public: // ------------------------------------------------------------------------ // 纹理 // ------------------------------------------------------------------------ - virtual Ptr createTexture(int width, int height, - const uint8_t *pixels, int channels) = 0; - virtual Ptr loadTexture(const std::string &filepath) = 0; + virtual SharedPtr + createTexture(int width, int height, const uint8_t *pixels, int channels) = 0; + virtual SharedPtr loadTexture(const std::string &filepath) = 0; // ------------------------------------------------------------------------ // 精灵批渲染 @@ -110,8 +110,9 @@ public: // ------------------------------------------------------------------------ // 文字渲染 // ------------------------------------------------------------------------ - virtual Ptr createFontAtlas(const std::string &filepath, - int fontSize, bool useSDF = false) = 0; + virtual SharedPtr 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, diff --git a/Extra2D/include/extra2d/graphics/render_target.h b/Extra2D/include/extra2d/graphics/render_target.h index 3dd4f1e..e5aac2b 100644 --- a/Extra2D/include/extra2d/graphics/render_target.h +++ b/Extra2D/include/extra2d/graphics/render_target.h @@ -49,7 +49,7 @@ public: /** * @brief 从现有纹理创建渲染目标 */ - bool createFromTexture(Ptr texture, bool hasDepth = false); + bool createFromTexture(SharedPtr texture, bool hasDepth = false); /** * @brief 销毁渲染目标 @@ -98,12 +98,12 @@ public: /** * @brief 获取颜色纹理 */ - Ptr getColorTexture() const { return colorTexture_; } + SharedPtr getColorTexture() const { return colorTexture_; } /** * @brief 获取深度纹理(如果有) */ - Ptr getDepthTexture() const { return depthTexture_; } + SharedPtr getDepthTexture() const { return depthTexture_; } // ------------------------------------------------------------------------ // 视口和裁剪 @@ -171,8 +171,8 @@ protected: GLuint fbo_ = 0; // 帧缓冲对象 GLuint rbo_ = 0; // 渲染缓冲对象(深度/模板) - Ptr colorTexture_; // 颜色纹理 - Ptr depthTexture_; // 深度纹理(可选) + SharedPtr colorTexture_; // 颜色纹理 + SharedPtr depthTexture_; // 深度纹理(可选) int width_ = 0; int height_ = 0; diff --git a/Extra2D/include/extra2d/graphics/texture_atlas.h b/Extra2D/include/extra2d/graphics/texture_atlas.h index 68b891b..015f4ee 100644 --- a/Extra2D/include/extra2d/graphics/texture_atlas.h +++ b/Extra2D/include/extra2d/graphics/texture_atlas.h @@ -48,7 +48,7 @@ public: const uint8_t* pixels, Rect& outUvRect); // 获取图集纹理 - Ptr getTexture() const { return texture_; } + SharedPtr getTexture() const { return texture_; } // 获取条目 const AtlasEntry* getEntry(const std::string& name) const; @@ -65,7 +65,7 @@ public: private: int width_, height_; - Ptr texture_; + SharedPtr texture_; std::unordered_map entries_; // 矩形打包数据 diff --git a/Extra2D/include/extra2d/graphics/texture_pool.h b/Extra2D/include/extra2d/graphics/texture_pool.h index 2bc517e..7a66409 100644 --- a/Extra2D/include/extra2d/graphics/texture_pool.h +++ b/Extra2D/include/extra2d/graphics/texture_pool.h @@ -105,7 +105,7 @@ struct TextureKeyHash { // 纹理池条目 // ============================================================================ struct TexturePoolEntry { - Ptr texture; // 纹理对象 + SharedPtr texture; // 纹理对象 mutable std::atomic refCount; // 引用计数 TextureKey key; // 纹理键 size_t memorySize; // 内存占用(字节) @@ -127,7 +127,7 @@ struct TexturePoolEntry { * @param k 纹理键 * @param memSize 内存占用 */ - TexturePoolEntry(Ptr tex, const TextureKey& k, size_t memSize) + TexturePoolEntry(SharedPtr tex, const TextureKey& k, size_t memSize) : texture(tex) , refCount(1) , key(k) @@ -198,7 +198,7 @@ public: * @param entry 纹理池条目 * @param mutex 互斥锁 */ - TextureRef(Ptr texture, TexturePoolEntry* entry, std::mutex* mutex) + TextureRef(SharedPtr texture, TexturePoolEntry* entry, std::mutex* mutex) : texture_(texture), entry_(entry), mutex_(mutex) {} /** @@ -206,7 +206,7 @@ public: * @param texture 纹理对象 * @return 独立的纹理引用 */ - static TextureRef fromTexture(Ptr texture) { + static TextureRef fromTexture(SharedPtr texture) { return TextureRef(texture, nullptr, nullptr); } @@ -298,7 +298,7 @@ public: * @brief 获取纹理对象(智能指针) * @return 纹理对象智能指针 */ - Ptr getPtr() const { return texture_; } + SharedPtr getPtr() const { return texture_; } /** * @brief 检查是否有效 @@ -322,7 +322,7 @@ public: Texture& operator*() const { return *texture_; } private: - Ptr texture_; + SharedPtr texture_; TexturePoolEntry* entry_; std::mutex* mutex_; }; diff --git a/Extra2D/include/extra2d/scene/sprite.h b/Extra2D/include/extra2d/scene/sprite.h index 7e54373..ff2b91e 100644 --- a/Extra2D/include/extra2d/scene/sprite.h +++ b/Extra2D/include/extra2d/scene/sprite.h @@ -12,12 +12,12 @@ namespace extra2d { class Sprite : public Node { public: Sprite(); - explicit Sprite(Ptr texture); + explicit Sprite(SharedPtr texture); ~Sprite() override = default; // 纹理 - void setTexture(Ptr texture); - Ptr getTexture() const { return texture_; } + void setTexture(SharedPtr texture); + SharedPtr getTexture() const { return texture_; } // 纹理矩形 (用于图集) void setTextureRect(const Rect &rect); @@ -35,8 +35,8 @@ public: // 静态创建方法 static SharedPtr create(); - static SharedPtr create(Ptr texture); - static SharedPtr create(Ptr texture, const Rect &rect); + static SharedPtr create(SharedPtr texture); + static SharedPtr create(SharedPtr texture, const Rect &rect); Rect getBounds() const override; @@ -46,7 +46,7 @@ protected: int zOrder) override; private: - Ptr texture_; + SharedPtr texture_; Rect textureRect_; Color color_ = Colors::White; bool flipX_ = false; diff --git a/Extra2D/src/graphics/opengl/gl_renderer.cpp b/Extra2D/src/graphics/opengl/gl_renderer.cpp index 6452568..abdc413 100644 --- a/Extra2D/src/graphics/opengl/gl_renderer.cpp +++ b/Extra2D/src/graphics/opengl/gl_renderer.cpp @@ -241,9 +241,10 @@ glm::mat4 GLRenderer::getCurrentTransform() const { * @param channels 颜色通道数 * @return 创建的纹理智能指针 */ -Ptr GLRenderer::createTexture(int width, int height, - const uint8_t *pixels, int channels) { - return makePtr(width, height, pixels, channels); +SharedPtr GLRenderer::createTexture(int width, int height, + const uint8_t *pixels, + int channels) { + return makeShared(width, height, pixels, channels); } /** @@ -251,8 +252,8 @@ Ptr GLRenderer::createTexture(int width, int height, * @param filepath 纹理文件路径 * @return 加载的纹理智能指针 */ -Ptr GLRenderer::loadTexture(const std::string &filepath) { - return makePtr(filepath); +SharedPtr GLRenderer::loadTexture(const std::string &filepath) { + return makeShared(filepath); } /** @@ -547,9 +548,9 @@ void GLRenderer::fillPolygon(const std::vector &points, * @param useSDF 是否使用SDF渲染 * @return 创建的字体图集智能指针 */ -Ptr GLRenderer::createFontAtlas(const std::string &filepath, - int fontSize, bool useSDF) { - return makePtr(filepath, fontSize, useSDF); +SharedPtr GLRenderer::createFontAtlas(const std::string &filepath, + int fontSize, bool useSDF) { + return makeShared(filepath, fontSize, useSDF); } /** diff --git a/Extra2D/src/graphics/opengl/gl_texture.cpp b/Extra2D/src/graphics/opengl/gl_texture.cpp index 30e2682..9c664f5 100644 --- a/Extra2D/src/graphics/opengl/gl_texture.cpp +++ b/Extra2D/src/graphics/opengl/gl_texture.cpp @@ -479,7 +479,7 @@ PixelFormat GLTexture::getFormat() const { return format_; } * @param format 像素格式 * @return 创建的纹理智能指针 */ -Ptr GLTexture::create(int width, int height, PixelFormat format) { +SharedPtr GLTexture::create(int width, int height, PixelFormat format) { int channels = 4; switch (format) { case PixelFormat::R8: @@ -498,7 +498,7 @@ Ptr GLTexture::create(int width, int height, PixelFormat format) { channels = 4; break; } - return makePtr(width, height, nullptr, channels); + return makeShared(width, height, nullptr, channels); } } // namespace extra2d diff --git a/Extra2D/src/graphics/render_target.cpp b/Extra2D/src/graphics/render_target.cpp index 7f12c7f..4afbfd9 100644 --- a/Extra2D/src/graphics/render_target.cpp +++ b/Extra2D/src/graphics/render_target.cpp @@ -111,7 +111,7 @@ bool RenderTarget::create(const RenderTargetConfig &config) { * * 使用现有纹理作为颜色附件创建帧缓冲对象 */ -bool RenderTarget::createFromTexture(Ptr texture, bool hasDepth) { +bool RenderTarget::createFromTexture(SharedPtr texture, bool hasDepth) { if (!texture || !texture->isValid()) { E2D_ERROR("无效的颜色纹理"); return false; diff --git a/Extra2D/src/graphics/texture_atlas.cpp b/Extra2D/src/graphics/texture_atlas.cpp index 0c47469..3be483a 100644 --- a/Extra2D/src/graphics/texture_atlas.cpp +++ b/Extra2D/src/graphics/texture_atlas.cpp @@ -20,7 +20,7 @@ TextureAtlasPage::TextureAtlasPage(int width, int height) : width_(width), height_(height), isFull_(false), usedArea_(0) { // 创建空白纹理 std::vector emptyData(width * height * 4, 0); - texture_ = makePtr(width, height, emptyData.data(), 4); + texture_ = makeShared(width, height, emptyData.data(), 4); // 初始化矩形打包根节点 root_ = std::make_unique(0, 0, width, height); diff --git a/Extra2D/src/graphics/texture_pool.cpp b/Extra2D/src/graphics/texture_pool.cpp index f5eb4dc..f33f63b 100644 --- a/Extra2D/src/graphics/texture_pool.cpp +++ b/Extra2D/src/graphics/texture_pool.cpp @@ -125,7 +125,7 @@ TextureRef TexturePool::load(const std::string& path, const Rect& region, } // 加载纹理 - Ptr texture = backend->loadTexture(path); + SharedPtr texture = backend->loadTexture(path); if (!texture) { E2D_LOG_ERROR("TexturePool: Failed to load texture: {}", path); return TextureRef(); @@ -201,7 +201,7 @@ TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int heigh } // 创建纹理 - Ptr texture = backend->createTexture(width, height, data, channels); + SharedPtr texture = backend->createTexture(width, height, data, channels); if (!texture) { E2D_LOG_ERROR("TexturePool: Failed to create texture from memory"); return TextureRef(); @@ -287,7 +287,7 @@ TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region, return TextureRef(); } - Ptr texture = backend->loadTexture(path); + SharedPtr texture = backend->loadTexture(path); if (!texture) { E2D_LOG_ERROR("TexturePool: Failed to load texture: {}", path); return TextureRef(); diff --git a/Extra2D/src/scene/sprite.cpp b/Extra2D/src/scene/sprite.cpp index f29aa64..3ef360d 100644 --- a/Extra2D/src/scene/sprite.cpp +++ b/Extra2D/src/scene/sprite.cpp @@ -20,7 +20,7 @@ Sprite::Sprite() = default; * * 创建精灵并设置纹理,纹理区域默认为整个纹理 */ -Sprite::Sprite(Ptr texture) { setTexture(texture); } +Sprite::Sprite(SharedPtr texture) { setTexture(texture); } /** * @brief 设置精灵纹理 @@ -28,7 +28,7 @@ Sprite::Sprite(Ptr texture) { setTexture(texture); } * * 设置纹理并将纹理区域初始化为整个纹理大小 */ -void Sprite::setTexture(Ptr texture) { +void Sprite::setTexture(SharedPtr texture) { texture_ = texture; if (texture_) { textureRect_ = Rect(0, 0, static_cast(texture_->getWidth()), @@ -75,7 +75,7 @@ SharedPtr Sprite::create() { return makeShared(); } * @param texture 精灵使用的纹理 * @return 新创建的精灵智能指针 */ -SharedPtr Sprite::create(Ptr texture) { +SharedPtr Sprite::create(SharedPtr texture) { return makeShared(texture); } @@ -85,7 +85,7 @@ SharedPtr Sprite::create(Ptr texture) { * @param rect 纹理区域 * @return 新创建的精灵智能指针 */ -SharedPtr Sprite::create(Ptr texture, const Rect &rect) { +SharedPtr Sprite::create(SharedPtr texture, const Rect &rect) { auto sprite = makeShared(texture); sprite->setTextureRect(rect); return sprite; diff --git a/docs/module_system.md b/docs/module_system.md index a1f7bd3..b24abd5 100644 --- a/docs/module_system.md +++ b/docs/module_system.md @@ -761,6 +761,101 @@ for (const auto& service : services) { --- +## 智能指针类型系统 + +### 概述 + +Extra2D 提供两种智能指针类型,用于不同的场景: + +```cpp +// 对象池支持的智能指针 +template using Ptr = PooledPtr; + +// 标准 shared_ptr(兼容旧代码) +template using SharedPtr = std::shared_ptr; +``` + +### 类型选择指南 + +| 类型 | 智能指针 | 原因 | +|------|----------|------| +| **节点类** | | | +| `Node`/`Scene`/`ShapeNode`/`Sprite` | `SharedPtr` | 需要 `enable_shared_from_this` 和 `weak_ptr` | +| **接口类** | | | +| `IShader`/`IShaderFactory` | `SharedPtr` | 多态接口,工厂模式创建 | +| `FontAtlas` | `SharedPtr` | 多态接口 | +| `RenderTarget` | `SharedPtr` | 需要精确生命周期管理 | +| **资源类** | | | +| `Texture` | `SharedPtr` | 有独立的缓存和引用计数系统 | +| **普通数据类** | `Ptr` | 可享受对象池优化 | + +### 创建对象 + +```cpp +// 使用对象池创建(适用于普通类) +Ptr data = makePtr(args...); + +// 使用 shared_ptr 创建(适用于节点、接口等) +SharedPtr node = makeShared(args...); +SharedPtr shader = makeShared(args...); +``` + +### 为什么节点类必须使用 SharedPtr + +节点类继承自 `std::enable_shared_from_this`,这要求对象必须由 `std::shared_ptr` 管理: + +```cpp +class Node : public std::enable_shared_from_this { + // 使用 shared_from_this() 获取自身的 shared_ptr + SharedPtr getSelf() { return shared_from_this(); } + + // 父子关系使用 weak_ptr 避免循环引用 + WeakPtr parent_; + std::vector> children_; +}; +``` + +### 为什么 Texture 使用 SharedPtr + +`Texture` 有独立的缓存和生命周期管理系统: + +```cpp +// TexturePool 有自己的引用计数和 LRU 缓存 +class TexturePool { + std::unordered_map cache_; + // TexturePoolEntry 使用 SharedPtr +}; + +// 如果使用 Ptr,对象池的引用计数会与缓存系统冲突 +``` + +### 对象池优势 + +对于普通数据类,使用 `Ptr` 可以获得: + +1. **内存池优化**:减少内存分配开销 +2. **对象复用**:对象归还池后可被重用 +3. **缓存友好**:连续内存布局 + +```cpp +// 适合使用对象池的类 +struct Particle { + Vec2 position; + Vec2 velocity; + Color color; + float lifetime; +}; + +// 创建大量粒子时,对象池效率更高 +for (int i = 0; i < 10000; ++i) { + Ptr p = makePtr(); + // 使用粒子... + // 离开作用域后自动归还池 +} +``` + +--- + ## 场景图系统 ### 概述 @@ -775,14 +870,14 @@ Extra2D 使用场景图(Scene Graph)管理游戏对象。场景图是一个 class Node : public std::enable_shared_from_this { public: // 层级管理 - void addChild(Ptr child); - void removeChild(Ptr child); + void addChild(SharedPtr child); + void removeChild(SharedPtr child); void detach(); void clearChildren(); - Ptr getParent() const; - const std::vector>& getChildren() const; - Ptr findChild(const std::string& name) const; + SharedPtr getParent() const; + const std::vector>& getChildren() const; + SharedPtr findChild(const std::string& name) const; // 变换属性 void setPos(const Vec2& pos); @@ -818,7 +913,7 @@ public: void setBackgroundColor(const Color& color); // 摄像机 - void setCamera(Ptr camera); + void setCamera(SharedPtr camera); Camera* getActiveCamera() const; // 视口 @@ -829,7 +924,7 @@ public: void updateScene(float dt); // 静态创建 - static Ptr create(); + static SharedPtr create(); }; ``` @@ -852,6 +947,25 @@ auto polygon = ShapeNode::createFilledPolygon( ); ``` +### Sprite 精灵节点 + +用于显示纹理图像: + +```cpp +// 创建精灵 +SharedPtr texture = renderer.loadTexture("sprite.png"); +SharedPtr sprite = Sprite::create(texture); + +// 设置属性 +sprite->setPos(100, 100); +sprite->setAnchor(0.5f, 0.5f); // 中心点锚点 +sprite->setFlipX(true); // 水平翻转 +sprite->setColor(Color(1.0f, 1.0f, 1.0f, 0.5f)); // 半透明 + +// 纹理区域(用于图集) +sprite->setTextureRect(Rect(0, 0, 64, 64)); +``` + ### 变换继承 子节点继承父节点的变换: