PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/cocos2d-2.x-ARC-iOS/libs/cocos2d/CCTexture2D.m

https://github.com/mcpoet/cocos2d-V2.x-ARC-UIKit
Objective C | 1001 lines | 669 code | 210 blank | 122 comment | 89 complexity | 33ce63532dad2aaeb387371646813b7a MD5 | raw file
Possible License(s): BSD-2-Clause
  1. /*
  2. ===== IMPORTANT =====
  3. This is sample code demonstrating API, technology or techniques in development.
  4. Although this sample code has been reviewed for technical accuracy, it is not
  5. final. Apple is supplying this information to help you plan for the adoption of
  6. the technologies and programming interfaces described herein. This information
  7. is subject to change, and software implemented based on this sample code should
  8. be tested with final operating system software and final documentation. Newer
  9. versions of this sample code may be provided with future seeds of the API or
  10. technology. For information about updates to this and other developer
  11. documentation, view the New & Updated sidebars in subsequent documentationd
  12. seeds.
  13. =====================
  14. File: Texture2D.m
  15. Abstract: Creates OpenGL 2D textures from images or text.
  16. Version: 1.6
  17. Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
  18. ("Apple") in consideration of your agreement to the following terms, and your
  19. use, installation, modification or redistribution of this Apple software
  20. constitutes acceptance of these terms. If you do not agree with these terms,
  21. please do not use, install, modify or redistribute this Apple software.
  22. In consideration of your agreement to abide by the following terms, and subject
  23. to these terms, Apple grants you a personal, non-exclusive license, under
  24. Apple's copyrights in this original Apple software (the "Apple Software"), to
  25. use, reproduce, modify and redistribute the Apple Software, with or without
  26. modifications, in source and/or binary forms; provided that if you redistribute
  27. the Apple Software in its entirety and without modifications, you must retain
  28. this notice and the following text and disclaimers in all such redistributions
  29. of the Apple Software.
  30. Neither the name, trademarks, service marks or logos of Apple Inc. may be used
  31. to endorse or promote products derived from the Apple Software without specific
  32. prior written permission from Apple. Except as expressly stated in this notice,
  33. no other rights or licenses, express or implied, are granted by Apple herein,
  34. including but not limited to any patent rights that may be infringed by your
  35. derivative works or by other works in which the Apple Software may be
  36. incorporated.
  37. The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
  38. WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
  39. WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  40. PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
  41. COMBINATION WITH YOUR PRODUCTS.
  42. IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
  43. CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  44. GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  45. ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
  46. DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
  47. CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
  48. APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  49. Copyright (C) 2008 Apple Inc. All Rights Reserved.
  50. */
  51. /*
  52. * Support for RGBA_4_4_4_4 and RGBA_5_5_5_1 was copied from:
  53. * https://devforums.apple.com/message/37855#37855 by a1studmuffin
  54. */
  55. /*
  56. * Added many additions for cocos2d
  57. */
  58. #import "Platforms/CCGL.h"
  59. #import "Platforms/CCNS.h"
  60. #import "CCTexture2D.h"
  61. #import "ccConfig.h"
  62. #import "ccMacros.h"
  63. #import "CCConfiguration.h"
  64. #import "CCTexturePVR.h"
  65. #import "CCGLProgram.h"
  66. #import "ccGLStateCache.h"
  67. #import "CCShaderCache.h"
  68. #import "CCDirector.h"
  69. #import "Support/ccUtils.h"
  70. #import "Support/CCFileUtils.h"
  71. #import "ccDeprecated.h"
  72. #if CC_USE_LA88_LABELS
  73. #define LABEL_PIXEL_FORMAT kCCTexture2DPixelFormat_AI88
  74. #else
  75. #define LABEL_PIXEL_FORMAT kCCTexture2DPixelFormat_A8
  76. #endif
  77. //CLASS IMPLEMENTATIONS:
  78. // If the image has alpha, you can create RGBA8 (32-bit) or RGBA4 (16-bit) or RGB5A1 (16-bit)
  79. // Default is: RGBA8888 (32-bit textures)
  80. static CCTexture2DPixelFormat defaultAlphaPixelFormat_ = kCCTexture2DPixelFormat_Default;
  81. #pragma mark -
  82. #pragma mark CCTexture2D - Main
  83. @implementation CCTexture2D
  84. @synthesize contentSizeInPixels = size_, pixelFormat = format_, pixelsWide = width_, pixelsHigh = height_, name = name_, maxS = maxS_, maxT = maxT_;
  85. @synthesize hasPremultipliedAlpha = hasPremultipliedAlpha_;
  86. @synthesize shaderProgram = shaderProgram_;
  87. #ifdef __CC_PLATFORM_IOS
  88. @synthesize resolutionType = resolutionType_;
  89. #endif
  90. - (id) initWithData:(const void*)data pixelFormat:(CCTexture2DPixelFormat)pixelFormat pixelsWide:(NSUInteger)width pixelsHigh:(NSUInteger)height contentSize:(CGSize)size
  91. {
  92. if((self = [super init])) {
  93. // XXX: 32 bits or POT textures uses UNPACK of 4 (is this correct ??? )
  94. if( pixelFormat == kCCTexture2DPixelFormat_RGBA8888 || ( ccNextPOT(width)==width && ccNextPOT(height)==height) )
  95. glPixelStorei(GL_UNPACK_ALIGNMENT,4);
  96. else
  97. glPixelStorei(GL_UNPACK_ALIGNMENT,1);
  98. glGenTextures(1, &name_);
  99. ccGLBindTexture2D( name_ );
  100. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  101. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  102. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
  103. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
  104. // Specify OpenGL texture image
  105. switch(pixelFormat)
  106. {
  107. case kCCTexture2DPixelFormat_RGBA8888:
  108. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) width, (GLsizei) height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
  109. break;
  110. case kCCTexture2DPixelFormat_RGBA4444:
  111. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) width, (GLsizei) height, 0, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data);
  112. break;
  113. case kCCTexture2DPixelFormat_RGB5A1:
  114. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei) width, (GLsizei) height, 0, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, data);
  115. break;
  116. case kCCTexture2DPixelFormat_RGB565:
  117. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei) width, (GLsizei) height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
  118. break;
  119. case kCCTexture2DPixelFormat_RGB888:
  120. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, (GLsizei) width, (GLsizei) height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
  121. break;
  122. case kCCTexture2DPixelFormat_AI88:
  123. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, (GLsizei) width, (GLsizei) height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);
  124. break;
  125. case kCCTexture2DPixelFormat_A8:
  126. glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, (GLsizei) width, (GLsizei) height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
  127. break;
  128. default:
  129. [NSException raise:NSInternalInconsistencyException format:@""];
  130. }
  131. size_ = size;
  132. width_ = width;
  133. height_ = height;
  134. format_ = pixelFormat;
  135. maxS_ = size.width / (float)width;
  136. maxT_ = size.height / (float)height;
  137. hasPremultipliedAlpha_ = NO;
  138. hasMipmaps_ = NO;
  139. #ifdef __CC_PLATFORM_IOS
  140. resolutionType_ = kCCResolutionUnknown;
  141. #endif
  142. self.shaderProgram = [[CCShaderCache sharedShaderCache] programForKey:kCCShader_PositionTexture];
  143. }
  144. return self;
  145. }
  146. - (void) releaseData:(void*)data
  147. {
  148. //Free data
  149. free(data);
  150. }
  151. - (void*) keepData:(void*)data length:(NSUInteger)length
  152. {
  153. //The texture data mustn't be saved becuase it isn't a mutable texture.
  154. return data;
  155. }
  156. - (void) dealloc
  157. {
  158. CCLOGINFO(@"cocos2d: deallocing %@", self);
  159. [shaderProgram_ release];
  160. if( name_ )
  161. ccGLDeleteTexture( name_ );
  162. [super dealloc];
  163. }
  164. - (NSString*) description
  165. {
  166. return [NSString stringWithFormat:@"<%@ = %p | Name = %i | Dimensions = %lux%lu | Pixel format = %@ | Coordinates = (%.2f, %.2f)>", [self class], self, name_, (unsigned long)width_, (unsigned long)height_, [self stringForFormat], maxS_, maxT_];
  167. }
  168. -(CGSize) contentSize
  169. {
  170. CGSize ret;
  171. ret.width = size_.width / CC_CONTENT_SCALE_FACTOR();
  172. ret.height = size_.height / CC_CONTENT_SCALE_FACTOR();
  173. return ret;
  174. }
  175. @end
  176. #pragma mark -
  177. #pragma mark CCTexture2D - Image
  178. @implementation CCTexture2D (Image)
  179. #ifdef __CC_PLATFORM_IOS
  180. - (id) initWithCGImage:(CGImageRef)cgImage resolutionType:(ccResolutionType)resolution
  181. #elif defined(__CC_PLATFORM_MAC)
  182. - (id) initWithCGImage:(CGImageRef)cgImage
  183. #endif
  184. {
  185. NSUInteger textureWidth, textureHeight;
  186. CGContextRef context = nil;
  187. void* data = nil;
  188. CGColorSpaceRef colorSpace;
  189. void* tempData;
  190. unsigned int* inPixel32;
  191. unsigned short* outPixel16;
  192. BOOL hasAlpha;
  193. CGImageAlphaInfo info;
  194. CGSize imageSize;
  195. CCTexture2DPixelFormat pixelFormat;
  196. if(cgImage == NULL) {
  197. CCLOG(@"cocos2d: CCTexture2D. Can't create Texture. cgImage is nil");
  198. [self release];
  199. return nil;
  200. }
  201. CCConfiguration *conf = [CCConfiguration sharedConfiguration];
  202. info = CGImageGetAlphaInfo(cgImage);
  203. #ifdef __CC_PLATFORM_IOS
  204. // Bug #886. It is present on iOS 4 only
  205. unsigned int version = [conf OSVersion];
  206. if( version >= kCCiOSVersion_4_0 && version < kCCiOSVersion_5_0 )
  207. hasAlpha = ((info == kCGImageAlphaNoneSkipLast) || (info == kCGImageAlphaPremultipliedLast) || (info == kCGImageAlphaPremultipliedFirst) || (info == kCGImageAlphaLast) || (info == kCGImageAlphaFirst) ? YES : NO);
  208. else
  209. #endif // __CC_PLATFORM_IOS
  210. hasAlpha = ((info == kCGImageAlphaPremultipliedLast) || (info == kCGImageAlphaPremultipliedFirst) || (info == kCGImageAlphaLast) || (info == kCGImageAlphaFirst) ? YES : NO);
  211. colorSpace = CGImageGetColorSpace(cgImage);
  212. if(colorSpace) {
  213. if( hasAlpha ) {
  214. pixelFormat = defaultAlphaPixelFormat_;
  215. info = kCGImageAlphaPremultipliedLast;
  216. }
  217. else
  218. {
  219. info = kCGImageAlphaNoneSkipLast;
  220. // Use RGBA8888 if default is RGBA8888, otherwise use RGB565.
  221. // DO NOT USE RGB888 since it is the same as RGBA8888, but it is more expensive to create it
  222. if( defaultAlphaPixelFormat_ == kCCTexture2DPixelFormat_RGBA8888 )
  223. pixelFormat = kCCTexture2DPixelFormat_RGBA8888;
  224. else
  225. pixelFormat = kCCTexture2DPixelFormat_RGB565;
  226. CCLOG(@"cocos2d: CCTexture2D: Using RGB565 texture since image has no alpha");
  227. }
  228. } else {
  229. // NOTE: No colorspace means a mask image
  230. CCLOG(@"cocos2d: CCTexture2D: Using A8 texture since image is a mask");
  231. pixelFormat = kCCTexture2DPixelFormat_A8;
  232. }
  233. if( ! [conf supportsNPOT] )
  234. {
  235. textureWidth = ccNextPOT(CGImageGetWidth(cgImage));
  236. textureHeight = ccNextPOT(CGImageGetHeight(cgImage));
  237. }
  238. else
  239. {
  240. textureWidth = CGImageGetWidth(cgImage);
  241. textureHeight = CGImageGetHeight(cgImage);
  242. }
  243. #ifdef __CC_PLATFORM_IOS
  244. // iOS 5 BUG:
  245. // If width is not word aligned, convert it to word aligned.
  246. // http://www.cocos2d-iphone.org/forum/topic/31092
  247. if( [conf OSVersion] >= kCCiOSVersion_5_0 )
  248. {
  249. NSUInteger bpp = [[self class] bitsPerPixelForFormat:pixelFormat];
  250. NSUInteger bytes = textureWidth * bpp / 8;
  251. // XXX: Should it be 4 or sizeof(int) ??
  252. NSUInteger mod = bytes % 4;
  253. // Not word aligned ?
  254. if( mod != 0 ) {
  255. NSUInteger neededBytes = (4 - mod ) / (bpp/8);
  256. CCLOGWARN(@"cocos2d: WARNING converting size=(%d,%d) to size=(%d,%d) due to iOS 5.x memory BUG. See: http://www.cocos2d-iphone.org/forum/topic/31092", textureWidth, textureHeight, textureWidth + neededBytes, textureHeight );
  257. textureWidth = textureWidth + neededBytes;
  258. }
  259. }
  260. #endif // IOS
  261. NSUInteger maxTextureSize = [conf maxTextureSize];
  262. if( textureHeight > maxTextureSize || textureWidth > maxTextureSize ) {
  263. CCLOGWARN(@"cocos2d: WARNING: Image (%lu x %lu) is bigger than the supported %ld x %ld",
  264. (long)textureWidth, (long)textureHeight,
  265. (long)maxTextureSize, (long)maxTextureSize);
  266. [self release];
  267. return nil;
  268. }
  269. imageSize = CGSizeMake(CGImageGetWidth(cgImage), CGImageGetHeight(cgImage));
  270. // Create the bitmap graphics context
  271. switch(pixelFormat) {
  272. case kCCTexture2DPixelFormat_RGBA8888:
  273. case kCCTexture2DPixelFormat_RGBA4444:
  274. case kCCTexture2DPixelFormat_RGB5A1:
  275. case kCCTexture2DPixelFormat_RGB565:
  276. case kCCTexture2DPixelFormat_RGB888:
  277. colorSpace = CGColorSpaceCreateDeviceRGB();
  278. data = malloc(textureHeight * textureWidth * 4);
  279. // info = hasAlpha ? kCGImageAlphaPremultipliedLast : kCGImageAlphaNoneSkipLast;
  280. // info = kCGImageAlphaPremultipliedLast; // issue #886. This patch breaks BMP images.
  281. context = CGBitmapContextCreate(data, textureWidth, textureHeight, 8, 4 * textureWidth, colorSpace, info | kCGBitmapByteOrder32Big);
  282. CGColorSpaceRelease(colorSpace);
  283. break;
  284. case kCCTexture2DPixelFormat_A8:
  285. data = malloc(textureHeight * textureWidth);
  286. info = kCGImageAlphaOnly;
  287. context = CGBitmapContextCreate(data, textureWidth, textureHeight, 8, textureWidth, NULL, info);
  288. break;
  289. default:
  290. [NSException raise:NSInternalInconsistencyException format:@"Invalid pixel format"];
  291. }
  292. CGContextClearRect(context, CGRectMake(0, 0, textureWidth, textureHeight));
  293. CGContextTranslateCTM(context, 0, textureHeight - imageSize.height);
  294. CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(cgImage), CGImageGetHeight(cgImage)), cgImage);
  295. // Repack the pixel data into the right format
  296. if(pixelFormat == kCCTexture2DPixelFormat_RGB565) {
  297. //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGGBBBBB"
  298. tempData = malloc(textureHeight * textureWidth * 2);
  299. inPixel32 = (unsigned int*)data;
  300. outPixel16 = (unsigned short*)tempData;
  301. for(unsigned int i = 0; i < textureWidth * textureHeight; ++i, ++inPixel32)
  302. *outPixel16++ = ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | ((((*inPixel32 >> 8) & 0xFF) >> 2) << 5) | ((((*inPixel32 >> 16) & 0xFF) >> 3) << 0);
  303. free(data);
  304. data = tempData;
  305. }
  306. else if(pixelFormat == kCCTexture2DPixelFormat_RGB888) {
  307. //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRRRRGGGGGGGGBBBBBBB"
  308. tempData = malloc(textureHeight * textureWidth * 3);
  309. char *inData = (char*)data;
  310. char *outData = (char*)tempData;
  311. int j=0;
  312. for(unsigned int i = 0; i < textureWidth * textureHeight *4; i++) {
  313. outData[j++] = inData[i++];
  314. outData[j++] = inData[i++];
  315. outData[j++] = inData[i++];
  316. }
  317. free(data);
  318. data = tempData;
  319. }
  320. else if (pixelFormat == kCCTexture2DPixelFormat_RGBA4444) {
  321. //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRGGGGBBBBAAAA"
  322. tempData = malloc(textureHeight * textureWidth * 2);
  323. inPixel32 = (unsigned int*)data;
  324. outPixel16 = (unsigned short*)tempData;
  325. for(unsigned int i = 0; i < textureWidth * textureHeight; ++i, ++inPixel32)
  326. *outPixel16++ =
  327. ((((*inPixel32 >> 0) & 0xFF) >> 4) << 12) | // R
  328. ((((*inPixel32 >> 8) & 0xFF) >> 4) << 8) | // G
  329. ((((*inPixel32 >> 16) & 0xFF) >> 4) << 4) | // B
  330. ((((*inPixel32 >> 24) & 0xFF) >> 4) << 0); // A
  331. free(data);
  332. data = tempData;
  333. }
  334. else if (pixelFormat == kCCTexture2DPixelFormat_RGB5A1) {
  335. //Convert "RRRRRRRRRGGGGGGGGBBBBBBBBAAAAAAAA" to "RRRRRGGGGGBBBBBA"
  336. /*
  337. Here was a bug.
  338. When you convert RGBA8888 texture to RGB5A1 texture and then render it on black background, you'll see a "ghost" image as if the texture is still RGBA8888.
  339. On background lighter than the pixel color this effect disappers.
  340. This happens because the old convertion function doesn't premultiply old RGB with new A.
  341. As Result = sourceRGB + destination*(1-source A), then
  342. if Destination = 0000, then Result = source. Here comes the ghost!
  343. We need to check new alpha value first (it may be 1 or 0) and depending on it whether convert RGB values or just set pixel to 0
  344. */
  345. tempData = malloc(textureHeight * textureWidth * 2);
  346. inPixel32 = (unsigned int*)data;
  347. outPixel16 = (unsigned short*)tempData;
  348. for(unsigned int i = 0; i < textureWidth * textureHeight; ++i, ++inPixel32) {
  349. if ((*inPixel32 >> 31))// A can be 1 or 0
  350. *outPixel16++ =
  351. ((((*inPixel32 >> 0) & 0xFF) >> 3) << 11) | // R
  352. ((((*inPixel32 >> 8) & 0xFF) >> 3) << 6) | // G
  353. ((((*inPixel32 >> 16) & 0xFF) >> 3) << 1) | // B
  354. 1; // A
  355. else
  356. *outPixel16++ = 0;
  357. }
  358. free(data);
  359. data = tempData;
  360. }
  361. self = [self initWithData:data pixelFormat:pixelFormat pixelsWide:textureWidth pixelsHigh:textureHeight contentSize:imageSize];
  362. // should be after calling super init
  363. hasPremultipliedAlpha_ = (info == kCGImageAlphaPremultipliedLast || info == kCGImageAlphaPremultipliedFirst);
  364. CGContextRelease(context);
  365. [self releaseData:data];
  366. #ifdef __CC_PLATFORM_IOS
  367. resolutionType_ = resolution;
  368. #endif
  369. return self;
  370. }
  371. @end
  372. #pragma mark -
  373. #pragma mark CCTexture2D - Text
  374. @implementation CCTexture2D (Text)
  375. #ifdef __CC_PLATFORM_IOS
  376. - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions hAlignment:(CCTextAlignment)hAlignment vAlignment:(CCVerticalTextAlignment) vAlignment lineBreakMode:(CCLineBreakMode)lineBreakMode font:(UIFont*)uifont
  377. {
  378. NSAssert( uifont, @"Invalid font");
  379. // MUST have the same order declared on ccTypes
  380. NSInteger linebreaks[] = {UILineBreakModeWordWrap, UILineBreakModeCharacterWrap, UILineBreakModeClip, UILineBreakModeHeadTruncation, UILineBreakModeTailTruncation, UILineBreakModeMiddleTruncation};
  381. NSUInteger textureWidth = ccNextPOT(dimensions.width);
  382. NSUInteger textureHeight = ccNextPOT(dimensions.height);
  383. unsigned char* data;
  384. CGContextRef context;
  385. CGColorSpaceRef colorSpace;
  386. #if CC_USE_LA88_LABELS
  387. data = calloc(textureHeight, textureWidth * 2);
  388. #else
  389. data = calloc(textureHeight, textureWidth);
  390. #endif
  391. colorSpace = CGColorSpaceCreateDeviceGray();
  392. context = CGBitmapContextCreate(data, textureWidth, textureHeight, 8, textureWidth, colorSpace, kCGImageAlphaNone);
  393. CGColorSpaceRelease(colorSpace);
  394. if( ! context ) {
  395. free(data);
  396. [self release];
  397. return nil;
  398. }
  399. CGContextSetGrayFillColor(context, 1.0f, 1.0f);
  400. CGContextTranslateCTM(context, 0.0f, textureHeight);
  401. CGContextScaleCTM(context, 1.0f, -1.0f); //NOTE: NSString draws in UIKit referential i.e. renders upside-down compared to CGBitmapContext referential
  402. UIGraphicsPushContext(context);
  403. CGRect drawArea;
  404. if(vAlignment == kCCVerticalTextAlignmentTop)
  405. {
  406. drawArea = CGRectMake(0, 0, dimensions.width, dimensions.height);
  407. }
  408. else
  409. {
  410. CGSize drawSize = [string sizeWithFont:uifont constrainedToSize:dimensions lineBreakMode:linebreaks[lineBreakMode] ];
  411. if(vAlignment == kCCVerticalTextAlignmentBottom)
  412. {
  413. drawArea = CGRectMake(0, dimensions.height - drawSize.height, dimensions.width, drawSize.height);
  414. }
  415. else // kCCVerticalTextAlignmentCenter
  416. {
  417. drawArea = CGRectMake(0, (dimensions.height - drawSize.height) / 2, dimensions.width, drawSize.height);
  418. }
  419. }
  420. // must follow the same order of CCTextureAligment
  421. NSUInteger alignments[] = { UITextAlignmentLeft, UITextAlignmentCenter, UITextAlignmentRight };
  422. [string drawInRect:drawArea withFont:uifont lineBreakMode:linebreaks[lineBreakMode] alignment:alignments[hAlignment]];
  423. UIGraphicsPopContext();
  424. #if CC_USE_LA88_LABELS
  425. NSUInteger textureSize = textureWidth*textureHeight;
  426. unsigned short *la88_data = (unsigned short*)data;
  427. for(int i = textureSize-1; i>=0; i--) //Convert A8 to AI88
  428. la88_data[i] = (data[i] << 8) | 0xff;
  429. #endif
  430. self = [self initWithData:data pixelFormat:LABEL_PIXEL_FORMAT pixelsWide:textureWidth pixelsHigh:textureHeight contentSize:dimensions];
  431. CGContextRelease(context);
  432. [self releaseData:data];
  433. return self;
  434. }
  435. #elif defined(__CC_PLATFORM_MAC)
  436. - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions hAlignment:(CCTextAlignment)hAlignment vAlignment:(CCVerticalTextAlignment)vAlignment attributedString:(NSAttributedString*)stringWithAttributes
  437. {
  438. NSAssert(stringWithAttributes, @"Invalid stringWithAttributes");
  439. // get nearest power of two
  440. NSSize POTSize = NSMakeSize(ccNextPOT(dimensions.width), ccNextPOT(dimensions.height));
  441. // Get actual rendered dimensions
  442. NSRect boundingRect = [stringWithAttributes boundingRectWithSize:NSSizeFromCGSize(dimensions) options:NSStringDrawingUsesLineFragmentOrigin];
  443. // Mac crashes if the width or height is 0
  444. if( boundingRect.size.width > 0 && boundingRect.size.height > 0 ) {
  445. CGSize offset = CGSizeMake(0, POTSize.height - dimensions.height);
  446. //Alignment
  447. switch (hAlignment) {
  448. case kCCTextAlignmentLeft: break;
  449. case kCCTextAlignmentCenter: offset.width = (dimensions.width-boundingRect.size.width)/2.0f; break;
  450. case kCCTextAlignmentRight: offset.width = dimensions.width-boundingRect.size.width; break;
  451. default: break;
  452. }
  453. switch (vAlignment) {
  454. case kCCVerticalTextAlignmentTop: offset.height += dimensions.height - boundingRect.size.height; break;
  455. case kCCVerticalTextAlignmentCenter: offset.height += (dimensions.height - boundingRect.size.height) / 2; break;
  456. case kCCVerticalTextAlignmentBottom: break;
  457. default: break;
  458. }
  459. CGRect drawArea = CGRectMake(offset.width, offset.height, boundingRect.size.width, boundingRect.size.height);
  460. //Disable antialias
  461. [[NSGraphicsContext currentContext] setShouldAntialias:NO];
  462. NSImage *image = [[NSImage alloc] initWithSize:POTSize];
  463. [image lockFocus];
  464. [stringWithAttributes drawWithRect:NSRectFromCGRect(drawArea) options:NSStringDrawingUsesLineFragmentOrigin];
  465. NSBitmapImageRep *bitmap = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect (0.0f, 0.0f, POTSize.width, POTSize.height)];
  466. [image unlockFocus];
  467. unsigned char *data = (unsigned char*) [bitmap bitmapData]; //Use the same buffer to improve the performance.
  468. NSUInteger textureSize = POTSize.width * POTSize.height;
  469. #if CC_USE_LA88_LABELS
  470. unsigned short *dst = (unsigned short*)data;
  471. for(int i = 0; i<textureSize; i++)
  472. dst[i] = (data[i*4+3] << 8) | 0xff; //Convert RGBA8888 to LA88
  473. #else
  474. unsigned char *dst = (unsigned char*)data;
  475. for(int i = 0; i<textureSize; i++)
  476. dst[i] = data[i*4+3]; //Convert RGBA8888 to A8
  477. #endif // ! CC_USE_LA88_LABELS
  478. data = [self keepData:dst length:textureSize];
  479. self = [self initWithData:data pixelFormat:LABEL_PIXEL_FORMAT pixelsWide:POTSize.width pixelsHigh:POTSize.height contentSize:dimensions];
  480. [bitmap release];
  481. [image release];
  482. }
  483. else
  484. {
  485. [self release];
  486. return nil;
  487. }
  488. return self;
  489. }
  490. #endif // __CC_PLATFORM_MAC
  491. - (id) initWithString:(NSString*)string fontName:(NSString*)name fontSize:(CGFloat)size
  492. {
  493. CGSize dim;
  494. #ifdef __CC_PLATFORM_IOS
  495. UIFont *font = [UIFont fontWithName:name size:size];
  496. if( ! font ) {
  497. CCLOG(@"cocos2d: Unable to load font %@", name);
  498. [self release];
  499. return nil;
  500. }
  501. // Is it a multiline ? sizeWithFont: only works with single line.
  502. CGSize boundingSize = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX);
  503. dim = [string sizeWithFont:font
  504. constrainedToSize:boundingSize
  505. lineBreakMode:UILineBreakModeWordWrap];
  506. return [self initWithString:string dimensions:dim hAlignment:kCCTextAlignmentCenter vAlignment:kCCVerticalTextAlignmentTop lineBreakMode:kCCLineBreakModeWordWrap font:font];
  507. #elif defined(__CC_PLATFORM_MAC)
  508. {
  509. NSFont* font = [NSFont fontWithName:name size:size];
  510. if( ! font ) {
  511. CCLOG(@"cocos2d: Unable to load font %@", name);
  512. [self release];
  513. return nil;
  514. }
  515. NSDictionary *dict = [NSDictionary dictionaryWithObject:font forKey:NSFontAttributeName];
  516. NSAttributedString *stringWithAttributes = [[[NSAttributedString alloc] initWithString:string attributes:dict] autorelease];
  517. dim = NSSizeToCGSize( [stringWithAttributes size] );
  518. return [self initWithString:string dimensions:dim hAlignment:kCCTextAlignmentCenter vAlignment:kCCVerticalTextAlignmentTop attributedString:stringWithAttributes];
  519. }
  520. #endif // __CC_PLATFORM_MAC
  521. }
  522. - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions hAlignment:(CCTextAlignment)alignment vAlignment:(CCVerticalTextAlignment)vAlignment fontName:(NSString*)name fontSize:(CGFloat)size
  523. {
  524. return [self initWithString:string dimensions:dimensions hAlignment:alignment vAlignment:vAlignment lineBreakMode:kCCLineBreakModeWordWrap fontName:name fontSize:size];
  525. }
  526. - (id) initWithString:(NSString*)string dimensions:(CGSize)dimensions hAlignment:(CCTextAlignment)hAlignment vAlignment:(CCVerticalTextAlignment)vAlignment lineBreakMode:(CCLineBreakMode)lineBreakMode fontName:(NSString*)name fontSize:(CGFloat)size
  527. {
  528. #ifdef __CC_PLATFORM_IOS
  529. UIFont *uifont = [UIFont fontWithName:name size:size];
  530. if( ! uifont ) {
  531. CCLOG(@"cocos2d: Texture2d: Invalid Font: %@. Verify the .ttf name", name);
  532. [self release];
  533. return nil;
  534. }
  535. return [self initWithString:string dimensions:dimensions hAlignment:hAlignment vAlignment:vAlignment lineBreakMode:lineBreakMode font:uifont];
  536. #elif defined(__CC_PLATFORM_MAC)
  537. // select font
  538. NSFont *font = [NSFont fontWithName:name size:size];
  539. if( ! font ) {
  540. CCLOG(@"cocos2d: Texture2d: Invalid Font: %@. Verify the .ttf name", name);
  541. [self release];
  542. return nil;
  543. }
  544. // create paragraph style
  545. NSInteger linebreaks[] = {NSLineBreakByWordWrapping, -1, -1, -1, -1, -1};
  546. NSUInteger alignments[] = { NSLeftTextAlignment, NSCenterTextAlignment, NSRightTextAlignment };
  547. NSMutableParagraphStyle *pstyle = [[NSMutableParagraphStyle alloc] init];
  548. [pstyle setAlignment: alignments[hAlignment] ];
  549. [pstyle setLineBreakMode: linebreaks[lineBreakMode] ];
  550. // put attributes into a NSDictionary
  551. NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, pstyle, NSParagraphStyleAttributeName, nil];
  552. [pstyle release];
  553. // create string with attributes
  554. NSAttributedString *stringWithAttributes = [[[NSAttributedString alloc] initWithString:string attributes:attributes] autorelease];
  555. return [self initWithString:string dimensions:dimensions hAlignment:hAlignment vAlignment:vAlignment attributedString:stringWithAttributes];
  556. #endif // Mac
  557. }
  558. @end
  559. #pragma mark -
  560. #pragma mark CCTexture2D - PVRSupport
  561. @implementation CCTexture2D (PVRSupport)
  562. // By default PVR images are treated as if they don't have the alpha channel premultiplied
  563. static BOOL PVRHaveAlphaPremultiplied_ = NO;
  564. -(id) initWithPVRFile: (NSString*) relPath
  565. {
  566. #ifdef __CC_PLATFORM_IOS
  567. ccResolutionType resolution;
  568. NSString *fullpath = [[CCFileUtils sharedFileUtils] fullPathFromRelativePath:relPath resolutionType:&resolution];
  569. #elif defined(__CC_PLATFORM_MAC)
  570. NSString *fullpath = [[CCFileUtils sharedFileUtils] fullPathFromRelativePath:relPath];
  571. #endif
  572. if( (self = [super init]) ) {
  573. CCTexturePVR *pvr = [[CCTexturePVR alloc] initWithContentsOfFile:fullpath];
  574. if( pvr ) {
  575. pvr.retainName = YES; // don't dealloc texture on release
  576. name_ = pvr.name; // texture id
  577. maxS_ = 1; // only POT texture are supported
  578. maxT_ = 1;
  579. width_ = pvr.width;
  580. height_ = pvr.height;
  581. size_ = CGSizeMake(width_, height_);
  582. hasPremultipliedAlpha_ = PVRHaveAlphaPremultiplied_;
  583. format_ = pvr.format;
  584. hasMipmaps_ = ( pvr.numberOfMipmaps > 1 );
  585. [pvr release];
  586. } else {
  587. CCLOG(@"cocos2d: Couldn't load PVR image: %@", relPath);
  588. [self release];
  589. return nil;
  590. }
  591. #ifdef __CC_PLATFORM_IOS
  592. resolutionType_ = resolution;
  593. #endif
  594. }
  595. return self;
  596. }
  597. +(void) PVRImagesHavePremultipliedAlpha:(BOOL)haveAlphaPremultiplied
  598. {
  599. PVRHaveAlphaPremultiplied_ = haveAlphaPremultiplied;
  600. }
  601. @end
  602. #pragma mark -
  603. #pragma mark CCTexture2D - Drawing
  604. @implementation CCTexture2D (Drawing)
  605. - (void) drawAtPoint:(CGPoint)point
  606. {
  607. GLfloat coordinates[] = { 0.0f, maxT_,
  608. maxS_, maxT_,
  609. 0.0f, 0.0f,
  610. maxS_, 0.0f };
  611. GLfloat width = (GLfloat)width_ * maxS_,
  612. height = (GLfloat)height_ * maxT_;
  613. GLfloat vertices[] = { point.x, point.y,
  614. width + point.x, point.y,
  615. point.x, height + point.y,
  616. width + point.x, height + point.y };
  617. ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords );
  618. [shaderProgram_ use];
  619. [shaderProgram_ setUniformForModelViewProjectionMatrix];
  620. ccGLBindTexture2D( name_ );
  621. glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);
  622. glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, coordinates);
  623. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  624. CC_INCREMENT_GL_DRAWS(1);
  625. }
  626. - (void) drawInRect:(CGRect)rect
  627. {
  628. GLfloat coordinates[] = { 0.0f, maxT_,
  629. maxS_, maxT_,
  630. 0.0f, 0.0f,
  631. maxS_, 0.0f };
  632. GLfloat vertices[] = { rect.origin.x, rect.origin.y,
  633. rect.origin.x + rect.size.width, rect.origin.y,
  634. rect.origin.x, rect.origin.y + rect.size.height,
  635. rect.origin.x + rect.size.width, rect.origin.y + rect.size.height };
  636. [shaderProgram_ use];
  637. [shaderProgram_ setUniformForModelViewProjectionMatrix];
  638. ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords );
  639. ccGLBindTexture2D( name_ );
  640. glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);
  641. glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, coordinates);
  642. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  643. CC_INCREMENT_GL_DRAWS(1);
  644. }
  645. @end
  646. #pragma mark -
  647. #pragma mark CCTexture2D - GLFilter
  648. //
  649. // Use to apply MIN/MAG filter
  650. //
  651. @implementation CCTexture2D (GLFilter)
  652. -(void) generateMipmap
  653. {
  654. NSAssert( width_ == ccNextPOT(width_) && height_ == ccNextPOT(height_), @"Mimpap texture only works in POT textures");
  655. ccGLBindTexture2D( name_ );
  656. glGenerateMipmap(GL_TEXTURE_2D);
  657. hasMipmaps_ = YES;
  658. }
  659. -(void) setTexParameters: (ccTexParams*) texParams
  660. {
  661. NSAssert( (width_ == ccNextPOT(width_) || texParams->wrapS == GL_CLAMP_TO_EDGE) &&
  662. (height_ == ccNextPOT(height_) || texParams->wrapT == GL_CLAMP_TO_EDGE),
  663. @"GL_CLAMP_TO_EDGE should be used in NPOT dimensions");
  664. ccGLBindTexture2D( name_ );
  665. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texParams->minFilter );
  666. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, texParams->magFilter );
  667. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texParams->wrapS );
  668. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texParams->wrapT );
  669. }
  670. -(void) setAliasTexParameters
  671. {
  672. ccGLBindTexture2D( name_ );
  673. if( ! hasMipmaps_ )
  674. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  675. else
  676. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
  677. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  678. }
  679. -(void) setAntiAliasTexParameters
  680. {
  681. ccGLBindTexture2D( name_ );
  682. if( ! hasMipmaps_ )
  683. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  684. else
  685. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST );
  686. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  687. }
  688. @end
  689. #pragma mark -
  690. #pragma mark CCTexture2D - Pixel Format
  691. //
  692. // Texture options for images that contains alpha
  693. //
  694. @implementation CCTexture2D (PixelFormat)
  695. +(void) setDefaultAlphaPixelFormat:(CCTexture2DPixelFormat)format
  696. {
  697. defaultAlphaPixelFormat_ = format;
  698. }
  699. +(CCTexture2DPixelFormat) defaultAlphaPixelFormat
  700. {
  701. return defaultAlphaPixelFormat_;
  702. }
  703. +(NSUInteger) bitsPerPixelForFormat:(CCTexture2DPixelFormat)format
  704. {
  705. NSUInteger ret=0;
  706. switch (format) {
  707. case kCCTexture2DPixelFormat_RGBA8888:
  708. ret = 32;
  709. break;
  710. case kCCTexture2DPixelFormat_RGB888:
  711. // It is 32 and not 24, since its internal representation uses 32 bits.
  712. ret = 32;
  713. break;
  714. case kCCTexture2DPixelFormat_RGB565:
  715. ret = 16;
  716. break;
  717. case kCCTexture2DPixelFormat_RGBA4444:
  718. ret = 16;
  719. break;
  720. case kCCTexture2DPixelFormat_RGB5A1:
  721. ret = 16;
  722. break;
  723. case kCCTexture2DPixelFormat_AI88:
  724. ret = 16;
  725. break;
  726. case kCCTexture2DPixelFormat_A8:
  727. ret = 8;
  728. break;
  729. case kCCTexture2DPixelFormat_I8:
  730. ret = 8;
  731. break;
  732. case kCCTexture2DPixelFormat_PVRTC4:
  733. ret = 4;
  734. break;
  735. case kCCTexture2DPixelFormat_PVRTC2:
  736. ret = 2;
  737. break;
  738. default:
  739. ret = -1;
  740. NSAssert1(NO , @"bitsPerPixelForFormat: %ld, unrecognised pixel format", (long)format);
  741. CCLOG(@"bitsPerPixelForFormat: %ld, cannot give useful result", (long)format);
  742. break;
  743. }
  744. return ret;
  745. }
  746. -(NSUInteger) bitsPerPixelForFormat
  747. {
  748. return [[self class] bitsPerPixelForFormat:format_];
  749. }
  750. -(NSString*) stringForFormat
  751. {
  752. switch (format_) {
  753. case kCCTexture2DPixelFormat_RGBA8888:
  754. return @"RGBA8888";
  755. case kCCTexture2DPixelFormat_RGB888:
  756. return @"RGB888";
  757. case kCCTexture2DPixelFormat_RGB565:
  758. return @"RGB565";
  759. case kCCTexture2DPixelFormat_RGBA4444:
  760. return @"RGBA4444";
  761. case kCCTexture2DPixelFormat_RGB5A1:
  762. return @"RGB5A1";
  763. case kCCTexture2DPixelFormat_AI88:
  764. return @"AI88";
  765. case kCCTexture2DPixelFormat_A8:
  766. return @"A8";
  767. case kCCTexture2DPixelFormat_I8:
  768. return @"I8";
  769. case kCCTexture2DPixelFormat_PVRTC4:
  770. return @"PVRTC4";
  771. case kCCTexture2DPixelFormat_PVRTC2:
  772. return @"PVRTC2";
  773. default:
  774. NSAssert1(NO , @"stringForFormat: %ld, unrecognised pixel format", (long)format_);
  775. CCLOG(@"stringForFormat: %ld, cannot give useful result", (long)format_);
  776. break;
  777. }
  778. return nil;
  779. }
  780. @end