首页 > 其他分享 >A piece of code for loading and caching Skeleton Animation in IO task [Cocos2dx.3.17.2]

A piece of code for loading and caching Skeleton Animation in IO task [Cocos2dx.3.17.2]

时间:2023-10-25 14:22:57浏览次数:28  
标签:std begin code end Skeleton atlasFile task str string

/****************************************************************************
 Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
 
 http://www.cocos2d-x.org
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 ****************************************************************************/

#include "HelloWorldScene.h"
#include "SimpleAudioEngine.h"
#include "spine/spine-cocos2dx.h"
#include "base/CCAsyncTaskPool.h"
#include  <mutex>

USING_NS_CC;
using namespace spine;

Scene* HelloWorld::createScene()
{
    return HelloWorld::create();
}


// Print useful error message instead of segfaulting when files are not there.
static void problemLoading(const char* filename)
{
    printf("Error while loading: %s\n", filename);
    printf("Depending on how you compiled you might have to add 'Resources/' in front of filenames in HelloWorldScene.cpp\n");
}
struct ImageData {
    std::string file;
    Data* data;
};
struct SkeletonCachedData {
    std::string* atlas;
    std::string* json;
    std::vector<ImageData> imagesData;
};
struct SkeletonLoadParam {
    std::string jsonFile;
    std::string atlasFile;
    SkeletonCachedData skeletonCachedData;
};

#define CACHE_SKELETON_IMAGE 1
class SkeletonCache {
public:
    static SkeletonCache * getInstance(){
        static SkeletonCache _instance;//c++11后静态变量的创建是线程安全的
        return &_instance;
    }
    
    SkeletonCachedData addSkeletonCachedData(const std::string& jsonFile, const std::string& atlasFile){
        SkeletonCachedData cachedData;
        
        std::lock_guard<std::mutex> lg(mtx);
        
        if(_atlasCache.find(atlasFile) == _atlasCache.end()){
            _atlasCache[atlasFile] = new std::string(FileUtils::getInstance()->getStringFromFile(atlasFile));//这个api是线程安全的
        }
        cachedData.atlas = _atlasCache[atlasFile];
        
        if(_jsonCache.find(jsonFile) == _jsonCache.end()){
            _jsonCache[jsonFile] = new std::string(FileUtils::getInstance()->getStringFromFile(jsonFile));
        }
        cachedData.json = _jsonCache[jsonFile];
        
        if(_imagesCache.find(atlasFile) == _imagesCache.end()){
            _imagesCache[atlasFile] = getImagesData(atlasFile, _atlasCache[atlasFile]);
        }
        cachedData.imagesData = _imagesCache[atlasFile];
        
        return cachedData;
    }
    
    void clearSkeletonCachedData(const std::string& jsonFile, const std::string& atlasFile){
        std::lock_guard<std::mutex> lg(mtx);
        
        auto atlasIter = _atlasCache.find(atlasFile);
        if(atlasIter != _atlasCache.end()) {
            delete atlasIter->second;
            _atlasCache.erase(atlasIter);
        }
        
        auto jsonIter = _jsonCache.find(jsonFile);
        if(jsonIter != _jsonCache.end()) {
            delete jsonIter->second;
            _jsonCache.erase(jsonIter);
        }
        
        auto imagesIter = _imagesCache.find(atlasFile);
        if(imagesIter != _imagesCache.end()){
            for(auto& imageData : imagesIter->second){
                delete imageData.data;
            }
            _imagesCache.erase(imagesIter);
        }
    }
    
    ~SkeletonCache(){
        std::lock_guard<std::mutex> lg(mtx);
        CCLOGWARN("The ~SkeletonCache shouldn't be called within game running!");
        
        for(auto it = _atlasCache.begin(); it != _atlasCache.end(); it++)
            delete it->second;
        
        for(auto it = _jsonCache.begin(); it != _jsonCache.end(); it++)
            delete it->second;
        
        for(auto it = _imagesCache.begin(); it != _imagesCache.end(); it++){
            for(auto& imageData : it->second){
                delete imageData.data;
            }
        }
    }
    
    static std::string getAtlasDir(const std::string& atlasFile){
        const char* path = atlasFile.c_str();
        const char* lastForwardSlash = strrchr(path, '/');
        const char* lastBackwardSlash = strrchr(path, '\\');
        const char* lastSlash = lastForwardSlash > lastBackwardSlash ? lastForwardSlash : lastBackwardSlash;
        if (lastSlash == path) lastSlash++; /* Never drop starting slash. */
        
        int dirLength = (int)(lastSlash ? lastSlash - path : 0);
        char *dir = (char*)malloc(sizeof(char) * (dirLength + 1));
    
        memcpy(dir, path, dirLength);
        dir[dirLength] = '\0';
        
        std::string sDir(dir);
        free(dir);
        
        return sDir;
    }
private:
    std::map<std::string, std::string*> _atlasCache;
    std::map<std::string, std::string*> _jsonCache;
    std::map<std::string, std::vector<ImageData>> _imagesCache;
    
    std::mutex mtx;
    
    typedef struct {
        const char* begin;
        const char* end;
    } spStr;
    
    //从atlas提取纹理
    std::vector<ImageData> getImagesData(const std::string& atlasFile, const std::string* atlas){
        std::vector<ImageData> imagesData;
        
        /* Get directory from atlas path. */
        const std::string dir = getAtlasDir(atlasFile);
        int length = (int)atlas->size();
        
        const char* begin = atlas->c_str();
        const char* end = begin + length;
        
        int dirLength = (int)dir.length();
        int needsSlash = dirLength > 0 && dir[dirLength - 1] != '/' && dir[dirLength - 1] != '\\';
        
        spStr str;
        bool page = false;
        while (readLine(&begin, end, &str)) {
            if (str.end - str.begin == 0) {
                page = false;
            }
            else if (!page) {
                page = true;
                
                char* name = mallocString(&str);
                char* path = (char*)malloc(sizeof(char) * (dirLength + needsSlash + strlen(name) + 1));
                memcpy(path, dir.c_str(), dirLength);
                if (needsSlash) path[dirLength] = '/';
                strcpy(path + dirLength + needsSlash, name);
                
                Data d = FileUtils::getInstance()->getDataFromFile(path);
                if(!d.isNull()){
                    ImageData imgData;
                    imgData.file = path;
                    imgData.data = new Data(std::move(d));
                    imagesData.push_back(imgData);;
                }else{
                    CCLOGERROR("Get imageData failled: %s", path);
                }

                free(path);
                free(name);
            }
        }
        
        return std::move(imagesData);
    }
    void trim(spStr* str) {
        while (isspace((unsigned char)*str->begin) && str->begin < str->end)
            (str->begin)++;
        if (str->begin == str->end) return;
        str->end--;
        while (isspace((unsigned char)*str->end) && str->end >= str->begin)
            str->end--;
        str->end++;
    }
    /* Tokenize string without modification. Returns 0 on failure. */
    int readLine(const char** begin, const char* end, spStr* str) {
        if (*begin == end) return 0;
        str->begin = *begin;

        /* Find next delimiter. */
        while (*begin != end && **begin != '\n')
            (*begin)++;

        str->end = *begin;
        trim(str);

        if (*begin != end) (*begin)++;
        return 1;
    }
    char* mallocString(spStr* str) {
        int length = (int)(str->end - str->begin);
        char* _string = (char*)malloc(sizeof(char) * (length + 1));
        memcpy(_string, str->begin, length);
        _string[length] = '\0';
        return _string;
    }
};

void createSkeletonAnimationAsync(const std::string& jsonFile, const std::string& atlasFile, const std::function<void(SkeletonAnimation*)>& callBack)
{
    SkeletonLoadParam* loadParam = new SkeletonLoadParam();
    loadParam->jsonFile = jsonFile;
    loadParam->atlasFile = atlasFile;
    
    AsyncTaskPool::getInstance()->enqueue(AsyncTaskPool::TaskType::TASK_IO,
        [callBack](void* param) {//cocos thread
            SkeletonLoadParam* loadParam = (SkeletonLoadParam*)param;
        
            for(auto imageData : loadParam->skeletonCachedData.imagesData){
                auto img = new Image();
                img->initWithImageData(imageData.data->getBytes(), imageData.data->getSize());
                Director::getInstance()->getTextureCache()->addImage(img, imageData.file);
            }
        
            std::string dir = SkeletonCache::getAtlasDir(loadParam->atlasFile);
            int length = (int)loadParam->skeletonCachedData.atlas->size();
            
            auto atlas = spAtlas_create(loadParam->skeletonCachedData.atlas->c_str(), length, dir.c_str(), NULL);
            CCLOG("texture id: %u",((Texture2D*)atlas->pages->rendererObject)->getName());
            auto attachmentLoader = Cocos2dAttachmentLoader_create(atlas);
            auto json = spSkeletonJson_createWithLoader(&attachmentLoader->super);
            auto skeletonData = spSkeletonJson_readSkeletonDataFile(json, loadParam->jsonFile.c_str());
            SkeletonAnimation* animation = SkeletonAnimation::createWithData(skeletonData);
            callBack(animation);
        
            spSkeletonJson_dispose(json);
            delete loadParam;
        },
        (void*)loadParam,
        [loadParam, atlasFile, jsonFile]() {
            auto skeletonCache = SkeletonCache::getInstance()->addSkeletonCachedData(jsonFile, atlasFile);
            loadParam->skeletonCachedData = skeletonCache;
        }
    );
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Scene::init() )
    {
        return false;
    }
    //test code
    createSkeletonAnimationAsync("welcome_back.json", "welcome_back.atlas", [this](SkeletonAnimation* am){
        auto winSize = Director::getInstance()->getWinSize();
        am->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
        addChild(am);
        am->setPosition(winSize / 2);
        am->setAnimation(0, "2", true);
        am->setDebugBonesEnabled(true);
    });
    return true;
}


void HelloWorld::menuCloseCallback(Ref* pSender)
{
    //Close the cocos2d-x game scene and quit the application
    Director::getInstance()->end();

    /*To navigate back to native iOS screen(if present) without quitting the application  ,do not use Director::getInstance()->end() as given above,instead trigger a custom event created in RootViewController.mm as below*/

    //EventCustom customEndEvent("game_scene_close_event");
    //_eventDispatcher->dispatchEvent(&customEndEvent);


}

标签:std,begin,code,end,Skeleton,atlasFile,task,str,string
From: https://www.cnblogs.com/pixs-union/p/17787112.html

相关文章

  • vscode右键没有open with live server
    写原生界面时右击html查看效果看结果没有liveserver如:安装插件"liveserver"......
  • 进程,线程,线程生命周期,原生线程,线程调度,Thread,ThreadPool,Task,Parallel,线程安全容器
    1.进程;程序在服务器上运行时,占用的计算机资源合集,就是进程2.线程:是程序能够独立运行的最小单位,共享进程的资源;3.线程的生命周期:3.1新建,启动,可运行,正在运行,new,start,runnable,running,dead,blocked阻塞4.原生线程:由操作系统负责创建、运行、切换、终止的线程就是原生线程5.线程......
  • Window 上 VS Code 无法编译Rust 文件的错误
    Window上VSCode无法编译Rust文件的错误error:linker`link.exe`notfound在CMD中运行以下命令1.rustuptoolchaininstallstable-x86_64-pc-windows-gnu2.rustupdefaultstable-x86_64-pc-windows-gnu参考:https://blog.csdn.net/Libigtong/article/details/131823204......
  • [Leetcode] 0101. 对称二叉树
    101.对称二叉树题目描述给你一个二叉树的根节点root,检查它是否轴对称。 示例1:输入:root=[1,2,2,3,4,4,3]输出:true示例2:输入:root=[1,2,2,null,3,null,3]输出:false 提示:树中节点数目在范围[1,1000]内-100<=Node.val<=100 进阶:你可以运用递......
  • 史上最全vscode配置使用教程
    欲善其事,必先利其器。想要优雅且高效的编写代码,必须熟练使用一款前端开发工具。但前端开发工具数不胜数,像HBuilder、SublimeText、WebStorm、VisualStudioCode......等等,其中VSCode以其轻量且强大的代码编辑功能和丰富的插件生态系统,独受前端工师的青睐。网上有很多vscode的配......
  • HashCode
    2023.10.241.开放定址法:基本思想是:当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi,将相应元素存入其中。比如ThreadLocal再哈希法:这种方法是同时构造多个不同的哈希函数:H......
  • LeetCode 283. 移动零
    移动零题目链接283.移动零给定一个数组nums,编写一个函数将所有0移动到数组的末尾,同时保持非零元素的相对顺序。请注意,必须在不复制数组的情况下原地对数组进行操作。示例1:输入:nums=[0,1,0,3,12]输出:[1,3,12,0,0]示例2:输入:nums=[0]输出:[0]题......
  • GraphPrompt: Unifying Pre-Training and Downstream Tasks for Graph Neural Network
    目录概符号说明GraphPrompt代码LiuZ.,YuX.,FangY.andZhangX.GraphPrompt:Unifyingpre-traininganddownstreamtasksforgraphneuralnetworks.WWW,2023.概统一的图预训练模型+Prompt微调.符号说明\(G=(V,E)\),图;\(\mathbf{X}\in\mathbb{R}^{|......
  • LeetCode 1089. 复写零
    复写零题目链接1089.复写零给你一个长度固定的整数数组arr,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。注意:请不要在超过该数组长度的位置写入元素。请对输入的数组就地进行上述修改,不要从函数返回任何东西。示例1:输入:arr=[1,0,2,3,0,4,5,0]输......
  • LeetCode 202. 快乐数
    快乐数题目链接202.快乐数编写一个算法来判断一个数n是不是快乐数。「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。然后重复这个过程直到这个数变为1,也可能是无限循环但始终变不到1。如果这个过程结果为1,那么这个数就是快乐......