diff --git a/cocos/2d/CCSpriteFrameCache.cpp b/cocos/2d/CCSpriteFrameCache.cpp index 94fc0fe559..b86d6054c8 100644 --- a/cocos/2d/CCSpriteFrameCache.cpp +++ b/cocos/2d/CCSpriteFrameCache.cpp @@ -210,6 +210,12 @@ void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist, Texture _loadedFileNames->insert(plist); } +void SpriteFrameCache::addSpriteFramesWithFileContent(const std::string& plist_content, Texture2D *texture) +{ + ValueMap dict = FileUtils::getInstance()->getValueMapFromData(plist_content.c_str(), plist_content.size()); + addSpriteFramesWithDictionary(dict, texture); +} + void SpriteFrameCache::addSpriteFramesWithFile(const std::string& plist, const std::string& textureFileName) { CCASSERT(textureFileName.size()>0, "texture name should not be null"); @@ -357,6 +363,17 @@ void SpriteFrameCache::removeSpriteFramesFromFile(const std::string& plist) } } +void SpriteFrameCache::removeSpriteFramesFromFileContent(const std::string& plist_content) +{ + ValueMap dict = FileUtils::getInstance()->getValueMapFromData(plist_content.data(), plist_content.size()); + if (dict.empty()) + { + CCLOG("cocos2d:SpriteFrameCache:removeSpriteFramesFromFileContent: create dict by fail."); + return; + } + removeSpriteFramesFromDictionary(dict); +} + void SpriteFrameCache::removeSpriteFramesFromDictionary(ValueMap& dictionary) { ValueMap framesDict = dictionary["frames"].asValueMap(); diff --git a/cocos/2d/CCSpriteFrameCache.h b/cocos/2d/CCSpriteFrameCache.h index b9eaa2973c..b0e5b1f391 100644 --- a/cocos/2d/CCSpriteFrameCache.h +++ b/cocos/2d/CCSpriteFrameCache.h @@ -106,6 +106,12 @@ public: */ void addSpriteFramesWithFile(const std::string&plist, Texture2D *texture); + /** Adds multiple Sprite Frames from a plist file content. The texture will be associated with the created sprite frames. + * @js addSpriteFrames + * @lua addSpriteFrames + */ + void addSpriteFramesWithFileContent(const std::string& plist_content, Texture2D *texture); + /** Adds an sprite frame with a given name. If the name already exists, then the contents of the old name will be replaced with the new one. */ @@ -135,6 +141,12 @@ public: */ void removeSpriteFramesFromFile(const std::string& plist); + /** Removes multiple Sprite Frames from a plist file content. + * Sprite Frames stored in this file will be removed. + * It is convenient to call this method when a specific texture needs to be removed. + */ + void removeSpriteFramesFromFileContent(const std::string& plist_content); + /** Removes all Sprite Frames associated with the specified textures. * It is convenient to call this method when a specific texture needs to be removed. * @since v0.995. diff --git a/cocos/platform/CCFileUtils.cpp b/cocos/platform/CCFileUtils.cpp index 598b086bbd..8ee935c546 100644 --- a/cocos/platform/CCFileUtils.cpp +++ b/cocos/platform/CCFileUtils.cpp @@ -105,6 +105,18 @@ public: return _rootDict; } + ValueMap dictionaryWithDataOfFile(const char* filedata, int filesize) + { + _resultType = SAX_RESULT_DICT; + SAXParser parser; + + CCASSERT(parser.init("UTF-8"), "The file format isn't UTF-8"); + parser.setDelegator(this); + + parser.parse(filedata, filesize); + return _rootDict; + } + ValueVector arrayWithContentsOfFile(const std::string& fileName) { _resultType = SAX_RESULT_ARRAY; @@ -321,6 +333,12 @@ ValueMap FileUtils::getValueMapFromFile(const std::string& filename) return tMaker.dictionaryWithContentsOfFile(fullPath.c_str()); } +ValueMap FileUtils::getValueMapFromData(const char* filedata, int filesize) +{ + DictMaker tMaker; + return tMaker.dictionaryWithDataOfFile(filedata, filesize); +} + ValueVector FileUtils::getValueVectorFromFile(const std::string& filename) { const std::string fullPath = fullPathForFilename(filename.c_str()); @@ -472,6 +490,7 @@ NS_CC_BEGIN /* The subclass FileUtilsApple should override these two method. */ ValueMap FileUtils::getValueMapFromFile(const std::string& filename) {return ValueMap();} +ValueMap FileUtils::getValueMapFromData(const char* filedata, int filesize) {return ValueMap();} ValueVector FileUtils::getValueVectorFromFile(const std::string& filename) {return ValueVector();} bool FileUtils::writeToFile(ValueMap& dict, const std::string &fullPath) {return false;} diff --git a/cocos/platform/CCFileUtils.h b/cocos/platform/CCFileUtils.h index 9594b52d11..fc8ec3b69a 100644 --- a/cocos/platform/CCFileUtils.h +++ b/cocos/platform/CCFileUtils.h @@ -294,6 +294,12 @@ public: * @note This method is used internally. */ virtual ValueMap getValueMapFromFile(const std::string& filename); + + /** + * Converts the contents of a file to a ValueMap. + * @note This method is used internally. + */ + virtual ValueMap getValueMapFromData(const char* filedata, int filesize); /** * Write a ValueMap to a plist file. diff --git a/cocos/platform/apple/CCFileUtilsApple.h b/cocos/platform/apple/CCFileUtilsApple.h index 8c563176ab..4a0e16fd96 100644 --- a/cocos/platform/apple/CCFileUtilsApple.h +++ b/cocos/platform/apple/CCFileUtilsApple.h @@ -49,6 +49,7 @@ public: virtual std::string getFullPathForDirectoryAndFilename(const std::string& directory, const std::string& filename) override; virtual ValueMap getValueMapFromFile(const std::string& filename) override; + virtual ValueMap getValueMapFromData(const char* filedata, int filesize); virtual bool writeToFile(ValueMap& dict, const std::string& fullPath) override; virtual ValueVector getValueVectorFromFile(const std::string& filename) override; diff --git a/cocos/platform/apple/CCFileUtilsApple.mm b/cocos/platform/apple/CCFileUtilsApple.mm index ae707b50f2..79c32e43c3 100644 --- a/cocos/platform/apple/CCFileUtilsApple.mm +++ b/cocos/platform/apple/CCFileUtilsApple.mm @@ -428,6 +428,26 @@ ValueMap FileUtilsApple::getValueMapFromFile(const std::string& filename) return ret; } +ValueMap FileUtilsApple::getValueMapFromData(const char* filedata, int filesize) +{ + NSData* file = [NSData dataWithBytes:filedata length:filesize]; + NSPropertyListFormat format; + NSError* error; + NSDictionary* dict = [NSPropertyListSerialization propertyListWithData:file options:NSPropertyListImmutable format:&format error:&error]; + + ValueMap ret; + + if (dict != nil) + { + for (id key in [dict allKeys]) + { + id value = [dict objectForKey:key]; + addValueToDict(key, value, ret); + } + } + return ret; +} + bool FileUtilsApple::writeToFile(ValueMap& dict, const std::string &fullPath) { //CCLOG("iOS||Mac Dictionary %d write to file %s", dict->_ID, fullPath.c_str()); diff --git a/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp b/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp index af90d8c5f5..354820ba84 100644 --- a/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp +++ b/tests/cpp-tests/Classes/SpriteTest/SpriteTest.cpp @@ -109,6 +109,7 @@ static std::function createFunctions[] = CL(SpriteAnimationSplit), CL(SpriteFrameTest), CL(SpriteFrameAliasNameTest), + CL(SpriteFramesFromFileContent), CL(SpriteBatchNodeReorder), CL(SpriteBatchNodeReorderIssue744), CL(SpriteBatchNodeReorderIssue766), @@ -1880,6 +1881,87 @@ std::string SpriteFrameAliasNameTest::subtitle() const return "SpriteFrames are obtained using the alias name"; } +//------------------------------------------------------------------ +// +// SpriteFramesFromFileContent +// +//------------------------------------------------------------------ +void SpriteFramesFromFileContent::onEnter() +{ + SpriteTestDemo::onEnter(); + auto s = Director::getInstance()->getWinSize(); + + std::string plist_content; + { + std::string fullPath = FileUtils::getInstance()->fullPathForFilename("animations/grossini.plist"); + Data data = FileUtils::getInstance()->getDataFromFile(fullPath); + if (!data.isNull()) + plist_content.assign((const char*)data.getBytes(), data.getSize()); + } + + std::string image_content; + { + std::string fullPath = FileUtils::getInstance()->fullPathForFilename("animations/grossini.png"); + Data data = FileUtils::getInstance()->getDataFromFile(fullPath); + if (!data.isNull()) + image_content.assign((const char*)data.getBytes(), data.getSize()); + } + + Image image; + image.initWithImageData((const uint8_t*)image_content.c_str(), image_content.size()); + Texture2D* texture = new Texture2D(); + texture->initWithImage(&image); + texture->autorelease(); + + auto cache = SpriteFrameCache::getInstance(); + cache->addSpriteFramesWithFileContent(plist_content, texture); + + // + // Animation using Sprite BatchNode + // + Sprite * sprite = Sprite::createWithSpriteFrameName("grossini_dance_01.png"); + sprite->setPosition( Vec2( s.width/2-80, s.height/2) ); + addChild(sprite); + + Vector animFrames(15); + + char str[100] = {0}; + for(int i = 1; i < 15; i++) + { + sprintf(str, "grossini_dance_%02d.png", i); + auto frame = cache->getSpriteFrameByName( str ); + animFrames.pushBack(frame); + } + + auto animation = Animation::createWithSpriteFrames(animFrames, 0.3f); + sprite->runAction( RepeatForever::create( Animate::create(animation) ) ); +} + +void SpriteFramesFromFileContent::onExit() +{ + SpriteTestDemo::onExit(); + + std::string plist_content; + { + std::string fullPath = FileUtils::getInstance()->fullPathForFilename("animations/grossini.plist"); + Data data = FileUtils::getInstance()->getDataFromFile(fullPath); + if (!data.isNull()) + plist_content.assign((const char*)data.getBytes(), data.getSize()); + } + + SpriteFrameCache::getInstance()->removeSpriteFramesFromFileContent(plist_content); +} + +std::string SpriteFramesFromFileContent::title() const +{ + return "SpriteFrameCache load form file content"; +} + +std::string SpriteFramesFromFileContent::subtitle() const +{ + return "SpriteFrameCache load from plist file content"; +} + //------------------------------------------------------------------ // // SpriteOffsetAnchorRotation diff --git a/tests/cpp-tests/Classes/SpriteTest/SpriteTest.h b/tests/cpp-tests/Classes/SpriteTest/SpriteTest.h index 5467d46482..e4b6f7cd4e 100644 --- a/tests/cpp-tests/Classes/SpriteTest/SpriteTest.h +++ b/tests/cpp-tests/Classes/SpriteTest/SpriteTest.h @@ -337,6 +337,17 @@ public: virtual std::string subtitle() const override; }; +class SpriteFramesFromFileContent : public SpriteTestDemo +{ +public: + CREATE_FUNC(SpriteFramesFromFileContent); + + virtual void onEnter() override; + virtual void onExit() override; + virtual std::string title() const override; + virtual std::string subtitle() const override; +}; + class SpriteOffsetAnchorRotation: public SpriteTestDemo { public: