Exemple #1
0
// "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
}
Exemple #2
0
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
}
Exemple #3
0
/* 
================== 
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);
}
Exemple #4
0
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
}
Exemple #5
0
/* 
================== 
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 );
}
Exemple #6
0
/*
 * 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);
}
Exemple #7
0
/*
====================
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 );
}
Exemple #8
0
/*
 * 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);
}
Exemple #9
0
/*
==================
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 );
}
Exemple #10
0
/*
==================
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);
}
Exemple #11
0
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);
}
Exemple #12
0
/*
==================
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);
}
Exemple #13
0
/* 
================== 
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 );
}
Exemple #14
0
/* 
================== 
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 );
}
Exemple #15
0
//	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 );
}
Exemple #17
0
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;
}
Exemple #18
0
/*
==================
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);
}
Exemple #19
0
/*
==================
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);	
}
Exemple #21
0
/*
==================
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);	
}
Exemple #22
0
/*
====================
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);
}
Exemple #23
0
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;
}
Exemple #24
0
/*
==================
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 );
}
Exemple #25
0
/*
==================
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);	
}
Exemple #26
0
/*
====================
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 );
}