diff options
Diffstat (limited to 'src/renderer/tr_init.c')
-rw-r--r-- | src/renderer/tr_init.c | 215 |
1 files changed, 160 insertions, 55 deletions
diff --git a/src/renderer/tr_init.c b/src/renderer/tr_init.c index 89fcf3e3..10ea222c 100644 --- a/src/renderer/tr_init.c +++ b/src/renderer/tr_init.c @@ -152,6 +152,9 @@ cvar_t *r_saveFontData; cvar_t *r_marksOnTriangleMeshes; +cvar_t *r_aviMotionJpegQuality; +cvar_t *r_screenshotJpegQuality; + cvar_t *r_maxpolys; int max_polys; cvar_t *r_maxpolyverts; @@ -362,15 +365,62 @@ FIXME: the statics don't get a reinit between fs_game changes /* ================== +RB_ReadPixels + +Reads an image but takes care of alignment issues for reading RGB images. + +Reads a minimum offset for where the RGB data starts in the image from +integer stored at pointer offset. When the function has returned the actual +offset was written back to address offset. This address will always have an +alignment of packAlign to ensure efficient copying. + +Stores the length of padding after a line of pixels to address padlen + +Return value must be freed with ri.Hunk_FreeTempMemory() +================== +*/ + +byte *RB_ReadPixels(int x, int y, int width, int height, size_t *offset, int *padlen) +{ + byte *buffer, *bufstart; + int padwidth, linelen; + GLint packAlign; + + qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); + + linelen = width * 3; + padwidth = PAD(linelen, packAlign); + + // Allocate a few more bytes so that we can choose an alignment we like + buffer = ri.Hunk_AllocateTempMemory(padwidth * height + *offset + packAlign - 1); + + bufstart = (byte *) PAD((intptr_t) buffer + *offset, packAlign); + qglReadPixels(x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, bufstart); + + *offset = bufstart - buffer; + *padlen = padwidth - linelen; + + return buffer; +} + +/* +================== RB_TakeScreenshot ================== */ -void RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { - byte *buffer; - int i, c, temp; +void RB_TakeScreenshot(int x, int y, int width, int height, char *fileName) +{ + byte *allbuf, *buffer; + byte *srcptr, *destptr; + byte *endline, *endmem; + byte temp; + + int linelen, padlen; + size_t offset = 18, memcount; - buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*3+18); - + allbuf = RB_ReadPixels(x, y, width, height, &offset, &padlen); + buffer = allbuf + offset - 18; + Com_Memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = width & 255; @@ -379,47 +429,62 @@ void RB_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { buffer[15] = height >> 8; buffer[16] = 24; // pixel size - qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); + // swap rgb to bgr and remove padding from line endings + linelen = width * 3; + + srcptr = destptr = allbuf + offset; + endmem = srcptr + (linelen + padlen) * height; + + while(srcptr < endmem) + { + endline = srcptr + linelen; - // swap rgb to bgr - c = 18 + width * height * 3; - for (i=18 ; i<c ; i+=3) { - temp = buffer[i]; - buffer[i] = buffer[i+2]; - buffer[i+2] = temp; + while(srcptr < endline) + { + temp = srcptr[0]; + *destptr++ = srcptr[2]; + *destptr++ = srcptr[1]; + *destptr++ = temp; + + srcptr += 3; + } + + // Skip the pad + srcptr += padlen; } + memcount = linelen * height; + // gamma correct - if ( glConfig.deviceSupportsGamma ) { - R_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 ); - } + if(glConfig.deviceSupportsGamma) + R_GammaCorrect(allbuf + offset, memcount); - ri.FS_WriteFile( fileName, buffer, c ); + ri.FS_WriteFile(fileName, buffer, memcount + 18); - ri.Hunk_FreeTempMemory( buffer ); + ri.Hunk_FreeTempMemory(allbuf); } /* ================== RB_TakeScreenshotJPEG ================== -*/ -void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) { - byte *buffer; +*/ - buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4); +void RB_TakeScreenshotJPEG(int x, int y, int width, int height, char *fileName) +{ + byte *buffer; + size_t offset = 0, memcount; + int padlen; - qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); + buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen); + memcount = (width * 3 + padlen) * height; // gamma correct - if ( glConfig.deviceSupportsGamma ) { - R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 ); - } - - ri.FS_WriteFile( fileName, buffer, 1 ); // create path - SaveJPG( fileName, 90, glConfig.vidWidth, glConfig.vidHeight, buffer); + if(glConfig.deviceSupportsGamma) + R_GammaCorrect(buffer + offset, memcount); - ri.Hunk_FreeTempMemory( buffer ); + RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen); + ri.Hunk_FreeTempMemory(buffer); } /* @@ -525,8 +590,10 @@ the menu system, sampled down from full screen distorted images void R_LevelShot( void ) { char checkname[MAX_OSPATH]; byte *buffer; - byte *source; + byte *source, *allsource; byte *src, *dst; + size_t offset = 0; + int padlen; int x, y; int r, g, b; float xScale, yScale; @@ -534,17 +601,16 @@ void R_LevelShot( void ) { Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName); - source = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 ); + allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen); + source = allsource + offset; - buffer = ri.Hunk_AllocateTempMemory( 128 * 128*3 + 18); + buffer = ri.Hunk_AllocateTempMemory(128 * 128*3 + 18); Com_Memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = 128; buffer[14] = 128; buffer[16] = 24; // pixel size - qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); - // resample from source xScale = glConfig.vidWidth / 512.0f; yScale = glConfig.vidHeight / 384.0f; @@ -553,7 +619,8 @@ void R_LevelShot( void ) { r = g = b = 0; for ( yy = 0 ; yy < 3 ; yy++ ) { for ( xx = 0 ; xx < 4 ; xx++ ) { - src = source + 3 * ( glConfig.vidWidth * (int)( (y*3+yy)*yScale ) + (int)( (x*4+xx)*xScale ) ); + src = source + (3 * glConfig.vidWidth + padlen) * (int)((y*3 + yy) * yScale) + + 3 * (int) ((x*4 + xx) * xScale); r += src[0]; g += src[1]; b += src[2]; @@ -573,8 +640,8 @@ void R_LevelShot( void ) { ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 ); - ri.Hunk_FreeTempMemory( buffer ); - ri.Hunk_FreeTempMemory( source ); + ri.Hunk_FreeTempMemory(buffer); + ri.Hunk_FreeTempMemory(allsource); ri.Printf( PRINT_ALL, "Wrote %s\n", checkname ); } @@ -707,36 +774,70 @@ RB_TakeVideoFrameCmd const void *RB_TakeVideoFrameCmd( const void *data ) { const videoFrameCommand_t *cmd; - int frameSize; - int i; + byte *cBuf; + size_t memcount, linelen; + int padwidth, avipadwidth, padlen, avipadlen; + GLint packAlign; cmd = (const videoFrameCommand_t *)data; - qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA, - GL_UNSIGNED_BYTE, cmd->captureBuffer ); + qglGetIntegerv(GL_PACK_ALIGNMENT, &packAlign); + + linelen = cmd->width * 3; + + // Alignment stuff for glReadPixels + padwidth = PAD(linelen, packAlign); + padlen = padwidth - linelen; + // AVI line padding + avipadwidth = PAD(linelen, AVI_LINE_PADDING); + avipadlen = avipadwidth - linelen; + + cBuf = (byte *) PAD((intptr_t) cmd->captureBuffer, packAlign); + + qglReadPixels(0, 0, cmd->width, cmd->height, GL_RGB, + GL_UNSIGNED_BYTE, cBuf); + + memcount = padwidth * cmd->height; // gamma correct - if( glConfig.deviceSupportsGamma ) - R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 ); + if(glConfig.deviceSupportsGamma) + R_GammaCorrect(cBuf, memcount); - if( cmd->motionJpeg ) + if(cmd->motionJpeg) { - frameSize = SaveJPGToBuffer( cmd->encodeBuffer, 90, - cmd->width, cmd->height, cmd->captureBuffer ); - ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize ); + memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height, + r_aviMotionJpegQuality->integer, + cmd->width, cmd->height, cBuf, padlen); + ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount); } else { - frameSize = cmd->width * cmd->height; - - for( i = 0; i < frameSize; i++) // Pack to 24bpp and swap R and B + byte *lineend, *memend; + byte *srcptr, *destptr; + + srcptr = cBuf; + destptr = cmd->encodeBuffer; + memend = srcptr + memcount; + + // swap R and B and remove line paddings + while(srcptr < memend) { - cmd->encodeBuffer[ i*3 ] = cmd->captureBuffer[ i*4 + 2 ]; - cmd->encodeBuffer[ i*3 + 1 ] = cmd->captureBuffer[ i*4 + 1 ]; - cmd->encodeBuffer[ i*3 + 2 ] = cmd->captureBuffer[ i*4 ]; + lineend = srcptr + linelen; + while(srcptr < lineend) + { + *destptr++ = srcptr[2]; + *destptr++ = srcptr[1]; + *destptr++ = srcptr[0]; + srcptr += 3; + } + + Com_Memset(destptr, '\0', avipadlen); + destptr += avipadlen; + + srcptr += padlen; } - - ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize * 3 ); + + ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, avipadwidth * cmd->height); } return (const void *)(cmd + 1); @@ -932,6 +1033,7 @@ void R_Register( void ) r_stereoEnabled = ri.Cvar_Get( "r_stereoEnabled", "0", CVAR_ARCHIVE | CVAR_LATCH); r_ignoreFastPath = ri.Cvar_Get( "r_ignoreFastPath", "1", CVAR_ARCHIVE | CVAR_LATCH ); r_greyscale = ri.Cvar_Get("r_greyscale", "0", CVAR_ARCHIVE | CVAR_LATCH); + ri.Cvar_CheckRange(r_greyscale, 0, 1, qfalse); // // temporary latched variables that can only change over a restart @@ -1024,6 +1126,9 @@ void R_Register( void ) r_marksOnTriangleMeshes = ri.Cvar_Get("r_marksOnTriangleMeshes", "0", CVAR_ARCHIVE); + r_aviMotionJpegQuality = ri.Cvar_Get("r_aviMotionJpegQuality", "90", CVAR_ARCHIVE); + r_screenshotJpegQuality = ri.Cvar_Get("r_screenshotJpegQuality", "90", CVAR_ARCHIVE); + r_maxpolys = ri.Cvar_Get( "r_maxpolys", va("%d", MAX_POLYS), 0); r_maxpolyverts = ri.Cvar_Get( "r_maxpolyverts", va("%d", MAX_POLYVERTS), 0); |