summary refs log tree commit diff stats
path: root/libs/cocos2d/CCRenderTexture.m
diff options
context:
space:
mode:
Diffstat (limited to 'libs/cocos2d/CCRenderTexture.m')
-rwxr-xr-xlibs/cocos2d/CCRenderTexture.m340
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