Esempio n. 1
0
/**
 * @brief Displays an error message and writes the error into crashlog.txt
 * @param[in] error Error String
 */
void Sys_ErrorDialog(const char *error)
{
	char         buffer[1024];
	unsigned int size;
	int          f         = -1;
	const char   *homepath = Cvar_VariableString("fs_homepath");
	const char   *gamedir  = Cvar_VariableString("fs_gamedir");
	const char   *fileName = "crashlog.txt";
	char         *dirpath  = FS_BuildOSPath(homepath, gamedir, "");
	char         *ospath   = FS_BuildOSPath(homepath, gamedir, fileName);

	Sys_Print(va("%s\n", error));

#ifndef DEDICATED
	// We may have grabbed input devices. Need to release.
	if (SDL_WasInit(SDL_INIT_VIDEO))
	{
		SDL_WM_GrabInput(SDL_GRAB_OFF);
	}

	Sys_Dialog(DT_ERROR, va("%s\nSee \"%s\" for details.\n", error, ospath), "Error");
#endif

	// Make sure the write path for the crashlog exists...
	// check homepath
	if (!Sys_Mkdir(homepath))
	{
		Com_Printf("ERROR: couldn't create path '%s' to write file '%s'.\n", homepath, ospath);
		return;
	}
	// check gamedir (inside homepath)
	if (!Sys_Mkdir(dirpath))
	{
		Com_Printf("ERROR: couldn't create path '%s' to write file '%s'.\n", dirpath, ospath);
		return;
	}

	// We might be crashing because we maxed out the Quake MAX_FILE_HANDLES,
	// which will come through here, so we don't want to recurse forever by
	// calling FS_FOpenFileWrite()...use the Unix system APIs instead.
	f = open(ospath, O_CREAT | O_TRUNC | O_WRONLY, 0640);
	if (f == -1)
	{
		Com_Printf("ERROR: couldn't open '%s'\n", fileName);
		return;
	}

	// We're crashing, so we don't care much if write() or close() fails.
	while ((size = CON_LogRead(buffer, sizeof(buffer))) > 0)
	{
		if (write(f, buffer, size) != size)
		{
			Com_Printf("ERROR: couldn't fully write to '%s'\n", fileName);
			break;
		}
	}

	close(f);
}
Esempio n. 2
0
/*
 * Creates any directories needed to store the given filename.
 */
void
FS_CreatePath(char *path)
{
	char *cur; /* Current '/'. */
	char *old; /* Old '/'. */

	FS_DPrintf("FS_CreatePath(%s)\n", path);

	if (strstr(path, "..") != NULL)
	{
		Com_Printf("WARNING: refusing to create relative path '%s'.\n", path);
		return;
	}

	cur = old = path;

	while (cur != NULL)
	{
		if ((cur - old) > 1)
		{
			*cur = '\0';
			Sys_Mkdir(path);
			*cur = '/';
		}

		old = cur;
		cur = strchr(old + 1, '/');
	}
}
Esempio n. 3
0
void CL_LocWrite(char *filename)
{
	char mapname[32];
    int i;
	FILE *f;

	strcpy(mapname, cl.configstrings[CS_MODELS + 1] + 5);   // Xile; lets just keep saving em to one file mmmkay?
	mapname[strlen(mapname) - 4] = 0;

	Sys_Mkdir("locs");

	if (!(f = fopen(va("locs/%s.loc", mapname), "w")))
	{
		Com_Printf("Warning: Unable to open locs/%s.loc for writing.\n", mapname);
		return;
	}

	for (i = 0; i < MAX_LOCATIONS; i++)
	{
		if (!locations[i].used)
			continue;

		fprintf(f, "%d %d %d %s\n",
			locations[i].origin[0], locations[i].origin[1], locations[i].origin[2], locations[i].name);
	}

	fclose(f);

	Com_Printf("locs/%s.loc was successfully saved.\n", mapname);
}
Esempio n. 4
0
const char* PbSv6makefn(char *outmodname, char *modulename)
{
	char homepath[MAX_OSPATH];

	if ( !pbsv.pbPath[0] )
	{
		PbSvBuildBasePath( pbsv.pbPath );
		PbSvBuildHomePath( homepath );

		if ( Q_stricmp(homepath, pbsv.pbPath) && homepath[0] && pbsv.pbPath[0] )
		{
		  Sys_Mkdir( pbsv.pbPath );
		  Sys_Mkdir( homepath );
		  PbSvMakeHomepathCopy("pbsv" DLL_EXT, homepath);
		  PbSvMakeHomepathCopy("pbcl" DLL_EXT, homepath);
		  PbSvMakeHomepathCopy("pbag" DLL_EXT, homepath);
		}
	}
	Q_strncpyz(outmodname, pbsv.pbPath, MAX_OSPATH);
	Q_strcat(outmodname, MAX_OSPATH, modulename);
	return outmodname;
}
Esempio n. 5
0
/*
============
FS_CreatePath

Creates any directories needed to store the given filename
============
*/
void	FS_CreatePath (char *path)
{
	char	*ofs;
	
	for (ofs = path+1 ; *ofs ; ofs++)
	{
		if (*ofs == '/')
		{	// create the directory
			*ofs = 0;
			Sys_Mkdir (path);
			*ofs = '/';
		}
	}
}
Esempio n. 6
0
/* 
================== 
R_ScreenShot_f
================== 
*/  
void R_ScreenShot_f (void) 
{ 
	int			i; 
	char		pcxname[80]; 
	char		checkname[MAX_OSPATH];
	FILE		*f;
	byte		palette[768];

	// create the scrnshots directory if it doesn't exist
	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
	Sys_Mkdir (checkname);

// 
// find a file name to save it to 
// 
	strcpy(pcxname,"quake00.pcx");
		
	for (i=0 ; i<=99 ; i++) 
	{ 
		pcxname[5] = i/10 + '0'; 
		pcxname[6] = i%10 + '0'; 
		Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname);
		f = fopen (checkname, "r");
		if (!f)
			break;	// file doesn't exist
		fclose (f);
	} 
	if (i==100) 
	{
		ri.Con_Printf (PRINT_ALL, "R_ScreenShot_f: Couldn't create a PCX"); 
		return;
	}

	// turn the current 32 bit palette into a 24 bit palette
	for (i=0 ; i<256 ; i++)
	{
		palette[i*3+0] = sw_state.currentpalette[i*4+0];
		palette[i*3+1] = sw_state.currentpalette[i*4+1];
		palette[i*3+2] = sw_state.currentpalette[i*4+2];
	}

// 
// save the pcx file 
// 

	WritePCXfile (checkname, vid.buffer, vid.width, vid.height, vid.rowbytes,
				  palette);

	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", checkname);
} 
Esempio n. 7
0
void
Sys_RedirectStdout(void)
{
	char *cur;
	char *old;
	char dir[MAX_OSPATH];
	char path_stdout[MAX_OSPATH];
	char path_stderr[MAX_OSPATH];
	const char *tmp;

	if (is_portable) {
		tmp = Sys_GetBinaryDir();
		Q_strlcpy(dir, tmp, sizeof(dir));
	} else {
		tmp = Sys_GetHomeDir();
		Q_strlcpy(dir, tmp, sizeof(dir));
	}

	if (dir == NULL)
	{
		return;
	}

	cur = old = dir;

	while (cur != NULL)
	{
		if ((cur - old) > 1)
		{
			*cur = '\0';
			Sys_Mkdir(dir);
			*cur = '/';
		}

		old = cur;
		cur = strchr(old + 1, '/');
	}

	snprintf(path_stdout, sizeof(path_stdout), "%s/%s", dir, "stdout.txt");
	snprintf(path_stderr, sizeof(path_stderr), "%s/%s", dir, "stderr.txt");

	freopen(path_stdout, "w", stdout);
	freopen(path_stderr, "w", stderr);
}
Esempio n. 8
0
static void Sys_ErrorDialog( const char *error )
{
	time_t rawtime;
	char timeStr[32] = {}; // should really only reach ~19 chars
	char crashLogPath[MAX_OSPATH];

	time( &rawtime );
	strftime( timeStr, sizeof( timeStr ), "%Y-%m-%d_%H-%M-%S", localtime( &rawtime ) ); // or gmtime
	Com_sprintf( crashLogPath, sizeof( crashLogPath ),
					"%s%ccrashlog-%s.txt",
					Sys_DefaultHomePath(), PATH_SEP, timeStr );

	Sys_Mkdir( Sys_DefaultHomePath() );

	FILE *fp = fopen( crashLogPath, "w" );
	if ( fp )
	{
		ConsoleLogWriteOut( fp );
		fclose( fp );

		const char *errorMessage = va( "%s\n\nThe crash log was written to %s", error, crashLogPath );
		if ( SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "Error", errorMessage, NULL ) < 0 )
		{
			fprintf( stderr, "%s", errorMessage );
		}
	}
	else
	{
		// Getting pretty desperate now
		ConsoleLogWriteOut( stderr );
		fflush( stderr );

		const char *errorMessage = va( "%s\nCould not write the crash log file, but we printed it to stderr.\n"
										"Try running the game using a command line interface.", error );
		if ( SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "Error", errorMessage, NULL ) < 0 )
		{
			// We really have hit rock bottom here :(
			fprintf( stderr, "%s", errorMessage );
		}
	}
}
Esempio n. 9
0
/*
============
FS_CreatePath

Creates any directories needed to store the given filename
============
*/
void	FS_CreatePath (char *OSPath) {
	char	*ofs;
	
	// make absolutely sure that it can't back up the path
	// FIXME: is c: allowed???
	if ( strstr( OSPath, ".." ) || strstr( OSPath, "::" ) ) {
		Com_Printf( "WARNING: refusing to create relative path \"%s\"\n", OSPath );
		return;
	}

	strlwr(OSPath);

	for (ofs = OSPath+1 ; *ofs ; ofs++) {
		if (*ofs == PATH_SEP) {	
			// create the directory
			*ofs = 0;
			Sys_Mkdir (OSPath);
			*ofs = PATH_SEP;
		}
	}
}
Esempio n. 10
0
File: files.c Progetto: qbism/qbq2
/*
============
FS_CreatePath

Creates any directories needed to store the given filename
============
*/
void	FS_CreatePath(char *path)
{
	char	*ofs;

	// Knightmare added
	if (strstr(path, "..") || strstr(path, "::") || strstr(path, "\\\\") || strstr(path, "//"))
	{
		Com_Printf("WARNING: refusing to create relative path '%s'\n", path);
		return;
	}

	for (ofs = path + 1; *ofs; ofs++)
	{
		if (*ofs == '/')
		{	// create the directory
			*ofs = 0;
			Sys_Mkdir(path);
			*ofs = '/';
		}
	}
}
Esempio n. 11
0
/* 
================== 
R_ScreenShot_f
================== 
*/  
void R_ScreenShot_f (void) 
{ 
	int			i; 
// >>> FIX: For Nintendo Wii using devkitPPC / libogc
// Allocating in big stack. Stack in this device is pretty small:
	//char		pcxname[80]; 
	//char		checkname[MAX_OSPATH];
	//FILE		*f;
	//byte		palette[768];
	FILE		*f;
	char*		pcxname = Sys_BigStackAlloc(80, "R_ScreenShot_f"); 
	char*		checkname = Sys_BigStackAlloc(MAX_OSPATH, "R_ScreenShot_f");
	byte*		palette = Sys_BigStackAlloc(768, "R_ScreenShot_f");
// <<< FIX

	// create the scrnshots directory if it doesn't exist
// >>> FIX: For Nintendo Wii using devkitPPC / libogc
// Adjusting for previous fix:
	//Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
	Com_sprintf (checkname, MAX_OSPATH, "%s/scrnshot", ri.FS_Gamedir());
// <<< FIX
	Sys_Mkdir (checkname);

// 
// find a file name to save it to 
// 
	strcpy(pcxname,"quake00.pcx");
		
	for (i=0 ; i<=99 ; i++) 
	{ 
		pcxname[5] = i/10 + '0'; 
		pcxname[6] = i%10 + '0'; 
// >>> FIX: For Nintendo Wii using devkitPPC / libogc
// Adjusting for previous fix:
		//Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname);
		Com_sprintf (checkname, MAX_OSPATH, "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname);
// <<< FIX
		f = fopen (checkname, "r");
		if (!f)
			break;	// file doesn't exist
		fclose (f);
	} 
	if (i==100) 
	{
		ri.Con_Printf (PRINT_ALL, "R_ScreenShot_f: Couldn't create a PCX"); 
// >>> FIX: For Nintendo Wii using devkitPPC / libogc
// Deallocating from previous fix:
		Sys_BigStackFree(80 + MAX_OSPATH + 768, "R_ScreenShot_f"); 
// <<< FIX
		return;
	}

	// turn the current 32 bit palette into a 24 bit palette
	for (i=0 ; i<256 ; i++)
	{
		palette[i*3+0] = sw_state.currentpalette[i*4+0];
		palette[i*3+1] = sw_state.currentpalette[i*4+1];
		palette[i*3+2] = sw_state.currentpalette[i*4+2];
	}

// 
// save the pcx file 
// 

	WritePCXfile (checkname, vid.buffer, vid.width, vid.height, vid.rowbytes,
				  palette);

	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", checkname);

// >>> FIX: For Nintendo Wii using devkitPPC / libogc
// Deallocating from previous fix:
	Sys_BigStackFree(80 + MAX_OSPATH + 768, "R_ScreenShot_f"); 
// <<< FIX
} 
Esempio n. 12
0
void
R_ScreenShot(void)
{
	byte *buffer, temp;
	char picname[80];
	char checkname[MAX_OSPATH];
	int i, c;
	FILE *f;

	/* create the scrnshots directory if it doesn't exist */
	Com_sprintf(checkname, sizeof(checkname), "%s/scrnshot", FS_Gamedir());
	Sys_Mkdir(checkname);

	/* find a file name to save it to */
	strcpy(picname, "quake00.tga");

	for (i = 0; i <= 99; i++)
	{
		picname[5] = i / 10 + '0';
		picname[6] = i % 10 + '0';
		Com_sprintf(checkname, sizeof(checkname), "%s/scrnshot/%s",
			   	FS_Gamedir(), picname);
		f = fopen(checkname, "rb");

		if (!f)
		{
			break; /* file doesn't exist */
		}

		fclose(f);
	}

	if (i == 100)
	{
		VID_Printf(PRINT_ALL, "SCR_ScreenShot_f: Couldn't create a file\n");
		return;
	}

	static const int headerLength = 18+4;

	c = headerLength + vid.width * vid.height * 3;

	buffer = malloc(c);
	if (!buffer)
	{
		VID_Printf(PRINT_ALL, "SCR_ScreenShot_f: Couldn't malloc %d bytes\n", c);
		return;
	}

	memset(buffer, 0, headerLength);
	buffer[0] = 4; // image ID: "yq2\0"
	buffer[2] = 2; /* uncompressed type */
	buffer[12] = vid.width & 255;
	buffer[13] = vid.width >> 8;
	buffer[14] = vid.height & 255;
	buffer[15] = vid.height >> 8;
	buffer[16] = 24; /* pixel size */
	buffer[17] = 0; // image descriptor
	buffer[18] = 'y'; // following: the 4 image ID fields
	buffer[19] = 'q';
	buffer[20] = '2';
	buffer[21] = '\0';

	glPixelStorei(GL_PACK_ALIGNMENT, 1);
	glReadPixels(0, 0, vid.width, vid.height, GL_RGB,
			GL_UNSIGNED_BYTE, buffer + headerLength);

	/* swap rgb to bgr */
	for (i = headerLength; i < c; i += 3)
	{
		temp = buffer[i];
		buffer[i] = buffer[i + 2];
		buffer[i + 2] = temp;
	}

	f = fopen(checkname, "wb");
	if (f)
	{
		fwrite(buffer, 1, c, f);
		fclose(f);
		VID_Printf(PRINT_ALL, "Wrote %s\n", picname);
	}
	else
	{
		VID_Printf(PRINT_ALL, "SCR_ScreenShot_f: Couldn't write %s\n", picname);
	}

	free(buffer);
}
Esempio n. 13
0
void CL_AnimDump (void) 
{
	byte		*buffer;
	char		checkname[MAX_OSPATH];
	int			c, temp,o;
	unsigned int i;
	FILE		*f;

	// create the scrnshots directory if it doesn't exist
	Com_sprintf (checkname, sizeof(checkname), "%s/animdump", ri.FS_Gamedir());
	Sys_Mkdir (checkname);

// 
// find a file name to save it to 
// 
	for (i = cl_anim_count; i <= 99999999; i++) 
	{ 
		Com_sprintf(checkname, sizeof(checkname), "%s/animdump/anim%5i.tga", ri.FS_Gamedir(), i);

		for (o = 0; o < strlen(checkname); o++)
			if (checkname[o] == ' ')
				checkname[o] = '0';

		f = fopen (checkname, "rb");

		if (!f)
			break;	// file doesn't exist

		fclose(f);
	} 

	if (i == 100000000) 
	{
		ri.Cvar_Set("cl_animdump", "0");
		ri.Con_Printf(PRINT_ALL, "CL_AnimDump: Max frames exported.\n"); 
		return;
 	}

	cl_anim_count = i;

	buffer = malloc(vid.width*vid.height*3 + 18);
	memset (buffer, 0, 18);
	buffer[2] = 2;		// uncompressed type
	buffer[12] = vid.width&255;
	buffer[13] = vid.width>>8;
	buffer[14] = vid.height&255;
	buffer[15] = vid.height>>8;
	buffer[16] = 24;	// pixel size
	qgl.PixelStorei(GL_PACK_ALIGNMENT, 1);
	qgl.ReadPixels(0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, buffer + 18); 
	apply_gamma(buffer + 18, vid.width, vid.height); // jitgamma -- apply video gammaramp to screenshot
	

	// swap rgb to bgr
	c = 18 + vid.width * vid.height * 3;
	for (i=18 ; i<c ; i+=3)
	{
		temp = buffer[i];
		buffer[i] = buffer[i+2];
		buffer[i+2] = temp;
	}

	f = fopen (checkname, "wb");
	fwrite (buffer, 1, c, f);
	fclose (f);

	free (buffer);
}
Esempio n. 14
0
/* 
================== 
GL_ScreenShot_f
================== 
*/  
void GL_ScreenShot_f (void) 
{
	byte		*buffer;
	char		picname[80]; 
	char		checkname[MAX_OSPATH];
	int			i, c, temp;
	FILE		*f;

	// create the scrnshots directory if it doesn't exist
	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
	Sys_Mkdir (checkname);

// 
// find a file name to save it to 
// 
	strcpy(picname,"quake00.tga");

	for (i=0 ; i<=99 ; i++) 
	{ 
		picname[5] = i/10 + '0'; 
		picname[6] = i%10 + '0'; 
		Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), picname);
		f = fopen (checkname, "rb");
		if (!f)
			break;	// file doesn't exist
		fclose (f);
	} 
	if (i==100) 
	{
		ri.Con_Printf (PRINT_ALL, "SCR_ScreenShot_f: Couldn't create a file\n"); 
		return;
 	}


	buffer = malloc(vid.width*vid.height*3 + 18);
	memset (buffer, 0, 18);
	buffer[2] = 2;		// uncompressed type
	buffer[12] = vid.width&255;
	buffer[13] = vid.width>>8;
	buffer[14] = vid.height&255;
	buffer[15] = vid.height>>8;
	buffer[16] = 24;	// pixel size

	qglReadPixels (0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); 

	// swap rgb to bgr
	c = 18+vid.width*vid.height*3;
	for (i=18 ; i<c ; i+=3)
	{
		temp = buffer[i];
		buffer[i] = buffer[i+2];
		buffer[i+2] = temp;
	}

	f = fopen (checkname, "wb");
	fwrite (buffer, 1, c, f);
	fclose (f);

	free (buffer);
	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", picname);
} 
Esempio n. 15
0
/* 
================== 
GL_ScreenShot_JPG
By Robert 'Heffo' Heffernan
================== 
*/
void GL_ScreenShot_JPG_f (void)
{
	struct jpeg_compress_struct		cinfo;
	struct jpeg_error_mgr			jerr;
	byte							*rgbdata;
	JSAMPROW						s[1];
	FILE							*file;
	char							picname[80], checkname[MAX_OSPATH];
	int								i, offset;

	// Create the scrnshots directory if it doesn't exist
	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
	Sys_Mkdir (checkname);

	// Find a file name to save it to 
	strcpy(picname,"quake00.jpg");

	for (i=0 ; i<=99 ; i++) 
	{ 
		picname[5] = i/10 + '0'; 
		picname[6] = i%10 + '0'; 
		Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), picname);
		file = fopen (checkname, "rb");
		if (!file)
			break;	// file doesn't exist
		fclose (file);
	} 
	if (i==100) 
	{
		ri.Con_Printf (PRINT_ALL, "SCR_JPGScreenShot_f: Couldn't create a file\n"); 
		return;
 	}

	// Open the file for Binary Output
	file = fopen(checkname, "wb");
	if(!file)
	{
		ri.Con_Printf (PRINT_ALL, "GL_ScreenShotJPG_f: Couldn't create a file\n"); 
		return;
 	}

	// Allocate room for a copy of the framebuffer
	rgbdata = malloc(vid.width * vid.height * 3);
	if(!rgbdata)
	{
		fclose(file);
		return;
	}

	// Read the framebuffer into our storage
	qglReadPixels(0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, rgbdata);

	// Initialise the JPEG compression object
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_compress(&cinfo);
	jpeg_stdio_dest(&cinfo, file);

	// Setup JPEG Parameters
	cinfo.image_width = vid.width;
	cinfo.image_height = vid.height;
	cinfo.in_color_space = JCS_RGB;
	cinfo.input_components = 3;
	jpeg_set_defaults(&cinfo);
	if((r_jpeg_quality->value >= 101) || (r_jpeg_quality->value <= 0))
		ri.Cvar_Set("r_jpeg_quality", "85");
	jpeg_set_quality(&cinfo, r_jpeg_quality->value, 1);

	// Start Compression
	jpeg_start_compress(&cinfo, 1);

	// Feed Scanline data
	offset = (cinfo.image_width * cinfo.image_height * 3) - (cinfo.image_width * 3);
	while(cinfo.next_scanline < cinfo.image_height)
	{
		s[0] = &rgbdata[offset - (cinfo.next_scanline * (cinfo.image_width * 3))];
		jpeg_write_scanlines(&cinfo, s, 1);
	}

	// Finish Compression
	jpeg_finish_compress(&cinfo);

	// Destroy JPEG object
	jpeg_destroy_compress(&cinfo);

	// Close File
	fclose(file);

	// Free Temp Framebuffer
	free(rgbdata);

	// Done!
	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", picname);
}
Esempio n. 16
0
void GL_ScreenShot_PNG (void)
{
	byte			*rgbdata;
	FILE			*file;
	char			picname[80], checkname[MAX_OSPATH];
	int				i, j, k;
	png_structp		png_ptr;
	png_infop		info_ptr;


	//not working yet...
	ri.Con_Printf (PRINT_ALL, "PNG Screenshot...(^iDisabled^r)\n"); 
	return;

	// Create the scrnshots directory if it doesn't exist
	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
	Sys_Mkdir (checkname);

	for (i=0 ; i<=999 ; i++) 
	{
		Com_sprintf (picname, sizeof(picname), "quake2max%i%i%i.png", (int)(i/100)%10, (int)(i/10)%10, i%10);
		Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), picname);
		file = fopen (checkname, "rb");
		if (!file)
			break;	// file doesn't exist
		fclose (file);
	} 
	if (i==1000) 
	{
		ri.Con_Printf (PRINT_ALL, "GL_ScreenShot_PNG: Couldn't create a file\n"); 
		return;
 	}

	// Allocate room for a copy of the framebuffer
	rgbdata = malloc(vid.width * vid.height * 3);
	if(!rgbdata)
		return;

	// Read the framebuffer into our storage
	qglReadPixels(0, 0, vid.width, vid.height, GL_RGB, GL_UNSIGNED_BYTE, rgbdata);

	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0,0,0);
	if (!png_ptr)
	{
		free(rgbdata);

		ri.Con_Printf (PRINT_ALL, "GL_ScreenShot_PNG: Couldn't create image (NO PNG_PTR)\n"); 
		return;
	}

	// Allocate/initialize the image information data.  REQUIRED
	info_ptr = png_create_info_struct(png_ptr);

	if (!info_ptr)
	{
		png_destroy_write_struct(&png_ptr,  0);
		free(rgbdata);

		ri.Con_Printf (PRINT_ALL, "GL_ScreenShot_PNG: Couldn't create image (NO INFO_PTR)\n"); 
		return;
	}

	if (setjmp(png_ptr->jmpbuf))
	{
		png_destroy_write_struct(&png_ptr, &info_ptr);
		free(rgbdata);

		ri.Con_Printf (PRINT_ALL, "GL_ScreenShot_PNG: Couldn't create image (BAD INFO)\n"); 
		return;
	}

	// Open the file for Binary Output
	file = fopen(checkname, "wb");
	if(!file)
	{
		ri.Con_Printf (PRINT_ALL, "GL_ScreenShot_PNG: Couldn't create a file\n"); 
		return;
 	}

	png_init_io(png_ptr, file);

	png_set_IHDR(png_ptr, info_ptr, 
		vid.width, 
		vid.height, 
		8, 
		PNG_COLOR_TYPE_RGB,		 
		PNG_INTERLACE_NONE,
		PNG_COMPRESSION_TYPE_BASE,
		PNG_FILTER_TYPE_BASE);

	png_write_info(png_ptr, info_ptr);

	for (k = 0; k < vid.height; k++)
	{
		void *pointer = rgbdata + k*vid.width*3;
		png_write_row(png_ptr, pointer);
	}

	png_write_end(png_ptr, info_ptr);

	png_destroy_write_struct(&png_ptr, &info_ptr);

	// Close File
	fclose(file);

	// Free Temp Framebuffer
	free(rgbdata);

	// Done!
	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", picname);
}