Created
January 13, 2012 14:09
-
-
Save rainerkohlberger/1606382 to your computer and use it in GitHub Desktop.
OpenGL ES snapshot for openFrameworks, Apple implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void ofxiPhoneScreenGrab(id delegate) { | |
// Technical Q&A QA1704 | |
// How do I take a snapshot of my OpenGL ES view and save the result in a UIImage? | |
// http://developer.apple.com/library/ios/#qa/qa1704/_index.html | |
GLint backingWidth, backingHeight; | |
// Bind the color renderbuffer used to render the OpenGL ES view | |
// If your application only creates a single color renderbuffer which is already bound at this point, | |
// this call is redundant, but it is needed if you're dealing with multiple renderbuffers. | |
// Note, replace "_colorRenderbuffer" with the actual name of the renderbuffer object defined in your class. | |
//glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer); | |
// http://stackoverflow.com/questions/6869577/problem-in-reading-data-using-glreadpixel | |
// http://stackoverflow.com/questions/7402504/multisampled-render-to-texture-in-ios | |
// not working | |
GLuint sampleFramebuffer, framebuffer; | |
glGenFramebuffersOES(1, &sampleFramebuffer); | |
glGenFramebuffersOES(1, &framebuffer); | |
glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, sampleFramebuffer); | |
glBindFramebufferOES(GL_DRAW_FRAMEBUFFER_APPLE, framebuffer); | |
glResolveMultisampleFramebufferAPPLE(); | |
NSLog(@"resolve 0x%x", glGetError()); // 0x0506 GL_INVALID_FRAMEBUFFER_OPERATION | |
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer); | |
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ; | |
if(status != GL_FRAMEBUFFER_COMPLETE) { | |
NSLog(@"failed to make complete framebuffer object %x", status); | |
} | |
// ------------- | |
// Get the size of the backing CAEAGLLayer | |
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth); | |
glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight); | |
NSInteger x = 0, y = 0, width = backingWidth, height = backingHeight; | |
NSInteger dataLength = width * height * 4; | |
GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte)); | |
// Read pixel data from the framebuffer | |
glPixelStorei(GL_PACK_ALIGNMENT, 4); | |
glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); | |
// Create a CGImage with the pixel data | |
// If your OpenGL ES content is opaque, use kCGImageAlphaNoneSkipLast to ignore the alpha channel | |
// otherwise, use kCGImageAlphaPremultipliedLast | |
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL); | |
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); | |
CGImageRef iref = CGImageCreate(width, height, 8, 32, width * 4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast, | |
ref, NULL, true, kCGRenderingIntentDefault); | |
// OpenGL ES measures data in PIXELS | |
// Create a graphics context with the target size measured in POINTS | |
NSInteger widthInPoints, heightInPoints; | |
if (NULL != UIGraphicsBeginImageContextWithOptions) { | |
// On iOS 4 and later, use UIGraphicsBeginImageContextWithOptions to take the scale into consideration | |
// Set the scale parameter to your OpenGL ES view's contentScaleFactor | |
// so that you get a high-resolution snapshot when its value is greater than 1.0 | |
//CGFloat scale = 2.0; //eaglview.contentScaleFactor; | |
CGFloat scale = [ofxiPhoneGetAppDelegate() getGLView].contentScaleFactor; | |
widthInPoints = width / scale; | |
heightInPoints = height / scale; | |
UIGraphicsBeginImageContextWithOptions(CGSizeMake(widthInPoints, heightInPoints), NO, scale); | |
} | |
else { | |
// On iOS prior to 4, fall back to use UIGraphicsBeginImageContext | |
widthInPoints = width; | |
heightInPoints = height; | |
UIGraphicsBeginImageContext(CGSizeMake(widthInPoints, heightInPoints)); | |
} | |
CGContextRef cgcontext = UIGraphicsGetCurrentContext(); | |
// UIKit coordinate system is upside down to GL/Quartz coordinate system | |
// Flip the CGImage by rendering it to the flipped bitmap context | |
// The size of the destination area is measured in POINTS | |
CGContextSetBlendMode(cgcontext, kCGBlendModeCopy); | |
CGContextDrawImage(cgcontext, CGRectMake(0.0, 0.0, widthInPoints, heightInPoints), iref); | |
// Retrieve the UIImage from the current context | |
UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); | |
// rewrap to get PNG file | |
NSData* imdata = UIImagePNGRepresentation ( image ); // get PNG representation | |
UIImage* im2 = [UIImage imageWithData:imdata]; // wrap UIImage around PNG representation | |
SaveDelegate *saveDelegate = [SaveDelegate new]; | |
saveDelegate.delegate = delegate; | |
UIImageWriteToSavedPhotosAlbum(im2, saveDelegate, @selector(image:didFinishSavingWithError:contextInfo:), nil); | |
UIGraphicsEndImageContext(); | |
// Clean up | |
free(data); | |
CFRelease(ref); | |
CFRelease(colorspace); | |
CGImageRelease(iref); | |
return image; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffers(1, &resolved_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, resolved_framebuffer);
glGenRenderbuffers(1, &resolvedColorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, resolvedColorRenderbuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glGenRenderbuffers(1, &colorRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_RGBA8_OES, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer);
glGenRenderbuffers(1, &depthRenderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderbuffer);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderbuffer);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER) ;
if(status != GL_FRAMEBUFFER_COMPLETE) {
NSLog(@"failed to make complete framebuffer object %x", status);
}
// Render my scene
glBindFramebuffer( GL_FRAMEBUFFER, framebuffer );
glViewport(0,0,width,height);
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Draw scene
// Then bind default framebuffer
glBindFramebuffer( GL_FRAMEBUFFER, 1 );
// Draw other things
// Now resolve the multisampling into the other fbo
glBindFramebuffer( GL_READ_FRAMEBUFFER_APPLE, framebuffer );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER_APPLE, resolved_framebuffer );
glResolveMultisampleFramebufferAPPLE();
glUseTexture( GL_TEXTURE_2D, texture );
// Draw with texture