PageRenderTime 79ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/TinySeal/TinySeal/libs/cocos2d/CCTextureCache.m

https://github.com/jdxyw/Tutorial
Objective C | 498 lines | 326 code | 118 blank | 54 comment | 45 complexity | fae8ad21e439d4479cb777891bfc6342 MD5 | raw file
  1. /*
  2. * cocos2d for iPhone: http://www.cocos2d-iphone.org
  3. *
  4. * Copyright (c) 2008-2010 Ricardo Quesada
  5. * Copyright (c) 2011 Zynga Inc.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. * THE SOFTWARE.
  24. *
  25. */
  26. #import <Availability.h>
  27. #import "Platforms/CCGL.h"
  28. #import "CCTextureCache.h"
  29. #import "CCTexture2D.h"
  30. #import "CCTexturePVR.h"
  31. #import "ccMacros.h"
  32. #import "CCConfiguration.h"
  33. #import "Support/CCFileUtils.h"
  34. #import "CCDirector.h"
  35. #import "ccConfig.h"
  36. // needed for CCCallFuncO in Mac-display_link version
  37. #import "CCActionManager.h"
  38. #import "CCActionInstant.h"
  39. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  40. static EAGLContext *auxGLcontext = nil;
  41. #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
  42. static NSOpenGLContext *auxGLcontext = nil;
  43. #endif
  44. @interface CCAsyncObject : NSObject
  45. {
  46. SEL selector_;
  47. id target_;
  48. id data_;
  49. }
  50. @property (nonatomic,readwrite,assign) SEL selector;
  51. @property (nonatomic,readwrite,retain) id target;
  52. @property (nonatomic,readwrite,retain) id data;
  53. @end
  54. @implementation CCAsyncObject
  55. @synthesize selector = selector_;
  56. @synthesize target = target_;
  57. @synthesize data = data_;
  58. - (void) dealloc
  59. {
  60. CCLOGINFO(@"cocos2d: deallocing %@", self);
  61. [target_ release];
  62. [data_ release];
  63. [super dealloc];
  64. }
  65. @end
  66. @implementation CCTextureCache
  67. #pragma mark TextureCache - Alloc, Init & Dealloc
  68. static CCTextureCache *sharedTextureCache;
  69. + (CCTextureCache *)sharedTextureCache
  70. {
  71. if (!sharedTextureCache)
  72. sharedTextureCache = [[CCTextureCache alloc] init];
  73. return sharedTextureCache;
  74. }
  75. +(id)alloc
  76. {
  77. NSAssert(sharedTextureCache == nil, @"Attempted to allocate a second instance of a singleton.");
  78. return [super alloc];
  79. }
  80. +(void)purgeSharedTextureCache
  81. {
  82. [sharedTextureCache release];
  83. sharedTextureCache = nil;
  84. }
  85. -(id) init
  86. {
  87. if( (self=[super init]) ) {
  88. textures_ = [[NSMutableDictionary dictionaryWithCapacity: 10] retain];
  89. dictLock_ = [[NSLock alloc] init];
  90. contextLock_ = [[NSLock alloc] init];
  91. }
  92. return self;
  93. }
  94. - (NSString*) description
  95. {
  96. return [NSString stringWithFormat:@"<%@ = %08X | num of textures = %i | keys: %@>",
  97. [self class],
  98. self,
  99. [textures_ count],
  100. [textures_ allKeys]
  101. ];
  102. }
  103. -(void) dealloc
  104. {
  105. CCLOGINFO(@"cocos2d: deallocing %@", self);
  106. [textures_ release];
  107. [dictLock_ release];
  108. [contextLock_ release];
  109. [auxGLcontext release];
  110. auxGLcontext = nil;
  111. sharedTextureCache = nil;
  112. [super dealloc];
  113. }
  114. #pragma mark TextureCache - Add Images
  115. -(void) addImageWithAsyncObject:(CCAsyncObject*)async
  116. {
  117. NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
  118. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  119. // textures will be created on the main OpenGL context
  120. // it seems that in SDK 2.2.x there can't be 2 threads creating textures at the same time
  121. // the lock is used for this purpose: issue #472
  122. [contextLock_ lock];
  123. if( auxGLcontext == nil ) {
  124. auxGLcontext = [[EAGLContext alloc]
  125. initWithAPI:kEAGLRenderingAPIOpenGLES1
  126. sharegroup:[[[[CCDirector sharedDirector] openGLView] context] sharegroup]];
  127. if( ! auxGLcontext )
  128. CCLOG(@"cocos2d: TextureCache: Could not create EAGL context");
  129. }
  130. if( [EAGLContext setCurrentContext:auxGLcontext] ) {
  131. // load / create the texture
  132. CCTexture2D *tex = [self addImage:async.data];
  133. // The callback will be executed on the main thread
  134. [async.target performSelectorOnMainThread:async.selector withObject:tex waitUntilDone:NO];
  135. [EAGLContext setCurrentContext:nil];
  136. } else {
  137. CCLOG(@"cocos2d: TetureCache: EAGLContext error");
  138. }
  139. [contextLock_ unlock];
  140. [autoreleasepool release];
  141. #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
  142. [contextLock_ lock];
  143. if( auxGLcontext == nil ) {
  144. MacGLView *view = [[CCDirector sharedDirector] openGLView];
  145. NSOpenGLPixelFormat *pf = [view pixelFormat];
  146. NSOpenGLContext *share = [view openGLContext];
  147. auxGLcontext = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:share];
  148. if( ! auxGLcontext )
  149. CCLOG(@"cocos2d: TextureCache: Could not create NSOpenGLContext");
  150. }
  151. [auxGLcontext makeCurrentContext];
  152. // load / create the texture
  153. CCTexture2D *tex = [self addImage:async.data];
  154. #if CC_DIRECTOR_MAC_USE_DISPLAY_LINK_THREAD
  155. id action = [CCCallFuncO actionWithTarget:async.target selector:async.selector object:tex];
  156. [[CCActionManager sharedManager] addAction:action target:async.target paused:NO];
  157. #else
  158. // The callback will be executed on the main thread
  159. [async.target performSelector:async.selector
  160. onThread:[[CCDirector sharedDirector] runningThread]
  161. withObject:tex
  162. waitUntilDone:NO];
  163. #endif
  164. [NSOpenGLContext clearCurrentContext];
  165. [contextLock_ unlock];
  166. [autoreleasepool release];
  167. #endif // __MAC_OS_X_VERSION_MAX_ALLOWED
  168. }
  169. -(void) addImageAsync: (NSString*)path target:(id)target selector:(SEL)selector
  170. {
  171. NSAssert(path != nil, @"TextureCache: fileimage MUST not be nill");
  172. // optimization
  173. CCTexture2D * tex;
  174. path = ccRemoveHDSuffixFromFile(path);
  175. if( (tex=[textures_ objectForKey: path] ) ) {
  176. [target performSelector:selector withObject:tex];
  177. return;
  178. }
  179. // schedule the load
  180. CCAsyncObject *asyncObject = [[CCAsyncObject alloc] init];
  181. asyncObject.selector = selector;
  182. asyncObject.target = target;
  183. asyncObject.data = path;
  184. [NSThread detachNewThreadSelector:@selector(addImageWithAsyncObject:) toTarget:self withObject:asyncObject];
  185. [asyncObject release];
  186. }
  187. -(CCTexture2D*) addImage: (NSString*) path
  188. {
  189. NSAssert(path != nil, @"TextureCache: fileimage MUST not be nill");
  190. CCTexture2D * tex = nil;
  191. // MUTEX:
  192. // Needed since addImageAsync calls this method from a different thread
  193. [dictLock_ lock];
  194. // remove possible -HD suffix to prevent caching the same image twice (issue #1040)
  195. path = ccRemoveHDSuffixFromFile( path );
  196. tex=[textures_ objectForKey: path];
  197. if( ! tex ) {
  198. NSString *lowerCase = [path lowercaseString];
  199. // all images are handled by UIImage except PVR extension that is handled by our own handler
  200. if ( [lowerCase hasSuffix:@".pvr"] || [lowerCase hasSuffix:@".pvr.gz"] || [lowerCase hasSuffix:@".pvr.ccz"] )
  201. tex = [self addPVRImage:path];
  202. // Only iPhone
  203. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  204. // Issue #886: TEMPORARY FIX FOR TRANSPARENT JPEGS IN IOS4
  205. else if ( ( [[CCConfiguration sharedConfiguration] OSVersion] >= kCCiOSVersion_4_0) &&
  206. ( [lowerCase hasSuffix:@".jpg"] || [lowerCase hasSuffix:@".jpeg"] )
  207. ) {
  208. // convert jpg to png before loading the texture
  209. NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ];
  210. UIImage *jpg = [[UIImage alloc] initWithContentsOfFile:fullpath];
  211. UIImage *png = [[UIImage alloc] initWithData:UIImagePNGRepresentation(jpg)];
  212. tex = [ [CCTexture2D alloc] initWithImage: png ];
  213. [png release];
  214. [jpg release];
  215. if( tex )
  216. [textures_ setObject: tex forKey:path];
  217. else
  218. CCLOG(@"cocos2d: Couldn't add image:%@ in CCTextureCache", path);
  219. // autorelease prevents possible crash in multithreaded environments
  220. [tex autorelease];
  221. }
  222. else {
  223. // prevents overloading the autorelease pool
  224. NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ];
  225. UIImage *image = [ [UIImage alloc] initWithContentsOfFile: fullpath ];
  226. tex = [ [CCTexture2D alloc] initWithImage: image ];
  227. [image release];
  228. if( tex )
  229. [textures_ setObject: tex forKey:path];
  230. else
  231. CCLOG(@"cocos2d: Couldn't add image:%@ in CCTextureCache", path);
  232. // autorelease prevents possible crash in multithreaded environments
  233. [tex autorelease];
  234. }
  235. // Only in Mac
  236. #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
  237. else {
  238. NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ];
  239. NSData *data = [[NSData alloc] initWithContentsOfFile:fullpath];
  240. NSBitmapImageRep *image = [[NSBitmapImageRep alloc] initWithData:data];
  241. tex = [ [CCTexture2D alloc] initWithImage:[image CGImage]];
  242. [data release];
  243. [image release];
  244. if( tex )
  245. [textures_ setObject: tex forKey:path];
  246. else
  247. CCLOG(@"cocos2d: Couldn't add image:%@ in CCTextureCache", path);
  248. // autorelease prevents possible crash in multithreaded environments
  249. [tex autorelease];
  250. }
  251. #endif // __MAC_OS_X_VERSION_MAX_ALLOWED
  252. }
  253. [dictLock_ unlock];
  254. return tex;
  255. }
  256. -(CCTexture2D*) addCGImage: (CGImageRef) imageref forKey: (NSString *)key
  257. {
  258. NSAssert(imageref != nil, @"TextureCache: image MUST not be nill");
  259. CCTexture2D * tex = nil;
  260. // If key is nil, then create a new texture each time
  261. if( key && (tex=[textures_ objectForKey: key] ) ) {
  262. return tex;
  263. }
  264. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  265. // prevents overloading the autorelease pool
  266. UIImage *image = [[UIImage alloc] initWithCGImage:imageref];
  267. tex = [[CCTexture2D alloc] initWithImage: image];
  268. [image release];
  269. #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
  270. tex = [[CCTexture2D alloc] initWithImage: imageref];
  271. #endif
  272. if(tex && key)
  273. [textures_ setObject: tex forKey:key];
  274. else
  275. CCLOG(@"cocos2d: Couldn't add CGImage in CCTextureCache");
  276. return [tex autorelease];
  277. }
  278. #pragma mark TextureCache - Remove
  279. -(void) removeAllTextures
  280. {
  281. [textures_ removeAllObjects];
  282. }
  283. -(void) removeUnusedTextures
  284. {
  285. NSArray *keys = [textures_ allKeys];
  286. for( id key in keys ) {
  287. id value = [textures_ objectForKey:key];
  288. if( [value retainCount] == 1 ) {
  289. CCLOG(@"cocos2d: CCTextureCache: removing unused texture: %@", key);
  290. [textures_ removeObjectForKey:key];
  291. }
  292. }
  293. }
  294. -(void) removeTexture: (CCTexture2D*) tex
  295. {
  296. if( ! tex )
  297. return;
  298. NSArray *keys = [textures_ allKeysForObject:tex];
  299. for( NSUInteger i = 0; i < [keys count]; i++ )
  300. [textures_ removeObjectForKey:[keys objectAtIndex:i]];
  301. }
  302. -(void) removeTextureForKey:(NSString*)name
  303. {
  304. if( ! name )
  305. return;
  306. [textures_ removeObjectForKey:name];
  307. }
  308. #pragma mark TextureCache - Get
  309. - (CCTexture2D *)textureForKey:(NSString *)key
  310. {
  311. return [textures_ objectForKey:key];
  312. }
  313. @end
  314. @implementation CCTextureCache (PVRSupport)
  315. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  316. -(CCTexture2D*) addPVRTCImage:(NSString*)path bpp:(int)bpp hasAlpha:(BOOL)alpha width:(int)w
  317. {
  318. NSAssert(path != nil, @"TextureCache: fileimage MUST not be nill");
  319. NSAssert( bpp==2 || bpp==4, @"TextureCache: bpp must be either 2 or 4");
  320. CCTexture2D * tex;
  321. // remove possible -HD suffix to prevent caching the same image twice (issue #1040)
  322. path = ccRemoveHDSuffixFromFile( path );
  323. if( (tex=[textures_ objectForKey: path] ) ) {
  324. return tex;
  325. }
  326. // Split up directory and filename
  327. NSString *fullpath = [CCFileUtils fullPathFromRelativePath:path];
  328. NSData *nsdata = [[NSData alloc] initWithContentsOfFile:fullpath];
  329. tex = [[CCTexture2D alloc] initWithPVRTCData:[nsdata bytes] level:0 bpp:bpp hasAlpha:alpha length:w pixelFormat:bpp==2?kCCTexture2DPixelFormat_PVRTC2:kCCTexture2DPixelFormat_PVRTC4];
  330. if( tex )
  331. [textures_ setObject: tex forKey:path];
  332. else
  333. CCLOG(@"cocos2d: Couldn't add PVRTCImage:%@ in CCTextureCache",path);
  334. [nsdata release];
  335. return [tex autorelease];
  336. }
  337. #endif // __IPHONE_OS_VERSION_MAX_ALLOWED
  338. -(CCTexture2D*) addPVRImage:(NSString*)path
  339. {
  340. NSAssert(path != nil, @"TextureCache: fileimage MUST not be nill");
  341. CCTexture2D * tex;
  342. // remove possible -HD suffix to prevent caching the same image twice (issue #1040)
  343. path = ccRemoveHDSuffixFromFile( path );
  344. if( (tex=[textures_ objectForKey: path] ) ) {
  345. return tex;
  346. }
  347. // Split up directory and filename
  348. NSString *fullpath = [CCFileUtils fullPathFromRelativePath:path];
  349. tex = [[CCTexture2D alloc] initWithPVRFile: fullpath];
  350. if( tex )
  351. [textures_ setObject: tex forKey:path];
  352. else
  353. CCLOG(@"cocos2d: Couldn't add PVRImage:%@ in CCTextureCache",path);
  354. return [tex autorelease];
  355. }
  356. @end
  357. @implementation CCTextureCache (Debug)
  358. -(void) dumpCachedTextureInfo
  359. {
  360. NSUInteger count = 0;
  361. NSUInteger totalBytes = 0;
  362. for (NSString* texKey in textures_) {
  363. CCTexture2D* tex = [textures_ objectForKey:texKey];
  364. NSUInteger bpp = [tex bitsPerPixelForFormat];
  365. // Each texture takes up width * height * bytesPerPixel bytes.
  366. NSUInteger bytes = tex.pixelsWide * tex.pixelsHigh * bpp / 8;
  367. totalBytes += bytes;
  368. count++;
  369. CCLOG( @"cocos2d: \"%@\" rc=%lu id=%lu %lu x %lu @ %ld bpp => %lu KB",
  370. texKey,
  371. (long)[tex retainCount],
  372. (long)tex.name,
  373. (long)tex.pixelsWide,
  374. (long)tex.pixelsHigh,
  375. (long)bpp,
  376. (long)bytes / 1024 );
  377. }
  378. CCLOG( @"cocos2d: CCTextureCache dumpDebugInfo: %ld textures, for %lu KB (%.2f MB)", (long)count, (long)totalBytes / 1024, totalBytes / (1024.0f*1024.0f));
  379. }
  380. @end