CCTextureCache是用来缓存和管理cctexture2d的单例工具类,提供的功能和CCSpriteFrameCache差不多,不过功能要复杂,因为提供了异步的载入图像和回调功能。
这里就简单的备注下代码框架:
//异步载入时相关结构体 typedef struct _AsyncStruct { std::string filename; //image文件名 CCObject *target; //回调指针 SEL_CallFuncO selector; //回调函数 } AsyncStruct; //图片信息结构体 typedef struct _ImageInfo { AsyncStruct *asyncStruct; CCImage *image; CCImage::EImageFormat imageType; } ImageInfo; //作者粗略的研究了下代码,这里的异步回调的大概原理是: //将要加载的图像封装成一个个结构体,放在队列A中,新建一个线程不停地读取队列,载入图像,让后将图像信息放到另一个队列B中。 //通过定时器函数,不停的读取队列B,进行回调处理。由于涉及到跨线程的队列操作,因此需要一大堆锁。就是下面的这些变量 static pthread_t s_loadingThread; static pthread_mutex_t s_SleepMutex; static pthread_cond_t s_SleepCondition; static pthread_mutex_t s_asyncStructQueueMutex; static pthread_mutex_t s_ImageInfoMutex; #ifdef EMSCRIPTEN // Hack to get ASM.JS validation (no undefined symbols allowed). #define pthread_cond_signal(_) #endif // EMSCRIPTEN static unsigned long s_nAsyncRefCount = 0; static bool need_quit = false; static std::queue<AsyncStruct*>* s_pAsyncStructQueue = NULL; //队列A static std::queue<ImageInfo*>* s_pImageQueue = NULL; //队列B static CCImage::EImageFormat computeImageFormatType(string& filename) { //查询文件类型 } //异步载入图像线程时读取图像函数 static void loadImageData(AsyncStruct *pAsyncStruct) { 。。。。。 //新建一个CCImage,载入图像,(估计此处耗时较久,顾用多线程来处理) CCImage *pImage = new CCImage(); if (pImage && !pImage->initWithImageFileThreadSafe(filename, imageType)) { CC_SAFE_RELEASE(pImage); CCLOG("can not load %s", filename); return; } //将image封成一个结构体,然后放入队列B // generate image info ImageInfo *pImageInfo = new ImageInfo(); pImageInfo->asyncStruct = pAsyncStruct; pImageInfo->image = pImage; pImageInfo->imageType = imageType; // put the image info into the queue pthread_mutex_lock(&s_ImageInfoMutex); s_pImageQueue->push(pImageInfo); pthread_mutex_unlock(&s_ImageInfoMutex); } //线程函数,不停的读取队列A,调用loadImageData static void* loadImage(void* data) { AsyncStruct *pAsyncStruct = NULL; while (true) { // create autorelease pool for iOS CCThread thread; thread.createAutoreleasePool(); std::queue<AsyncStruct*> *pQueue = s_pAsyncStructQueue; pthread_mutex_lock(&s_asyncStructQueueMutex);// get async struct from queue if (pQueue->empty()) { pthread_mutex_unlock(&s_asyncStructQueueMutex); if (need_quit) { break; } else { pthread_cond_wait(&s_SleepCondition, &s_SleepMutex); continue; } } else { pAsyncStruct = pQueue->front(); pQueue->pop(); pthread_mutex_unlock(&s_asyncStructQueueMutex); loadImageData(pAsyncStruct); } } if( s_pAsyncStructQueue != NULL ) { delete s_pAsyncStructQueue; s_pAsyncStructQueue = NULL; delete s_pImageQueue; s_pImageQueue = NULL; pthread_mutex_destroy(&s_asyncStructQueueMutex); pthread_mutex_destroy(&s_ImageInfoMutex); pthread_mutex_destroy(&s_SleepMutex); pthread_cond_destroy(&s_SleepCondition); } return 0; } //单例相关代码: 。。。。。 。。。。。 const char* CCTextureCache::description() {。。。。。} CCDictionary* CCTextureCache::snapshotTextures() { //生成快照 } //异步载入图像 void CCTextureCache::addImageAsync(const char *path, CCObject *target, SEL_CallFuncO selector) { 。。。。。 //已经存在,直接回调,个人感觉怪怪的 if (texture != NULL) { if (target && selector) { (target->*selector)(texture); } return; } //将线程起起来 if (s_pAsyncStructQueue == NULL) { s_pAsyncStructQueue = new queue<AsyncStruct*>(); s_pImageQueue = new queue<ImageInfo*>(); pthread_mutex_init(&s_asyncStructQueueMutex, NULL); pthread_mutex_init(&s_ImageInfoMutex, NULL); pthread_mutex_init(&s_SleepMutex, NULL); pthread_cond_init(&s_SleepCondition, NULL); #if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) pthread_create(&s_loadingThread, NULL, loadImage, NULL); #endif need_quit = false; } //启动定时器 if (0 == s_nAsyncRefCount) { CCDirector::sharedDirector()->getScheduler()->scheduleSelector(schedule_selector(CCTextureCache::addImageAsyncCallBack), this, 0, false); } ++s_nAsyncRefCount; if (target) { target->retain(); } //将信息生成结构体,放入队列A AsyncStruct *data = new AsyncStruct(); data->filename = fullpath.c_str(); data->target = target; data->selector = selector; #if (CC_TARGET_PLATFORM != CC_PLATFORM_WINRT) && (CC_TARGET_PLATFORM != CC_PLATFORM_WP8) // add async struct into queue pthread_mutex_lock(&s_asyncStructQueueMutex); s_pAsyncStructQueue->push(data); pthread_mutex_unlock(&s_asyncStructQueueMutex); pthread_cond_signal(&s_SleepCondition); #else // WinRT uses an Async Task to load the image since the ThreadPool has a limited number of threads //std::replace( data->filename.begin(), data->filename.end(), '/', '\\'); create_task([this, data] { loadImageData(data); }); #endif } //定时器函数,不停的读取队列B,进行回调操作 void CCTextureCache::addImageAsyncCallBack(float dt) { // the image is generated in loading thread std::queue<ImageInfo*> *imagesQueue = s_pImageQueue; pthread_mutex_lock(&s_ImageInfoMutex); if (imagesQueue->empty()) { pthread_mutex_unlock(&s_ImageInfoMutex); } else { ImageInfo *pImageInfo = imagesQueue->front(); imagesQueue->pop(); pthread_mutex_unlock(&s_ImageInfoMutex); AsyncStruct *pAsyncStruct = pImageInfo->asyncStruct; CCImage *pImage = pImageInfo->image; CCObject *target = pAsyncStruct->target; SEL_CallFuncO selector = pAsyncStruct->selector; const char* filename = pAsyncStruct->filename.c_str(); // generate texture in render thread CCTexture2D *texture = new CCTexture2D(); #if 0 //TODO: (CC_TARGET_PLATFORM == CC_PLATFORM_IOS) texture->initWithImage(pImage, kCCResolutioniPhone); #else texture->initWithImage(pImage); #endif #if CC_ENABLE_CACHE_TEXTURE_DATA // cache the texture file name VolatileTexture::addImageTexture(texture, filename, pImageInfo->imageType); #endif // cache the texture m_pTextures->setObject(texture, filename); texture->autorelease(); if (target && selector) { (target->*selector)(texture); target->release(); } pImage->release(); delete pAsyncStruct; delete pImageInfo; --s_nAsyncRefCount; if (0 == s_nAsyncRefCount) { CCDirector::sharedDirector()->getScheduler()->unscheduleSelector(schedule_selector(CCTextureCache::addImageAsyncCallBack), this); } } } //阻塞方式加载image,和异步加载的函数流程差不多。 CCTexture2D * CCTextureCache::addImage(const char * path) { CCAssert(path != NULL, "TextureCache: fileimage MUST not be NULL"); CCTexture2D * texture = NULL; CCImage* pImage = NULL; // Split up directory and filename // MUTEX: // Needed since addImageAsync calls this method from a different thread //pthread_mutex_lock(m_pDictLock); std::string pathKey = path; pathKey = CCFileUtils::sharedFileUtils()->fullPathForFilename(pathKey.c_str()); if (pathKey.size() == 0) { return NULL; } texture = (CCTexture2D*)m_pTextures->objectForKey(pathKey.c_str()); std::string fullpath = pathKey; // (CCFileUtils::sharedFileUtils()->fullPathFromRelativePath(path)); if (! texture) { std::string lowerCase(pathKey); for (unsigned int i = 0; i < lowerCase.length(); ++i) { lowerCase[i] = tolower(lowerCase[i]); } // all images are handled by UIImage except PVR extension that is handled by our own handler do { //获取文件类型 。。。。。 pImage = new CCImage(); CC_BREAK_IF(NULL == pImage); bool bRet = pImage->initWithImageFile(fullpath.c_str(), eImageFormat); CC_BREAK_IF(!bRet); texture = new CCTexture2D(); if( texture && texture->initWithImage(pImage) ) { #if CC_ENABLE_CACHE_TEXTURE_DATA // cache the texture file name VolatileTexture::addImageTexture(texture, fullpath.c_str(), eImageFormat); #endif m_pTextures->setObject(texture, pathKey.c_str()); texture->release(); } else { CCLOG("cocos2d: Couldn't create texture for file:%s in CCTextureCache", path); } } } while (0); } CC_SAFE_RELEASE(pImage); //pthread_mutex_unlock(m_pDictLock); return texture; } //特殊图片构造 CCTexture2D * CCTextureCache::addPVRImage(const char* path) { } //特殊图片构造 CCTexture2D* CCTextureCache::addETCImage(const char* path) { } //其他方法,省略 。。。。。 。。。。。
发表评论