PDA

View Full Version : OpenGL screenshot


rogue
2003.09.26, 05:15 PM
Hi all, I'd like to add the possibility to take screenshots to my little OpenGL app, but I can't figure out how to do that. Generally I have no Idea whatsoever when it comes to save things to files... really I must have been creating completely useless software so far :rolleyes:

KittyMac
2003.09.26, 05:33 PM
Greetings,

Use glReadPixels() to capture the rendered buffer, then reformat the data and save it to a file in the image format you're most comfortable with (I use targa's, mostly because I use them for input as well, check out NEHE's tutorials for information on the format of targa files).

Cheers,
Rocco

Jake
2003.09.26, 05:41 PM
Hit command shift 3, sometimes it doesn't work with GL games or DivX movies, so make sure the scene is static

MacFiend
2003.09.26, 08:00 PM
The follow group of functions allow you to write the pixels of the current OpenGL context to a TIFF image. It may have to be tweaked to suit your code.


-(void)saveSnapshotToFile:(NSString*)filePath
{
NSBitmapImageRep * bitmap;
GLint viewport[4];
long bytewidth;
GLint width, height;
long bytes;

glReadBuffer(GL_FRONT);
glGetIntegerv(GL_VIEWPORT, viewport);

width = viewport[2];
height = viewport[3];

bytewidth = width * 4;
bytewidth = (bytewidth + 3) & ~3;
bytes = bytewidth * height;

bitmap = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL
pixelsWide:width
pixelsHigh:height
bitsPerSample:8
samplesPerPixel:3
hasAlpha:NO
isPlanar:NO
colorSpaceName:NSDeviceRGBColorSpace
bytesPerRow:bytewidth
bitsPerPixel:8 * 4];

glFinish();
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
glPixelStorei(GL_PACK_SKIP_ROWS, 0);
glPixelStorei(GL_PACK_SKIP_PIXELS, 0);


glReadPixels(0, 0, width, height,
GL_BGRA,
GL_UNSIGNED_INT_8_8_8_8_REV,
[bitmap bitmapData]);

swizzleBitmap(bitmap);

NSData * tiff;

if (bitmap == NULL)
return;

tiff = [bitmap TIFFRepresentation];
[tiff writeToFile:filePath atomically:YES];
}

static inline void swapcopy32(void * src, void * dst, int bytecount )
{
uint32_t *srcP;
uint32_t *dstP;
uint32_t p0, p1, p2, p3;
uint32_t u0, u1, u2, u3;

srcP = src;
dstP = dst;
#define SWAB_PIXEL(p) (((p) << 8) | ((p) >> 24))

while ( bytecount >= 16 )
{
p3 = srcP[3];
p2 = srcP[2];
p1 = srcP[1];
p0 = srcP[0];

u3 = SWAB_PIXEL(p3);
u2 = SWAB_PIXEL(p2);
u1 = SWAB_PIXEL(p1);
u0 = SWAB_PIXEL(p0);
srcP += 4;

dstP[3] = u3;
dstP[2] = u2;
dstP[1] = u1;
dstP[0] = u0;
bytecount -= 16;
dstP += 4;
}
while ( bytecount >= 4 )
{
p0 = *srcP++;
bytecount -= 4;
*dstP++ = SWAB_PIXEL(p0);
}
}

static void swizzleBitmap(NSBitmapImageRep * bitmap)
{
int top, bottom;
void * buffer;
void * topP;
void * bottomP;
void * base;
int rowBytes;

rowBytes = [bitmap bytesPerRow];
top = 0;
bottom = [bitmap pixelsHigh] - 1;
base = [bitmap bitmapData];
buffer = malloc(rowBytes);

while ( top < bottom )
{
topP = (top * rowBytes) + base;
bottomP = (bottom * rowBytes) + base;

swapcopy32( topP, buffer, rowBytes );
swapcopy32( bottomP, topP, rowBytes );
bcopy( buffer, bottomP, rowBytes );

++top;
--bottom;
}
free( buffer );
}

Mars_999
2003.09.27, 12:20 AM
Be aware glReadPixels() is slow.

David
2003.09.27, 01:24 AM
But faster than the alternative, i.e. pausing the game and painting everything you see on a piece of canvas

rogue
2003.09.27, 08:59 AM
to be honest, I haven't yet found my way around cocoa or obj-c. my whole code is basically the cocoa-app template, but without the nib or main.m files. GLUT handles all the windowing stuff, and all my drawing and interaction functions. its all written in plain C. I don't think I can use all these fancy cocoa NSBitmap things without major overhaul of the whole thing, which is not what I really want to do.

I think a library which makes such tasks like saving a frame to a picture would be the most straightforward way, or am I wrong?

Steven
2003.09.27, 10:43 AM
You don't even have to deal with NSBitmap, all you have to do is call saveSnapshotToBuffer, with an NSString.

MacFiend
2003.09.27, 01:10 PM
Yes, calling that function for each and every frame will drastically hamper your frame rate. It's meant as a snapshot function, not a recording function. If you want to record, then you'd probably do what Steven suggested: save all the data to a buffer, then dump the buffer into images/movie whenever the animation is done (or when memory is full).

Sta7ic
2003.09.27, 03:44 PM
If you're running GLUT, just select File/Save As...
Kudos to Smashspeak for finding that oddity out.

-"Sta7ic" Matt

rogue
2003.09.27, 04:36 PM
thats cool... GLUT, eh?! ;)

MacFiend
2003.09.30, 01:27 PM
Wow, that really is odd. I never expected it to be able to do that.