diff options
Diffstat (limited to 'libs/cocos2d/CCRenderTexture.m')
| -rwxr-xr-x | libs/cocos2d/CCRenderTexture.m | 340 |
1 files changed, 340 insertions, 0 deletions
| diff --git a/libs/cocos2d/CCRenderTexture.m b/libs/cocos2d/CCRenderTexture.m new file mode 100755 index 0000000..4a4768e --- /dev/null +++ b/libs/cocos2d/CCRenderTexture.m | |||
| @@ -0,0 +1,340 @@ | |||
| 1 | /* | ||
| 2 | * cocos2d for iPhone: http://www.cocos2d-iphone.org | ||
| 3 | * | ||
| 4 | * Copyright (c) 2009 Jason Booth | ||
| 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 | |||
| 26 | #import <Availability.h> | ||
| 27 | #import "CCRenderTexture.h" | ||
| 28 | #import "CCDirector.h" | ||
| 29 | #import "ccMacros.h" | ||
| 30 | #import "Support/ccUtils.h" | ||
| 31 | #import "Support/CCFileUtils.h" | ||
| 32 | |||
| 33 | @implementation CCRenderTexture | ||
| 34 | |||
| 35 | @synthesize sprite=sprite_; | ||
| 36 | |||
| 37 | // issue #994 | ||
| 38 | +(id)renderTextureWithWidth:(int)w height:(int)h pixelFormat:(CCTexture2DPixelFormat) format | ||
| 39 | { | ||
| 40 | return [[[self alloc] initWithWidth:w height:h pixelFormat:format] autorelease]; | ||
| 41 | } | ||
| 42 | |||
| 43 | +(id)renderTextureWithWidth:(int)w height:(int)h | ||
| 44 | { | ||
| 45 | return [[[self alloc] initWithWidth:w height:h pixelFormat:kCCTexture2DPixelFormat_RGBA8888] autorelease]; | ||
| 46 | } | ||
| 47 | |||
| 48 | -(id)initWithWidth:(int)w height:(int)h | ||
| 49 | { | ||
| 50 | return [self initWithWidth:w height:h pixelFormat:kCCTexture2DPixelFormat_RGBA8888]; | ||
| 51 | } | ||
| 52 | |||
| 53 | -(id)initWithWidth:(int)w height:(int)h pixelFormat:(CCTexture2DPixelFormat) format | ||
| 54 | { | ||
| 55 | if ((self = [super init])) | ||
| 56 | { | ||
| 57 | NSAssert(format != kCCTexture2DPixelFormat_A8,@"only RGB and RGBA formats are valid for a render texture"); | ||
| 58 | |||
| 59 | w *= CC_CONTENT_SCALE_FACTOR(); | ||
| 60 | h *= CC_CONTENT_SCALE_FACTOR(); | ||
| 61 | |||
| 62 | glGetIntegerv(CC_GL_FRAMEBUFFER_BINDING, &oldFBO_); | ||
| 63 | |||
| 64 | // textures must be power of two | ||
| 65 | NSUInteger powW = ccNextPOT(w); | ||
| 66 | NSUInteger powH = ccNextPOT(h); | ||
| 67 | |||
| 68 | void *data = malloc((int)(powW * powH * 4)); | ||
| 69 | memset(data, 0, (int)(powW * powH * 4)); | ||
| 70 | pixelFormat_=format; | ||
| 71 | |||
| 72 | texture_ = [[CCTexture2D alloc] initWithData:data pixelFormat:pixelFormat_ pixelsWide:powW pixelsHigh:powH contentSize:CGSizeMake(w, h)]; | ||
| 73 | free( data ); | ||
| 74 | |||
| 75 | // generate FBO | ||
| 76 | ccglGenFramebuffers(1, &fbo_); | ||
| 77 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, fbo_); | ||
| 78 | |||
| 79 | // associate texture with FBO | ||
| 80 | ccglFramebufferTexture2D(CC_GL_FRAMEBUFFER, CC_GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_.name, 0); | ||
| 81 | |||
| 82 | // check if it worked (probably worth doing :) ) | ||
| 83 | GLuint status = ccglCheckFramebufferStatus(CC_GL_FRAMEBUFFER); | ||
| 84 | if (status != CC_GL_FRAMEBUFFER_COMPLETE) | ||
| 85 | { | ||
| 86 | [NSException raise:@"Render Texture" format:@"Could not attach texture to framebuffer"]; | ||
| 87 | } | ||
| 88 | [texture_ setAliasTexParameters]; | ||
| 89 | |||
| 90 | sprite_ = [CCSprite spriteWithTexture:texture_]; | ||
| 91 | |||
| 92 | [texture_ release]; | ||
| 93 | [sprite_ setScaleY:-1]; | ||
| 94 | [self addChild:sprite_]; | ||
| 95 | |||
| 96 | // issue #937 | ||
| 97 | [sprite_ setBlendFunc:(ccBlendFunc){GL_ONE, GL_ONE_MINUS_SRC_ALPHA}]; | ||
| 98 | |||
| 99 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, oldFBO_); | ||
| 100 | } | ||
| 101 | return self; | ||
| 102 | } | ||
| 103 | |||
| 104 | -(void)dealloc | ||
| 105 | { | ||
| 106 | // [self removeAllChildrenWithCleanup:YES]; | ||
| 107 | ccglDeleteFramebuffers(1, &fbo_); | ||
| 108 | [super dealloc]; | ||
| 109 | } | ||
| 110 | |||
| 111 | -(void)begin | ||
| 112 | { | ||
| 113 | // Save the current matrix | ||
| 114 | glPushMatrix(); | ||
| 115 | |||
| 116 | CGSize texSize = [texture_ contentSizeInPixels]; | ||
| 117 | |||
| 118 | |||
| 119 | // Calculate the adjustment ratios based on the old and new projections | ||
| 120 | CGSize size = [[CCDirector sharedDirector] displaySizeInPixels]; | ||
| 121 | float widthRatio = size.width / texSize.width; | ||
| 122 | float heightRatio = size.height / texSize.height; | ||
| 123 | |||
| 124 | |||
| 125 | // Adjust the orthographic propjection and viewport | ||
| 126 | ccglOrtho((float)-1.0 / widthRatio, (float)1.0 / widthRatio, (float)-1.0 / heightRatio, (float)1.0 / heightRatio, -1,1); | ||
| 127 | glViewport(0, 0, texSize.width, texSize.height); | ||
| 128 | |||
| 129 | |||
| 130 | glGetIntegerv(CC_GL_FRAMEBUFFER_BINDING, &oldFBO_); | ||
| 131 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, fbo_);//Will direct drawing to the frame buffer created above | ||
| 132 | |||
| 133 | // Issue #1145 | ||
| 134 | // There is no need to enable the default GL states here | ||
| 135 | // but since CCRenderTexture is mostly used outside the "render" loop | ||
| 136 | // these states needs to be enabled. | ||
| 137 | // Since this bug was discovered in API-freeze (very close of 1.0 release) | ||
| 138 | // This bug won't be fixed to prevent incompatibilities with code. | ||
| 139 | // | ||
| 140 | // If you understand the above mentioned message, then you can comment the following line | ||
| 141 | // and enable the gl states manually, in case you need them. | ||
| 142 | CC_ENABLE_DEFAULT_GL_STATES(); | ||
| 143 | } | ||
| 144 | |||
| 145 | -(void)beginWithClear:(float)r g:(float)g b:(float)b a:(float)a | ||
| 146 | { | ||
| 147 | [self begin]; | ||
| 148 | |||
| 149 | // save clear color | ||
| 150 | GLfloat clearColor[4]; | ||
| 151 | glGetFloatv(GL_COLOR_CLEAR_VALUE,clearColor); | ||
| 152 | |||
| 153 | glClearColor(r, g, b, a); | ||
| 154 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||
| 155 | |||
| 156 | // restore clear color | ||
| 157 | glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]); | ||
| 158 | } | ||
| 159 | |||
| 160 | -(void)end | ||
| 161 | { | ||
| 162 | ccglBindFramebuffer(CC_GL_FRAMEBUFFER, oldFBO_); | ||
| 163 | // Restore the original matrix and viewport | ||
| 164 | glPopMatrix(); | ||
| 165 | CGSize size = [[CCDirector sharedDirector] displaySizeInPixels]; | ||
| 166 | glViewport(0, 0, size.width, size.height); | ||
| 167 | } | ||
| 168 | |||
| 169 | -(void)clear:(float)r g:(float)g b:(float)b a:(float)a | ||
| 170 | { | ||
| 171 | [self beginWithClear:r g:g b:b a:a]; | ||
| 172 | [self end]; | ||
| 173 | } | ||
| 174 | |||
| 175 | #pragma mark RenderTexture - Save Image | ||
| 176 | |||
| 177 | #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED | ||
| 178 | -(BOOL)saveBuffer:(NSString*)name | ||
| 179 | { | ||
| 180 | return [self saveBuffer:name format:kCCImageFormatJPG]; | ||
| 181 | } | ||
| 182 | |||
| 183 | -(BOOL)saveBuffer:(NSString*)fileName format:(int)format | ||
| 184 | { | ||
| 185 | NSString *fullPath = [CCFileUtils fullPathFromRelativePath:fileName]; | ||
| 186 | |||
| 187 | NSData *data = [self getUIImageAsDataFromBuffer:format]; | ||
| 188 | |||
| 189 | return [data writeToFile:fullPath atomically:YES]; | ||
| 190 | } | ||
| 191 | |||
| 192 | /* get buffer as UIImage */ | ||
| 193 | -(UIImage *)getUIImageFromBuffer | ||
| 194 | { | ||
| 195 | NSAssert(pixelFormat_ == kCCTexture2DPixelFormat_RGBA8888,@"only RGBA8888 can be saved as image"); | ||
| 196 | |||
| 197 | CGSize s = [texture_ contentSizeInPixels]; | ||
| 198 | int tx = s.width; | ||
| 199 | int ty = s.height; | ||
| 200 | |||
| 201 | int bitsPerComponent = 8; | ||
| 202 | int bitsPerPixel = 32; | ||
| 203 | int bytesPerPixel = (bitsPerComponent * 4)/8; | ||
| 204 | int bytesPerRow = bytesPerPixel * tx; | ||
| 205 | NSInteger myDataLength = bytesPerRow * ty; | ||
| 206 | |||
| 207 | NSMutableData *buffer = [[NSMutableData alloc] initWithCapacity:myDataLength]; | ||
| 208 | NSMutableData *pixels = [[NSMutableData alloc] initWithCapacity:myDataLength]; | ||
| 209 | |||
| 210 | if( ! (buffer && pixels) ) { | ||
| 211 | CCLOG(@"cocos2d: CCRenderTexture#getUIImageFromBuffer: not enough memory"); | ||
| 212 | [buffer release]; | ||
| 213 | [pixels release]; | ||
| 214 | return nil; | ||
| 215 | } | ||
| 216 | |||
| 217 | [self begin]; | ||
| 218 | glReadPixels(0,0,tx,ty,GL_RGBA,GL_UNSIGNED_BYTE, [buffer mutableBytes]); | ||
| 219 | [self end]; | ||
| 220 | |||
| 221 | // make data provider with data. | ||
| 222 | |||
| 223 | CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault; | ||
| 224 | CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, [buffer mutableBytes], myDataLength, NULL); | ||
| 225 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); | ||
| 226 | CGImageRef iref = CGImageCreate(tx, ty, | ||
| 227 | bitsPerComponent, bitsPerPixel, bytesPerRow, | ||
| 228 | colorSpaceRef, bitmapInfo, provider, | ||
| 229 | NULL, false, | ||
| 230 | kCGRenderingIntentDefault); | ||
| 231 | |||
| 232 | CGContextRef context = CGBitmapContextCreate([pixels mutableBytes], tx, | ||
| 233 | ty, CGImageGetBitsPerComponent(iref), | ||
| 234 | CGImageGetBytesPerRow(iref), CGImageGetColorSpace(iref), | ||
| 235 | bitmapInfo); | ||
| 236 | CGContextTranslateCTM(context, 0.0f, ty); | ||
| 237 | CGContextScaleCTM(context, 1.0f, -1.0f); | ||
| 238 | CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, tx, ty), iref); | ||
| 239 | CGImageRef outputRef = CGBitmapContextCreateImage(context); | ||
| 240 | UIImage* image = [[UIImage alloc] initWithCGImage:outputRef]; | ||
| 241 | |||
| 242 | CGImageRelease(iref); | ||
| 243 | CGContextRelease(context); | ||
| 244 | CGColorSpaceRelease(colorSpaceRef); | ||
| 245 | CGDataProviderRelease(provider); | ||
| 246 | CGImageRelease(outputRef); | ||
| 247 | |||
| 248 | [pixels release]; | ||
| 249 | [buffer release]; | ||
| 250 | |||
| 251 | return [image autorelease]; | ||
| 252 | } | ||
| 253 | |||
| 254 | -(NSData*)getUIImageAsDataFromBuffer:(int) format | ||
| 255 | { | ||
| 256 | NSAssert(pixelFormat_ == kCCTexture2DPixelFormat_RGBA8888,@"only RGBA8888 can be saved as image"); | ||
| 257 | |||
| 258 | CGSize s = [texture_ contentSizeInPixels]; | ||
| 259 | int tx = s.width; | ||
| 260 | int ty = s.height; | ||
| 261 | |||
| 262 | int bitsPerComponent=8; | ||
| 263 | int bitsPerPixel=32; | ||
| 264 | |||
| 265 | int bytesPerRow = (bitsPerPixel/8) * tx; | ||
| 266 | NSInteger myDataLength = bytesPerRow * ty; | ||
| 267 | |||
| 268 | GLubyte *buffer = malloc(sizeof(GLubyte)*myDataLength); | ||
| 269 | GLubyte *pixels = malloc(sizeof(GLubyte)*myDataLength); | ||
| 270 | |||
| 271 | if( ! (buffer && pixels) ) { | ||
| 272 | CCLOG(@"cocos2d: CCRenderTexture#getUIImageFromBuffer: not enough memory"); | ||
| 273 | free(buffer); | ||
| 274 | free(pixels); | ||
| 275 | return nil; | ||
| 276 | } | ||
| 277 | |||
| 278 | [self begin]; | ||
| 279 | glReadPixels(0,0,tx,ty,GL_RGBA,GL_UNSIGNED_BYTE, buffer); | ||
| 280 | [self end]; | ||
| 281 | |||
| 282 | int x,y; | ||
| 283 | |||
| 284 | for(y = 0; y <ty; y++) { | ||
| 285 | for(x = 0; x <tx * 4; x++) { | ||
| 286 | pixels[((ty - 1 - y) * tx * 4 + x)] = buffer[(y * 4 * tx + x)]; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | NSData* data; | ||
| 291 | |||
| 292 | if (format == kCCImageFormatRawData) | ||
| 293 | { | ||
| 294 | free(buffer); | ||
| 295 | //data frees buffer when it is deallocated | ||
| 296 | data = [NSData dataWithBytesNoCopy:pixels length:myDataLength]; | ||
| 297 | |||
| 298 | } else { | ||
| 299 | |||
| 300 | /* | ||
| 301 | CGImageCreate(size_t width, size_t height, | ||
| 302 | size_t bitsPerComponent, size_t bitsPerPixel, size_t bytesPerRow, | ||
| 303 | CGColorSpaceRef space, CGBitmapInfo bitmapInfo, CGDataProviderRef provider, | ||
| 304 | const CGFloat decode[], bool shouldInterpolate, | ||
| 305 | CGColorRenderingIntent intent) | ||
| 306 | */ | ||
| 307 | // make data provider with data. | ||
| 308 | CGBitmapInfo bitmapInfo = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrderDefault; | ||
| 309 | CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, pixels, myDataLength, NULL); | ||
| 310 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); | ||
| 311 | CGImageRef iref = CGImageCreate(tx, ty, | ||
| 312 | bitsPerComponent, bitsPerPixel, bytesPerRow, | ||
| 313 | colorSpaceRef, bitmapInfo, provider, | ||
| 314 | NULL, false, | ||
| 315 | kCGRenderingIntentDefault); | ||
| 316 | |||
| 317 | UIImage* image = [[UIImage alloc] initWithCGImage:iref]; | ||
| 318 | |||
| 319 | CGImageRelease(iref); | ||
| 320 | CGColorSpaceRelease(colorSpaceRef); | ||
| 321 | CGDataProviderRelease(provider); | ||
| 322 | |||
| 323 | |||
| 324 | |||
| 325 | if (format == kCCImageFormatPNG) | ||
| 326 | data = UIImagePNGRepresentation(image); | ||
| 327 | else | ||
| 328 | data = UIImageJPEGRepresentation(image, 1.0f); | ||
| 329 | |||
| 330 | [image release]; | ||
| 331 | |||
| 332 | free(pixels); | ||
| 333 | free(buffer); | ||
| 334 | } | ||
| 335 | |||
| 336 | return data; | ||
| 337 | } | ||
| 338 | |||
| 339 | #endif // __IPHONE_OS_VERSION_MAX_ALLOWED | ||
| 340 | @end | ||
