#include "RUResLoader.h" #include "AudioEngine.h" #include "RUPlatform.h" NS_RU_BEGIN //日志输出宏定义 #define RESLOG_DEBUG #if !defined(COCOS2D_DEBUG) || COCOS2D_DEBUG == 0 #define RESLOG(...) do {} while (0) #else #ifdef RESLOG_DEBUG #define RESLOG(format, ...) cocos2d::log("[资源loader日志] " format, ##__VA_ARGS__) #else #define RESLOG(...) do {} while (0) #endif #endif #define TEXTURE_LOAD_WEIGHT 100 #define SHADER_COMPILE_WEIGHT 10 #define AUDIO_PRELOAD_WEIGHT 5 #define FUNC_LOAD_WEIGHT 50 std::unordered_map ResLoader::_gResLoaders; ResLoader* ResLoader::instance(std::string key4Loader) { auto loaderGot = _gResLoaders.find(key4Loader); if (loaderGot == _gResLoaders.end()) { auto loader = new ResLoader(); loader->autorelease(); loader->retain(); loader->_loaderName = key4Loader; _gResLoaders.insert(pair(key4Loader, loader)); return loader; } return loaderGot->second; } ResLoader::ResLoader() { } ResLoader::~ResLoader() { } void ResLoader::addImgs2Load(const vector& imgs) { for (string img : imgs) { _vecImgs.push_back(img); } _progresssTotal += imgs.size() * TEXTURE_LOAD_WEIGHT; } void ResLoader::addPlists2Load(const vector& plists) { for (string plist : plists) { _vecPlists.push_back(plist); } _progresssTotal += plists.size() * TEXTURE_LOAD_WEIGHT; } void ResLoader::addAudios2Load(const vector& audios) { for (string audio : audios) { _vecSounds.push_back(audio); } _progresssTotal += audios.size() * AUDIO_PRELOAD_WEIGHT; } void ResLoader::addShaders2Compile(const vector>& shaders) { for (const vector& shader : shaders) { vector shaderFilePaths; shaderFilePaths.emplace_back(cocos2d::FileUtils::getInstance()->fullPathForFilename(shader.at(0))); shaderFilePaths.emplace_back(cocos2d::FileUtils::getInstance()->fullPathForFilename(shader.at(1))); shaderFilePaths.emplace_back(shader.at(2)); _cfgShaders.push_back(shaderFilePaths); } _progresssTotal += shaders.size() * SHADER_COMPILE_WEIGHT; } void ResLoader::addFuncs2Load(const std::vector>& funcs) { for (std::function func : funcs) { _vecFuncs.push_back(func); } _progresssTotal += funcs.size() * FUNC_LOAD_WEIGHT; } void ResLoader::startLoad() { auto cacheShader = [](const string& vsh, const string& fsh, const string& name) { GLProgram* prog = nullptr; prog = GLProgramCache::getInstance()->getGLProgram(name); if (prog) { return; } auto fragmentFullPath = cocos2d::FileUtils::getInstance()->fullPathForFilename(fsh); auto fragSource = cocos2d::FileUtils::getInstance()->getStringFromFile(fragmentFullPath); if (vsh.size() == 0) { prog = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, fragSource.c_str()); } else { auto vertexFullPath = cocos2d::FileUtils::getInstance()->fullPathForFilename(vsh); auto vertexSource = cocos2d::FileUtils::getInstance()->getStringFromFile(vertexFullPath); prog = GLProgram::createWithByteArrays(vertexSource.c_str(), fragSource.c_str()); } GLProgramCache::getInstance()->addGLProgram(prog, name); }; for(auto img : _vecImgs){ Director::getInstance()->getTextureCache()->addImage(img); } for(auto plist : _vecPlists){ std::string fn = plist; int npos = fn.find("."); std::string fnNew = fn.substr(0, npos); SpriteFrameCache::getInstance()->addSpriteFramesWithFile(fnNew + ".plist"); } for(auto sound : _vecSounds){ experimental::AudioEngine::preload(sound); } for(auto shader : _cfgShaders){ cacheShader(shader[0], shader[1], shader[2]); } for(auto func : _vecFuncs){ func(); } _state = kLoaderState::LOADED; } void ResLoader::startLoadAsync(std::function cbUpdateProgress, std::function cbWhileFinished) { RESLOG("ResLoader::startLoadAsync : _state %d", (int)_state); if (_state != kLoaderState::WAIT) { return; } _progressNow = 0; _cbWhileFinihsed = cbWhileFinished; _cbUpdateProgress = cbUpdateProgress; for(auto img : _vecImgs){ Director::getInstance()->getTextureCache()->addImageAsync(img, CC_CALLBACK_1(ResLoader::_imgTextureAsyncCallback, this)); } for(auto plist : _vecPlists){ Director::getInstance()->getTextureCache()->addImageAsync(plist, CC_CALLBACK_1(ResLoader::_plistImageAsyncCallback, this)); } if(_vecImgs.size() == 0 && _vecPlists.size() == 0){ _loadNextResourceAsyns(); } } bool ResLoader::isFinished() { RESLOG("loaderName :%s isFinished %d %d", _loaderName.c_str(), _progressNow, _progresssTotal); return _state == kLoaderState::LOADED; } void ResLoader::_imgTextureAsyncCallback(cocos2d::Texture2D* texture) { CCASSERT(texture,"加载失败"); _idx4Img++; _progressNow += TEXTURE_LOAD_WEIGHT; if (_cbUpdateProgress) { _cbUpdateProgress(_progressNow * 100.0 / _progresssTotal); } RESLOG("%s load img %d/%lu", _loaderName.c_str(), _idx4Img, _vecImgs.size()); if (_idx4Img == _vecImgs.size() && _idx4Plist == _vecPlists.size()) { _loadNextResourceAsyns(); } } void ResLoader::_plistImageAsyncCallback(cocos2d::Texture2D* texture) { CCASSERT(texture,"加载失败"); _idx4Plist++; _progressNow += TEXTURE_LOAD_WEIGHT; if (_cbUpdateProgress) { _cbUpdateProgress(_progressNow * 100.0 / _progresssTotal); } RESLOG("%s load plist %d/%lu", _loaderName.c_str(), _idx4Plist, _vecPlists.size()); if (_idx4Plist == _vecPlists.size()) { for(auto plist : _vecPlists){ std::string fn = plist; int npos = fn.find("."); std::string fnNew = fn.substr(0, npos); SpriteFrameCache::getInstance()->addSpriteFramesWithFile(fnNew + ".plist"); } } if (_idx4Img == _vecImgs.size() && _idx4Plist == _vecPlists.size()) { _loadNextResourceAsyns(); } } void ResLoader::_loadNextResourceAsyns() { RESLOG("ResLoader::_loadNextResourceAsyns : _state %d", (int)_state); if (_state == kLoaderState::PAUSE) { return; } if (_idx4Sound < _vecSounds.size()) { RESLOG("%s load audio %d/%lu", _loaderName.c_str(), _idx4Sound, _vecSounds.size()); experimental::AudioEngine::preload(_vecSounds.at(_idx4Sound), [=](bool) { _idx4Sound ++; _progressNow += AUDIO_PRELOAD_WEIGHT; if (_cbUpdateProgress) { _cbUpdateProgress(_progressNow * 100.0 / _progresssTotal); } _loadNextResourceAsyns(); }); } else if (_idx4Shader < _cfgShaders.size()) { RESLOG("%s load shader %d/%lu", _loaderName.c_str(), _idx4Shader, _cfgShaders.size()); AsyncTaskPool::getInstance()->enqueue(AsyncTaskPool::TaskType::TASK_IO, [=](void *) { GLProgram* prog = nullptr; prog = GLProgramCache::getInstance()->getGLProgram(_cfgShaders[_idx4Shader][2]); if (prog == nullptr) { if (_strVert.size() == 0) { prog = GLProgram::createWithByteArrays(ccPositionTextureColor_noMVP_vert, _strFrag.c_str()); } else { prog = GLProgram::createWithByteArrays(_strVert.c_str(), _strFrag.c_str()); } GLProgramCache::getInstance()->addGLProgram(prog, _cfgShaders[_idx4Shader][2]); } _idx4Shader ++; _progressNow += SHADER_COMPILE_WEIGHT; if (_cbUpdateProgress) { _cbUpdateProgress(_progressNow * 100.0 / _progresssTotal); } _loadNextResourceAsyns(); }, nullptr, [=](){ _strFrag = cocos2d::FileUtils::getInstance()->getStringFromFile(_cfgShaders[_idx4Shader][1]); if (_cfgShaders[_idx4Shader][0].size() != 0) { _strVert = cocos2d::FileUtils::getInstance()->getStringFromFile(_cfgShaders[_idx4Shader][0]); } else { _strVert = ""; } }); } else if (_idx4Func < _vecFuncs.size()) { RESLOG("%s load func %d/%lu", _loaderName.c_str(), _idx4Func, _vecFuncs.size()); std::function func = _vecFuncs.at(_idx4Func); func(); _idx4Func++; auto scheduler = Director::getInstance()->getScheduler(); scheduler->schedule([=](float dt){ _loadNextResourceAsyns(); }, this, 0, 0, 1.0/60, false, _loaderName); //add by yuntao _progressNow += FUNC_LOAD_WEIGHT; if (_cbUpdateProgress) { _cbUpdateProgress(_progressNow * 100.0 / _progresssTotal); } } else { _state = kLoaderState::LOADED; RESLOG("%s load finished", _loaderName.c_str()); if (_cbWhileFinihsed) { _cbWhileFinihsed(); } // Director::getInstance()->getScheduler()->schedule([=](float dt) { // _instance->release(); // _instance = nullptr; // }, this, 0.1, 0, 0.1, false, "SCH_RM_SELF"); } } void ResLoader::pauseLoading() { if (_state == kLoaderState::LOADING) { _state = kLoaderState::PAUSE; } } void ResLoader::resumeLoading() { if (_state == kLoaderState::PAUSE) { _state = kLoaderState::LOADING; _loadNextResourceAsyns(); } } NS_RU_END