Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Capturing Isgl3d output as image

I am having a pile of difficulties taking a UIImage snapshot of a Isgl3d controlled view. Seems whatever I do, I just end up with a black square.

I have a working camera view and a 3d model in my view, I try with both buffer methods and regular screen captures to get a image out of it, but without any fruitful result.

Does anyone have some source code where they successfully take a picture of a Isgl3d view ?

like image 325
Nils Munch Avatar asked Feb 27 '12 00:02

Nils Munch


2 Answers

Is this what you want ?

This will take a screenshot from the current context and framebuffer and save it to the photo album.

If you don't want to save to the photo album just get the resulting UIImage at the end.

Also remember to call this only after you've finished drawing, but before switching buffers.

Also if you're using MSAA, this has to be called after glResolveMultisampleFramebufferAPPLE and the new buffer bind.

#ifdef AUTOSCREENSHOT

// callback for CGDataProviderCreateWithData
void releaseData(void *info, const void *data, size_t dataSize) {
    free((void*)data);
}

// callback for UIImageWriteToSavedPhotosAlbum
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
    NSLog(@"Save finished");
    [image release];
}

-(void)saveCurrentScreenToPhotoAlbum {
    int height = (int)screenSize.y*retina;
    int width = (int)screenSize.x*retina;

    NSInteger myDataLength = width * height * 4;
    GLubyte *buffer = (GLubyte *) malloc(myDataLength);
    GLubyte *buffer2 = (GLubyte *) malloc(myDataLength);
    glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
    for(int y = 0; y <height; y++) {
        for(int x = 0; x < width * 4; x++) {
            buffer2[(int)((height - 1 - y) * width * 4 + x)] = buffer[(int)(y * 4 * width + x)];
        }
    }
    free(buffer);   

    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer2, myDataLength, releaseData);
    int bitsPerComponent = 8;
    int bitsPerPixel = 32;
    int bytesPerRow = 4 * width;
    CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
    CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
    CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
    CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

    CGColorSpaceRelease(colorSpaceRef);
    CGDataProviderRelease(provider);

    UIImage *image = [[UIImage alloc] initWithCGImage:imageRef];
    CGImageRelease(imageRef);

    UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}

#endif

I use this code to save timed screenshots while I'm playing so I have god material to put in the app store.

like image 27
led42 Avatar answered Oct 04 '22 20:10

led42


Here are Apple's instructions & official code for snapshotting a GL view to a UIImage (takes into account retina displays, flipped coords, etc) and I've been using it successfully. This isn't iSGL3D-specific, of course, but as long as you can get the right context and framebuffer to bind to, it should do the right thing. (As the page notes, you must be sure to take the snapshot before a -presentRenderbuffer: is called so the renderbuffer is valid.)

https://developer.apple.com/library/ios/#qa/qa1704/_index.html

I have only a cursory familiarity with the iSGL3D library, and it doesn't look like there are obvious hooks there to let you render the scene but not present it (or render it to an offscreen buffer first). The place where you might need to intervene is in the -finalizeRender method of the Isgl3dGLContext subclass you're using, just prior to the call to -presentRenderbuffer call. That context is an internal framework class here, so you might need to shuffle things around a little bit within the library to set up (say) a delegate from the context that works back out of the view and the director to eventually ask your app to take any action just prior to the "present" call, during which you could choose to run the screenshot code if you wanted to, or do nothing if you didn't want to.

like image 62
Ben Zotto Avatar answered Oct 04 '22 21:10

Ben Zotto