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;
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;
Ptr<Texture> loadTexture(const std::string &filepath) override;
SharedPtr<Texture> 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<Vec2> &points,
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;
void drawText(const FontAtlas &font, const std::string &text,
const Vec2 &position, const Color &color) override;

View File

@ -31,7 +31,7 @@ public:
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 格式)
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;
// ------------------------------------------------------------------------
@ -71,9 +71,9 @@ public:
// ------------------------------------------------------------------------
// 纹理
// ------------------------------------------------------------------------
virtual Ptr<Texture> createTexture(int width, int height,
const uint8_t *pixels, int channels) = 0;
virtual Ptr<Texture> loadTexture(const std::string &filepath) = 0;
virtual SharedPtr<Texture>
createTexture(int width, int height, const uint8_t *pixels, int channels) = 0;
virtual SharedPtr<Texture> loadTexture(const std::string &filepath) = 0;
// ------------------------------------------------------------------------
// 精灵批渲染
@ -110,8 +110,9 @@ public:
// ------------------------------------------------------------------------
// 文字渲染
// ------------------------------------------------------------------------
virtual Ptr<FontAtlas> createFontAtlas(const std::string &filepath,
int fontSize, bool useSDF = false) = 0;
virtual SharedPtr<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,

View File

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

View File

@ -48,7 +48,7 @@ public:
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;
@ -65,7 +65,7 @@ public:
private:
int width_, height_;
Ptr<Texture> texture_;
SharedPtr<Texture> texture_;
std::unordered_map<std::string, AtlasEntry> entries_;
// 矩形打包数据

View File

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

View File

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

View File

@ -241,9 +241,10 @@ glm::mat4 GLRenderer::getCurrentTransform() const {
* @param channels
* @return
*/
Ptr<Texture> GLRenderer::createTexture(int width, int height,
const uint8_t *pixels, int channels) {
return makePtr<GLTexture>(width, height, pixels, channels);
SharedPtr<Texture> GLRenderer::createTexture(int width, int height,
const uint8_t *pixels,
int channels) {
return makeShared<GLTexture>(width, height, pixels, channels);
}
/**
@ -251,8 +252,8 @@ Ptr<Texture> GLRenderer::createTexture(int width, int height,
* @param filepath
* @return
*/
Ptr<Texture> GLRenderer::loadTexture(const std::string &filepath) {
return makePtr<GLTexture>(filepath);
SharedPtr<Texture> GLRenderer::loadTexture(const std::string &filepath) {
return makeShared<GLTexture>(filepath);
}
/**
@ -547,9 +548,9 @@ void GLRenderer::fillPolygon(const std::vector<Vec2> &points,
* @param useSDF 使SDF渲染
* @return
*/
Ptr<FontAtlas> GLRenderer::createFontAtlas(const std::string &filepath,
SharedPtr<FontAtlas> GLRenderer::createFontAtlas(const std::string &filepath,
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
* @return
*/
Ptr<Texture> GLTexture::create(int width, int height, PixelFormat format) {
SharedPtr<Texture> GLTexture::create(int width, int height, PixelFormat format) {
int channels = 4;
switch (format) {
case PixelFormat::R8:
@ -498,7 +498,7 @@ Ptr<Texture> GLTexture::create(int width, int height, PixelFormat format) {
channels = 4;
break;
}
return makePtr<GLTexture>(width, height, nullptr, channels);
return makeShared<GLTexture>(width, height, nullptr, channels);
}
} // 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()) {
E2D_ERROR("无效的颜色纹理");
return false;

View File

@ -20,7 +20,7 @@ TextureAtlasPage::TextureAtlasPage(int width, int height)
: width_(width), height_(height), isFull_(false), usedArea_(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);

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) {
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> texture = backend->createTexture(width, height, data, channels);
SharedPtr<Texture> 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> texture = backend->loadTexture(path);
SharedPtr<Texture> texture = backend->loadTexture(path);
if (!texture) {
E2D_LOG_ERROR("TexturePool: Failed to load texture: {}", path);
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
@ -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;
if (texture_) {
textureRect_ = Rect(0, 0, static_cast<float>(texture_->getWidth()),
@ -75,7 +75,7 @@ SharedPtr<Sprite> Sprite::create() { return makeShared<Sprite>(); }
* @param texture 使
* @return
*/
SharedPtr<Sprite> Sprite::create(Ptr<Texture> texture) {
SharedPtr<Sprite> Sprite::create(SharedPtr<Texture> texture) {
return makeShared<Sprite>(texture);
}
@ -85,7 +85,7 @@ SharedPtr<Sprite> Sprite::create(Ptr<Texture> texture) {
* @param rect
* @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);
sprite->setTextureRect(rect);
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> {
public:
// 层级管理
void addChild(Ptr<Node> child);
void removeChild(Ptr<Node> child);
void addChild(SharedPtr<Node> child);
void removeChild(SharedPtr<Node> child);
void detach();
void clearChildren();
Ptr<Node> getParent() const;
const std::vector<Ptr<Node>>& getChildren() const;
Ptr<Node> findChild(const std::string& name) const;
SharedPtr<Node> getParent() const;
const std::vector<SharedPtr<Node>>& getChildren() const;
SharedPtr<Node> 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> camera);
void setCamera(SharedPtr<Camera> camera);
Camera* getActiveCamera() const;
// 视口
@ -829,7 +924,7 @@ public:
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));
```
### 变换继承
子节点继承父节点的变换: