refactor(core): 替换shared_ptr为侵入式引用计数IntrusivePtr

重构整个项目,将std::shared_ptr替换为自定义的IntrusivePtr实现:
1. 新增RefCounted基类,提供引用计数功能
2. 实现IntrusivePtr智能指针模板类
3. 修改所有资源管理类使用IntrusivePtr
4. 更新Node类继承自RefCounted
5. 移除types.h中的shared_ptr相关定义
6. 统一使用makeRef替代shared创建对象
This commit is contained in:
ChestnutYueyue 2026-02-26 21:17:11 +08:00
parent 4afd52cc82
commit b4a55239aa
32 changed files with 425 additions and 270 deletions

View File

@ -85,7 +85,7 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 便捷方法 // 便捷方法
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void enterScene(Ptr<class Scene> scene); void enterScene(IntrusivePtr<class Scene> scene);
float deltaTime() const { return deltaTime_; } float deltaTime() const { return deltaTime_; }
float totalTime() const { return totalTime_; } float totalTime() const { return totalTime_; }

View File

@ -1,9 +1,9 @@
#pragma once #pragma once
#include <core/intrusive_ptr.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <core/types.h>
namespace extra2d { namespace extra2d {
@ -21,10 +21,10 @@ public:
bool initialize(); bool initialize();
void shutdown(); void shutdown();
std::shared_ptr<Sound> loadSound(const std::string& filePath); IntrusivePtr<Sound> loadSound(const std::string& filePath);
std::shared_ptr<Sound> loadSound(const std::string& name, const std::string& filePath); IntrusivePtr<Sound> loadSound(const std::string& name, const std::string& filePath);
std::shared_ptr<Sound> getSound(const std::string& name); IntrusivePtr<Sound> getSound(const std::string& name);
void unloadSound(const std::string& name); void unloadSound(const std::string& name);
void unloadAllSounds(); void unloadAllSounds();
@ -39,7 +39,7 @@ private:
AudioEngine() = default; AudioEngine() = default;
~AudioEngine(); ~AudioEngine();
std::unordered_map<std::string, std::shared_ptr<Sound>> sounds_; std::unordered_map<std::string, IntrusivePtr<Sound>> sounds_;
float masterVolume_ = 1.0f; float masterVolume_ = 1.0f;
bool initialized_ = false; bool initialized_ = false;
}; };

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <core/ref_counted.h>
#include <string> #include <string>
#include <core/types.h>
struct Mix_Chunk; struct Mix_Chunk;
@ -9,7 +9,7 @@ namespace extra2d {
class AudioEngine; class AudioEngine;
class Sound { class Sound : public RefCounted {
public: public:
~Sound(); ~Sound();

View File

@ -0,0 +1,172 @@
#pragma once
#include <core/ref_counted.h>
#include <functional>
#include <utility>
namespace extra2d {
// ============================================================================
// 侵入式智能指针
// 参考 Cocos2d-x 的 IntrusivePtr 设计
// ============================================================================
template <class T>
class IntrusivePtr {
public:
using element_type = T;
// 默认构造函数
IntrusivePtr() : _ptr(nullptr) {}
// 从原始指针构造
IntrusivePtr(T* p) : _ptr(p) {
if (_ptr) {
_ptr->addRef();
}
}
// 拷贝构造函数
IntrusivePtr(const IntrusivePtr<T>& r) : _ptr(r._ptr) {
if (_ptr) {
_ptr->addRef();
}
}
// 从派生类拷贝构造
template <typename U>
IntrusivePtr(const IntrusivePtr<U>& r) : _ptr(r.get()) {
if (_ptr) {
_ptr->addRef();
}
}
// 移动构造函数
IntrusivePtr(IntrusivePtr<T>&& r) noexcept : _ptr(r.release()) {}
// 从派生类移动构造
template <typename U>
IntrusivePtr(IntrusivePtr<U>&& r) noexcept : _ptr(r.release()) {}
// 析构函数
~IntrusivePtr() {
if (_ptr) {
_ptr->release();
}
}
// 获取原始指针
T* get() const { return _ptr; }
// 解引用操作符
T& operator*() const { return *_ptr; }
// 箭头操作符
T* operator->() const { return _ptr; }
// 转换为原始指针(隐式转换)
operator T*() const { return _ptr; }
// 赋值操作符 - 原始指针
IntrusivePtr<T>& operator=(T* p) {
reset(p);
return *this;
}
// 赋值操作符 - 同类型
IntrusivePtr<T>& operator=(const IntrusivePtr<T>& r) {
return *this = r._ptr;
}
// 赋值操作符 - 派生类
template <typename U>
IntrusivePtr<T>& operator=(const IntrusivePtr<U>& r) {
return *this = r.get();
}
// 移动赋值
IntrusivePtr<T>& operator=(IntrusivePtr<T>&& r) noexcept {
IntrusivePtr<T>(std::move(r)).swap(*this);
return *this;
}
// 从派生类移动赋值
template <typename U>
IntrusivePtr<T>& operator=(IntrusivePtr<U>&& r) noexcept {
IntrusivePtr<T>(std::move(r)).swap(*this);
return *this;
}
// 比较操作符
bool operator==(std::nullptr_t) const { return _ptr == nullptr; }
bool operator==(T* r) const { return _ptr == r; }
bool operator!=(std::nullptr_t) const { return _ptr != nullptr; }
bool operator!=(T* r) const { return _ptr != r; }
bool operator<(const IntrusivePtr<T>& r) const { return _ptr < r._ptr; }
// 重置指针
void reset() noexcept {
if (_ptr) {
_ptr->release();
}
_ptr = nullptr;
}
void reset(T* p) {
// 先增加新指针的引用计数,再释放旧指针
// 这样可以处理自赋值的情况
if (p) {
p->addRef();
}
if (_ptr) {
_ptr->release();
}
_ptr = p;
}
// 交换指针
void swap(T** pp) noexcept {
T* p = _ptr;
_ptr = *pp;
*pp = p;
}
void swap(IntrusivePtr<T>& r) noexcept {
swap(&r._ptr);
}
// 释放指针所有权(不减少引用计数)
T* release() {
T* retVal = _ptr;
_ptr = nullptr;
return retVal;
}
private:
T* _ptr;
};
// ============================================================================
// 辅助函数
// ============================================================================
// 创建 IntrusivePtr 的便捷函数
template <typename T, typename... Args>
inline IntrusivePtr<T> makePtr(Args&&... args) {
return IntrusivePtr<T>(new T(std::forward<Args>(args)...));
}
} // namespace extra2d
// ============================================================================
// std::hash 特化
// ============================================================================
namespace std {
template <class T>
struct hash<extra2d::IntrusivePtr<T>> {
size_t operator()(const extra2d::IntrusivePtr<T>& val) const noexcept {
return hash<T*>{}(val.get());
}
};
} // namespace std

View File

@ -0,0 +1,41 @@
#pragma once
#include <atomic>
#include <cstdint>
namespace extra2d {
// ============================================================================
// 侵入式引用计数基类
// 参考 Cocos2d-x 的 RefCounted 设计
// ============================================================================
class RefCounted {
public:
virtual ~RefCounted() = default;
// 增加引用计数
void addRef() {
++_referenceCount;
}
// 减少引用计数当计数为0时删除对象
void release() {
if (--_referenceCount == 0) {
delete this;
}
}
// 获取当前引用计数
uint32_t getRefCount() const {
return _referenceCount.load();
}
protected:
// 构造函数初始引用计数为1
RefCounted() : _referenceCount(1) {}
private:
std::atomic<uint32_t> _referenceCount;
};
} // namespace extra2d

View File

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <core/intrusive_ptr.h>
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
#include <memory> #include <memory>
@ -9,15 +10,12 @@ namespace extra2d {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// 智能指针别名 // 智能指针别名
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
template <typename T> using Ptr = std::shared_ptr<T>;
template <typename T> using UniquePtr = std::unique_ptr<T>; template <typename T> using UniquePtr = std::unique_ptr<T>;
template <typename T> using WeakPtr = std::weak_ptr<T>; /// 创建 IntrusivePtr 的便捷函数
template <typename T, typename... Args>
/// 创建 shared_ptr 的便捷函数 inline IntrusivePtr<T> makeRef(Args &&...args) {
template <typename T, typename... Args> inline Ptr<T> shared(Args &&...args) { return makePtr<T>(std::forward<Args>(args)...);
return std::make_shared<T>(std::forward<Args>(args)...);
} }
/// 创建 unique_ptr 的便捷函数 /// 创建 unique_ptr 的便捷函数

View File

@ -2,7 +2,7 @@
#include <core/color.h> #include <core/color.h>
#include <core/rect.h> #include <core/rect.h>
#include <core/types.h> #include <core/ref_counted.h>
#include <core/vec2.h> #include <core/vec2.h>
namespace extra2d { namespace extra2d {
@ -23,7 +23,7 @@ struct Glyph {
// ============================================================================ // ============================================================================
// 字体图集接口 // 字体图集接口
// ============================================================================ // ============================================================================
class FontAtlas { class FontAtlas : public RefCounted {
public: public:
virtual ~FontAtlas() = default; virtual ~FontAtlas() = default;

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, IntrusivePtr<Texture> createTexture(int width, int height, const uint8_t *pixels,
int channels) override; int channels) override;
Ptr<Texture> loadTexture(const std::string &filepath) override; IntrusivePtr<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, IntrusivePtr<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

@ -35,7 +35,7 @@ public:
void setWrap(bool repeat) override; void setWrap(bool repeat) override;
// 从参数创建纹理的工厂方法 // 从参数创建纹理的工厂方法
static Ptr<Texture> create(int width, int height, PixelFormat format); static IntrusivePtr<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

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <core/ref_counted.h>
#include <core/size.h> #include <core/size.h>
#include <core/types.h>
namespace extra2d { namespace extra2d {
@ -33,7 +33,7 @@ enum class PixelFormat {
// ============================================================================ // ============================================================================
// 纹理接口 // 纹理接口
// ============================================================================ // ============================================================================
class Texture { class Texture : public RefCounted {
public: public:
virtual ~Texture() = default; virtual ~Texture() = default;

View File

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

View File

@ -2,8 +2,8 @@
#include <core/color.h> #include <core/color.h>
#include <core/rect.h> #include <core/rect.h>
#include <core/ref_counted.h>
#include <core/size.h> #include <core/size.h>
#include <core/types.h>
#include <core/vec2.h> #include <core/vec2.h>
#include <glm/mat4x4.hpp> #include <glm/mat4x4.hpp>
@ -12,7 +12,7 @@ namespace extra2d {
// ============================================================================ // ============================================================================
// 2D 正交相机 // 2D 正交相机
// ============================================================================ // ============================================================================
class Camera { class Camera : public RefCounted {
public: public:
Camera(); Camera();
Camera(float left, float right, float bottom, float top); Camera(float left, float right, float bottom, float top);

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include <core/color.h> #include <core/color.h>
#include <core/types.h> #include <core/ref_counted.h>
#include <graphics/opengl/gl_texture.h> #include <graphics/opengl/gl_texture.h>
#include <graphics/texture.h> #include <graphics/texture.h>
#include <mutex> #include <mutex>
@ -25,7 +25,7 @@ struct RenderTargetConfig {
// ============================================================================ // ============================================================================
// 渲染目标 - 基于FBO的离屏渲染 // 渲染目标 - 基于FBO的离屏渲染
// ============================================================================ // ============================================================================
class RenderTarget { class RenderTarget : public RefCounted {
public: public:
RenderTarget(); RenderTarget();
~RenderTarget(); ~RenderTarget();
@ -55,7 +55,7 @@ public:
/** /**
* @brief * @brief
*/ */
bool createFromTexture(Ptr<Texture> texture, bool hasDepth = false); bool createFromTexture(IntrusivePtr<Texture> texture, bool hasDepth = false);
/** /**
* @brief * @brief
@ -109,12 +109,12 @@ public:
/** /**
* @brief * @brief
*/ */
Ptr<Texture> getColorTexture() const { return colorTexture_; } IntrusivePtr<Texture> getColorTexture() const { return colorTexture_; }
/** /**
* @brief * @brief
*/ */
Ptr<Texture> getDepthTexture() const { return depthTexture_; } IntrusivePtr<Texture> getDepthTexture() const { return depthTexture_; }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 视口和裁剪 // 视口和裁剪
@ -169,7 +169,7 @@ public:
/** /**
* @brief * @brief
*/ */
static Ptr<RenderTarget> createFromConfig(const RenderTargetConfig &config); static IntrusivePtr<RenderTarget> createFromConfig(const RenderTargetConfig &config);
/** /**
* @brief ID * @brief ID
@ -190,8 +190,8 @@ protected:
GLuint fbo_ = 0; // 帧缓冲对象 GLuint fbo_ = 0; // 帧缓冲对象
GLuint rbo_ = 0; // 渲染缓冲对象(深度/模板) GLuint rbo_ = 0; // 渲染缓冲对象(深度/模板)
Ptr<Texture> colorTexture_; // 颜色纹理 IntrusivePtr<Texture> colorTexture_; // 颜色纹理
Ptr<Texture> depthTexture_; // 深度纹理(可选) IntrusivePtr<Texture> depthTexture_; // 深度纹理(可选)
int width_ = 0; int width_ = 0;
int height_ = 0; int height_ = 0;
@ -293,7 +293,7 @@ public:
/** /**
* @brief * @brief
*/ */
Ptr<RenderTarget> createRenderTarget(const RenderTargetConfig &config); IntrusivePtr<RenderTarget> createRenderTarget(const RenderTargetConfig &config);
/** /**
* @brief * @brief
@ -318,8 +318,8 @@ private:
RenderTargetManager(const RenderTargetManager &) = delete; RenderTargetManager(const RenderTargetManager &) = delete;
RenderTargetManager &operator=(const RenderTargetManager &) = delete; RenderTargetManager &operator=(const RenderTargetManager &) = delete;
Ptr<RenderTarget> defaultRenderTarget_; IntrusivePtr<RenderTarget> defaultRenderTarget_;
std::vector<Ptr<RenderTarget>> renderTargets_; std::vector<IntrusivePtr<RenderTarget>> renderTargets_;
bool initialized_ = false; bool initialized_ = false;
}; };

View File

@ -73,9 +73,9 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 纹理 // 纹理
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual Ptr<Texture> createTexture(int width, int height, virtual IntrusivePtr<Texture> createTexture(int width, int height,
const uint8_t *pixels, int channels) = 0; const uint8_t *pixels, int channels) = 0;
virtual Ptr<Texture> loadTexture(const std::string &filepath) = 0; virtual IntrusivePtr<Texture> loadTexture(const std::string &filepath) = 0;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 精灵批渲染 // 精灵批渲染
@ -112,7 +112,7 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 文字渲染 // 文字渲染
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
virtual Ptr<FontAtlas> createFontAtlas(const std::string &filepath, virtual IntrusivePtr<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;

View File

@ -39,14 +39,14 @@ enum class TextureFormat {
// 纹理LRU缓存项 // 纹理LRU缓存项
// ============================================================================ // ============================================================================
struct TextureCacheEntry { struct TextureCacheEntry {
Ptr<Texture> texture; IntrusivePtr<Texture> texture;
size_t size = 0; // 纹理大小(字节) size_t size = 0; // 纹理大小(字节)
float lastAccessTime = 0.0f; // 最后访问时间 float lastAccessTime = 0.0f; // 最后访问时间
uint32_t accessCount = 0; // 访问次数 uint32_t accessCount = 0; // 访问次数
}; };
// 异步加载回调类型 // 异步加载回调类型
using TextureLoadCallback = std::function<void(Ptr<Texture>)>; using TextureLoadCallback = std::function<void(IntrusivePtr<Texture>)>;
class ResourceManager { class ResourceManager {
public: public:
@ -60,13 +60,13 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/// 加载纹理(带缓存) /// 加载纹理(带缓存)
Ptr<Texture> loadTexture(const std::string &filepath); IntrusivePtr<Texture> loadTexture(const std::string &filepath);
/// 加载纹理(指定是否异步) /// 加载纹理(指定是否异步)
Ptr<Texture> loadTexture(const std::string &filepath, bool async); IntrusivePtr<Texture> loadTexture(const std::string &filepath, bool async);
/// 加载纹理(完整参数:异步 + 压缩格式) /// 加载纹理(完整参数:异步 + 压缩格式)
Ptr<Texture> loadTexture(const std::string &filepath, bool async, IntrusivePtr<Texture> loadTexture(const std::string &filepath, bool async,
TextureFormat format); TextureFormat format);
/// 异步加载纹理(带回调) /// 异步加载纹理(带回调)
@ -78,10 +78,10 @@ public:
TextureLoadCallback callback); TextureLoadCallback callback);
/// 加载纹理并生成Alpha遮罩用于不规则形状图片 /// 加载纹理并生成Alpha遮罩用于不规则形状图片
Ptr<Texture> loadTextureWithAlphaMask(const std::string &filepath); IntrusivePtr<Texture> loadTextureWithAlphaMask(const std::string &filepath);
/// 通过key获取已缓存的纹理 /// 通过key获取已缓存的纹理
Ptr<Texture> getTexture(const std::string &key) const; IntrusivePtr<Texture> getTexture(const std::string &key) const;
/// 检查纹理是否已缓存 /// 检查纹理是否已缓存
bool hasTexture(const std::string &key) const; bool hasTexture(const std::string &key) const;
@ -107,11 +107,11 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/// 加载字体图集(带缓存) /// 加载字体图集(带缓存)
Ptr<FontAtlas> loadFont(const std::string &filepath, int fontSize, IntrusivePtr<FontAtlas> loadFont(const std::string &filepath, int fontSize,
bool useSDF = false); bool useSDF = false);
/// 通过key获取已缓存的字体图集 /// 通过key获取已缓存的字体图集
Ptr<FontAtlas> getFont(const std::string &key) const; IntrusivePtr<FontAtlas> getFont(const std::string &key) const;
/// 检查字体是否已缓存 /// 检查字体是否已缓存
bool hasFont(const std::string &key) const; bool hasFont(const std::string &key) const;
@ -124,11 +124,11 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/// 加载音效(带缓存) /// 加载音效(带缓存)
Ptr<Sound> loadSound(const std::string &filepath); IntrusivePtr<Sound> loadSound(const std::string &filepath);
Ptr<Sound> loadSound(const std::string &name, const std::string &filepath); IntrusivePtr<Sound> loadSound(const std::string &name, const std::string &filepath);
/// 通过key获取已缓存的音效 /// 通过key获取已缓存的音效
Ptr<Sound> getSound(const std::string &key) const; IntrusivePtr<Sound> getSound(const std::string &key) const;
/// 检查音效是否已缓存 /// 检查音效是否已缓存
bool hasSound(const std::string &key) const; bool hasSound(const std::string &key) const;
@ -255,7 +255,7 @@ private:
bool useSDF) const; bool useSDF) const;
// 内部加载实现 // 内部加载实现
Ptr<Texture> loadTextureInternal(const std::string &filepath, IntrusivePtr<Texture> loadTextureInternal(const std::string &filepath,
TextureFormat format); TextureFormat format);
// 选择最佳纹理格式 // 选择最佳纹理格式
@ -273,9 +273,9 @@ private:
mutable std::mutex textFileMutex_; mutable std::mutex textFileMutex_;
mutable std::mutex jsonFileMutex_; mutable std::mutex jsonFileMutex_;
// 资源缓存 - 使用弱指针实现自动清理 // 资源缓存 - 使用 IntrusivePtr 强引用
std::unordered_map<std::string, WeakPtr<FontAtlas>> fontCache_; std::unordered_map<std::string, IntrusivePtr<FontAtlas>> fontCache_;
std::unordered_map<std::string, WeakPtr<Sound>> soundCache_; std::unordered_map<std::string, IntrusivePtr<Sound>> soundCache_;
// 文本文件缓存 - 使用强引用(字符串值类型) // 文本文件缓存 - 使用强引用(字符串值类型)
std::unordered_map<std::string, std::string> textFileCache_; std::unordered_map<std::string, std::string> textFileCache_;
@ -318,7 +318,7 @@ private:
std::string filepath; std::string filepath;
TextureFormat format; TextureFormat format;
TextureLoadCallback callback; TextureLoadCallback callback;
std::promise<Ptr<Texture>> promise; std::promise<IntrusivePtr<Texture>> promise;
}; };
std::queue<AsyncLoadTask> asyncTaskQueue_; std::queue<AsyncLoadTask> asyncTaskQueue_;

View File

@ -1,14 +1,11 @@
#pragma once #pragma once
#include <algorithm>
#include <core/color.h> #include <core/color.h>
#include <core/rect.h> #include <core/rect.h>
#include <core/types.h> #include <core/types.h>
#include <core/vec2.h> #include <core/vec2.h>
#include <event/event_dispatcher.h> #include <event/event_dispatcher.h>
#include <functional>
#include <renderer/renderer.h> #include <renderer/renderer.h>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -22,7 +19,7 @@ struct RenderCommand;
// ============================================================================ // ============================================================================
// 节点基类 - 场景图的基础 // 节点基类 - 场景图的基础
// ============================================================================ // ============================================================================
class Node : public std::enable_shared_from_this<Node> { class Node : public RefCounted {
public: public:
Node(); Node();
virtual ~Node(); virtual ~Node();
@ -30,23 +27,23 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 层级管理 // 层级管理
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void addChild(Ptr<Node> child); void addChild(IntrusivePtr<Node> child);
/** /**
* @brief * @brief
* @param children * @param children
*/ */
void addChildren(std::vector<Ptr<Node>> &&children); void addChildren(std::vector<IntrusivePtr<Node>> &&children);
void removeChild(Ptr<Node> child); void removeChild(IntrusivePtr<Node> child);
void removeChildByName(const std::string &name); void removeChildByName(const std::string &name);
void removeFromParent(); void removeFromParent();
void removeAllChildren(); void removeAllChildren();
Ptr<Node> parent() const { return parent_.lock(); } Node* parent() const { return parent_; }
const std::vector<Ptr<Node>> &children() const { return children_; } const std::vector<IntrusivePtr<Node>> &children() const { return children_; }
Ptr<Node> childByName(const std::string &name) const; IntrusivePtr<Node> childByName(const std::string &name) const;
Ptr<Node> childByTag(int tag) const; IntrusivePtr<Node> childByTag(int tag) const;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 变换属性 // 变换属性
@ -195,17 +192,17 @@ private:
// 2. 字符串和容器24-32字节 // 2. 字符串和容器24-32字节
std::string name_; // 32 bytes std::string name_; // 32 bytes
std::vector<Ptr<Node>> children_; // 24 bytes std::vector<IntrusivePtr<Node>> children_; // 24 bytes
// 3. 子节点索引(加速查找) // 3. 子节点索引(加速查找)
std::unordered_map<std::string, WeakPtr<Node>> nameIndex_; // 56 bytes std::unordered_map<std::string, Node*> nameIndex_; // 56 bytes
std::unordered_map<int, WeakPtr<Node>> tagIndex_; // 56 bytes std::unordered_map<int, Node*> tagIndex_; // 56 bytes
// 4. 事件分发器 // 4. 事件分发器
EventDispatcher eventDispatcher_; // 大小取决于实现 EventDispatcher eventDispatcher_; // 大小取决于实现
// 5. 父节点引用 // 5. 父节点引用
WeakPtr<Node> parent_; // 16 bytes Node* parent_ = nullptr; // 8 bytes
// 7. 变换属性(按访问频率分组) // 7. 变换属性(按访问频率分组)
Vec2 position_ = Vec2::Zero(); // 8 bytes Vec2 position_ = Vec2::Zero(); // 8 bytes
@ -237,8 +234,6 @@ private:
bool childrenOrderDirty_ = false; // 1 byte bool childrenOrderDirty_ = false; // 1 byte
bool visible_ = true; // 1 byte bool visible_ = true; // 1 byte
bool running_ = false; // 1 byte bool running_ = false; // 1 byte
}; };
} // namespace extra2d } // namespace extra2d

View File

@ -27,8 +27,8 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 摄像机 // 摄像机
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void setCamera(Ptr<Camera> camera); void setCamera(IntrusivePtr<Camera> camera);
Ptr<Camera> getCamera() const { return camera_; } IntrusivePtr<Camera> getCamera() const { return camera_; }
Camera *getActiveCamera() const { Camera *getActiveCamera() const {
return camera_ ? camera_.get() : defaultCamera_.get(); return camera_ ? camera_.get() : defaultCamera_.get();
@ -63,7 +63,7 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 静态创建方法 // 静态创建方法
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
static Ptr<Scene> create(); static IntrusivePtr<Scene> create();
protected: protected:
void onEnter() override; void onEnter() override;
@ -75,8 +75,8 @@ private:
Color backgroundColor_ = Colors::Black; Color backgroundColor_ = Colors::Black;
Size viewportSize_ = Size::Zero(); Size viewportSize_ = Size::Zero();
Ptr<Camera> camera_; IntrusivePtr<Camera> camera_;
Ptr<Camera> defaultCamera_; IntrusivePtr<Camera> defaultCamera_;
bool paused_ = false; bool paused_ = false;
}; };

View File

@ -29,13 +29,13 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 运行第一个场景 // 运行第一个场景
void runWithScene(Ptr<Scene> scene); void runWithScene(IntrusivePtr<Scene> scene);
// 替换当前场景 // 替换当前场景
void replaceScene(Ptr<Scene> scene); void replaceScene(IntrusivePtr<Scene> scene);
// 压入新场景(当前场景暂停) // 压入新场景(当前场景暂停)
void pushScene(Ptr<Scene> scene); void pushScene(IntrusivePtr<Scene> scene);
// 弹出当前场景(恢复上一个场景) // 弹出当前场景(恢复上一个场景)
void popScene(); void popScene();
@ -49,12 +49,12 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 获取场景 // 获取场景
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
Ptr<Scene> getCurrentScene() const; IntrusivePtr<Scene> getCurrentScene() const;
Ptr<Scene> getPreviousScene() const; IntrusivePtr<Scene> getPreviousScene() const;
Ptr<Scene> getRootScene() const; IntrusivePtr<Scene> getRootScene() const;
// 通过名称获取场景 // 通过名称获取场景
Ptr<Scene> getSceneByName(const std::string &name) const; IntrusivePtr<Scene> getSceneByName(const std::string &name) const;
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 查询 // 查询
@ -83,17 +83,17 @@ public:
SceneManager &operator=(const SceneManager &) = delete; SceneManager &operator=(const SceneManager &) = delete;
// 场景切换(供 Application 使用) // 场景切换(供 Application 使用)
void enterScene(Ptr<Scene> scene); void enterScene(IntrusivePtr<Scene> scene);
private: private:
void doSceneSwitch(); void doSceneSwitch();
void dispatchPointerEvents(Scene &scene); void dispatchPointerEvents(Scene &scene);
std::stack<Ptr<Scene>> sceneStack_; std::stack<IntrusivePtr<Scene>> sceneStack_;
std::unordered_map<std::string, Ptr<Scene>> namedScenes_; std::unordered_map<std::string, IntrusivePtr<Scene>> namedScenes_;
// Next scene to switch to (queued during transition) // Next scene to switch to (queued during transition)
Ptr<Scene> nextScene_; IntrusivePtr<Scene> nextScene_;
bool sendCleanupToScene_ = false; bool sendCleanupToScene_ = false;
Node *hoverTarget_ = nullptr; Node *hoverTarget_ = nullptr;

View File

@ -23,40 +23,40 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// 静态创建方法 // 静态创建方法
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
static Ptr<ShapeNode> create(); static IntrusivePtr<ShapeNode> create();
// 点 // 点
static Ptr<ShapeNode> createPoint(const Vec2 &pos, const Color &color); static IntrusivePtr<ShapeNode> createPoint(const Vec2 &pos, const Color &color);
// 线 // 线
static Ptr<ShapeNode> createLine(const Vec2 &start, const Vec2 &end, static IntrusivePtr<ShapeNode> createLine(const Vec2 &start, const Vec2 &end,
const Color &color, float width = 1.0f); const Color &color, float width = 1.0f);
// 矩形 // 矩形
static Ptr<ShapeNode> createRect(const Rect &rect, const Color &color, static IntrusivePtr<ShapeNode> createRect(const Rect &rect, const Color &color,
float width = 1.0f); float width = 1.0f);
static Ptr<ShapeNode> createFilledRect(const Rect &rect, const Color &color); static IntrusivePtr<ShapeNode> createFilledRect(const Rect &rect, const Color &color);
// 圆形 // 圆形
static Ptr<ShapeNode> createCircle(const Vec2 &center, float radius, static IntrusivePtr<ShapeNode> createCircle(const Vec2 &center, float radius,
const Color &color, int segments = 32, const Color &color, int segments = 32,
float width = 1.0f); float width = 1.0f);
static Ptr<ShapeNode> createFilledCircle(const Vec2 &center, float radius, static IntrusivePtr<ShapeNode> createFilledCircle(const Vec2 &center, float radius,
const Color &color, const Color &color,
int segments = 32); int segments = 32);
// 三角形 // 三角形
static Ptr<ShapeNode> createTriangle(const Vec2 &p1, const Vec2 &p2, static IntrusivePtr<ShapeNode> createTriangle(const Vec2 &p1, const Vec2 &p2,
const Vec2 &p3, const Color &color, const Vec2 &p3, const Color &color,
float width = 1.0f); float width = 1.0f);
static Ptr<ShapeNode> createFilledTriangle(const Vec2 &p1, const Vec2 &p2, static IntrusivePtr<ShapeNode> createFilledTriangle(const Vec2 &p1, const Vec2 &p2,
const Vec2 &p3, const Vec2 &p3,
const Color &color); const Color &color);
// 多边形 // 多边形
static Ptr<ShapeNode> createPolygon(const std::vector<Vec2> &points, static IntrusivePtr<ShapeNode> createPolygon(const std::vector<Vec2> &points,
const Color &color, float width = 1.0f); const Color &color, float width = 1.0f);
static Ptr<ShapeNode> createFilledPolygon(const std::vector<Vec2> &points, static IntrusivePtr<ShapeNode> createFilledPolygon(const std::vector<Vec2> &points,
const Color &color); const Color &color);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

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

View File

@ -362,7 +362,7 @@ EventDispatcher &Application::eventDispatcher() { return *eventDispatcher_; }
Camera &Application::camera() { return *camera_; } Camera &Application::camera() { return *camera_; }
void Application::enterScene(Ptr<Scene> scene) { void Application::enterScene(IntrusivePtr<Scene> scene) {
if (sceneManager_ && scene) { if (sceneManager_ && scene) {
scene->setViewportSize(static_cast<float>(window_->width()), scene->setViewportSize(static_cast<float>(window_->width()),
static_cast<float>(window_->height())); static_cast<float>(window_->height()));

View File

@ -54,11 +54,11 @@ void AudioEngine::shutdown() {
E2D_LOG_INFO("AudioEngine shutdown"); E2D_LOG_INFO("AudioEngine shutdown");
} }
std::shared_ptr<Sound> AudioEngine::loadSound(const std::string &filePath) { IntrusivePtr<Sound> AudioEngine::loadSound(const std::string &filePath) {
return loadSound(filePath, filePath); return loadSound(filePath, filePath);
} }
std::shared_ptr<Sound> AudioEngine::loadSound(const std::string &name, IntrusivePtr<Sound> AudioEngine::loadSound(const std::string &name,
const std::string &filePath) { const std::string &filePath) {
if (!initialized_) { if (!initialized_) {
E2D_LOG_ERROR("AudioEngine not initialized"); E2D_LOG_ERROR("AudioEngine not initialized");
@ -77,14 +77,14 @@ std::shared_ptr<Sound> AudioEngine::loadSound(const std::string &name,
return nullptr; return nullptr;
} }
auto sound = std::shared_ptr<Sound>(new Sound(name, filePath, chunk)); auto sound = IntrusivePtr<Sound>(new Sound(name, filePath, chunk));
sounds_[name] = sound; sounds_[name] = sound;
E2D_LOG_DEBUG("Loaded sound: {}", filePath); E2D_LOG_DEBUG("Loaded sound: {}", filePath);
return sound; return sound;
} }
std::shared_ptr<Sound> AudioEngine::getSound(const std::string &name) { IntrusivePtr<Sound> AudioEngine::getSound(const std::string &name) {
auto it = sounds_.find(name); auto it = sounds_.find(name);
if (it != sounds_.end()) { if (it != sounds_.end()) {
return it->second; return it->second;

View File

@ -256,13 +256,13 @@ glm::mat4 GLRenderer::getCurrentTransform() const {
return transformStack_.back(); return transformStack_.back();
} }
Ptr<Texture> GLRenderer::createTexture(int width, int height, IntrusivePtr<Texture> GLRenderer::createTexture(int width, int height,
const uint8_t *pixels, int channels) { const uint8_t *pixels, int channels) {
return shared<GLTexture>(width, height, pixels, channels); return makeRef<GLTexture>(width, height, pixels, channels);
} }
Ptr<Texture> GLRenderer::loadTexture(const std::string &filepath) { IntrusivePtr<Texture> GLRenderer::loadTexture(const std::string &filepath) {
return shared<GLTexture>(filepath); return makeRef<GLTexture>(filepath);
} }
void GLRenderer::beginSpriteBatch() { spriteBatch_.begin(viewProjection_); } void GLRenderer::beginSpriteBatch() { spriteBatch_.begin(viewProjection_); }
@ -476,9 +476,9 @@ void GLRenderer::fillPolygon(const std::vector<Vec2> &points,
} }
} }
Ptr<FontAtlas> GLRenderer::createFontAtlas(const std::string &filepath, IntrusivePtr<FontAtlas> GLRenderer::createFontAtlas(const std::string &filepath,
int fontSize, bool useSDF) { int fontSize, bool useSDF) {
return shared<GLFontAtlas>(filepath, fontSize, useSDF); return makeRef<GLFontAtlas>(filepath, fontSize, useSDF);
} }
void GLRenderer::drawText(const FontAtlas &font, const std::string &text, void GLRenderer::drawText(const FontAtlas &font, const std::string &text,

View File

@ -438,7 +438,7 @@ void GLTexture::generateAlphaMask() {
PixelFormat GLTexture::getFormat() const { return format_; } PixelFormat GLTexture::getFormat() const { return format_; }
Ptr<Texture> GLTexture::create(int width, int height, PixelFormat format) { IntrusivePtr<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:
@ -457,7 +457,7 @@ Ptr<Texture> GLTexture::create(int width, int height, PixelFormat format) {
channels = 4; channels = 4;
break; break;
} }
return shared<GLTexture>(width, height, nullptr, channels); return makeRef<GLTexture>(width, height, nullptr, channels);
} }
} // namespace extra2d } // namespace extra2d

View File

@ -14,7 +14,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_ = shared<GLTexture>(width, height, emptyData.data(), 4); texture_ = makeRef<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

@ -73,7 +73,7 @@ bool RenderTarget::create(const RenderTargetConfig &config) {
return true; return true;
} }
bool RenderTarget::createFromTexture(Ptr<Texture> texture, bool hasDepth) { bool RenderTarget::createFromTexture(IntrusivePtr<Texture> texture, bool hasDepth) {
if (!texture || !texture->isValid()) { if (!texture || !texture->isValid()) {
E2D_ERROR("无效的颜色纹理"); E2D_ERROR("无效的颜色纹理");
return false; return false;
@ -296,9 +296,9 @@ bool RenderTarget::saveToFile(const std::string &filepath) {
return true; return true;
} }
Ptr<RenderTarget> IntrusivePtr<RenderTarget>
RenderTarget::createFromConfig(const RenderTargetConfig &config) { RenderTarget::createFromConfig(const RenderTargetConfig &config) {
auto rt = std::make_shared<RenderTarget>(); auto rt = makeRef<RenderTarget>();
if (rt->create(config)) { if (rt->create(config)) {
return rt; return rt;
} }
@ -556,7 +556,7 @@ void RenderTargetManager::shutdown() {
E2D_INFO("渲染目标管理器已关闭"); E2D_INFO("渲染目标管理器已关闭");
} }
Ptr<RenderTarget> IntrusivePtr<RenderTarget>
RenderTargetManager::createRenderTarget(const RenderTargetConfig &config) { RenderTargetManager::createRenderTarget(const RenderTargetConfig &config) {
if (!initialized_) { if (!initialized_) {
E2D_ERROR("渲染目标管理器未初始化"); E2D_ERROR("渲染目标管理器未初始化");

View File

@ -22,7 +22,7 @@ static bool fileExists(const std::string &path) {
// 辅助函数:检查是否是 romfs 路径 // 辅助函数:检查是否是 romfs 路径
static bool isRomfsPath(const std::string &path) { static bool isRomfsPath(const std::string &path) {
return path.find("romfs:/") == 0 || path.find("romfs:\\") == 0; return path.find("romfs:/") == 0 || path.find("romfs:") == 0;
} }
// 辅助函数获取可执行文件所在目录Windows 平台) // 辅助函数获取可执行文件所在目录Windows 平台)
@ -169,16 +169,16 @@ void ResourceManager::asyncLoadLoop() {
// 纹理资源 - 同步加载 // 纹理资源 - 同步加载
// ============================================================================ // ============================================================================
Ptr<Texture> ResourceManager::loadTexture(const std::string &filepath) { IntrusivePtr<Texture> ResourceManager::loadTexture(const std::string &filepath) {
return loadTexture(filepath, false, TextureFormat::Auto); return loadTexture(filepath, false, TextureFormat::Auto);
} }
Ptr<Texture> ResourceManager::loadTexture(const std::string &filepath, IntrusivePtr<Texture> ResourceManager::loadTexture(const std::string &filepath,
bool async) { bool async) {
return loadTexture(filepath, async, TextureFormat::Auto); return loadTexture(filepath, async, TextureFormat::Auto);
} }
Ptr<Texture> ResourceManager::loadTexture(const std::string &filepath, IntrusivePtr<Texture> ResourceManager::loadTexture(const std::string &filepath,
bool async, TextureFormat format) { bool async, TextureFormat format) {
if (async) { if (async) {
// 异步加载:返回空指针,实际纹理通过回调获取 // 异步加载:返回空指针,实际纹理通过回调获取
@ -235,7 +235,7 @@ void ResourceManager::loadTextureAsync(const std::string &filepath,
E2D_LOG_DEBUG("ResourceManager: queued async texture load: {}", filepath); E2D_LOG_DEBUG("ResourceManager: queued async texture load: {}", filepath);
} }
Ptr<Texture> ResourceManager::loadTextureInternal(const std::string &filepath, IntrusivePtr<Texture> ResourceManager::loadTextureInternal(const std::string &filepath,
TextureFormat format) { TextureFormat format) {
std::lock_guard<std::mutex> lock(textureMutex_); std::lock_guard<std::mutex> lock(textureMutex_);
@ -262,7 +262,7 @@ Ptr<Texture> ResourceManager::loadTextureInternal(const std::string &filepath,
// 创建新纹理 // 创建新纹理
try { try {
auto texture = shared<GLTexture>(fullPath); auto texture = makeRef<GLTexture>(fullPath);
if (!texture->isValid()) { if (!texture->isValid()) {
E2D_LOG_ERROR("ResourceManager: failed to load texture: {}", filepath); E2D_LOG_ERROR("ResourceManager: failed to load texture: {}", filepath);
return nullptr; return nullptr;
@ -338,7 +338,7 @@ std::vector<uint8_t> ResourceManager::compressTexture(const uint8_t *data,
return result; return result;
} }
Ptr<Texture> IntrusivePtr<Texture>
ResourceManager::loadTextureWithAlphaMask(const std::string &filepath) { ResourceManager::loadTextureWithAlphaMask(const std::string &filepath) {
// 先加载纹理 // 先加载纹理
auto texture = loadTexture(filepath); auto texture = loadTexture(filepath);
@ -389,7 +389,7 @@ bool ResourceManager::hasAlphaMask(const std::string &textureKey) const {
return false; return false;
} }
Ptr<Texture> ResourceManager::getTexture(const std::string &key) const { IntrusivePtr<Texture> ResourceManager::getTexture(const std::string &key) const {
std::lock_guard<std::mutex> lock(textureMutex_); std::lock_guard<std::mutex> lock(textureMutex_);
auto it = textureCache_.find(key); auto it = textureCache_.find(key);
@ -439,7 +439,7 @@ std::string ResourceManager::makeFontKey(const std::string &filepath,
return filepath + "#" + std::to_string(fontSize) + (useSDF ? "#sdf" : ""); return filepath + "#" + std::to_string(fontSize) + (useSDF ? "#sdf" : "");
} }
Ptr<FontAtlas> ResourceManager::loadFont(const std::string &filepath, IntrusivePtr<FontAtlas> ResourceManager::loadFont(const std::string &filepath,
int fontSize, bool useSDF) { int fontSize, bool useSDF) {
std::lock_guard<std::mutex> lock(fontMutex_); std::lock_guard<std::mutex> lock(fontMutex_);
@ -448,12 +448,8 @@ Ptr<FontAtlas> ResourceManager::loadFont(const std::string &filepath,
// 检查缓存 // 检查缓存
auto it = fontCache_.find(key); auto it = fontCache_.find(key);
if (it != fontCache_.end()) { if (it != fontCache_.end()) {
if (auto font = it->second.lock()) {
E2D_LOG_TRACE("ResourceManager: font cache hit: {}", key); E2D_LOG_TRACE("ResourceManager: font cache hit: {}", key);
return font; return it->second;
}
// 弱引用已失效,移除
fontCache_.erase(it);
} }
// 解析资源路径(优先尝试 romfs:/ 前缀) // 解析资源路径(优先尝试 romfs:/ 前缀)
@ -465,7 +461,7 @@ Ptr<FontAtlas> ResourceManager::loadFont(const std::string &filepath,
// 创建新字体图集 // 创建新字体图集
try { try {
auto font = shared<GLFontAtlas>(fullPath, fontSize, useSDF); auto font = makeRef<GLFontAtlas>(fullPath, fontSize, useSDF);
if (!font->getTexture() || !font->getTexture()->isValid()) { if (!font->getTexture() || !font->getTexture()->isValid()) {
E2D_LOG_ERROR("ResourceManager: failed to load font: {}", filepath); E2D_LOG_ERROR("ResourceManager: failed to load font: {}", filepath);
return nullptr; return nullptr;
@ -482,24 +478,19 @@ Ptr<FontAtlas> ResourceManager::loadFont(const std::string &filepath,
} }
} }
Ptr<FontAtlas> ResourceManager::getFont(const std::string &key) const { IntrusivePtr<FontAtlas> ResourceManager::getFont(const std::string &key) const {
std::lock_guard<std::mutex> lock(fontMutex_); std::lock_guard<std::mutex> lock(fontMutex_);
auto it = fontCache_.find(key); auto it = fontCache_.find(key);
if (it != fontCache_.end()) { if (it != fontCache_.end()) {
return it->second.lock(); return it->second;
} }
return nullptr; return nullptr;
} }
bool ResourceManager::hasFont(const std::string &key) const { bool ResourceManager::hasFont(const std::string &key) const {
std::lock_guard<std::mutex> lock(fontMutex_); std::lock_guard<std::mutex> lock(fontMutex_);
return fontCache_.find(key) != fontCache_.end();
auto it = fontCache_.find(key);
if (it != fontCache_.end()) {
return !it->second.expired();
}
return false;
} }
void ResourceManager::unloadFont(const std::string &key) { void ResourceManager::unloadFont(const std::string &key) {
@ -512,23 +503,19 @@ void ResourceManager::unloadFont(const std::string &key) {
// 音效资源 // 音效资源
// ============================================================================ // ============================================================================
Ptr<Sound> ResourceManager::loadSound(const std::string &filepath) { IntrusivePtr<Sound> ResourceManager::loadSound(const std::string &filepath) {
return loadSound(filepath, filepath); return loadSound(filepath, filepath);
} }
Ptr<Sound> ResourceManager::loadSound(const std::string &name, IntrusivePtr<Sound> ResourceManager::loadSound(const std::string &name,
const std::string &filepath) { const std::string &filepath) {
std::lock_guard<std::mutex> lock(soundMutex_); std::lock_guard<std::mutex> lock(soundMutex_);
// 检查缓存 // 检查缓存
auto it = soundCache_.find(name); auto it = soundCache_.find(name);
if (it != soundCache_.end()) { if (it != soundCache_.end()) {
if (auto sound = it->second.lock()) {
E2D_LOG_TRACE("ResourceManager: sound cache hit: {}", name); E2D_LOG_TRACE("ResourceManager: sound cache hit: {}", name);
return sound; return it->second;
}
// 弱引用已失效,移除
soundCache_.erase(it);
} }
// 解析资源路径(优先尝试 romfs:/ 前缀) // 解析资源路径(优先尝试 romfs:/ 前缀)
@ -551,24 +538,19 @@ Ptr<Sound> ResourceManager::loadSound(const std::string &name,
return sound; return sound;
} }
Ptr<Sound> ResourceManager::getSound(const std::string &key) const { IntrusivePtr<Sound> ResourceManager::getSound(const std::string &key) const {
std::lock_guard<std::mutex> lock(soundMutex_); std::lock_guard<std::mutex> lock(soundMutex_);
auto it = soundCache_.find(key); auto it = soundCache_.find(key);
if (it != soundCache_.end()) { if (it != soundCache_.end()) {
return it->second.lock(); return it->second;
} }
return nullptr; return nullptr;
} }
bool ResourceManager::hasSound(const std::string &key) const { bool ResourceManager::hasSound(const std::string &key) const {
std::lock_guard<std::mutex> lock(soundMutex_); std::lock_guard<std::mutex> lock(soundMutex_);
return soundCache_.find(key) != soundCache_.end();
auto it = soundCache_.find(key);
if (it != soundCache_.end()) {
return !it->second.expired();
}
return false;
} }
void ResourceManager::unloadSound(const std::string &key) { void ResourceManager::unloadSound(const std::string &key) {
@ -586,31 +568,8 @@ void ResourceManager::unloadSound(const std::string &key) {
void ResourceManager::purgeUnused() { void ResourceManager::purgeUnused() {
// 纹理缓存使用LRU策略不需要清理失效引用 // 纹理缓存使用LRU策略不需要清理失效引用
// 字体缓存 // 字体和音效缓存使用 IntrusivePtr 强引用,不需要清理失效引用
{ // 当外部没有引用时,缓存会自动释放
std::lock_guard<std::mutex> lock(fontMutex_);
for (auto it = fontCache_.begin(); it != fontCache_.end();) {
if (it->second.expired()) {
E2D_LOG_TRACE("ResourceManager: purging unused font: {}", it->first);
it = fontCache_.erase(it);
} else {
++it;
}
}
}
// 音效缓存
{
std::lock_guard<std::mutex> lock(soundMutex_);
for (auto it = soundCache_.begin(); it != soundCache_.end();) {
if (it->second.expired()) {
E2D_LOG_TRACE("ResourceManager: purging unused sound: {}", it->first);
it = soundCache_.erase(it);
} else {
++it;
}
}
}
} }
void ResourceManager::clearTextureCache() { void ResourceManager::clearTextureCache() {

View File

@ -11,22 +11,22 @@ Node::Node() = default;
Node::~Node() { removeAllChildren(); } Node::~Node() { removeAllChildren(); }
void Node::addChild(Ptr<Node> child) { void Node::addChild(IntrusivePtr<Node> child) {
if (!child || child.get() == this) { if (!child || child.get() == this) {
return; return;
} }
child->removeFromParent(); child->removeFromParent();
child->parent_ = weak_from_this(); child->parent_ = this;
children_.push_back(child); children_.push_back(child);
childrenOrderDirty_ = true; childrenOrderDirty_ = true;
// 更新索引 // 更新索引
if (!child->name().empty()) { if (!child->name().empty()) {
nameIndex_[child->name()] = child; nameIndex_[child->name()] = child.get();
} }
if (child->tag() != -1) { if (child->tag() != -1) {
tagIndex_[child->tag()] = child; tagIndex_[child->tag()] = child.get();
} }
if (running_) { if (running_) {
@ -37,7 +37,7 @@ void Node::addChild(Ptr<Node> child) {
} }
} }
void Node::addChildren(std::vector<Ptr<Node>> &&children) { void Node::addChildren(std::vector<IntrusivePtr<Node>> &&children) {
// 预留空间,避免多次扩容 // 预留空间,避免多次扩容
size_t newSize = children_.size() + children.size(); size_t newSize = children_.size() + children.size();
if (newSize > children_.capacity()) { if (newSize > children_.capacity()) {
@ -50,15 +50,15 @@ void Node::addChildren(std::vector<Ptr<Node>> &&children) {
} }
child->removeFromParent(); child->removeFromParent();
child->parent_ = weak_from_this(); child->parent_ = this;
children_.push_back(child); children_.push_back(child);
// 更新索引 // 更新索引
if (!child->name().empty()) { if (!child->name().empty()) {
nameIndex_[child->name()] = child; nameIndex_[child->name()] = child.get();
} }
if (child->tag() != -1) { if (child->tag() != -1) {
tagIndex_[child->tag()] = child; tagIndex_[child->tag()] = child.get();
} }
if (running_) { if (running_) {
@ -74,7 +74,7 @@ void Node::addChildren(std::vector<Ptr<Node>> &&children) {
} }
} }
void Node::removeChild(Ptr<Node> child) { void Node::removeChild(IntrusivePtr<Node> child) {
if (!child) if (!child)
return; return;
@ -94,7 +94,7 @@ void Node::removeChild(Ptr<Node> child) {
if ((*it)->tag() != -1) { if ((*it)->tag() != -1) {
tagIndex_.erase((*it)->tag()); tagIndex_.erase((*it)->tag());
} }
(*it)->parent_.reset(); (*it)->parent_ = nullptr;
children_.erase(it); children_.erase(it);
} }
} }
@ -107,18 +107,9 @@ void Node::removeChildByName(const std::string &name) {
} }
void Node::removeFromParent() { void Node::removeFromParent() {
auto p = parent_.lock(); auto p = parent_;
if (p) { if (p) {
// 安全获取 shared_ptr避免在对象未由 shared_ptr 管理时崩溃 p->removeChild(IntrusivePtr<Node>(this));
Ptr<Node> self;
try {
self = shared_from_this();
} catch (const std::bad_weak_ptr &) {
// 对象不是由 shared_ptr 管理的,直接重置父节点引用
parent_.reset();
return;
}
p->removeChild(self);
} }
} }
@ -128,27 +119,27 @@ void Node::removeAllChildren() {
child->onDetachFromScene(); child->onDetachFromScene();
child->onExit(); child->onExit();
} }
child->parent_.reset(); child->parent_ = nullptr;
} }
children_.clear(); children_.clear();
nameIndex_.clear(); nameIndex_.clear();
tagIndex_.clear(); tagIndex_.clear();
} }
Ptr<Node> Node::childByName(const std::string &name) const { IntrusivePtr<Node> Node::childByName(const std::string &name) const {
// 使用哈希索引O(1) 查找 // 使用哈希索引O(1) 查找
auto it = nameIndex_.find(name); auto it = nameIndex_.find(name);
if (it != nameIndex_.end()) { if (it != nameIndex_.end()) {
return it->second.lock(); return IntrusivePtr<Node>(it->second);
} }
return nullptr; return nullptr;
} }
Ptr<Node> Node::childByTag(int tag) const { IntrusivePtr<Node> Node::childByTag(int tag) const {
// 使用哈希索引O(1) 查找 // 使用哈希索引O(1) 查找
auto it = tagIndex_.find(tag); auto it = tagIndex_.find(tag);
if (it != tagIndex_.end()) { if (it != tagIndex_.end()) {
return it->second.lock(); return IntrusivePtr<Node>(it->second);
} }
return nullptr; return nullptr;
} }
@ -261,8 +252,7 @@ glm::mat4 Node::getWorldTransform() const {
const Node *current = this; const Node *current = this;
while (current && chainCount < nodeChainCache.size()) { while (current && chainCount < nodeChainCache.size()) {
nodeChainCache[chainCount++] = current; nodeChainCache[chainCount++] = current;
auto p = current->parent_.lock(); current = current->parent_;
current = p.get();
} }
// 从根节点开始计算 // 从根节点开始计算
@ -297,7 +287,7 @@ void Node::batchUpdateTransforms() {
// 如果世界变换脏了,需要重新计算 // 如果世界变换脏了,需要重新计算
if (worldTransformDirty_) { if (worldTransformDirty_) {
auto parent = parent_.lock(); auto parent = parent_;
if (parent) { if (parent) {
// 使用父节点的世界变换(确保父节点已经更新) // 使用父节点的世界变换(确保父节点已经更新)
worldTransform_ = parent->getWorldTransform() * localTransform_; worldTransform_ = parent->getWorldTransform() * localTransform_;
@ -403,7 +393,7 @@ void Node::sortChildren() {
} else { } else {
// 大数组使用标准排序 // 大数组使用标准排序
std::sort(children_.begin(), children_.end(), std::sort(children_.begin(), children_.end(),
[](const Ptr<Node> &a, const Ptr<Node> &b) { [](const IntrusivePtr<Node> &a, const IntrusivePtr<Node> &b) {
return a->zOrder() < b->zOrder(); return a->zOrder() < b->zOrder();
}); });
} }

View File

@ -5,9 +5,9 @@
namespace extra2d { namespace extra2d {
Scene::Scene() { defaultCamera_ = shared<Camera>(); } Scene::Scene() { defaultCamera_ = makeRef<Camera>(); }
void Scene::setCamera(Ptr<Camera> camera) { camera_ = camera; } void Scene::setCamera(IntrusivePtr<Camera> camera) { camera_ = camera; }
void Scene::setViewportSize(float width, float height) { void Scene::setViewportSize(float width, float height) {
viewportSize_ = Size(width, height); viewportSize_ = Size(width, height);
@ -68,6 +68,6 @@ void Scene::collectRenderCommands(std::vector<RenderCommand> &commands,
Node::collectRenderCommands(commands, parentZOrder); Node::collectRenderCommands(commands, parentZOrder);
} }
Ptr<Scene> Scene::create() { return shared<Scene>(); } IntrusivePtr<Scene> Scene::create() { return makeRef<Scene>(); }
} // namespace extra2d } // namespace extra2d

View File

@ -11,14 +11,14 @@ namespace extra2d {
namespace { namespace {
Node *hitTestTopmost(const Ptr<Node> &node, const Vec2 &worldPos) { Node *hitTestTopmost(const IntrusivePtr<Node> &node, const Vec2 &worldPos) {
if (!node || !node->visible()) { if (!node || !node->visible()) {
return nullptr; return nullptr;
} }
std::vector<Ptr<Node>> children = node->children(); std::vector<IntrusivePtr<Node>> children = node->children();
std::stable_sort(children.begin(), children.end(), std::stable_sort(children.begin(), children.end(),
[](const Ptr<Node> &a, const Ptr<Node> &b) { [](const IntrusivePtr<Node> &a, const IntrusivePtr<Node> &b) {
return a->zOrder() < b->zOrder(); return a->zOrder() < b->zOrder();
}); });
@ -54,7 +54,7 @@ SceneManager &SceneManager::getInstance() {
return instance; return instance;
} }
void SceneManager::runWithScene(Ptr<Scene> scene) { void SceneManager::runWithScene(IntrusivePtr<Scene> scene) {
if (!scene) { if (!scene) {
return; return;
} }
@ -69,7 +69,7 @@ void SceneManager::runWithScene(Ptr<Scene> scene) {
sceneStack_.push(scene); sceneStack_.push(scene);
} }
void SceneManager::replaceScene(Ptr<Scene> scene) { void SceneManager::replaceScene(IntrusivePtr<Scene> scene) {
if (!scene) { if (!scene) {
return; return;
} }
@ -91,7 +91,7 @@ void SceneManager::replaceScene(Ptr<Scene> scene) {
sceneStack_.push(scene); sceneStack_.push(scene);
} }
void SceneManager::enterScene(Ptr<Scene> scene) { void SceneManager::enterScene(IntrusivePtr<Scene> scene) {
if (!scene) { if (!scene) {
return; return;
} }
@ -103,7 +103,7 @@ void SceneManager::enterScene(Ptr<Scene> scene) {
} }
} }
void SceneManager::pushScene(Ptr<Scene> scene) { void SceneManager::pushScene(IntrusivePtr<Scene> scene) {
if (!scene) { if (!scene) {
return; return;
} }
@ -154,8 +154,8 @@ void SceneManager::popToRootScene() {
void SceneManager::popToScene(const std::string &name) { void SceneManager::popToScene(const std::string &name) {
// Find target scene in stack // Find target scene in stack
std::stack<Ptr<Scene>> tempStack; std::stack<IntrusivePtr<Scene>> tempStack;
Ptr<Scene> target = nullptr; IntrusivePtr<Scene> target = nullptr;
while (!sceneStack_.empty()) { while (!sceneStack_.empty()) {
auto scene = sceneStack_.top(); auto scene = sceneStack_.top();
@ -173,14 +173,14 @@ void SceneManager::popToScene(const std::string &name) {
} }
} }
Ptr<Scene> SceneManager::getCurrentScene() const { IntrusivePtr<Scene> SceneManager::getCurrentScene() const {
if (sceneStack_.empty()) { if (sceneStack_.empty()) {
return nullptr; return nullptr;
} }
return sceneStack_.top(); return sceneStack_.top();
} }
Ptr<Scene> SceneManager::getPreviousScene() const { IntrusivePtr<Scene> SceneManager::getPreviousScene() const {
if (sceneStack_.size() < 2) { if (sceneStack_.size() < 2) {
return nullptr; return nullptr;
} }
@ -191,14 +191,14 @@ Ptr<Scene> SceneManager::getPreviousScene() const {
return tempStack.top(); return tempStack.top();
} }
Ptr<Scene> SceneManager::getRootScene() const { IntrusivePtr<Scene> SceneManager::getRootScene() const {
if (sceneStack_.empty()) { if (sceneStack_.empty()) {
return nullptr; return nullptr;
} }
// Copy stack to access bottom // Copy stack to access bottom
auto tempStack = sceneStack_; auto tempStack = sceneStack_;
Ptr<Scene> root; IntrusivePtr<Scene> root;
while (!tempStack.empty()) { while (!tempStack.empty()) {
root = tempStack.top(); root = tempStack.top();
tempStack.pop(); tempStack.pop();
@ -206,7 +206,7 @@ Ptr<Scene> SceneManager::getRootScene() const {
return root; return root;
} }
Ptr<Scene> SceneManager::getSceneByName(const std::string &name) const { IntrusivePtr<Scene> SceneManager::getSceneByName(const std::string &name) const {
auto it = namedScenes_.find(name); auto it = namedScenes_.find(name);
if (it != namedScenes_.end()) { if (it != namedScenes_.end()) {
return it->second; return it->second;
@ -285,7 +285,7 @@ void SceneManager::dispatchPointerEvents(Scene &scene) {
worldPos = camera->screenToWorld(screenPos); worldPos = camera->screenToWorld(screenPos);
} }
Ptr<Node> root = scene.shared_from_this(); IntrusivePtr<Node> root = IntrusivePtr<Node>(&scene);
Node *newHover = hitTestTopmost(root, worldPos); Node *newHover = hitTestTopmost(root, worldPos);
if (newHover != hoverTarget_) { if (newHover != hoverTarget_) {

View File

@ -9,19 +9,19 @@ namespace extra2d {
ShapeNode::ShapeNode() = default; ShapeNode::ShapeNode() = default;
Ptr<ShapeNode> ShapeNode::create() { return shared<ShapeNode>(); } IntrusivePtr<ShapeNode> ShapeNode::create() { return makeRef<ShapeNode>(); }
Ptr<ShapeNode> ShapeNode::createPoint(const Vec2 &pos, const Color &color) { IntrusivePtr<ShapeNode> ShapeNode::createPoint(const Vec2 &pos, const Color &color) {
auto node = shared<ShapeNode>(); auto node = makeRef<ShapeNode>();
node->shapeType_ = ShapeType::Point; node->shapeType_ = ShapeType::Point;
node->color_ = color; node->color_ = color;
node->points_ = {pos}; node->points_ = {pos};
return node; return node;
} }
Ptr<ShapeNode> ShapeNode::createLine(const Vec2 &start, const Vec2 &end, IntrusivePtr<ShapeNode> ShapeNode::createLine(const Vec2 &start, const Vec2 &end,
const Color &color, float width) { const Color &color, float width) {
auto node = shared<ShapeNode>(); auto node = makeRef<ShapeNode>();
node->shapeType_ = ShapeType::Line; node->shapeType_ = ShapeType::Line;
node->color_ = color; node->color_ = color;
node->lineWidth_ = width; node->lineWidth_ = width;
@ -29,9 +29,9 @@ Ptr<ShapeNode> ShapeNode::createLine(const Vec2 &start, const Vec2 &end,
return node; return node;
} }
Ptr<ShapeNode> ShapeNode::createRect(const Rect &rect, const Color &color, IntrusivePtr<ShapeNode> ShapeNode::createRect(const Rect &rect, const Color &color,
float width) { float width) {
auto node = shared<ShapeNode>(); auto node = makeRef<ShapeNode>();
node->shapeType_ = ShapeType::Rect; node->shapeType_ = ShapeType::Rect;
node->color_ = color; node->color_ = color;
node->lineWidth_ = width; node->lineWidth_ = width;
@ -42,17 +42,17 @@ Ptr<ShapeNode> ShapeNode::createRect(const Rect &rect, const Color &color,
return node; return node;
} }
Ptr<ShapeNode> ShapeNode::createFilledRect(const Rect &rect, IntrusivePtr<ShapeNode> ShapeNode::createFilledRect(const Rect &rect,
const Color &color) { const Color &color) {
auto node = createRect(rect, color, 0); auto node = createRect(rect, color, 0);
node->filled_ = true; node->filled_ = true;
return node; return node;
} }
Ptr<ShapeNode> ShapeNode::createCircle(const Vec2 &center, float radius, IntrusivePtr<ShapeNode> ShapeNode::createCircle(const Vec2 &center, float radius,
const Color &color, int segments, const Color &color, int segments,
float width) { float width) {
auto node = shared<ShapeNode>(); auto node = makeRef<ShapeNode>();
node->shapeType_ = ShapeType::Circle; node->shapeType_ = ShapeType::Circle;
node->color_ = color; node->color_ = color;
node->lineWidth_ = width; node->lineWidth_ = width;
@ -64,17 +64,17 @@ Ptr<ShapeNode> ShapeNode::createCircle(const Vec2 &center, float radius,
return node; return node;
} }
Ptr<ShapeNode> ShapeNode::createFilledCircle(const Vec2 &center, float radius, IntrusivePtr<ShapeNode> ShapeNode::createFilledCircle(const Vec2 &center, float radius,
const Color &color, int segments) { const Color &color, int segments) {
auto node = createCircle(center, radius, color, segments, 0); auto node = createCircle(center, radius, color, segments, 0);
node->filled_ = true; node->filled_ = true;
return node; return node;
} }
Ptr<ShapeNode> ShapeNode::createTriangle(const Vec2 &p1, const Vec2 &p2, IntrusivePtr<ShapeNode> ShapeNode::createTriangle(const Vec2 &p1, const Vec2 &p2,
const Vec2 &p3, const Color &color, const Vec2 &p3, const Color &color,
float width) { float width) {
auto node = shared<ShapeNode>(); auto node = makeRef<ShapeNode>();
node->shapeType_ = ShapeType::Triangle; node->shapeType_ = ShapeType::Triangle;
node->color_ = color; node->color_ = color;
node->lineWidth_ = width; node->lineWidth_ = width;
@ -83,7 +83,7 @@ Ptr<ShapeNode> ShapeNode::createTriangle(const Vec2 &p1, const Vec2 &p2,
return node; return node;
} }
Ptr<ShapeNode> ShapeNode::createFilledTriangle(const Vec2 &p1, const Vec2 &p2, IntrusivePtr<ShapeNode> ShapeNode::createFilledTriangle(const Vec2 &p1, const Vec2 &p2,
const Vec2 &p3, const Vec2 &p3,
const Color &color) { const Color &color) {
auto node = createTriangle(p1, p2, p3, color, 0); auto node = createTriangle(p1, p2, p3, color, 0);
@ -91,9 +91,9 @@ Ptr<ShapeNode> ShapeNode::createFilledTriangle(const Vec2 &p1, const Vec2 &p2,
return node; return node;
} }
Ptr<ShapeNode> ShapeNode::createPolygon(const std::vector<Vec2> &points, IntrusivePtr<ShapeNode> ShapeNode::createPolygon(const std::vector<Vec2> &points,
const Color &color, float width) { const Color &color, float width) {
auto node = shared<ShapeNode>(); auto node = makeRef<ShapeNode>();
node->shapeType_ = ShapeType::Polygon; node->shapeType_ = ShapeType::Polygon;
node->color_ = color; node->color_ = color;
node->lineWidth_ = width; node->lineWidth_ = width;
@ -102,7 +102,7 @@ Ptr<ShapeNode> ShapeNode::createPolygon(const std::vector<Vec2> &points,
return node; return node;
} }
Ptr<ShapeNode> ShapeNode::createFilledPolygon(const std::vector<Vec2> &points, IntrusivePtr<ShapeNode> ShapeNode::createFilledPolygon(const std::vector<Vec2> &points,
const Color &color) { const Color &color) {
auto node = createPolygon(points, color, 0); auto node = createPolygon(points, color, 0);
node->filled_ = true; node->filled_ = true;

View File

@ -9,9 +9,9 @@ namespace extra2d {
Sprite::Sprite() = default; Sprite::Sprite() = default;
Sprite::Sprite(Ptr<Texture> texture) { setTexture(texture); } Sprite::Sprite(IntrusivePtr<Texture> texture) { setTexture(texture); }
void Sprite::setTexture(Ptr<Texture> texture) { void Sprite::setTexture(IntrusivePtr<Texture> texture) {
texture_ = texture; texture_ = texture;
if (texture_) { if (texture_) {
textureRect_ = Rect(0, 0, static_cast<float>(texture_->width()), textureRect_ = Rect(0, 0, static_cast<float>(texture_->width()),
@ -27,14 +27,14 @@ void Sprite::setFlipX(bool flip) { flipX_ = flip; }
void Sprite::setFlipY(bool flip) { flipY_ = flip; } void Sprite::setFlipY(bool flip) { flipY_ = flip; }
Ptr<Sprite> Sprite::create() { return shared<Sprite>(); } IntrusivePtr<Sprite> Sprite::create() { return makeRef<Sprite>(); }
Ptr<Sprite> Sprite::create(Ptr<Texture> texture) { IntrusivePtr<Sprite> Sprite::create(IntrusivePtr<Texture> texture) {
return shared<Sprite>(texture); return makeRef<Sprite>(texture);
} }
Ptr<Sprite> Sprite::create(Ptr<Texture> texture, const Rect &rect) { IntrusivePtr<Sprite> Sprite::create(IntrusivePtr<Texture> texture, const Rect &rect) {
auto sprite = shared<Sprite>(texture); auto sprite = makeRef<Sprite>(texture);
sprite->setTextureRect(rect); sprite->setTextureRect(rect);
return sprite; return sprite;
} }