SpriteFrameCache: keep plist filenames when trying to remove sprite (#19083)

This commit is contained in:
Arnold 2018-10-16 17:06:21 +08:00 committed by minggo
parent d1e6b8ace9
commit 7770234367
2 changed files with 161 additions and 71 deletions

View File

@ -68,15 +68,13 @@ void SpriteFrameCache::destroyInstance()
bool SpriteFrameCache::init() bool SpriteFrameCache::init()
{ {
_spriteFrames.reserve(20);
_spriteFramesAliases.reserve(20); _spriteFramesAliases.reserve(20);
_loadedFileNames = new std::set<std::string>(); _spriteFramesCache.init();
return true; return true;
} }
SpriteFrameCache::~SpriteFrameCache() SpriteFrameCache::~SpriteFrameCache()
{ {
CC_SAFE_DELETE(_loadedFileNames);
} }
void SpriteFrameCache::parseIntegerList(const std::string &string, std::vector<int> &res) void SpriteFrameCache::parseIntegerList(const std::string &string, std::vector<int> &res)
@ -136,7 +134,7 @@ void SpriteFrameCache::initializePolygonInfo(const Size &textureSize,
info.setRect(Rect(0, 0, spriteSize.width, spriteSize.height)); info.setRect(Rect(0, 0, spriteSize.width, spriteSize.height));
} }
void SpriteFrameCache::addSpriteFramesWithDictionary(ValueMap& dictionary, Texture2D* texture) void SpriteFrameCache::addSpriteFramesWithDictionary(ValueMap& dictionary, Texture2D* texture, const std::string &plist)
{ {
/* /*
Supported Zwoptex Formats: Supported Zwoptex Formats:
@ -180,7 +178,7 @@ void SpriteFrameCache::addSpriteFramesWithDictionary(ValueMap& dictionary, Textu
{ {
ValueMap& frameDict = iter.second.asValueMap(); ValueMap& frameDict = iter.second.asValueMap();
std::string spriteFrameName = iter.first; std::string spriteFrameName = iter.first;
SpriteFrame* spriteFrame = _spriteFrames.at(spriteFrameName); SpriteFrame* spriteFrame = _spriteFramesCache.at(spriteFrameName);
if (spriteFrame) if (spriteFrame)
{ {
continue; continue;
@ -293,12 +291,12 @@ void SpriteFrameCache::addSpriteFramesWithDictionary(ValueMap& dictionary, Textu
texture->addSpriteFrameCapInset(spriteFrame, parser.parseCapInset()); texture->addSpriteFrameCapInset(spriteFrame, parser.parseCapInset());
} }
// add sprite frame // add sprite frame
_spriteFrames.insert(spriteFrameName, spriteFrame); _spriteFramesCache.insertFrame(plist, spriteFrameName, spriteFrame);
} }
CC_SAFE_DELETE(image); CC_SAFE_DELETE(image);
} }
void SpriteFrameCache::addSpriteFramesWithDictionary(ValueMap& dict, const std::string &texturePath) void SpriteFrameCache::addSpriteFramesWithDictionary(ValueMap& dict, const std::string &texturePath, const std::string &plist)
{ {
std::string pixelFormatName; std::string pixelFormatName;
if (dict.find("metadata") != dict.end()) if (dict.find("metadata") != dict.end())
@ -342,7 +340,7 @@ void SpriteFrameCache::addSpriteFramesWithDictionary(ValueMap& dict, const std::
if (texture) if (texture)
{ {
addSpriteFramesWithDictionary(dict, texture); addSpriteFramesWithDictionary(dict, texture, plist);
} }
else else
{ {
@ -352,7 +350,7 @@ void SpriteFrameCache::addSpriteFramesWithDictionary(ValueMap& dict, const std::
void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist, Texture2D *texture) void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist, Texture2D *texture)
{ {
if (_loadedFileNames->find(plist) != _loadedFileNames->end()) if (_spriteFramesCache.hasPlist(plist))
{ {
return; // We already added it return; // We already added it
} }
@ -360,28 +358,25 @@ void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist, Texture
std::string fullPath = FileUtils::getInstance()->fullPathForFilename(plist); std::string fullPath = FileUtils::getInstance()->fullPathForFilename(plist);
ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(fullPath); ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(fullPath);
addSpriteFramesWithDictionary(dict, texture); addSpriteFramesWithDictionary(dict, texture, plist);
_loadedFileNames->insert(plist);
} }
void SpriteFrameCache::addSpriteFramesWithFileContent(const std::string& plist_content, Texture2D *texture) void SpriteFrameCache::addSpriteFramesWithFileContent(const std::string& plist_content, Texture2D *texture)
{ {
ValueMap dict = FileUtils::getInstance()->getValueMapFromData(plist_content.c_str(), static_cast<int>(plist_content.size())); ValueMap dict = FileUtils::getInstance()->getValueMapFromData(plist_content.c_str(), static_cast<int>(plist_content.size()));
addSpriteFramesWithDictionary(dict, texture); addSpriteFramesWithDictionary(dict, texture, "by#addSpriteFramesWithFileContent()");
} }
void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist, const std::string& textureFileName) void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist, const std::string& textureFileName)
{ {
CCASSERT(textureFileName.size()>0, "texture name should not be null"); CCASSERT(textureFileName.size()>0, "texture name should not be null");
if (_loadedFileNames->find(plist) != _loadedFileNames->end()) if (_spriteFramesCache.hasPlist(plist))
{ {
return; // We already added it return; // We already added it
} }
const std::string fullPath = FileUtils::getInstance()->fullPathForFilename(plist); const std::string fullPath = FileUtils::getInstance()->fullPathForFilename(plist);
ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(fullPath); ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(fullPath);
addSpriteFramesWithDictionary(dict, textureFileName); addSpriteFramesWithDictionary(dict, textureFileName, plist);
_loadedFileNames->insert(plist);
} }
void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist) void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist)
@ -396,7 +391,7 @@ void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist)
return; return;
} }
if (_loadedFileNames->find(plist) == _loadedFileNames->end()) if (!_spriteFramesCache.hasPlist(plist))
{ {
ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(fullPath); ValueMap dict = FileUtils::getInstance()->getValueMapFromFile(fullPath);
@ -428,34 +423,25 @@ void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist)
CCLOG("cocos2d: SpriteFrameCache: Trying to use file %s as texture", texturePath.c_str()); CCLOG("cocos2d: SpriteFrameCache: Trying to use file %s as texture", texturePath.c_str());
} }
addSpriteFramesWithDictionary(dict, texturePath); addSpriteFramesWithDictionary(dict, texturePath, plist);
_loadedFileNames->insert(plist);
} }
} }
bool SpriteFrameCache::isSpriteFramesWithFileLoaded(const std::string& plist) const bool SpriteFrameCache::isSpriteFramesWithFileLoaded(const std::string& plist) const
{ {
bool result = false; return _spriteFramesCache.hasPlist(plist);
if (_loadedFileNames->find(plist) != _loadedFileNames->end())
{
result = true;
}
return result;
} }
void SpriteFrameCache::addSpriteFrame(SpriteFrame* frame, const std::string& frameName) void SpriteFrameCache::addSpriteFrame(SpriteFrame* frame, const std::string& frameName)
{ {
CCASSERT(frame, "frame should not be nil"); CCASSERT(frame, "frame should not be nil");
_spriteFrames.insert(frameName, frame); _spriteFramesCache.insertFrame("by#addSpriteFrame()", frameName, frame);
} }
void SpriteFrameCache::removeSpriteFrames() void SpriteFrameCache::removeSpriteFrames()
{ {
_spriteFrames.clear();
_spriteFramesAliases.clear(); _spriteFramesAliases.clear();
_loadedFileNames->clear(); _spriteFramesCache.clear();
} }
void SpriteFrameCache::removeUnusedSpriteFrames() void SpriteFrameCache::removeUnusedSpriteFrames()
@ -463,7 +449,7 @@ void SpriteFrameCache::removeUnusedSpriteFrames()
bool removed = false; bool removed = false;
std::vector<std::string> toRemoveFrames; std::vector<std::string> toRemoveFrames;
for (auto& iter : _spriteFrames) for (auto& iter : _spriteFramesCache.getSpriteFrames())
{ {
SpriteFrame* spriteFrame = iter.second; SpriteFrame* spriteFrame = iter.second;
if( spriteFrame->getReferenceCount() == 1 ) if( spriteFrame->getReferenceCount() == 1 )
@ -475,12 +461,10 @@ void SpriteFrameCache::removeUnusedSpriteFrames()
} }
} }
_spriteFrames.erase(toRemoveFrames);
// FIXME:. Since we don't know the .plist file that originated the frame, we must remove all .plist from the cache
if( removed ) if( removed )
{ {
_loadedFileNames->clear(); _spriteFramesCache.eraseFrames(toRemoveFrames);
} }
} }
@ -497,16 +481,10 @@ void SpriteFrameCache::removeSpriteFrameByName(const std::string& name)
if (!key.empty()) if (!key.empty())
{ {
_spriteFrames.erase(key);
_spriteFramesAliases.erase(key); _spriteFramesAliases.erase(key);
} }
else
{
_spriteFrames.erase(name);
}
// FIXME:. Since we don't know the .plist file that originated the frame, we must remove all .plist from the cache _spriteFramesCache.eraseFrame(name);
_loadedFileNames->clear();
} }
void SpriteFrameCache::removeSpriteFramesFromFile(const std::string& plist) void SpriteFrameCache::removeSpriteFramesFromFile(const std::string& plist)
@ -521,11 +499,7 @@ void SpriteFrameCache::removeSpriteFramesFromFile(const std::string& plist)
removeSpriteFramesFromDictionary(dict); removeSpriteFramesFromDictionary(dict);
// remove it from the cache // remove it from the cache
set<string>::iterator ret = _loadedFileNames->find(plist); _spriteFramesCache.erasePlistIndex(plist);
if (ret != _loadedFileNames->end())
{
_loadedFileNames->erase(ret);
}
} }
void SpriteFrameCache::removeSpriteFramesFromFileContent(const std::string& plist_content) void SpriteFrameCache::removeSpriteFramesFromFileContent(const std::string& plist_content)
@ -549,35 +523,35 @@ void SpriteFrameCache::removeSpriteFramesFromDictionary(ValueMap& dictionary)
for (const auto& iter : framesDict) for (const auto& iter : framesDict)
{ {
if (_spriteFrames.at(iter.first)) if (_spriteFramesCache.at(iter.first))
{ {
keysToRemove.push_back(iter.first); keysToRemove.push_back(iter.first);
} }
} }
_spriteFrames.erase(keysToRemove); _spriteFramesCache.eraseFrames(keysToRemove);
} }
void SpriteFrameCache::removeSpriteFramesFromTexture(Texture2D* texture) void SpriteFrameCache::removeSpriteFramesFromTexture(Texture2D* texture)
{ {
std::vector<std::string> keysToRemove; std::vector<std::string> keysToRemove;
for (auto& iter : _spriteFrames) for (auto& iter : _spriteFramesCache.getSpriteFrames())
{ {
std::string key = iter.first; std::string key = iter.first;
SpriteFrame* frame = _spriteFrames.at(key); SpriteFrame* frame = _spriteFramesCache.at(key);
if (frame && (frame->getTexture() == texture)) if (frame && (frame->getTexture() == texture))
{ {
keysToRemove.push_back(key); keysToRemove.push_back(key);
} }
} }
_spriteFrames.erase(keysToRemove); _spriteFramesCache.eraseFrames(keysToRemove);
} }
SpriteFrame* SpriteFrameCache::getSpriteFrameByName(const std::string& name) SpriteFrame* SpriteFrameCache::getSpriteFrameByName(const std::string& name)
{ {
SpriteFrame* frame = _spriteFrames.at(name); SpriteFrame* frame = _spriteFramesCache.at(name);
if (!frame) if (!frame)
{ {
// try alias dictionary // try alias dictionary
@ -586,7 +560,7 @@ SpriteFrame* SpriteFrameCache::getSpriteFrameByName(const std::string& name)
std::string key = _spriteFramesAliases[name].asString(); std::string key = _spriteFramesAliases[name].asString();
if (!key.empty()) if (!key.empty())
{ {
frame = _spriteFrames.at(key); frame = _spriteFramesCache.at(key);
if (!frame) if (!frame)
{ {
CCLOG("cocos2d: SpriteFrameCache: Frame aliases '%s' isn't found", key.c_str()); CCLOG("cocos2d: SpriteFrameCache: Frame aliases '%s' isn't found", key.c_str());
@ -601,7 +575,7 @@ SpriteFrame* SpriteFrameCache::getSpriteFrameByName(const std::string& name)
return frame; return frame;
} }
void SpriteFrameCache::reloadSpriteFramesWithDictionary(ValueMap& dictionary, Texture2D *texture) void SpriteFrameCache::reloadSpriteFramesWithDictionary(ValueMap& dictionary, Texture2D *texture, const std::string &plist)
{ {
ValueMap& framesDict = dictionary["frames"].asValueMap(); ValueMap& framesDict = dictionary["frames"].asValueMap();
int format = 0; int format = 0;
@ -621,11 +595,7 @@ void SpriteFrameCache::reloadSpriteFramesWithDictionary(ValueMap& dictionary, Te
ValueMap& frameDict = iter.second.asValueMap(); ValueMap& frameDict = iter.second.asValueMap();
std::string spriteFrameName = iter.first; std::string spriteFrameName = iter.first;
auto it = _spriteFrames.find(spriteFrameName); _spriteFramesCache.eraseFrame(spriteFrameName);
if (it != _spriteFrames.end())
{
_spriteFrames.erase(it);
}
SpriteFrame* spriteFrame = nullptr; SpriteFrame* spriteFrame = nullptr;
@ -708,7 +678,7 @@ void SpriteFrameCache::reloadSpriteFramesWithDictionary(ValueMap& dictionary, Te
} }
// add sprite frame // add sprite frame
_spriteFrames.insert(spriteFrameName, spriteFrame); _spriteFramesCache.insertFrame(plist, spriteFrameName, spriteFrame);
} }
} }
@ -716,9 +686,8 @@ bool SpriteFrameCache::reloadTexture(const std::string& plist)
{ {
CCASSERT(plist.size()>0, "plist filename should not be nullptr"); CCASSERT(plist.size()>0, "plist filename should not be nullptr");
auto it = _loadedFileNames->find(plist); if (_spriteFramesCache.hasPlist(plist)) {
if (it != _loadedFileNames->end()) { _spriteFramesCache.erasePlistIndex(plist);
_loadedFileNames->erase(it);
} }
else else
{ {
@ -762,8 +731,7 @@ bool SpriteFrameCache::reloadTexture(const std::string& plist)
if (texture) if (texture)
{ {
reloadSpriteFramesWithDictionary(dict, texture); reloadSpriteFramesWithDictionary(dict, texture, plist);
_loadedFileNames->insert(plist);
} }
else else
{ {
@ -772,4 +740,85 @@ bool SpriteFrameCache::reloadTexture(const std::string& plist)
return true; return true;
} }
void SpriteFrameCache::PlistFramesCache::insertFrame(const std::string &plist, const std::string &frame, SpriteFrame *spriteFrame)
{
_spriteFrames.insert(frame, spriteFrame); //add SpriteFrame
_indexPlist2Frames[plist].insert(frame); //insert index plist->[frameName]
_indexFrame2plist[frame] = plist; //insert index frameName->plist
}
bool SpriteFrameCache::PlistFramesCache::isPlistUsed(const std::string &plist) const
{
//plist loaded && not empty
auto it = _indexPlist2Frames.find(plist);
return it != _indexPlist2Frames.end() && !it->second.empty();
}
bool SpriteFrameCache::PlistFramesCache::eraseFrame(const std::string &frame)
{
_spriteFrames.erase(frame); //drop SpriteFrame
auto itFrame = _indexFrame2plist.find(frame);
if (itFrame != _indexFrame2plist.end())
{
_indexPlist2Frames[itFrame->second].erase(frame); //update index plist->[frameNames]
_indexFrame2plist.erase(itFrame); //update index frame->plist
return true;
}
return false;
}
bool SpriteFrameCache::PlistFramesCache::eraseFrames(const std::vector<std::string> &frames)
{
auto ret = false;
for (const auto & frame : frames)
{
ret |= eraseFrame(frame);
}
return ret;
}
bool SpriteFrameCache::PlistFramesCache::erasePlistIndex(const std::string &plist)
{
auto it = _indexPlist2Frames.find(plist);
if (it == _indexPlist2Frames.end()) return false;
auto &frames = it->second;
for (auto f : frames)
{
// !!do not!! call `_spriteFrames.erase(f);` to erase SpriteFrame
// only erase index here
_indexFrame2plist.erase(f); //erase plist frame frameName->plist
}
_indexPlist2Frames.erase(plist); //update index plist->[frameNames]
return true;
}
void SpriteFrameCache::PlistFramesCache::clear()
{
_indexPlist2Frames.clear();
_indexFrame2plist.clear();
_spriteFrames.clear();
}
bool SpriteFrameCache::PlistFramesCache::hasFrame(const std::string &frame) const
{
return _indexFrame2plist.find(frame) != _indexFrame2plist.end();
}
bool SpriteFrameCache::PlistFramesCache::hasPlist(const std::string &plist) const
{
return _indexPlist2Frames.find(plist) != _indexPlist2Frames.end();
}
SpriteFrame * SpriteFrameCache::PlistFramesCache::at(const std::string &frame)
{
return _spriteFrames.at(frame);
}
Map<std::string, SpriteFrame*>& SpriteFrameCache::PlistFramesCache::getSpriteFrames()
{
return _spriteFrames;
}
NS_CC_END NS_CC_END

View File

@ -32,6 +32,7 @@ THE SOFTWARE.
#define __SPRITE_CCSPRITE_FRAME_CACHE_H__ #define __SPRITE_CCSPRITE_FRAME_CACHE_H__
#include <set> #include <set>
#include <unordered_map>
#include <string> #include <string>
#include "2d/CCSpriteFrame.h" #include "2d/CCSpriteFrame.h"
#include "base/CCRef.h" #include "base/CCRef.h"
@ -87,6 +88,47 @@ class PolygonInfo;
*/ */
class CC_DLL SpriteFrameCache : public Ref class CC_DLL SpriteFrameCache : public Ref
{ {
protected:
/**
* used to wrap plist & frame names & SpriteFrames
*/
class PlistFramesCache {
public:
PlistFramesCache() { }
void init() {
_spriteFrames.reserve(20); clear();
}
/** Record SpriteFrame with plist and frame name, add frame name
* and plist to index
*/
void insertFrame(const std::string &plist, const std::string &frame, SpriteFrame *frameObj);
/** Delete frame from cache, rebuild index
*/
bool eraseFrame(const std::string &frame);
/** Delete a list of frames from cache, rebuild index
*/
bool eraseFrames(const std::vector<std::string> &frame);
/** Delete frame from index and SpriteFrame is kept.
*/
bool erasePlistIndex(const std::string &frame);
/** Clear index and all SpriteFrames.
*/
void clear();
inline bool hasFrame(const std::string &frame) const;
inline bool hasPlist(const std::string &plist) const;
inline SpriteFrame *at(const std::string &frame);
inline Map<std::string, SpriteFrame*>& getSpriteFrames();
inline bool isPlistUsed(const std::string &plist) const;
private:
Map<std::string, SpriteFrame*> _spriteFrames;
std::unordered_map<std::string, std::set<std::string>> _indexPlist2Frames;
std::unordered_map<std::string, std::string> _indexFrame2plist;
};
public: public:
/** Returns the shared instance of the Sprite Frame cache. /** Returns the shared instance of the Sprite Frame cache.
* *
@ -246,11 +288,11 @@ protected:
/*Adds multiple Sprite Frames with a dictionary. The texture will be associated with the created sprite frames. /*Adds multiple Sprite Frames with a dictionary. The texture will be associated with the created sprite frames.
*/ */
void addSpriteFramesWithDictionary(ValueMap& dictionary, Texture2D *texture); void addSpriteFramesWithDictionary(ValueMap& dictionary, Texture2D *texture, const std::string &plist);
/*Adds multiple Sprite Frames with a dictionary. The texture will be associated with the created sprite frames. /*Adds multiple Sprite Frames with a dictionary. The texture will be associated with the created sprite frames.
*/ */
void addSpriteFramesWithDictionary(ValueMap& dictionary, const std::string &texturePath); void addSpriteFramesWithDictionary(ValueMap& dictionary, const std::string &texturePath, const std::string &plist);
/** Removes multiple Sprite Frames from Dictionary. /** Removes multiple Sprite Frames from Dictionary.
* @since v0.99.5 * @since v0.99.5
@ -268,11 +310,10 @@ protected:
const std::vector<int> &triangleIndices, const std::vector<int> &triangleIndices,
PolygonInfo &polygonInfo); PolygonInfo &polygonInfo);
void reloadSpriteFramesWithDictionary(ValueMap& dictionary, Texture2D *texture); void reloadSpriteFramesWithDictionary(ValueMap& dictionary, Texture2D *texture, const std::string &plist);
Map<std::string, SpriteFrame*> _spriteFrames;
ValueMap _spriteFramesAliases; ValueMap _spriteFramesAliases;
std::set<std::string>* _loadedFileNames; PlistFramesCache _spriteFramesCache;
}; };
// end of _2d group // end of _2d group