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
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.
vBulletin® v3.6.8, Copyright ©2000-2008, Jelsoft Enterprises Ltd.