refactor(graphics): 将Ptr替换为SharedPtr以统一智能指针使用

将代码中的Ptr<T>统一替换为SharedPtr<T>,主要涉及纹理、渲染目标、精灵等图形相关类。修改包括:
1. 纹理创建和加载接口
2. 渲染目标与纹理的关联
3. 精灵节点的纹理引用
4. 纹理池的条目管理

同时更新文档说明智能指针类型选择策略
This commit is contained in:
ChestnutYueyue 2026-02-15 15:21:31 +08:00
parent 79772c4b49
commit cba2a5eb31
14 changed files with 171 additions and 55 deletions

View File

@ -37,9 +37,9 @@ public:
void popTransform() override; void popTransform() override;
glm::mat4 getCurrentTransform() const override; glm::mat4 getCurrentTransform() const override;
Ptr<Texture> createTexture(int width, int height, const uint8_t *pixels, SharedPtr<Texture> createTexture(int width, int height, const uint8_t *pixels,
int channels) override; int channels) override;
Ptr<Texture> loadTexture(const std::string &filepath) override; SharedPtr<Texture> loadTexture(const std::string &filepath) override;
void beginSpriteBatch() override; void beginSpriteBatch() override;
void drawSprite(const Texture &texture, const Rect &destRect, void drawSprite(const Texture &texture, const Rect &destRect,
@ -66,7 +66,7 @@ public:
void fillPolygon(const std::vector<Vec2> &points, void fillPolygon(const std::vector<Vec2> &points,
const Color &color) override; const Color &color) override;
Ptr<FontAtlas> createFontAtlas(const std::string &filepath, int fontSize, SharedPtr<FontAtlas> createFontAtlas(const std::string &filepath, int fontSize,
bool useSDF = false) override; bool useSDF = false) override;
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) override;

View File

@ -31,7 +31,7 @@ public:
void setWrap(bool repeat) override; void setWrap(bool repeat) override;
// 从参数创建纹理的工厂方法 // 从参数创建纹理的工厂方法
static Ptr<Texture> create(int width, int height, PixelFormat format); static SharedPtr<Texture> create(int width, int height, PixelFormat format);
// 加载压缩纹理KTX/DDS 格式) // 加载压缩纹理KTX/DDS 格式)
bool loadCompressed(const std::string& filepath); bool loadCompressed(const std::string& filepath);

View File

@ -44,7 +44,7 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 生命周期 // 生命周期
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual bool init(IWindow* window) = 0; virtual bool init(IWindow *window) = 0;
virtual void shutdown() = 0; virtual void shutdown() = 0;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -71,9 +71,9 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 纹理 // 纹理
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual Ptr<Texture> createTexture(int width, int height, virtual SharedPtr<Texture>
const uint8_t *pixels, int channels) = 0; createTexture(int width, int height, const uint8_t *pixels, int channels) = 0;
virtual Ptr<Texture> loadTexture(const std::string &filepath) = 0; virtual SharedPtr<Texture> loadTexture(const std::string &filepath) = 0;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 精灵批渲染 // 精灵批渲染
@ -110,8 +110,9 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 文字渲染 // 文字渲染
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual Ptr<FontAtlas> createFontAtlas(const std::string &filepath, virtual SharedPtr<FontAtlas> createFontAtlas(const std::string &filepath,
int fontSize, bool useSDF = false) = 0; int fontSize,
bool useSDF = false) = 0;
virtual void drawText(const FontAtlas &font, const std::string &text, virtual void drawText(const FontAtlas &font, const std::string &text,
const Vec2 &position, const Color &color) = 0; const Vec2 &position, const Color &color) = 0;
virtual void drawText(const FontAtlas &font, const std::string &text, float x, virtual void drawText(const FontAtlas &font, const std::string &text, float x,

View File

@ -49,7 +49,7 @@ public:
/** /**
* @brief * @brief
*/ */
bool createFromTexture(Ptr<Texture> texture, bool hasDepth = false); bool createFromTexture(SharedPtr<Texture> texture, bool hasDepth = false);
/** /**
* @brief * @brief
@ -98,12 +98,12 @@ public:
/** /**
* @brief * @brief
*/ */
Ptr<Texture> getColorTexture() const { return colorTexture_; } SharedPtr<Texture> getColorTexture() const { return colorTexture_; }
/** /**
* @brief * @brief
*/ */
Ptr<Texture> getDepthTexture() const { return depthTexture_; } SharedPtr<Texture> getDepthTexture() const { return depthTexture_; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 视口和裁剪 // 视口和裁剪
@ -171,8 +171,8 @@ protected:
GLuint fbo_ = 0; // 帧缓冲对象 GLuint fbo_ = 0; // 帧缓冲对象
GLuint rbo_ = 0; // 渲染缓冲对象(深度/模板) GLuint rbo_ = 0; // 渲染缓冲对象(深度/模板)
Ptr<Texture> colorTexture_; // 颜色纹理 SharedPtr<Texture> colorTexture_; // 颜色纹理
Ptr<Texture> depthTexture_; // 深度纹理(可选) SharedPtr<Texture> depthTexture_; // 深度纹理(可选)
int width_ = 0; int width_ = 0;
int height_ = 0; int height_ = 0;

View File

@ -48,7 +48,7 @@ public:
const uint8_t* pixels, Rect& outUvRect); const uint8_t* pixels, Rect& outUvRect);
// 获取图集纹理 // 获取图集纹理
Ptr<Texture> getTexture() const { return texture_; } SharedPtr<Texture> getTexture() const { return texture_; }
// 获取条目 // 获取条目
const AtlasEntry* getEntry(const std::string& name) const; const AtlasEntry* getEntry(const std::string& name) const;
@ -65,7 +65,7 @@ public:
private: private:
int width_, height_; int width_, height_;
Ptr<Texture> texture_; SharedPtr<Texture> texture_;
std::unordered_map<std::string, AtlasEntry> entries_; std::unordered_map<std::string, AtlasEntry> entries_;
// 矩形打包数据 // 矩形打包数据

View File

@ -105,7 +105,7 @@ struct TextureKeyHash {
// 纹理池条目 // 纹理池条目
// ============================================================================ // ============================================================================
struct TexturePoolEntry { struct TexturePoolEntry {
Ptr<Texture> texture; // 纹理对象 SharedPtr<Texture> texture; // 纹理对象
mutable std::atomic<uint32_t> refCount; // 引用计数 mutable std::atomic<uint32_t> refCount; // 引用计数
TextureKey key; // 纹理键 TextureKey key; // 纹理键
size_t memorySize; // 内存占用(字节) size_t memorySize; // 内存占用(字节)
@ -127,7 +127,7 @@ struct TexturePoolEntry {
* @param k * @param k
* @param memSize * @param memSize
*/ */
TexturePoolEntry(Ptr<Texture> tex, const TextureKey& k, size_t memSize) TexturePoolEntry(SharedPtr<Texture> tex, const TextureKey& k, size_t memSize)
: texture(tex) : texture(tex)
, refCount(1) , refCount(1)
, key(k) , key(k)
@ -198,7 +198,7 @@ public:
* @param entry * @param entry
* @param mutex * @param mutex
*/ */
TextureRef(Ptr<Texture> texture, TexturePoolEntry* entry, std::mutex* mutex) TextureRef(SharedPtr<Texture> texture, TexturePoolEntry* entry, std::mutex* mutex)
: texture_(texture), entry_(entry), mutex_(mutex) {} : texture_(texture), entry_(entry), mutex_(mutex) {}
/** /**
@ -206,7 +206,7 @@ public:
* @param texture * @param texture
* @return * @return
*/ */
static TextureRef fromTexture(Ptr<Texture> texture) { static TextureRef fromTexture(SharedPtr<Texture> texture) {
return TextureRef(texture, nullptr, nullptr); return TextureRef(texture, nullptr, nullptr);
} }
@ -298,7 +298,7 @@ public:
* @brief * @brief
* @return * @return
*/ */
Ptr<Texture> getPtr() const { return texture_; } SharedPtr<Texture> getPtr() const { return texture_; }
/** /**
* @brief * @brief
@ -322,7 +322,7 @@ public:
Texture& operator*() const { return *texture_; } Texture& operator*() const { return *texture_; }
private: private:
Ptr<Texture> texture_; SharedPtr<Texture> texture_;
TexturePoolEntry* entry_; TexturePoolEntry* entry_;
std::mutex* mutex_; std::mutex* mutex_;
}; };

View File

@ -12,12 +12,12 @@ namespace extra2d {
class Sprite : public Node { class Sprite : public Node {
public: public:
Sprite(); Sprite();
explicit Sprite(Ptr<Texture> texture); explicit Sprite(SharedPtr<Texture> texture);
~Sprite() override = default; ~Sprite() override = default;
// 纹理 // 纹理
void setTexture(Ptr<Texture> texture); void setTexture(SharedPtr<Texture> texture);
Ptr<Texture> getTexture() const { return texture_; } SharedPtr<Texture> getTexture() const { return texture_; }
// 纹理矩形 (用于图集) // 纹理矩形 (用于图集)
void setTextureRect(const Rect &rect); void setTextureRect(const Rect &rect);
@ -35,8 +35,8 @@ public:
// 静态创建方法 // 静态创建方法
static SharedPtr<Sprite> create(); static SharedPtr<Sprite> create();
static SharedPtr<Sprite> create(Ptr<Texture> texture); static SharedPtr<Sprite> create(SharedPtr<Texture> texture);
static SharedPtr<Sprite> create(Ptr<Texture> texture, const Rect &rect); static SharedPtr<Sprite> create(SharedPtr<Texture> texture, const Rect &rect);
Rect getBounds() const override; Rect getBounds() const override;
@ -46,7 +46,7 @@ protected:
int zOrder) override; int zOrder) override;
private: private:
Ptr<Texture> texture_; SharedPtr<Texture> texture_;
Rect textureRect_; Rect textureRect_;
Color color_ = Colors::White; Color color_ = Colors::White;
bool flipX_ = false; bool flipX_ = false;

View File

@ -241,9 +241,10 @@ glm::mat4 GLRenderer::getCurrentTransform() const {
* @param channels * @param channels
* @return * @return
*/ */
Ptr<Texture> GLRenderer::createTexture(int width, int height, SharedPtr<Texture> GLRenderer::createTexture(int width, int height,
const uint8_t *pixels, int channels) { const uint8_t *pixels,
return makePtr<GLTexture>(width, height, pixels, channels); int channels) {
return makeShared<GLTexture>(width, height, pixels, channels);
} }
/** /**
@ -251,8 +252,8 @@ Ptr<Texture> GLRenderer::createTexture(int width, int height,
* @param filepath * @param filepath
* @return * @return
*/ */
Ptr<Texture> GLRenderer::loadTexture(const std::string &filepath) { SharedPtr<Texture> GLRenderer::loadTexture(const std::string &filepath) {
return makePtr<GLTexture>(filepath); return makeShared<GLTexture>(filepath);
} }
/** /**
@ -547,9 +548,9 @@ void GLRenderer::fillPolygon(const std::vector<Vec2> &points,
* @param useSDF 使SDF渲染 * @param useSDF 使SDF渲染
* @return * @return
*/ */
Ptr<FontAtlas> GLRenderer::createFontAtlas(const std::string &filepath, SharedPtr<FontAtlas> GLRenderer::createFontAtlas(const std::string &filepath,
int fontSize, bool useSDF) { int fontSize, bool useSDF) {
return makePtr<GLFontAtlas>(filepath, fontSize, useSDF); return makeShared<GLFontAtlas>(filepath, fontSize, useSDF);
} }
/** /**

View File

@ -479,7 +479,7 @@ PixelFormat GLTexture::getFormat() const { return format_; }
* @param format * @param format
* @return * @return
*/ */
Ptr<Texture> GLTexture::create(int width, int height, PixelFormat format) { SharedPtr<Texture> GLTexture::create(int width, int height, PixelFormat format) {
int channels = 4; int channels = 4;
switch (format) { switch (format) {
case PixelFormat::R8: case PixelFormat::R8:
@ -498,7 +498,7 @@ Ptr<Texture> GLTexture::create(int width, int height, PixelFormat format) {
channels = 4; channels = 4;
break; break;
} }
return makePtr<GLTexture>(width, height, nullptr, channels); return makeShared<GLTexture>(width, height, nullptr, channels);
} }
} // namespace extra2d } // namespace extra2d

View File

@ -111,7 +111,7 @@ bool RenderTarget::create(const RenderTargetConfig &config) {
* *
* 使 * 使
*/ */
bool RenderTarget::createFromTexture(Ptr<Texture> texture, bool hasDepth) { bool RenderTarget::createFromTexture(SharedPtr<Texture> texture, bool hasDepth) {
if (!texture || !texture->isValid()) { if (!texture || !texture->isValid()) {
E2D_ERROR("无效的颜色纹理"); E2D_ERROR("无效的颜色纹理");
return false; return false;

View File

@ -20,7 +20,7 @@ TextureAtlasPage::TextureAtlasPage(int width, int height)
: width_(width), height_(height), isFull_(false), usedArea_(0) { : width_(width), height_(height), isFull_(false), usedArea_(0) {
// 创建空白纹理 // 创建空白纹理
std::vector<uint8_t> emptyData(width * height * 4, 0); std::vector<uint8_t> emptyData(width * height * 4, 0);
texture_ = makePtr<GLTexture>(width, height, emptyData.data(), 4); texture_ = makeShared<GLTexture>(width, height, emptyData.data(), 4);
// 初始化矩形打包根节点 // 初始化矩形打包根节点
root_ = std::make_unique<PackNode>(0, 0, width, height); root_ = std::make_unique<PackNode>(0, 0, width, height);

View File

@ -125,7 +125,7 @@ TextureRef TexturePool::load(const std::string& path, const Rect& region,
} }
// 加载纹理 // 加载纹理
Ptr<Texture> texture = backend->loadTexture(path); SharedPtr<Texture> texture = backend->loadTexture(path);
if (!texture) { if (!texture) {
E2D_LOG_ERROR("TexturePool: Failed to load texture: {}", path); E2D_LOG_ERROR("TexturePool: Failed to load texture: {}", path);
return TextureRef(); return TextureRef();
@ -201,7 +201,7 @@ TextureRef TexturePool::loadFromMemory(const uint8_t* data, int width, int heigh
} }
// 创建纹理 // 创建纹理
Ptr<Texture> texture = backend->createTexture(width, height, data, channels); SharedPtr<Texture> texture = backend->createTexture(width, height, data, channels);
if (!texture) { if (!texture) {
E2D_LOG_ERROR("TexturePool: Failed to create texture from memory"); E2D_LOG_ERROR("TexturePool: Failed to create texture from memory");
return TextureRef(); return TextureRef();
@ -287,7 +287,7 @@ TextureRef TexturePool::getOrLoad(const std::string& path, const Rect& region,
return TextureRef(); return TextureRef();
} }
Ptr<Texture> texture = backend->loadTexture(path); SharedPtr<Texture> texture = backend->loadTexture(path);
if (!texture) { if (!texture) {
E2D_LOG_ERROR("TexturePool: Failed to load texture: {}", path); E2D_LOG_ERROR("TexturePool: Failed to load texture: {}", path);
return TextureRef(); return TextureRef();

View File

@ -20,7 +20,7 @@ Sprite::Sprite() = default;
* *
* *
*/ */
Sprite::Sprite(Ptr<Texture> texture) { setTexture(texture); } Sprite::Sprite(SharedPtr<Texture> texture) { setTexture(texture); }
/** /**
* @brief * @brief
@ -28,7 +28,7 @@ Sprite::Sprite(Ptr<Texture> texture) { setTexture(texture); }
* *
* *
*/ */
void Sprite::setTexture(Ptr<Texture> texture) { void Sprite::setTexture(SharedPtr<Texture> texture) {
texture_ = texture; texture_ = texture;
if (texture_) { if (texture_) {
textureRect_ = Rect(0, 0, static_cast<float>(texture_->getWidth()), textureRect_ = Rect(0, 0, static_cast<float>(texture_->getWidth()),
@ -75,7 +75,7 @@ SharedPtr<Sprite> Sprite::create() { return makeShared<Sprite>(); }
* @param texture 使 * @param texture 使
* @return * @return
*/ */
SharedPtr<Sprite> Sprite::create(Ptr<Texture> texture) { SharedPtr<Sprite> Sprite::create(SharedPtr<Texture> texture) {
return makeShared<Sprite>(texture); return makeShared<Sprite>(texture);
} }
@ -85,7 +85,7 @@ SharedPtr<Sprite> Sprite::create(Ptr<Texture> texture) {
* @param rect * @param rect
* @return * @return
*/ */
SharedPtr<Sprite> Sprite::create(Ptr<Texture> texture, const Rect &rect) { SharedPtr<Sprite> Sprite::create(SharedPtr<Texture> texture, const Rect &rect) {
auto sprite = makeShared<Sprite>(texture); auto sprite = makeShared<Sprite>(texture);
sprite->setTextureRect(rect); sprite->setTextureRect(rect);
return sprite; return sprite;

View File

@ -761,6 +761,101 @@ for (const auto& service : services) {
--- ---
## 智能指针类型系统
### 概述
Extra2D 提供两种智能指针类型,用于不同的场景:
```cpp
// 对象池支持的智能指针
template <typename T> using Ptr = PooledPtr<T>;
// 标准 shared_ptr兼容旧代码
template <typename T> using SharedPtr = std::shared_ptr<T>;
```
### 类型选择指南
| 类型 | 智能指针 | 原因 |
|------|----------|------|
| **节点类** | | |
| `Node`/`Scene`/`ShapeNode`/`Sprite` | `SharedPtr` | 需要 `enable_shared_from_this``weak_ptr` |
| **接口类** | | |
| `IShader`/`IShaderFactory` | `SharedPtr` | 多态接口,工厂模式创建 |
| `FontAtlas` | `SharedPtr` | 多态接口 |
| `RenderTarget` | `SharedPtr` | 需要精确生命周期管理 |
| **资源类** | | |
| `Texture` | `SharedPtr` | 有独立的缓存和引用计数系统 |
| **普通数据类** | `Ptr` | 可享受对象池优化 |
### 创建对象
```cpp
// 使用对象池创建(适用于普通类)
Ptr<MyData> data = makePtr<MyData>(args...);
// 使用 shared_ptr 创建(适用于节点、接口等)
SharedPtr<Node> node = makeShared<Node>(args...);
SharedPtr<IShader> shader = makeShared<GLShader>(args...);
```
### 为什么节点类必须使用 SharedPtr
节点类继承自 `std::enable_shared_from_this`,这要求对象必须由 `std::shared_ptr` 管理:
```cpp
class Node : public std::enable_shared_from_this<Node> {
// 使用 shared_from_this() 获取自身的 shared_ptr
SharedPtr<Node> getSelf() { return shared_from_this(); }
// 父子关系使用 weak_ptr 避免循环引用
WeakPtr<Node> parent_;
std::vector<SharedPtr<Node>> children_;
};
```
### 为什么 Texture 使用 SharedPtr
`Texture` 有独立的缓存和生命周期管理系统:
```cpp
// TexturePool 有自己的引用计数和 LRU 缓存
class TexturePool {
std::unordered_map<TextureKey, TexturePoolEntry> cache_;
// TexturePoolEntry 使用 SharedPtr<Texture>
};
// 如果使用 Ptr<Texture>,对象池的引用计数会与缓存系统冲突
```
### 对象池优势
对于普通数据类,使用 `Ptr<T>` 可以获得:
1. **内存池优化**:减少内存分配开销
2. **对象复用**:对象归还池后可被重用
3. **缓存友好**:连续内存布局
```cpp
// 适合使用对象池的类
struct Particle {
Vec2 position;
Vec2 velocity;
Color color;
float lifetime;
};
// 创建大量粒子时,对象池效率更高
for (int i = 0; i < 10000; ++i) {
Ptr<Particle> p = makePtr<Particle>();
// 使用粒子...
// 离开作用域后自动归还池
}
```
---
## 场景图系统 ## 场景图系统
### 概述 ### 概述
@ -775,14 +870,14 @@ Extra2D 使用场景图Scene Graph管理游戏对象。场景图是一个
class Node : public std::enable_shared_from_this<Node> { class Node : public std::enable_shared_from_this<Node> {
public: public:
// 层级管理 // 层级管理
void addChild(Ptr<Node> child); void addChild(SharedPtr<Node> child);
void removeChild(Ptr<Node> child); void removeChild(SharedPtr<Node> child);
void detach(); void detach();
void clearChildren(); void clearChildren();
Ptr<Node> getParent() const; SharedPtr<Node> getParent() const;
const std::vector<Ptr<Node>>& getChildren() const; const std::vector<SharedPtr<Node>>& getChildren() const;
Ptr<Node> findChild(const std::string& name) const; SharedPtr<Node> findChild(const std::string& name) const;
// 变换属性 // 变换属性
void setPos(const Vec2& pos); void setPos(const Vec2& pos);
@ -818,7 +913,7 @@ public:
void setBackgroundColor(const Color& color); void setBackgroundColor(const Color& color);
// 摄像机 // 摄像机
void setCamera(Ptr<Camera> camera); void setCamera(SharedPtr<Camera> camera);
Camera* getActiveCamera() const; Camera* getActiveCamera() const;
// 视口 // 视口
@ -829,7 +924,7 @@ public:
void updateScene(float dt); void updateScene(float dt);
// 静态创建 // 静态创建
static Ptr<Scene> create(); static SharedPtr<Scene> create();
}; };
``` ```
@ -852,6 +947,25 @@ auto polygon = ShapeNode::createFilledPolygon(
); );
``` ```
### Sprite 精灵节点
用于显示纹理图像:
```cpp
// 创建精灵
SharedPtr<Texture> texture = renderer.loadTexture("sprite.png");
SharedPtr<Sprite> 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));
```
### 变换继承 ### 变换继承
子节点继承父节点的变换: 子节点继承父节点的变换: