iosuiimageeaglview

convert multiple EAGLView to UIImage


I've got an UITableView with 3 EAGLView inside each cell, where the user is able to draw something (following apple GLPaint, i'm just using PaintingView class from that example)

I'm trying to convert this 3 EAGLView to 3 distinct UIImage on button pressure event, but the generated UIImages are always equal to the last EAGLView edited

this is the code I'm using (copied from here):

- (UIImage*)saveImageFromGLView:(UIView *)glView withName:(NSString *)name{

if(glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
{
    /// This IS being activated with code 0
    NSLog(@"failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
}

int s = 1;
UIScreen* screen = [ UIScreen mainScreen ];
if ( [ screen respondsToSelector:@selector(scale) ] )
    s = (int) [ screen scale ];

const int w = self.frame.size.width;
const int h = self.frame.size.height;
const NSInteger myDataLength = w * h * 4 * s * s;
// allocate array and read pixels into it.
GLubyte *buffer = (GLubyte *) malloc(myDataLength);
glReadPixels(0, 0, w*s, h*s, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
// gl renders "upside down" so swap top to bottom into new array.
// there's gotta be a better way, but this works.
GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
for(int y = 0; y < h*s; y++)
{
    memcpy( buffer2 + (h*s - 1 - y) * w * 4 * s, buffer + (y * 4 * w * s), w * 4 * s );
}
free(buffer); // work with the flipped buffer, so get rid of the original one.

// make data provider with data.
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, NULL);
// prep the ingredients
int bitsPerComponent = 8;
int bitsPerPixel = 32;
int bytesPerRow = 4 * w * s;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
// make the cgimage
CGImageRef imageRef = CGImageCreate(w*s, h*s, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);
// then make the uiimage from that
UIImage *myImage = [ UIImage imageWithCGImage:imageRef scale:s orientation:UIImageOrientationUp ];

// Create path.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:name];

// Save image.
[UIImagePNGRepresentation(myImage) writeToFile:filePath atomically:YES];

CGImageRelease( imageRef );
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorSpaceRef);
free(buffer2);

return myImage;
}

I think it's a context problem, how could I obtain three distinct images?


Solution

  • Assuming that you're using retained backing for these views (otherwise glReadPixels() doesn't work after you've presented to the screen), my guess is that you have a different OpenGL ES context for each view. glReadPixels() will only pull from the currently active context, and thus the last view that was rendered.

    Before you read from each view's context in the method above, you'll want to use code like the following:

    [EAGLContext setCurrentContext:context];
    

    where context is pulled from your OpenGL ES rendering UIView. You'll probably want to make that context a read-only property on your UIView subclass, and then change the above method to take in that subclass. You can then switch to the appropriate context before using glReadPixels().

    As a side issue, you shouldn't be using glCheckFramebufferStatusOES() in the above. That only really belongs in your framebuffer creation code, and serves no real purpose in your above method.