PageRenderTime 55ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/libs/cocos2d/CCTextureCache.m

https://bitbucket.org/stavrossk/ipong
Objective C | 462 lines | 286 code | 110 blank | 66 comment | 44 complexity | 36c9adca00561017c5e70ac84a98df35 MD5 | raw file
  1. /*
  2. * cocos2d for iPhone: http://www.cocos2d-iphone.org
  3. *
  4. * Copyright (c) 2008-2010 Ricardo Quesada
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining a copy
  7. * of this software and associated documentation files (the "Software"), to deal
  8. * in the Software without restriction, including without limitation the rights
  9. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. * copies of the Software, and to permit persons to whom the Software is
  11. * furnished to do so, subject to the following conditions:
  12. *
  13. * The above copyright notice and this permission notice shall be included in
  14. * all copies or substantial portions of the Software.
  15. *
  16. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22. * THE SOFTWARE.
  23. *
  24. */
  25. #import <Availability.h>
  26. #import "Platforms/CCGL.h"
  27. #import "CCTextureCache.h"
  28. #import "CCTexture2D.h"
  29. #import "CCTexturePVR.h"
  30. #import "ccMacros.h"
  31. #import "CCConfiguration.h"
  32. #import "Support/CCFileUtils.h"
  33. #import "CCDirector.h"
  34. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  35. static EAGLContext *auxGLcontext = nil;
  36. #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
  37. static NSOpenGLContext *auxGLcontext = nil;
  38. #endif
  39. //static NSString* loadHiResImage( NSString* path )
  40. //{
  41. // NSString *newPath = nil;
  42. //
  43. // if([[UIScreen mainScreen] scale] == 2.0)
  44. // {
  45. // NSString *path2x = [path stringByReplacingCharactersInRange:NSMakeRange([path length] - 4, 0) withString:@"@2x"];
  46. // newPath = [[UIImage alloc] initWithContentsOfFile:path2x];
  47. //
  48. // if(!newPath)
  49. // {
  50. // newPath = [[UIImage alloc] initWithContentsOfFile:path];
  51. // }
  52. // }
  53. // else
  54. // {
  55. // newPath = [[UIImage alloc] initWithContentsOfFile:path];
  56. // }
  57. //
  58. // return newPath;
  59. //}
  60. @interface CCAsyncObject : NSObject
  61. {
  62. SEL selector_;
  63. id target_;
  64. id data_;
  65. }
  66. @property (readwrite,assign) SEL selector;
  67. @property (readwrite,retain) id target;
  68. @property (readwrite,retain) id data;
  69. @end
  70. @implementation CCAsyncObject
  71. @synthesize selector = selector_;
  72. @synthesize target = target_;
  73. @synthesize data = data_;
  74. - (void) dealloc
  75. {
  76. CCLOGINFO(@"cocos2d: deallocing %@", self);
  77. [target_ release];
  78. [data_ release];
  79. [super dealloc];
  80. }
  81. @end
  82. @implementation CCTextureCache
  83. #pragma mark TextureCache - Alloc, Init & Dealloc
  84. static CCTextureCache *sharedTextureCache;
  85. + (CCTextureCache *)sharedTextureCache
  86. {
  87. if (!sharedTextureCache)
  88. sharedTextureCache = [[CCTextureCache alloc] init];
  89. return sharedTextureCache;
  90. }
  91. +(id)alloc
  92. {
  93. NSAssert(sharedTextureCache == nil, @"Attempted to allocate a second instance of a singleton.");
  94. return [super alloc];
  95. }
  96. +(void)purgeSharedTextureCache
  97. {
  98. [sharedTextureCache release];
  99. sharedTextureCache = nil;
  100. }
  101. -(id) init
  102. {
  103. if( (self=[super init]) ) {
  104. textures_ = [[NSMutableDictionary dictionaryWithCapacity: 10] retain];
  105. dictLock_ = [[NSLock alloc] init];
  106. contextLock_ = [[NSLock alloc] init];
  107. }
  108. return self;
  109. }
  110. - (NSString*) description
  111. {
  112. return [NSString stringWithFormat:@"<%@ = %08X | num of textures = %i>", [self class], self, [textures_ count]];
  113. }
  114. -(void) dealloc
  115. {
  116. CCLOG(@"cocos2d: deallocing %@", self);
  117. [textures_ release];
  118. [dictLock_ release];
  119. [contextLock_ release];
  120. [auxGLcontext release];
  121. auxGLcontext = nil;
  122. sharedTextureCache = nil;
  123. [super dealloc];
  124. }
  125. #pragma mark TextureCache - Add Images
  126. -(void) addImageWithAsyncObject:(CCAsyncObject*)async
  127. {
  128. NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init];
  129. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  130. // textures will be created on the main OpenGL context
  131. // it seems that in SDK 2.2.x there can't be 2 threads creating textures at the same time
  132. // the lock is used for this purpose: issue #472
  133. [contextLock_ lock];
  134. if( auxGLcontext == nil ) {
  135. auxGLcontext = [[EAGLContext alloc]
  136. initWithAPI:kEAGLRenderingAPIOpenGLES1
  137. sharegroup:[[[[CCDirector sharedDirector] openGLView] context] sharegroup]];
  138. if( ! auxGLcontext )
  139. CCLOG(@"cocos2d: TextureCache: Could not create EAGL context");
  140. }
  141. if( [EAGLContext setCurrentContext:auxGLcontext] ) {
  142. // load / create the texture
  143. CCTexture2D *tex = [self addImage:async.data];
  144. // The callback will be executed on the main thread
  145. [async.target performSelectorOnMainThread:async.selector withObject:tex waitUntilDone:NO];
  146. [EAGLContext setCurrentContext:nil];
  147. } else {
  148. CCLOG(@"cocos2d: TetureCache: EAGLContext error");
  149. }
  150. [contextLock_ unlock];
  151. [autoreleasepool release];
  152. #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
  153. [contextLock_ lock];
  154. if( auxGLcontext == nil ) {
  155. MacGLView *view = [[CCDirector sharedDirector] openGLView];
  156. NSOpenGLPixelFormat *pf = [view pixelFormat];
  157. NSOpenGLContext *share = [view openGLContext];
  158. auxGLcontext = [[NSOpenGLContext alloc] initWithFormat:pf shareContext:share];
  159. if( ! auxGLcontext )
  160. CCLOG(@"cocos2d: TextureCache: Could not create NSOpenGLContext");
  161. }
  162. [auxGLcontext makeCurrentContext];
  163. // load / create the texture
  164. CCTexture2D *tex = [self addImage:async.data];
  165. // The callback will be executed on the main thread
  166. [async.target performSelector:async.selector
  167. onThread:[[CCDirector sharedDirector] runningThread]
  168. withObject:tex
  169. waitUntilDone:NO];
  170. [NSOpenGLContext clearCurrentContext];
  171. [contextLock_ unlock];
  172. [autoreleasepool release];
  173. #endif // __MAC_OS_X_VERSION_MAX_ALLOWED
  174. }
  175. -(void) addImageAsync: (NSString*) filename target:(id)target selector:(SEL)selector
  176. {
  177. NSAssert(filename != nil, @"TextureCache: fileimage MUST not be nill");
  178. // optimization
  179. CCTexture2D * tex;
  180. if( (tex=[textures_ objectForKey: filename] ) ) {
  181. [target performSelector:selector withObject:tex];
  182. return;
  183. }
  184. // schedule the load
  185. CCAsyncObject *asyncObject = [[CCAsyncObject alloc] init];
  186. asyncObject.selector = selector;
  187. asyncObject.target = target;
  188. asyncObject.data = filename;
  189. [NSThread detachNewThreadSelector:@selector(addImageWithAsyncObject:) toTarget:self withObject:asyncObject];
  190. [asyncObject release];
  191. }
  192. -(CCTexture2D*) addImage: (NSString*) path
  193. {
  194. NSAssert(path != nil, @"TextureCache: fileimage MUST not be nill");
  195. CCTexture2D * tex = nil;
  196. // MUTEX:
  197. // Needed since addImageAsync calls this method from a different thread
  198. [dictLock_ lock];
  199. tex=[textures_ objectForKey: path];
  200. if( ! tex ) {
  201. NSString *lowerCase = [path lowercaseString];
  202. // all images are handled by UIImage except PVR extension that is handled by our own handler
  203. if ( [lowerCase hasSuffix:@".pvr"] || [lowerCase hasSuffix:@".pvr.gz"] || [lowerCase hasSuffix:@".pvr.ccz"] )
  204. tex = [self addPVRImage:path];
  205. // Only iPhone
  206. #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
  207. // Issue #886: TEMPORARY FIX FOR TRANSPARENT JPEGS IN IOS4
  208. else if ( ( [[CCConfiguration sharedConfiguration] OSVersion] >= kCCiOSVersion_4_0) &&
  209. ( [lowerCase hasSuffix:@".jpg"] || [lowerCase hasSuffix:@".jpeg"] )
  210. ) {
  211. // convert jpg to png before loading the texture
  212. NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ];
  213. UIImage *jpg = [[UIImage alloc] initWithContentsOfFile:fullpath];
  214. UIImage *png = [[UIImage alloc] initWithData:UIImagePNGRepresentation(jpg)];
  215. tex = [ [CCTexture2D alloc] initWithImage: png ];
  216. [png release];
  217. [jpg release];
  218. if( tex )
  219. [textures_ setObject: tex forKey:path];
  220. else
  221. CCLOG(@"cocos2d: Couldn't add image:%@ in CCTextureCache", path);
  222. [tex release];
  223. }
  224. else {
  225. // prevents overloading the autorelease pool
  226. NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ];
  227. UIImage *image = [ [UIImage alloc] initWithContentsOfFile: fullpath ];
  228. tex = [ [CCTexture2D alloc] initWithImage: image ];
  229. [image release];
  230. if( tex )
  231. [textures_ setObject: tex forKey:path];
  232. else
  233. CCLOG(@"cocos2d: Couldn't add image:%@ in CCTextureCache", path);
  234. [tex release];
  235. }
  236. // Only in Mac
  237. #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
  238. else {
  239. NSString *fullpath = [CCFileUtils fullPathFromRelativePath: path ];
  240. NSData *data = [[NSData alloc] initWithContentsOfFile:fullpath];
  241. NSBitmapImageRep *image = [[NSBitmapImageRep alloc] initWithData:data];
  242. tex = [ [CCTexture2D alloc] initWithImage:[image CGImage]];
  243. [data release];
  244. [image release];
  245. if( tex )
  246. [textures_ setObject: tex forKey:path];
  247. else
  248. CCLOG(@"cocos2d: Couldn't add image:%@ in CCTextureCache", path);
  249. [tex release];
  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. if( (tex=[textures_ objectForKey: path] ) ) {
  322. return tex;
  323. }
  324. // Split up directory and filename
  325. NSString *fullpath = [CCFileUtils fullPathFromRelativePath:path];
  326. NSData *nsdata = [[NSData alloc] initWithContentsOfFile:fullpath];
  327. tex = [[CCTexture2D alloc] initWithPVRTCData:[nsdata bytes] level:0 bpp:bpp hasAlpha:alpha length:w];
  328. if( tex )
  329. [textures_ setObject: tex forKey:path];
  330. else
  331. CCLOG(@"cocos2d: Couldn't add PVRTCImage:%@ in CCTextureCache",path);
  332. [nsdata release];
  333. return [tex autorelease];
  334. }
  335. #endif // __IPHONE_OS_VERSION_MAX_ALLOWED
  336. -(CCTexture2D*) addPVRImage: (NSString*) fileimage
  337. {
  338. NSAssert(fileimage != nil, @"TextureCache: fileimage MUST not be nill");
  339. CCTexture2D * tex;
  340. if( (tex=[textures_ objectForKey: fileimage] ) ) {
  341. return tex;
  342. }
  343. // Split up directory and filename
  344. NSString *fullpath = [CCFileUtils fullPathFromRelativePath:fileimage];
  345. tex = [[CCTexture2D alloc] initWithPVRFile: fullpath];
  346. if( tex )
  347. [textures_ setObject: tex forKey:fileimage];
  348. else
  349. CCLOG(@"cocos2d: Couldn't add PVRImage:%@ in CCTextureCache",fileimage);
  350. return [tex autorelease];
  351. }
  352. @end