summary refs log tree commit diff stats
path: root/libs/cocos2d/CCTexturePVR.m
diff options
context:
space:
mode:
Diffstat (limited to 'libs/cocos2d/CCTexturePVR.m')
-rwxr-xr-xlibs/cocos2d/CCTexturePVR.m428
1 files changed, 428 insertions, 0 deletions
diff --git a/libs/cocos2d/CCTexturePVR.m b/libs/cocos2d/CCTexturePVR.m new file mode 100755 index 0000000..692d5f9 --- /dev/null +++ b/libs/cocos2d/CCTexturePVR.m
@@ -0,0 +1,428 @@
1/*
2
3File: PVRTexture.m
4Abstract: The PVRTexture class is responsible for loading .pvr files.
5
6Version: 1.0
7
8Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
9("Apple") in consideration of your agreement to the following terms, and your
10use, installation, modification or redistribution of this Apple software
11constitutes acceptance of these terms. If you do not agree with these terms,
12please do not use, install, modify or redistribute this Apple software.
13
14In consideration of your agreement to abide by the following terms, and subject
15to these terms, Apple grants you a personal, non-exclusive license, under
16Apple's copyrights in this original Apple software (the "Apple Software"), to
17use, reproduce, modify and redistribute the Apple Software, with or without
18modifications, in source and/or binary forms; provided that if you redistribute
19the Apple Software in its entirety and without modifications, you must retain
20this notice and the following text and disclaimers in all such redistributions
21of the Apple Software.
22Neither the name, trademarks, service marks or logos of Apple Inc. may be used
23to endorse or promote products derived from the Apple Software without specific
24prior written permission from Apple. Except as expressly stated in this notice,
25no other rights or licenses, express or implied, are granted by Apple herein,
26including but not limited to any patent rights that may be infringed by your
27derivative works or by other works in which the Apple Software may be
28incorporated.
29
30The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
31WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
32WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
34COMBINATION WITH YOUR PRODUCTS.
35
36IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
37CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
38GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR
40DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF
41CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
42APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43
44Copyright (C) 2008 Apple Inc. All Rights Reserved.
45
46*/
47
48/*
49 * Extended PVR formats for cocos2d project ( http://www.cocos2d-iphone.org )
50 * - RGBA8888
51 * - BGRA8888
52 * - RGBA4444
53 * - RGBA5551
54 * - RGB565
55 * - A8
56 * - I8
57 * - AI88
58 */
59
60#import <Availability.h>
61
62#import <zlib.h>
63
64#import "CCTexturePVR.h"
65#import "ccMacros.h"
66#import "CCConfiguration.h"
67#import "Support/ccUtils.h"
68#import "Support/CCFileUtils.h"
69#import "Support/ZipUtils.h"
70#import "Support/OpenGL_Internal.h"
71
72#pragma mark -
73#pragma mark CCTexturePVR
74
75#define PVR_TEXTURE_FLAG_TYPE_MASK 0xff
76
77// Values taken from PVRTexture.h from http://www.imgtec.com
78enum {
79 kPVRTextureFlagMipmap = (1<<8), // has mip map levels
80 kPVRTextureFlagTwiddle = (1<<9), // is twiddled
81 kPVRTextureFlagBumpmap = (1<<10), // has normals encoded for a bump map
82 kPVRTextureFlagTiling = (1<<11), // is bordered for tiled pvr
83 kPVRTextureFlagCubemap = (1<<12), // is a cubemap/skybox
84 kPVRTextureFlagFalseMipCol = (1<<13), // are there false coloured MIP levels
85 kPVRTextureFlagVolume = (1<<14), // is this a volume texture
86 kPVRTextureFlagAlpha = (1<<15), // v2.1 is there transparency info in the texture
87 kPVRTextureFlagVerticalFlip = (1<<16), // v2.1 is the texture vertically flipped
88};
89
90
91static char gPVRTexIdentifier[4] = "PVR!";
92
93enum
94{
95 kPVRTexturePixelTypeRGBA_4444= 0x10,
96 kPVRTexturePixelTypeRGBA_5551,
97 kPVRTexturePixelTypeRGBA_8888,
98 kPVRTexturePixelTypeRGB_565,
99 kPVRTexturePixelTypeRGB_555, // unsupported
100 kPVRTexturePixelTypeRGB_888, // unsupported
101 kPVRTexturePixelTypeI_8,
102 kPVRTexturePixelTypeAI_88,
103 kPVRTexturePixelTypePVRTC_2,
104 kPVRTexturePixelTypePVRTC_4,
105 kPVRTexturePixelTypeBGRA_8888,
106 kPVRTexturePixelTypeA_8,
107};
108
109static const uint32_t tableFormats[][7] = {
110
111 // - PVR texture format
112 // - OpenGL internal format
113 // - OpenGL format
114 // - OpenGL type
115 // - bpp
116 // - compressed
117 // - Cocos2d texture format constant
118 { kPVRTexturePixelTypeRGBA_4444, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 16, NO, kCCTexture2DPixelFormat_RGBA4444 },
119 { kPVRTexturePixelTypeRGBA_5551, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 16, NO, kCCTexture2DPixelFormat_RGB5A1 },
120 { kPVRTexturePixelTypeRGBA_8888, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, 32, NO, kCCTexture2DPixelFormat_RGBA8888 },
121 { kPVRTexturePixelTypeRGB_565, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, NO, kCCTexture2DPixelFormat_RGB565 },
122 { kPVRTexturePixelTypeA_8, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, 8, NO, kCCTexture2DPixelFormat_A8 },
123 { kPVRTexturePixelTypeI_8, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, 8, NO, kCCTexture2DPixelFormat_I8 },
124 { kPVRTexturePixelTypeAI_88, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 16, NO, kCCTexture2DPixelFormat_AI88 },
125#ifdef __IPHONE_OS_VERSION_MAX_ALLOWED
126 { kPVRTexturePixelTypePVRTC_2, GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, -1, -1, 2, YES, kCCTexture2DPixelFormat_PVRTC2 },
127 { kPVRTexturePixelTypePVRTC_4, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, -1, -1, 4, YES, kCCTexture2DPixelFormat_PVRTC4 },
128#endif // iphone only
129 { kPVRTexturePixelTypeBGRA_8888, GL_RGBA, GL_BGRA, GL_UNSIGNED_BYTE, 32, NO, kCCTexture2DPixelFormat_RGBA8888 },
130};
131#define MAX_TABLE_ELEMENTS (sizeof(tableFormats) / sizeof(tableFormats[0]))
132
133enum {
134 kCCInternalPVRTextureFormat,
135 kCCInternalOpenGLInternalFormat,
136 kCCInternalOpenGLFormat,
137 kCCInternalOpenGLType,
138 kCCInternalBPP,
139 kCCInternalCompressedImage,
140 kCCInternalCCTexture2DPixelFormat,
141};
142
143typedef struct _PVRTexHeader
144{
145 uint32_t headerLength;
146 uint32_t height;
147 uint32_t width;
148 uint32_t numMipmaps;
149 uint32_t flags;
150 uint32_t dataLength;
151 uint32_t bpp;
152 uint32_t bitmaskRed;
153 uint32_t bitmaskGreen;
154 uint32_t bitmaskBlue;
155 uint32_t bitmaskAlpha;
156 uint32_t pvrTag;
157 uint32_t numSurfs;
158} PVRTexHeader;
159
160
161@implementation CCTexturePVR
162
163@synthesize name = name_;
164@synthesize width = width_;
165@synthesize height = height_;
166@synthesize hasAlpha = hasAlpha_;
167
168// cocos2d integration
169@synthesize retainName = retainName_;
170@synthesize format = format_;
171
172
173- (BOOL)unpackPVRData:(unsigned char*)data PVRLen:(NSUInteger)len
174{
175 BOOL success = FALSE;
176 PVRTexHeader *header = NULL;
177 uint32_t flags, pvrTag;
178 uint32_t dataLength = 0, dataOffset = 0, dataSize = 0;
179 uint32_t blockSize = 0, widthBlocks = 0, heightBlocks = 0;
180 uint32_t width = 0, height = 0, bpp = 4;
181 uint8_t *bytes = NULL;
182 uint32_t formatFlags;
183
184 header = (PVRTexHeader *)data;
185
186 pvrTag = CFSwapInt32LittleToHost(header->pvrTag);
187
188 if ((uint32_t)gPVRTexIdentifier[0] != ((pvrTag >> 0) & 0xff) ||
189 (uint32_t)gPVRTexIdentifier[1] != ((pvrTag >> 8) & 0xff) ||
190 (uint32_t)gPVRTexIdentifier[2] != ((pvrTag >> 16) & 0xff) ||
191 (uint32_t)gPVRTexIdentifier[3] != ((pvrTag >> 24) & 0xff))
192 {
193 return FALSE;
194 }
195
196 CCConfiguration *configuration = [CCConfiguration sharedConfiguration];
197
198 flags = CFSwapInt32LittleToHost(header->flags);
199 formatFlags = flags & PVR_TEXTURE_FLAG_TYPE_MASK;
200 BOOL flipped = flags & kPVRTextureFlagVerticalFlip;
201 if( flipped )
202 CCLOG(@"cocos2d: WARNING: Image is flipped. Regenerate it using PVRTexTool");
203
204 if( ! [configuration supportsNPOT] &&
205 ( header->width != ccNextPOT(header->width) || header->height != ccNextPOT(header->height ) ) ) {
206 CCLOG(@"cocos2d: ERROR: Loding an NPOT texture (%dx%d) but is not supported on this device", header->width, header->height);
207 return FALSE;
208 }
209
210 for( tableFormatIndex_=0; tableFormatIndex_ < (unsigned int)MAX_TABLE_ELEMENTS ; tableFormatIndex_++) {
211 if( tableFormats[tableFormatIndex_][kCCInternalPVRTextureFormat] == formatFlags ) {
212
213 numberOfMipmaps_ = 0;
214
215 width_ = width = CFSwapInt32LittleToHost(header->width);
216 height_ = height = CFSwapInt32LittleToHost(header->height);
217
218 if (CFSwapInt32LittleToHost(header->bitmaskAlpha))
219 hasAlpha_ = TRUE;
220 else
221 hasAlpha_ = FALSE;
222
223 dataLength = CFSwapInt32LittleToHost(header->dataLength);
224 bytes = ((uint8_t *)data) + sizeof(PVRTexHeader);
225 format_ = tableFormats[tableFormatIndex_][kCCInternalCCTexture2DPixelFormat];
226 bpp = tableFormats[tableFormatIndex_][kCCInternalBPP];
227
228 // Calculate the data size for each texture level and respect the minimum number of blocks
229 while (dataOffset < dataLength)
230 {
231 switch (formatFlags) {
232 case kPVRTexturePixelTypePVRTC_2:
233 blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
234 widthBlocks = width / 8;
235 heightBlocks = height / 4;
236 break;
237 case kPVRTexturePixelTypePVRTC_4:
238 blockSize = 4 * 4; // Pixel by pixel block size for 4bpp
239 widthBlocks = width / 4;
240 heightBlocks = height / 4;
241 break;
242 case kPVRTexturePixelTypeBGRA_8888:
243 if( ! [[CCConfiguration sharedConfiguration] supportsBGRA8888] ) {
244 CCLOG(@"cocos2d: TexturePVR. BGRA8888 not supported on this device");
245 return FALSE;
246 }
247 default:
248 blockSize = 1;
249 widthBlocks = width;
250 heightBlocks = height;
251 break;
252 }
253
254 // Clamp to minimum number of blocks
255 if (widthBlocks < 2)
256 widthBlocks = 2;
257 if (heightBlocks < 2)
258 heightBlocks = 2;
259
260 dataSize = widthBlocks * heightBlocks * ((blockSize * bpp) / 8);
261 float packetLength = (dataLength-dataOffset);
262 packetLength = packetLength > dataSize ? dataSize : packetLength;
263
264 mipmaps_[numberOfMipmaps_].address = bytes+dataOffset;
265 mipmaps_[numberOfMipmaps_].len = packetLength;
266 numberOfMipmaps_++;
267
268 NSAssert( numberOfMipmaps_ < CC_PVRMIPMAP_MAX, @"TexturePVR: Maximum number of mimpaps reached. Increate the CC_PVRMIPMAP_MAX value");
269
270 dataOffset += packetLength;
271
272 width = MAX(width >> 1, 1);
273 height = MAX(height >> 1, 1);
274 }
275
276 success = TRUE;
277 break;
278 }
279 }
280
281 if( ! success )
282 CCLOG(@"cocos2d: WARNING: Unsupported PVR Pixel Format: 0x%2x. Re-encode it with a OpenGL pixel format variant", formatFlags);
283
284 return success;
285}
286
287
288- (BOOL)createGLTexture
289{
290 GLsizei width = width_;
291 GLsizei height = height_;
292 GLenum err;
293
294 if (numberOfMipmaps_ > 0)
295 {
296 if (name_ != 0)
297 glDeleteTextures(1, &name_);
298
299 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
300 glGenTextures(1, &name_);
301 glBindTexture(GL_TEXTURE_2D, name_);
302 }
303
304 CHECK_GL_ERROR(); // clean possible GL error
305
306 // Generate textures with mipmaps
307 for (GLint i=0; i < numberOfMipmaps_; i++)
308 {
309 GLenum internalFormat = tableFormats[tableFormatIndex_][kCCInternalOpenGLInternalFormat];
310 GLenum format = tableFormats[tableFormatIndex_][kCCInternalOpenGLFormat];
311 GLenum type = tableFormats[tableFormatIndex_][kCCInternalOpenGLType];
312 BOOL compressed = tableFormats[tableFormatIndex_][kCCInternalCompressedImage];
313
314 if( compressed && ! [[CCConfiguration sharedConfiguration] supportsPVRTC] ) {
315 CCLOG(@"cocos2d: WARNING: PVRTC images are not supported");
316 return FALSE;
317 }
318
319 unsigned char *data = mipmaps_[i].address;
320 unsigned int datalen = mipmaps_[i].len;
321
322 if( compressed)
323 glCompressedTexImage2D(GL_TEXTURE_2D, i, internalFormat, width, height, 0, datalen, data);
324 else
325 glTexImage2D(GL_TEXTURE_2D, i, internalFormat, width, height, 0, format, type, data);
326
327 if( i > 0 && (width != height || ccNextPOT(width) != width ) )
328 CCLOG(@"cocos2d: TexturePVR. WARNING. Mipmap level %u is not squared. Texture won't render correctly. width=%u != height=%u", i, width, height);
329
330 err = glGetError();
331 if (err != GL_NO_ERROR)
332 {
333 CCLOG(@"cocos2d: TexturePVR: Error uploading compressed texture level: %u . glError: 0x%04X", i, err);
334 return FALSE;
335 }
336
337 width = MAX(width >> 1, 1);
338 height = MAX(height >> 1, 1);
339 }
340
341 return TRUE;
342}
343
344
345- (id)initWithContentsOfFile:(NSString *)path
346{
347 if((self = [super init]))
348 {
349 unsigned char *pvrdata = NULL;
350 NSInteger pvrlen = 0;
351 NSString *lowerCase = [path lowercaseString];
352
353 if ( [lowerCase hasSuffix:@".ccz"])
354 pvrlen = ccInflateCCZFile( [path UTF8String], &pvrdata );
355
356 else if( [lowerCase hasSuffix:@".gz"] )
357 pvrlen = ccInflateGZipFile( [path UTF8String], &pvrdata );
358
359 else
360 pvrlen = ccLoadFileIntoMemory( [path UTF8String], &pvrdata );
361
362 if( pvrlen < 0 ) {
363 [self release];
364 return nil;
365 }
366
367
368 numberOfMipmaps_ = 0;
369
370 name_ = 0;
371 width_ = height_ = 0;
372 tableFormatIndex_ = -1;
373 hasAlpha_ = FALSE;
374
375 retainName_ = NO; // cocos2d integration
376
377 if( ! [self unpackPVRData:pvrdata PVRLen:pvrlen] || ![self createGLTexture] ) {
378 free(pvrdata);
379 [self release];
380 return nil;
381 }
382
383 free(pvrdata);
384 }
385
386 return self;
387}
388
389- (id)initWithContentsOfURL:(NSURL *)url
390{
391 if (![url isFileURL])
392 {
393 CCLOG(@"cocos2d: CCPVRTexture: Only files are supported");
394 [self release];
395 return nil;
396 }
397
398 return [self initWithContentsOfFile:[url path]];
399}
400
401
402+ (id)pvrTextureWithContentsOfFile:(NSString *)path
403{
404 return [[[self alloc] initWithContentsOfFile:path] autorelease];
405}
406
407
408+ (id)pvrTextureWithContentsOfURL:(NSURL *)url
409{
410 if (![url isFileURL])
411 return nil;
412
413 return [CCTexturePVR pvrTextureWithContentsOfFile:[url path]];
414}
415
416
417- (void)dealloc
418{
419 CCLOGINFO( @"cocos2d: deallocing %@", self);
420
421 if (name_ != 0 && ! retainName_ )
422 glDeleteTextures(1, &name_);
423
424 [super dealloc];
425}
426
427@end
428