对应源码位置:cocos2d-x-3.3\cocos\render\CCTexture*
从Sprite谈起
Sprite
其实内部必然包含一个纹理图片,但我们写代码时候用到的是传入一个图片路径,从下面看:
//直接 传入Texture2D 对象
Sprite* Sprite::createWithTexture(Texture2D *texture)
{
Sprite *sprite = new (std::nothrow) Sprite();
if (sprite && sprite->initWithTexture(texture))
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
//直接 传入Texture2D 对象
Sprite* Sprite::createWithTexture(Texture2D *texture, const Rect& rect, bool rotated)
{
Sprite *sprite = new (std::nothrow) Sprite();
if (sprite && sprite->initWithTexture(texture, rect, rotated))
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
//传入路径
Sprite* Sprite::create(const std::string& filename)
{
Sprite *sprite = new (std::nothrow) Sprite();
if (sprite && sprite->initWithFile(filename))
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
Sprite* Sprite::create(const std::string& filename, const Rect& rect)
{
Sprite *sprite = new (std::nothrow) Sprite();
if (sprite && sprite->initWithFile(filename, rect))
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
//直接 传入SpriteFrame 对象
Sprite* Sprite::createWithSpriteFrame(SpriteFrame *spriteFrame)
{
Sprite *sprite = new (std::nothrow) Sprite();
if (sprite && spriteFrame && sprite->initWithSpriteFrame(spriteFrame))
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
Sprite* Sprite::createWithSpriteFrameName(const std::string& spriteFrameName)
{
SpriteFrame *frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(spriteFrameName);
#if COCOS2D_DEBUG > 0
char msg[256] = {
0};
sprintf(msg, "Invalid spriteFrameName: %s", spriteFrameName.c_str());
CCASSERT(frame != nullptr, msg);
#endif
return createWithSpriteFrame(frame);
}
Sprite* Sprite::create()
{
Sprite *sprite = new (std::nothrow) Sprite();
if (sprite && sprite->init())
{
sprite->autorelease();
return sprite;
}
CC_SAFE_DELETE(sprite);
return nullptr;
}
bool Sprite::init(void)
{
return initWithTexture(nullptr, Rect::ZERO );
}
bool Sprite::initWithTexture(Texture2D *texture)
{
CCASSERT(texture != nullptr, "Invalid texture for sprite");
Rect rect = Rect::ZERO;
rect.size = texture->getContentSize();
return initWithTexture(texture, rect);
}
bool Sprite::initWithTexture(Texture2D *texture, const Rect& rect)
{
return initWithTexture(texture, rect, false);
}
//传入路径
bool Sprite::initWithFile(const std::string& filename)
{
CCASSERT(filename.size()>0, "Invalid filename for sprite");
//获取对应的 Texture2D
Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename);
if (texture)
{
Rect rect = Rect::ZERO;
rect.size = texture->getContentSize();
return initWithTexture(texture, rect);
}
// don't release here.
// when load texture failed, it's better to get a "transparent" sprite then a crashed program
// this->release();
return false;
}
bool Sprite::initWithFile(const std::string &filename, const Rect& rect)
{
CCASSERT(filename.size()>0, "Invalid filename");
//同理 获取Texture2D
Texture2D *texture = Director::getInstance()->getTextureCache()->addImage(filename);
if (texture)
{
return initWithTexture(texture, rect);
}
// don't release here.
// when load texture failed, it's better to get a "transparent" sprite then a crashed program
// this->release();
return false;
}
bool Sprite::initWithSpriteFrameName(const std::string& spriteFrameName)
{
CCASSERT(spriteFrameName.size() > 0, "Invalid spriteFrameName");
SpriteFrame *frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(spriteFrameName);
return initWithSpriteFrame(frame);
}
bool Sprite::initWithSpriteFrame(SpriteFrame *spriteFrame)
{
CCASSERT(spriteFrame != nullptr, "");
//最终从 spriteFrame获取Texture2D
bool bRet = initWithTexture(spriteFrame->getTexture(), spriteFrame->getRect());
setSpriteFrame(spriteFrame);
return bRet;
}
//最终的初始化位置
bool Sprite::initWithTexture(Texture2D *texture, const Rect& rect, bool rotated)
TextureCache 类的分析
class CC_DLL TextureCache : public Ref
{
public:
CC_DEPRECATED_ATTRIBUTE static TextureCache * getInstance();
public:
//根据文件 路径 添加图片 返回Texture2D
Texture2D* addImage(const std::string &filepath);
//在 单独线程中 加载图片
virtual void addImageAsync(const std::string &filepath, const std::function<void(Texture2D*)>& callback);
//添加的时候 传入Image key
Texture2D* addImage(Image *image, const std::string &key);
private:
void addImageAsyncCallBack(float dt);
void loadImage();
public:
//异步 结构体 传入 文件名 以及 回调
struct AsyncStruct
{
public:
AsyncStruct(const std::string& fn, std::function<void(Texture2D*)> f) : filename(fn), callback(f) {
}
std::string filename;
std::function<void(Texture2D*)> callback;
};
protected:
// 图片信息 文件名 回调 以及 image对象
typedef struct _ImageInfo
{
AsyncStruct *asyncStruct;
//后面细讲
Image *image;
} ImageInfo;
//用于 加载的线程
std::thread* _loadingThread;
std::queue<AsyncStruct*>* _asyncStructQueue;
std::deque<ImageInfo*>* _imageInfoQueue;
//两个 互斥量
std::mutex _asyncStructQueueMutex;
std::mutex _imageInfoMutex;
std::mutex _sleepMutex;
//条件变量
std::condition_variable _sleepCondition;
bool _needQuit;
int _asyncRefCount;
//最重要的 用于存储 Texture2D的map
std::unordered_map<std::string, Texture2D*> _textures;
};
其中 addImage
的实现
Texture2D * TextureCache::addImage(const std::string &path)
{
//这两个 对象后面说
Texture2D * texture = nullptr;
Image* image = nullptr;
// Split up directory and filename
// MUTEX:
// Needed since addImageAsync calls this method from a different thread
//获取 全路径
std::string fullpath = FileUtils::getInstance()->fullPathForFilename(path);
if (fullpath.size() == 0)
{
return nullptr;
}
//先以全路径为 key 查找一下
auto it = _textures.find(fullpath);
//找到了 直接返回 这就是cache的作用
if( it != _textures.end() )
texture = it->second;
//没找到
if (! texture)
{
// all images are handled by UIImage except PVR extension that is handled by our own handler
do
{
image = new (std::nothrow) Image();
CC_BREAK_IF(nullptr == image);
//加载一下
bool bRet = image->initWithImageFile(fullpath);
CC_BREAK_IF(!bRet);
//以Image初始化 texture
texture = new (std::nothrow) Texture2D();
if( texture && texture->initWithImage(image) )
{
#if CC_ENABLE_CACHE_TEXTURE_DATA
// cache the texture file name
//支持缓存 就存起来
VolatileTextureMgr::addImageTexture(texture, fullpath);
#endif
// texture already retained, no need to re-retain it
//加入 map中
_textures.insert( std::make_pair(fullpath, texture) );
}
else
{
CCLOG("cocos2d: Couldn't create texture for file:%s in TextureCache", path.c_str());
}
} while (0);
}
//没用了
CC_SAFE_RELEASE(image);
//返回 texture
return texture;
}
Texture2D* TextureCache::addImage(Image *image, const std::string &key)
{
CCASSERT(image != nullptr, "TextureCache: image MUST not be nil");
Texture2D * texture = nullptr;
do
{
//不同点在于 用的是key
auto it = _textures.find(key);
if( it != _textures.end() ) {
texture = it->second;
break;
}
// prevents overloading the autorelease pool
//此时 已经有了Image
texture = new (std::nothrow) Texture2D();
texture->initWithImage(image);
if(texture)
{
_textures.insert( std::make_pair(key, texture) );
texture->retain();
texture->autorelease();
}
else
{
CCLOG("cocos2d: Couldn't add UIImage in TextureCache");
}
} while <