// "filename" param is something like "screenshots/shot0000.tga" // note that if the last extension is ".jpg", then it'll save a JPG, else TGA // void R_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { #ifndef _XBOX byte *buffer; int i, c, temp; qboolean bSaveAsJPG = !strnicmp(&fileName[strlen(fileName)-4],".jpg",4); if (bSaveAsJPG) { // JPG saver expects to be fed RGBA data, though it presumably ignores 'A'... // buffer = (unsigned char *) Z_Malloc(glConfig.vidWidth*glConfig.vidHeight*4, TAG_TEMP_WORKSPACE, qfalse); qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); // gamma correct if ( tr.overbrightBits>0 && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 ); } SaveJPG(fileName, 95, width, height, buffer); } else { // TGA... // buffer = (unsigned char *) Z_Malloc(glConfig.vidWidth*glConfig.vidHeight*3 + 18, TAG_TEMP_WORKSPACE, qfalse); memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = width & 255; buffer[13] = width >> 8; buffer[14] = height & 255; 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 c = 18 + width * height * 3; for (i=18 ; i<c ; i+=3) { temp = buffer[i]; buffer[i] = buffer[i+2]; buffer[i+2] = temp; } // gamma correct if ( tr.overbrightBits>0 && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 ); } FS_WriteFile( fileName, buffer, c ); } Z_Free( buffer ); #endif }
static void R_LevelShot( void ) { #ifndef _XBOX char checkname[MAX_OSPATH]; byte *buffer; byte *source; byte *src, *dst; int x, y; int r, g, b; float xScale, yScale; int xx, yy; sprintf( checkname, "levelshots/%s.tga", tr.world->baseName ); source = (unsigned char *)Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 ); buffer = (unsigned char *)Hunk_AllocateTempMemory( LEVELSHOTSIZE * LEVELSHOTSIZE*3 + 18); Com_Memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = LEVELSHOTSIZE & 255; buffer[13] = LEVELSHOTSIZE >> 8; buffer[14] = LEVELSHOTSIZE & 255; buffer[15] = LEVELSHOTSIZE >> 8; buffer[16] = 24; // pixel size qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); // resample from source xScale = glConfig.vidWidth / (4.0*LEVELSHOTSIZE); yScale = glConfig.vidHeight / (3.0*LEVELSHOTSIZE); for ( y = 0 ; y < LEVELSHOTSIZE ; y++ ) { for ( x = 0 ; x < LEVELSHOTSIZE ; x++ ) { 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 ) ); r += src[0]; g += src[1]; b += src[2]; } } dst = buffer + 18 + 3 * ( y * LEVELSHOTSIZE + x ); dst[0] = b / 12; dst[1] = g / 12; dst[2] = r / 12; } } // gamma correct if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, LEVELSHOTSIZE * LEVELSHOTSIZE * 3 ); } FS_WriteFile( checkname, buffer, LEVELSHOTSIZE * LEVELSHOTSIZE*3 + 18 ); Hunk_FreeTempMemory( buffer ); Hunk_FreeTempMemory( source ); Com_Printf ("Wrote %s\n", checkname ); #endif }
/* ================== RB_TakeScreenshot ================== */ 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; 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; buffer[13] = width >> 8; buffer[14] = height & 255; buffer[15] = height >> 8; buffer[16] = 24; // pixel size // 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; 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 //openarena: altbright && !r_alternateBrightness->integer //-openarena ) { R_GammaCorrect(allbuf + offset, memcount); } ri.FS_WriteFile(fileName, buffer, memcount + 18); ri.Hunk_FreeTempMemory(allbuf); }
void R_LevelShot( void ) { #ifndef _XBOX char checkname[MAX_OSPATH]; byte *buffer; byte *source; byte *src, *dst; int x, y; int r, g, b; float xScale, yScale; int xx, yy; sprintf( checkname, "levelshots/%s.tga", tr.worldDir + strlen("maps/") ); source = (byte*) Z_Malloc( glConfig.vidWidth * glConfig.vidHeight * 3, TAG_TEMP_WORKSPACE, qfalse ); buffer = (byte*) Z_Malloc( LEVELSHOTSIZE * LEVELSHOTSIZE*3 + 18, TAG_TEMP_WORKSPACE, qfalse ); memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = LEVELSHOTSIZE & 255; buffer[13] = LEVELSHOTSIZE >> 8; buffer[14] = LEVELSHOTSIZE & 255; buffer[15] = LEVELSHOTSIZE >> 8; buffer[16] = 24; // pixel size qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); // resample from source xScale = glConfig.vidWidth / (4.0*LEVELSHOTSIZE); yScale = glConfig.vidHeight / (3.0*LEVELSHOTSIZE); for ( y = 0 ; y < LEVELSHOTSIZE ; y++ ) { for ( x = 0 ; x < LEVELSHOTSIZE ; x++ ) { 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 ) ); r += src[0]; g += src[1]; b += src[2]; } } dst = buffer + 18 + 3 * ( y * LEVELSHOTSIZE + x ); dst[0] = b / 12; dst[1] = g / 12; dst[2] = r / 12; } } // gamma correct if ( glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, LEVELSHOTSIZE * LEVELSHOTSIZE * 3 ); } FS_WriteFile( checkname, buffer, LEVELSHOTSIZE * LEVELSHOTSIZE*3 + 18 ); Z_Free( buffer ); Z_Free( source ); VID_Printf( PRINT_ALL, "Wrote %s\n", checkname ); #endif }
/* ================== R_TakeScreenshot ================== */ void R_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { byte *buffer; int i, c, temp; buffer = (unsigned char *)Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*3+18); Com_Memset (buffer, 0, 18); buffer[2] = 2; // uncompressed type buffer[12] = width & 255; buffer[13] = width >> 8; buffer[14] = height & 255; 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 c = 18 + width * height * 3; for (i=18 ; i<c ; i+=3) { temp = buffer[i]; buffer[i] = buffer[i+2]; buffer[i+2] = temp; } // gamma correct if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, glConfig.vidWidth * glConfig.vidHeight * 3 ); } FS_WriteFile( fileName, buffer, c ); Hunk_FreeTempMemory( buffer ); }
/* * R_LevelShot * * levelshots are specialized 128*128 thumbnails for * the menu system, sampled down from full screen distorted images */ void R_LevelShot(void) { char checkname[MAX_OSPATH]; byte *buffer; byte *source, *allsource; byte *src, *dst; size_t offset = 0; int padlen; int x, y; int r, g, b; float xScale, yScale; int xx, yy; Q_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName); allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen); source = allsource + offset; buffer = ri.hunkalloctemp(128 * 128*3 + 18); Q_Memset (buffer, 0, 18); buffer[2] = 2; /* uncompressed type */ buffer[12] = 128; buffer[14] = 128; buffer[16] = 24; /* pixel size */ /* resample from source */ xScale = glConfig.vidWidth / 512.0f; yScale = glConfig.vidHeight / 384.0f; for(y = 0; y < 128; y++) for(x = 0; x < 128; x++){ r = g = b = 0; for(yy = 0; yy < 3; yy++) for(xx = 0; xx < 4; xx++){ 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]; } dst = buffer + 18 + 3 * (y * 128 + x); dst[0] = b / 12; dst[1] = g / 12; dst[2] = r / 12; } /* gamma correct */ if(glConfig.deviceSupportsGamma){ R_GammaCorrect(buffer + 18, 128 * 128 * 3); } ri.fswritefile(checkname, buffer, 128 * 128*3 + 18); ri.hunkfreetemp(buffer); ri.hunkfreetemp(allsource); ri.Printf(PRINT_ALL, "Wrote %s\n", checkname); }
/* ==================== R_LevelShot levelshots are specialized 128*128 thumbnails for the menu system, sampled down from full screen distorted images ==================== */ void R_LevelShot( void ) { char checkname[MAX_OSPATH]; byte *buffer; byte *source; byte *src, *dst; int x, y; int r, g, b; float xScale, yScale; int xx, yy; sprintf( checkname, "levelshots/%s.tga", tr.world->baseName ); source = ri.Hunk_AllocateTempMemory( glConfig.vidWidth * glConfig.vidHeight * 3 ); 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; for ( y = 0 ; y < 128 ; y++ ) { for ( x = 0 ; x < 128 ; x++ ) { 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 ) ); r += src[0]; g += src[1]; b += src[2]; } } dst = buffer + 18 + 3 * ( y * 128 + x ); dst[0] = b / 12; dst[1] = g / 12; dst[2] = r / 12; } } // gamma correct if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, 128 * 128 * 3 ); } ri.FS_WriteFile( checkname, buffer, 128 * 128*3 + 18 ); ri.Hunk_FreeTempMemory( buffer ); ri.Hunk_FreeTempMemory( source ); ri.Printf( PRINT_ALL, "Wrote %s\n", checkname ); }
/* * RB_TakeScreenshot */ 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; allbuf = RB_ReadPixels(x, y, width, height, &offset, &padlen); buffer = allbuf + offset - 18; Q_Memset (buffer, 0, 18); buffer[2] = 2; /* uncompressed type */ buffer[12] = width & 255; buffer[13] = width >> 8; buffer[14] = height & 255; buffer[15] = height >> 8; buffer[16] = 24; /* pixel size */ /* 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; 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(allbuf + offset, memcount); ri.fswritefile(fileName, buffer, memcount + 18); ri.hunkfreetemp(allbuf); }
/* ================== R_TakeScreenshotPNG ================== */ static void R_TakeScreenshotPNG( int x, int y, int width, int height, char *fileName ) { byte *buffer = RB_ReadPixels( x, y, width, height, 0 ); if ( tr.overbrightBits > 0 && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer, 3 * width * height ); } SavePNG( fileName, buffer, width, height, 3, qfalse ); ri.Hunk_FreeTempMemory( buffer ); }
/* ================== R_TakeScreenshot ================== */ void R_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) { byte *buffer; size_t offset = 0, memcount; int padlen; buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen); memcount = (width * 3 + padlen) * height; // gamma correct if(glConfig.deviceSupportsGamma) R_GammaCorrect(buffer + offset, memcount); RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen); Hunk_FreeTempMemory(buffer); }
void R_TakeScreenshotJPEG(int x, int y, int width, int height, char *fileName) { byte *buffer; size_t offset = 0, memcount; int padlen; buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen); memcount = (width * 3 + padlen) * height; // gamma correct if (r_gammamethod->integer == GAMMA_HARDWARE) R_GammaCorrect(buffer + offset, (int)memcount); SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, buffer + offset, padlen); ri.Hunk_FreeTempMemory(buffer); }
/* ================== RB_TakeScreenshotPNG ================== */ static void RB_TakeScreenshotPNG(int x, int y, int width, int height, char *fileName) { byte *buffer; size_t offset = 0, memcount; int padlen; buffer = RB_ReadPixels(x, y, width, height, &offset, &padlen); memcount = (width * 3 + padlen) * height; // gamma correct if(glConfig.deviceSupportsGamma) R_GammaCorrect(buffer + offset, memcount); RE_SavePNG(fileName, width, height, buffer+offset, 3, padlen, qfalse); ri.Hunk_FreeTempMemory(buffer); }
/* ================== R_TakeScreenshot ================== */ void R_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) { byte *buffer; buffer = (unsigned char *)Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4); qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); // gamma correct if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 ); } FS_WriteFile( fileName, buffer, 1 ); // create path SaveJPG( fileName, 95, glConfig.vidWidth, glConfig.vidHeight, buffer); Hunk_FreeTempMemory( buffer ); }
/* ================== RB_TakeScreenshotJPEG ================== */ void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) { byte *buffer; buffer = (byte *)ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4); // ***GREGS_VC9_PORT_MOD*** -- needed typecast qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); // gamma correct if ( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 ); } ri.FS_WriteFile( fileName, buffer, 1 ); // create path SaveJPG( fileName, 95, glConfig.vidWidth, glConfig.vidHeight, buffer); ri.Hunk_FreeTempMemory( buffer ); }
// levelshots are specialized 128*128 thumbnails for the menu system, sampled // down from full screen distorted images static void R_LevelShot() { char checkname[ MAX_OSPATH ]; String::Sprintf( checkname, MAX_OSPATH, "levelshots/%s.tga", tr.world->baseName ); byte* source = new byte[ glConfig.vidWidth * glConfig.vidHeight * 3 ]; byte* buffer = new byte[ 128 * 128 * 3 ]; qglReadPixels( 0, 0, glConfig.vidWidth, glConfig.vidHeight, GL_RGB, GL_UNSIGNED_BYTE, source ); // resample from source float xScale = glConfig.vidWidth / 512.0f; float yScale = glConfig.vidHeight / 384.0f; for ( int y = 0; y < 128; y++ ) { for ( int x = 0; x < 128; x++ ) { int r = 0; int g = 0; int b = 0; for ( int yy = 0; yy < 3; yy++ ) { for ( int xx = 0; xx < 4; xx++ ) { byte* src = source + 3 * ( glConfig.vidWidth * ( int )( ( y * 3 + yy ) * yScale ) + ( int )( ( x * 4 + xx ) * xScale ) ); r += src[ 0 ]; g += src[ 1 ]; b += src[ 2 ]; } } byte* dst = buffer + 3 * ( y * 128 + x ); dst[ 0 ] = r / 12; dst[ 1 ] = g / 12; dst[ 2 ] = b / 12; } } // gamma correct if ( tr.overbrightBits > 0 && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer, 128 * 128 * 3 ); } R_SaveTGA( checkname, buffer, 128, 128, false ); delete[] buffer; delete[] source; common->Printf( "Wrote %s\n", checkname ); }
/* ================== RB_TakeScreenshotJPEG ================== */ void RB_TakeScreenshotJPEG( int x, int y, int width, int height, char *fileName ) { byte *buffer; int quality = r_jpegQuality -> value; buffer = ri.Hunk_AllocateTempMemory(glConfig.vidWidth*glConfig.vidHeight*4); qglReadPixels( x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); // gamma correct if ( glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer, glConfig.vidWidth * glConfig.vidHeight * 4 ); } ri.FS_WriteFile( fileName, buffer, 1 ); // create path SaveJPG( fileName, quality, glConfig.vidWidth, glConfig.vidHeight, buffer); ri.Hunk_FreeTempMemory( buffer ); }
static void RB_TakeScreenshot( int x, int y, int width, int height, const char* fileName, bool IsJpeg ) { byte* buffer = new byte[ width * height * 3 ]; qglReadPixels( x, y, width, height, GL_RGB, GL_UNSIGNED_BYTE, buffer ); // gamma correct if ( tr.overbrightBits > 0 && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer, width * height * 3 ); } if ( IsJpeg ) { FS_WriteFile( fileName, buffer, 1 ); // create path R_SaveJPG( fileName, 95, width, height, buffer ); } else { R_SaveTGA( fileName, buffer, width, height, false ); } delete[] buffer; }
/* ================== RB_TakeVideoFrameCmd ================== */ const void *RB_TakeVideoFrameCmd(const void *data) { const videoFrameCommand_t *cmd; int frameSize; int i; cmd = (const videoFrameCommand_t *)data; // check if the recording is still going on, the buffer might have cmds eventho the recording has stopped if (ri.CL_VideoRecording()) { glReadPixels(0, 0, cmd->width, cmd->height, GL_RGBA, GL_UNSIGNED_BYTE, cmd->captureBuffer); // gamma correct if ((tr.overbrightBits > 0) && glConfig.deviceSupportsGamma) { R_GammaCorrect(cmd->captureBuffer, cmd->width * cmd->height * 4); } if (cmd->motionJpeg) { /* This should be fixed frameSize = RE_SaveJPGToBuffer(cmd->encodeBuffer, 90, cmd->width, cmd->height, cmd->captureBuffer); ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, frameSize); */ } else { frameSize = cmd->width * cmd->height; for (i = 0; i < frameSize; i++) // Pack to 24bpp and swap R and B { 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]; } ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, frameSize * 3); } } return (const void *)(cmd + 1); }
/* ================== R_TakeScreenshot ================== */ static void R_TakeScreenshot( int x, int y, int width, int height, char *fileName ) { byte *buffer; int dataSize; byte *end, *p; // with 18 bytes for the TGA file header buffer = RB_ReadPixels( x, y, width, height, 18 ); Com_Memset( buffer, 0, 18 ); buffer[ 2 ] = 2; // uncompressed type buffer[ 12 ] = width & 255; buffer[ 13 ] = width >> 8; buffer[ 14 ] = height & 255; buffer[ 15 ] = height >> 8; buffer[ 16 ] = 24; // pixel size dataSize = 3 * width * height; // RGB to BGR end = buffer + 18 + dataSize; for ( p = buffer + 18; p < end; p += 3 ) { byte temp = p[ 0 ]; p[ 0 ] = p[ 2 ]; p[ 2 ] = temp; } if ( tr.overbrightBits > 0 && glConfig.deviceSupportsGamma ) { R_GammaCorrect( buffer + 18, dataSize ); } ri.FS_WriteFile( fileName, buffer, 18 + dataSize ); ri.Hunk_FreeTempMemory( buffer ); }
/* ================== RB_TakeVideoFrameCmd ================== */ const void *RB_TakeVideoFrameCmd( const void *data ) { const videoFrameCommand_t *cmd; int frameSize; int i; cmd = (const videoFrameCommand_t *)data; qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA, GL_UNSIGNED_BYTE, cmd->captureBuffer ); // gamma correct if( glConfig.deviceSupportsGamma ) R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 ); if( cmd->motionJpeg ) { frameSize = SaveJPGToBuffer( cmd->encodeBuffer, 90, cmd->width, cmd->height, cmd->captureBuffer ); ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize ); } else { frameSize = cmd->width * cmd->height; for( i = 0; i < frameSize; i++) // Pack to 24bpp and swap R and B { 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 ]; } ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize * 3 ); } return (const void *)(cmd + 1); }
/* ================== RB_TakeVideoFrameCmd ================== */ const void *RB_TakeVideoFrameCmd( const void *data ) { const videoFrameCommand_t *cmd; int frameSize; int i; cmd = (const videoFrameCommand_t *)data; qglReadPixels( 0, 0, cmd->width, cmd->height, GL_RGBA, GL_UNSIGNED_BYTE, cmd->captureBuffer ); // gamma correct if( ( tr.overbrightBits > 0 ) && glConfig.deviceSupportsGamma ) R_GammaCorrect( cmd->captureBuffer, cmd->width * cmd->height * 4 ); if( cmd->motionJpeg ) { frameSize = SaveJPGToBuffer( cmd->encodeBuffer, 95, cmd->width, cmd->height, cmd->captureBuffer ); } else { frameSize = cmd->width * cmd->height * 4; // Vertically flip the image for( i = 0; i < cmd->height; i++ ) { Com_Memcpy( &cmd->encodeBuffer[ i * ( cmd->width * 4 ) ], &cmd->captureBuffer[ ( cmd->height - i - 1 ) * ( cmd->width * 4 ) ], cmd->width * 4 ); } } ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, frameSize ); return (const void *)(cmd + 1); }
/* ==================== R_LevelShot levelshots are specialized 128*128 thumbnails for the menu system, sampled down from full screen distorted images ==================== */ void R_LevelShot(void) { char checkname[MAX_OSPATH]; byte *buffer; byte *source, *allsource; byte *src, *dst; size_t offset = 0; int padlen; int x, y; int r, g, b; float xScale, yScale; int xx, yy; Com_sprintf(checkname, sizeof(checkname), "levelshots/%s.tga", tr.world->baseName); allsource = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &padlen); source = allsource + offset; 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 // resample from source xScale = glConfig.vidWidth / 512.0f; yScale = glConfig.vidHeight / 384.0f; for (y = 0 ; y < 128 ; y++) { for (x = 0 ; x < 128 ; x++) { r = g = b = 0; for (yy = 0 ; yy < 3 ; yy++) { for (xx = 0 ; xx < 4 ; xx++) { 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]; } } dst = buffer + 18 + 3 * (y * 128 + x); dst[0] = b / 12; dst[1] = g / 12; dst[2] = r / 12; } } // gamma correct if (glConfig.deviceSupportsGamma) { R_GammaCorrect(buffer + 18, 128 * 128 * 3); } ri.FS_WriteFile(checkname, buffer, 128 * 128 * 3 + 18); ri.Hunk_FreeTempMemory(buffer); ri.Hunk_FreeTempMemory(allsource); Ren_Print("Wrote %s\n", checkname); }
qboolean R_MME_TakeShot( void ) { int pixelCount; byte inSound[MME_SAMPLERATE] = {0}; int sizeSound = 0; qboolean audio = qfalse, audioTaken = qfalse; qboolean doGamma; mmeBlurControl_t* blurControl = &blurData.control; if ( !shotData.take || allocFailed || tr.finishStereo ) return qfalse; shotData.take = qfalse; pixelCount = glConfig.vidHeight * glConfig.vidWidth; doGamma = (qboolean)(( mme_screenShotGamma->integer || (tr.overbrightBits > 0) ) && (glConfig.deviceSupportsGamma )); R_MME_CheckCvars(); //Special early version using the framebuffer if ( mme_saveShot->integer && blurControl->totalFrames > 0 && R_FrameBuffer_Blur( blurControl->Float[ blurControl->totalIndex ], blurControl->totalIndex, blurControl->totalFrames ) ) { byte *shotBuf; float fps; if ( ++(blurControl->totalIndex) < blurControl->totalFrames ) return qtrue; blurControl->totalIndex = 0; shotBuf = (byte *)ri.Hunk_AllocateTempMemory( pixelCount * 3 ); R_MME_MultiShot( shotBuf ); if ( doGamma ) R_GammaCorrect( shotBuf, pixelCount * 3 ); fps = shotData.fps / ( blurControl->totalFrames ); audio = ri.S_MMEAviImport(inSound, &sizeSound); R_MME_SaveShot( &shotData.main, glConfig.vidWidth, glConfig.vidHeight, fps, shotBuf, audio, sizeSound, inSound ); ri.Hunk_FreeTempMemory( shotBuf ); return qtrue; } /* Test if we need to do blurred shots */ if ( blurControl->totalFrames > 0 ) { mmeBlurBlock_t *blurShot = &blurData.shot; mmeBlurBlock_t *blurDepth = &blurData.depth; // mmeBlurBlock_t *blurStencil = &blurData.stencil; /* Test if we blur with overlapping frames */ if ( blurControl->overlapFrames ) { /* First frame in a sequence, fill the buffer with the last frames */ if (blurControl->totalIndex == 0) { int i; for ( i = 0; i < blurControl->overlapFrames; i++ ) { if ( mme_saveShot->integer ) { R_MME_BlurOverlapAdd( blurShot, i ); } if ( mme_saveDepth->integer ) { R_MME_BlurOverlapAdd( blurDepth, i ); } // if ( mme_saveStencil->integer ) { // R_MME_BlurOverlapAdd( blurStencil, i ); // } blurControl->totalIndex++; } } if ( mme_saveShot->integer == 1 ) { byte* shotBuf = R_MME_BlurOverlapBuf( blurShot ); R_MME_MultiShot( shotBuf ); if ( doGamma && mme_blurGamma->integer ) { R_GammaCorrect( shotBuf, glConfig.vidWidth * glConfig.vidHeight * 3 ); } R_MME_BlurOverlapAdd( blurShot, 0 ); } if ( mme_saveDepth->integer == 1 ) { R_MME_GetDepth( R_MME_BlurOverlapBuf( blurDepth ) ); R_MME_BlurOverlapAdd( blurDepth, 0 ); } // if ( mme_saveStencil->integer == 1 ) { // R_MME_GetStencil( R_MME_BlurOverlapBuf( blurStencil ) ); // R_MME_BlurOverlapAdd( blurStencil, 0 ); // } blurControl->overlapIndex++; blurControl->totalIndex++; } else { byte *outAlloc; __m64 *outAlign; outAlloc = (byte *)ri.Hunk_AllocateTempMemory( pixelCount * 3 + 16); outAlign = (__m64 *)((((intptr_t)(outAlloc)) + 15) & ~15); if ( mme_saveShot->integer == 1 ) { R_MME_MultiShot( (byte*)outAlign ); if ( doGamma && mme_blurGamma->integer ) { R_GammaCorrect( (byte *) outAlign, pixelCount * 3 ); } R_MME_BlurAccumAdd( blurShot, outAlign ); } if ( mme_saveDepth->integer == 1 ) { R_MME_GetDepth( (byte *)outAlign ); R_MME_BlurAccumAdd( blurDepth, outAlign ); } // if ( mme_saveStencil->integer == 1 ) { // R_MME_GetStencil( (byte *)outAlign ); // R_MME_BlurAccumAdd( blurStencil, outAlign ); // } ri.Hunk_FreeTempMemory( outAlloc ); blurControl->totalIndex++; } if ( blurControl->totalIndex >= blurControl->totalFrames ) { float fps; blurControl->totalIndex = 0; fps = shotData.fps / ( blurControl->totalFrames ); if ( mme_saveShot->integer == 1 ) { R_MME_BlurAccumShift( blurShot ); if (doGamma && !mme_blurGamma->integer) R_GammaCorrect( (byte *)blurShot->accum, pixelCount * 3); } if ( mme_saveDepth->integer == 1 ) R_MME_BlurAccumShift( blurDepth ); // if ( mme_saveStencil->integer == 1 ) // R_MME_BlurAccumShift( blurStencil ); audio = ri.S_MMEAviImport(inSound, &sizeSound); audioTaken = qtrue; // Big test for an rgba shot if ( mme_saveShot->integer == 1 && shotData.main.type == mmeShotTypeRGBA ) { int i; byte *alphaShot = (byte *)ri.Hunk_AllocateTempMemory( pixelCount * 4); byte *rgbData = (byte *)(blurShot->accum ); if ( mme_saveDepth->integer == 1 ) { byte *depthData = (byte *)( blurDepth->accum ); for ( i = 0;i < pixelCount; i++ ) { alphaShot[i*4+0] = rgbData[i*3+0]; alphaShot[i*4+1] = rgbData[i*3+1]; alphaShot[i*4+2] = rgbData[i*3+2]; alphaShot[i*4+3] = depthData[i]; } /* } else if ( mme_saveStencil->integer == 1) { byte *stencilData = (byte *)( blurStencil->accum ); for ( i = 0;i < pixelCount; i++ ) { alphaShot[i*4+0] = rgbData[i*3+0]; alphaShot[i*4+1] = rgbData[i*3+1]; alphaShot[i*4+2] = rgbData[i*3+2]; alphaShot[i*4+3] = stencilData[i]; } */ } R_MME_SaveShot( &shotData.main, glConfig.vidWidth, glConfig.vidHeight, fps, alphaShot, audio, sizeSound, inSound ); ri.Hunk_FreeTempMemory( alphaShot ); } else { if ( mme_saveShot->integer == 1 ) R_MME_SaveShot( &shotData.main, glConfig.vidWidth, glConfig.vidHeight, fps, (byte *)( blurShot->accum ), audio, sizeSound, inSound ); if ( mme_saveDepth->integer == 1 ) R_MME_SaveShot( &shotData.depth, glConfig.vidWidth, glConfig.vidHeight, fps, (byte *)( blurDepth->accum ), audio, sizeSound, inSound ); // if ( mme_saveStencil->integer == 1 ) // R_MME_SaveShot( &shotData.stencil, glConfig.vidWidth, glConfig.vidHeight, fps, (byte *)( blurStencil->accum), audio, sizeSound, inSound ); } } } if ( mme_saveShot->integer > 1 || (!blurControl->totalFrames && mme_saveShot->integer )) { byte *shotBuf = (byte *)ri.Hunk_AllocateTempMemory( pixelCount * 5 ); R_MME_MultiShot( shotBuf ); if ( doGamma ) R_GammaCorrect( shotBuf, pixelCount * 3 ); if ( shotData.main.type == mmeShotTypeRGBA ) { int i; byte *alphaBuf = shotBuf + pixelCount * 4; if ( mme_saveDepth->integer > 1 || (!blurControl->totalFrames && mme_saveDepth->integer )) { R_MME_GetDepth( alphaBuf ); // } else if ( mme_saveStencil->integer > 1 || (!blurControl->totalFrames && mme_saveStencil->integer )) { // R_MME_GetStencil( alphaBuf ); } for ( i = pixelCount - 1 ; i >= 0; i-- ) { shotBuf[i * 4 + 0] = shotBuf[i*3 + 0]; shotBuf[i * 4 + 1] = shotBuf[i*3 + 1]; shotBuf[i * 4 + 2] = shotBuf[i*3 + 2]; shotBuf[i * 4 + 3] = alphaBuf[i]; } } if (!audioTaken) audio = ri.S_MMEAviImport(inSound, &sizeSound); audioTaken = qtrue; R_MME_SaveShot( &shotData.main, glConfig.vidWidth, glConfig.vidHeight, shotData.fps, shotBuf, audio, sizeSound, inSound ); ri.Hunk_FreeTempMemory( shotBuf ); } if ( shotData.main.type == mmeShotTypeRGB ) { /* if ( mme_saveStencil->integer > 1 || ( !blurControl->totalFrames && mme_saveStencil->integer) ) { byte *stencilShot = (byte *)ri.Hunk_AllocateTempMemory( pixelCount * 1); R_MME_GetStencil( stencilShot ); if (!audioTaken && ((mme_saveStencil->integer > 1 && mme_saveShot->integer > 1) || (mme_saveStencil->integer == 1 && mme_saveShot->integer == 1))) audio = ri.S_MMEAviImport(inSound, &sizeSound); R_MME_SaveShot( &shotData.stencil, glConfig.vidWidth, glConfig.vidHeight, shotData.fps, stencilShot, audio, sizeSound, inSound ); ri.Hunk_FreeTempMemory( stencilShot ); } */ if ( mme_saveDepth->integer > 1 || ( !blurControl->totalFrames && mme_saveDepth->integer) ) { byte *depthShot = (byte *)ri.Hunk_AllocateTempMemory( pixelCount * 1); R_MME_GetDepth( depthShot ); if (!audioTaken && ((mme_saveDepth->integer > 1 && mme_saveShot->integer > 1) || (mme_saveDepth->integer == 1 && mme_saveShot->integer == 1))) audio = ri.S_MMEAviImport(inSound, &sizeSound); R_MME_SaveShot( &shotData.depth, glConfig.vidWidth, glConfig.vidHeight, shotData.fps, depthShot, audio, sizeSound, inSound ); ri.Hunk_FreeTempMemory( depthShot ); } } return qtrue; }
/* ================== RB_TakeVideoFrameCmd ================== */ const void *RB_TakeVideoFrameCmd( const void *data ) { const videoFrameCommand_t *cmd; GLint packAlign; int lineLen, captureLineLen; byte *pixels; int i; int outputSize; int j; int aviLineLen; cmd = ( const videoFrameCommand_t * ) data; // RB: it is possible to we still have a videoFrameCommand_t but we already stopped // video recording if ( ri.CL_VideoRecording() ) { // take care of alignment issues for reading RGB images.. glGetIntegerv( GL_PACK_ALIGNMENT, &packAlign ); lineLen = cmd->width * 3; captureLineLen = PAD( lineLen, packAlign ); pixels = ( byte * ) PADP( cmd->captureBuffer, packAlign ); glReadPixels( 0, 0, cmd->width, cmd->height, GL_RGB, GL_UNSIGNED_BYTE, pixels ); if ( tr.overbrightBits > 0 && glConfig.deviceSupportsGamma ) { // this also runs over the padding... R_GammaCorrect( pixels, captureLineLen * cmd->height ); } if ( cmd->motionJpeg ) { // Drop alignment and line padding bytes for ( i = 0; i < cmd->height; ++i ) { memmove( cmd->captureBuffer + i * lineLen, pixels + i * captureLineLen, lineLen ); } outputSize = SaveJPGToBuffer( cmd->encodeBuffer, 3 * cmd->width * cmd->height, 90, cmd->width, cmd->height, cmd->captureBuffer ); ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, outputSize ); } else { aviLineLen = PAD( lineLen, AVI_LINE_PADDING ); for ( i = 0; i < cmd->height; ++i ) { for ( j = 0; j < lineLen; j += 3 ) { cmd->encodeBuffer[ i * aviLineLen + j + 0 ] = pixels[ i * captureLineLen + j + 2 ]; cmd->encodeBuffer[ i * aviLineLen + j + 1 ] = pixels[ i * captureLineLen + j + 1 ]; cmd->encodeBuffer[ i * aviLineLen + j + 2 ] = pixels[ i * captureLineLen + j + 0 ]; } while ( j < aviLineLen ) { cmd->encodeBuffer[ i * aviLineLen + j++ ] = 0; } } ri.CL_WriteAVIVideoFrame( cmd->encodeBuffer, aviLineLen * cmd->height ); } } return ( const void * )( cmd + 1 ); }
/* ================== RB_TakeVideoFrameCmd ================== */ const void *RB_TakeVideoFrameCmd( const void *data ) { const videoFrameCommand_t *cmd; byte *cBuf; size_t memcount, linelen; int padwidth, avipadwidth, padlen, avipadlen; GLint packAlign; cmd = (const videoFrameCommand_t *)data; 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 = PADP(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(cBuf, memcount); if(cmd->motionJpeg) { memcount = RE_SaveJPGToBuffer(cmd->encodeBuffer, linelen * cmd->height, r_aviMotionJpegQuality->integer, cmd->width, cmd->height, cBuf, padlen); ri.CL_WriteAVIVideoFrame(cmd->encodeBuffer, memcount); } else { 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) { 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, avipadwidth * cmd->height); } return (const void *)(cmd + 1); }
/* ==================== R_LevelShot levelshots are specialized 128*128 thumbnails for the menu system, sampled down from full screen distorted images ==================== */ void R_LevelShot( screenshotType_e type, const char *ext ) { char fileName[MAX_OSPATH]; byte *source; byte *resample, *resamplestart; size_t offset = 0, memcount; int spadlen, rpadlen; int padwidth, linelen; GLint packAlign; byte *src, *dst; int x, y; int r, g, b; float xScale, yScale; int xx, yy; int width, height; int arg; // Allow custom resample width/height arg = atoi(ri.Cmd_Argv(2)); if (arg > 0) width = height = arg; else width = height = 128; if (width > glConfig.vidWidth) width = glConfig.vidWidth; if (height > glConfig.vidHeight) height = glConfig.vidHeight; Com_sprintf(fileName, sizeof(fileName), "levelshots/%s_small%s", tr.world->baseName, ext); source = RB_ReadPixels(0, 0, glConfig.vidWidth, glConfig.vidHeight, &offset, &spadlen); // // Based on RB_ReadPixels 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 resample = ri.Hunk_AllocateTempMemory(padwidth * height + offset + packAlign - 1); resamplestart = PADP((intptr_t) resample + offset, packAlign); offset = resamplestart - resample; rpadlen = padwidth - linelen; // // resample from source xScale = glConfig.vidWidth / (float)(width * 4.0f); yScale = glConfig.vidHeight / (float)(height * 3.0f); for ( y = 0 ; y < height ; y++ ) { for ( x = 0 ; x < width ; x++ ) { r = g = b = 0; for ( yy = 0 ; yy < 3 ; yy++ ) { for ( xx = 0 ; xx < 4 ; xx++ ) { src = source + (3 * glConfig.vidWidth + spadlen) * (int)((y*3 + yy) * yScale) + 3 * (int) ((x*4 + xx) * xScale); r += src[0]; g += src[1]; b += src[2]; } } dst = resample + 3 * ( y * width + x ); dst[0] = r / 12; dst[1] = g / 12; dst[2] = b / 12; } } memcount = (width * 3 + rpadlen) * height; // gamma correct if(glConfig.deviceSupportsGamma) R_GammaCorrect(resample + offset, memcount); if ( type == ST_TGA ) RE_SaveTGA(fileName, width, height, resample + offset, rpadlen); else if ( type == ST_JPEG ) RE_SaveJPG(fileName, r_screenshotJpegQuality->integer, width, height, resample + offset, rpadlen); else if ( type == ST_PNG ) RE_SavePNG(fileName, width, height, resample + offset, rpadlen); ri.Hunk_FreeTempMemory(resample); ri.Hunk_FreeTempMemory(source); ri.Printf( PRINT_ALL, "Wrote %s\n", fileName ); }