Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

r_misc.c (14934B)


      1 /*
      2 Copyright (C) 1997-2001 Id Software, Inc.
      3 
      4 This program is free software; you can redistribute it and/or
      5 modify it under the terms of the GNU General Public License
      6 as published by the Free Software Foundation; either version 2
      7 of the License, or (at your option) any later version.
      8 
      9 This program is distributed in the hope that it will be useful,
     10 but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
     12 
     13 See the GNU General Public License for more details.
     14 
     15 You should have received a copy of the GNU General Public License
     16 along with this program; if not, write to the Free Software
     17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
     18 
     19 */
     20 // r_misc.c
     21 
     22 #include "r_local.h"
     23 
     24 #define NUM_MIPS	4
     25 
     26 cvar_t	*sw_mipcap;
     27 cvar_t	*sw_mipscale;
     28 
     29 surfcache_t		*d_initial_rover;
     30 qboolean		d_roverwrapped;
     31 int				d_minmip;
     32 float			d_scalemip[NUM_MIPS-1];
     33 
     34 static float	basemip[NUM_MIPS-1] = {1.0, 0.5*0.8, 0.25*0.8};
     35 
     36 extern int			d_aflatcolor;
     37 
     38 int	d_vrectx, d_vrecty, d_vrectright_particle, d_vrectbottom_particle;
     39 
     40 int	d_pix_min, d_pix_max, d_pix_shift;
     41 
     42 int		d_scantable[MAXHEIGHT];
     43 short	*zspantable[MAXHEIGHT]; 
     44 
     45 /*
     46 ================
     47 D_Patch
     48 ================
     49 */
     50 void D_Patch (void)
     51 {
     52 #if id386
     53 	extern void D_Aff8Patch( void );
     54 	static qboolean protectset8 = false;
     55 	extern void D_PolysetAff8Start( void );
     56 
     57 	if (!protectset8)
     58 	{
     59 		Sys_MakeCodeWriteable ((int)D_PolysetAff8Start,
     60 						     (int)D_Aff8Patch - (int)D_PolysetAff8Start);
     61 		Sys_MakeCodeWriteable ((long)R_Surf8Start,
     62 						 (long)R_Surf8End - (long)R_Surf8Start);
     63 		protectset8 = true;
     64 	}
     65 	colormap = vid.colormap;
     66 
     67 	R_Surf8Patch ();
     68 	D_Aff8Patch();
     69 #endif
     70 }
     71 /*
     72 ================
     73 D_ViewChanged
     74 ================
     75 */
     76 unsigned char *alias_colormap;
     77 
     78 void D_ViewChanged (void)
     79 {
     80 	int		i;
     81 
     82 	scale_for_mip = xscale;
     83 	if (yscale > xscale)
     84 		scale_for_mip = yscale;
     85 
     86 	d_zrowbytes = vid.width * 2;
     87 	d_zwidth = vid.width;
     88 
     89 	d_pix_min = r_refdef.vrect.width / 320;
     90 	if (d_pix_min < 1)
     91 		d_pix_min = 1;
     92 
     93 	d_pix_max = (int)((float)r_refdef.vrect.width / (320.0 / 4.0) + 0.5);
     94 	d_pix_shift = 8 - (int)((float)r_refdef.vrect.width / 320.0 + 0.5);
     95 	if (d_pix_max < 1)
     96 		d_pix_max = 1;
     97 
     98 	d_vrectx = r_refdef.vrect.x;
     99 	d_vrecty = r_refdef.vrect.y;
    100 	d_vrectright_particle = r_refdef.vrectright - d_pix_max;
    101 	d_vrectbottom_particle =
    102 			r_refdef.vrectbottom - d_pix_max;
    103 
    104 	for (i=0 ; i<vid.height; i++)
    105 	{
    106 		d_scantable[i] = i*r_screenwidth;
    107 		zspantable[i] = d_pzbuffer + i*d_zwidth;
    108 	}
    109 
    110 	/*
    111 	** clear Z-buffer and color-buffers if we're doing the gallery
    112 	*/
    113 	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
    114 	{
    115 		memset( d_pzbuffer, 0xff, vid.width * vid.height * sizeof( d_pzbuffer[0] ) );
    116 		Draw_Fill( r_newrefdef.x, r_newrefdef.y, r_newrefdef.width, r_newrefdef.height,( int ) sw_clearcolor->value & 0xff );
    117 	}
    118 
    119 	alias_colormap = vid.colormap;
    120 
    121 	D_Patch ();
    122 }
    123 
    124 
    125 
    126 /*
    127 =============
    128 R_PrintTimes
    129 =============
    130 */
    131 void R_PrintTimes (void)
    132 {
    133 	int		r_time2;
    134 	int		ms;
    135 
    136 	r_time2 = Sys_Milliseconds ();
    137 
    138 	ms = r_time2 - r_time1;
    139 	
    140 	ri.Con_Printf (PRINT_ALL,"%5i ms %3i/%3i/%3i poly %3i surf\n",
    141 				ms, c_faceclip, r_polycount, r_drawnpolycount, c_surf);
    142 	c_surf = 0;
    143 }
    144 
    145 
    146 /*
    147 =============
    148 R_PrintDSpeeds
    149 =============
    150 */
    151 void R_PrintDSpeeds (void)
    152 {
    153 	int	ms, dp_time, r_time2, rw_time, db_time, se_time, de_time, da_time;
    154 
    155 	r_time2 = Sys_Milliseconds ();
    156 
    157 	da_time = (da_time2 - da_time1);
    158 	dp_time = (dp_time2 - dp_time1);
    159 	rw_time = (rw_time2 - rw_time1);
    160 	db_time = (db_time2 - db_time1);
    161 	se_time = (se_time2 - se_time1);
    162 	de_time = (de_time2 - de_time1);
    163 	ms = (r_time2 - r_time1);
    164 
    165 	ri.Con_Printf (PRINT_ALL,"%3i %2ip %2iw %2ib %2is %2ie %2ia\n",
    166 				ms, dp_time, rw_time, db_time, se_time, de_time, da_time);
    167 }
    168 
    169 
    170 /*
    171 =============
    172 R_PrintAliasStats
    173 =============
    174 */
    175 void R_PrintAliasStats (void)
    176 {
    177 	ri.Con_Printf (PRINT_ALL,"%3i polygon model drawn\n", r_amodels_drawn);
    178 }
    179 
    180 
    181 
    182 /*
    183 ===================
    184 R_TransformFrustum
    185 ===================
    186 */
    187 void R_TransformFrustum (void)
    188 {
    189 	int		i;
    190 	vec3_t	v, v2;
    191 	
    192 	for (i=0 ; i<4 ; i++)
    193 	{
    194 		v[0] = screenedge[i].normal[2];
    195 		v[1] = -screenedge[i].normal[0];
    196 		v[2] = screenedge[i].normal[1];
    197 
    198 		v2[0] = v[1]*vright[0] + v[2]*vup[0] + v[0]*vpn[0];
    199 		v2[1] = v[1]*vright[1] + v[2]*vup[1] + v[0]*vpn[1];
    200 		v2[2] = v[1]*vright[2] + v[2]*vup[2] + v[0]*vpn[2];
    201 
    202 		VectorCopy (v2, view_clipplanes[i].normal);
    203 
    204 		view_clipplanes[i].dist = DotProduct (modelorg, v2);
    205 	}
    206 }
    207 
    208 
    209 #if !(defined __linux__ && defined __i386__)
    210 #if !id386
    211 
    212 /*
    213 ================
    214 TransformVector
    215 ================
    216 */
    217 void TransformVector (vec3_t in, vec3_t out)
    218 {
    219 	out[0] = DotProduct(in,vright);
    220 	out[1] = DotProduct(in,vup);
    221 	out[2] = DotProduct(in,vpn);		
    222 }
    223 
    224 #else
    225 
    226 __declspec( naked ) void TransformVector( vec3_t vin, vec3_t vout )
    227 {
    228 	__asm mov eax, dword ptr [esp+4]
    229 	__asm mov edx, dword ptr [esp+8]
    230 
    231 	__asm fld  dword ptr [eax+0]
    232 	__asm fmul dword ptr [vright+0]
    233 	__asm fld  dword ptr [eax+0]
    234 	__asm fmul dword ptr [vup+0]
    235 	__asm fld  dword ptr [eax+0]
    236 	__asm fmul dword ptr [vpn+0]
    237 
    238 	__asm fld  dword ptr [eax+4]
    239 	__asm fmul dword ptr [vright+4]
    240 	__asm fld  dword ptr [eax+4]
    241 	__asm fmul dword ptr [vup+4]
    242 	__asm fld  dword ptr [eax+4]
    243 	__asm fmul dword ptr [vpn+4]
    244 
    245 	__asm fxch st(2)
    246 
    247 	__asm faddp st(5), st(0)
    248 	__asm faddp st(3), st(0)
    249 	__asm faddp st(1), st(0)
    250 
    251 	__asm fld  dword ptr [eax+8]
    252 	__asm fmul dword ptr [vright+8]
    253 	__asm fld  dword ptr [eax+8]
    254 	__asm fmul dword ptr [vup+8]
    255 	__asm fld  dword ptr [eax+8]
    256 	__asm fmul dword ptr [vpn+8]
    257 
    258 	__asm fxch st(2)
    259 
    260 	__asm faddp st(5), st(0)
    261 	__asm faddp st(3), st(0)
    262 	__asm faddp st(1), st(0)
    263 
    264 	__asm fstp dword ptr [edx+8]
    265 	__asm fstp dword ptr [edx+4]
    266 	__asm fstp dword ptr [edx+0]
    267 
    268 	__asm ret
    269 }
    270 
    271 #endif
    272 #endif
    273 
    274 
    275 /*
    276 ================
    277 R_TransformPlane
    278 ================
    279 */
    280 void R_TransformPlane (mplane_t *p, float *normal, float *dist)
    281 {
    282 	float	d;
    283 	
    284 	d = DotProduct (r_origin, p->normal);
    285 	*dist = p->dist - d;
    286 // TODO: when we have rotating entities, this will need to use the view matrix
    287 	TransformVector (p->normal, normal);
    288 }
    289 
    290 
    291 /*
    292 ===============
    293 R_SetUpFrustumIndexes
    294 ===============
    295 */
    296 void R_SetUpFrustumIndexes (void)
    297 {
    298 	int		i, j, *pindex;
    299 
    300 	pindex = r_frustum_indexes;
    301 
    302 	for (i=0 ; i<4 ; i++)
    303 	{
    304 		for (j=0 ; j<3 ; j++)
    305 		{
    306 			if (view_clipplanes[i].normal[j] < 0)
    307 			{
    308 				pindex[j] = j;
    309 				pindex[j+3] = j+3;
    310 			}
    311 			else
    312 			{
    313 				pindex[j] = j+3;
    314 				pindex[j+3] = j;
    315 			}
    316 		}
    317 
    318 	// FIXME: do just once at start
    319 		pfrustum_indexes[i] = pindex;
    320 		pindex += 6;
    321 	}
    322 }
    323 
    324 /*
    325 ===============
    326 R_ViewChanged
    327 
    328 Called every time the vid structure or r_refdef changes.
    329 Guaranteed to be called before the first refresh
    330 ===============
    331 */
    332 void R_ViewChanged (vrect_t *vr)
    333 {
    334 	int		i;
    335 
    336 	r_refdef.vrect = *vr;
    337 
    338 	r_refdef.horizontalFieldOfView = 2*tan((float)r_newrefdef.fov_x/360*M_PI);;
    339 	verticalFieldOfView = 2*tan((float)r_newrefdef.fov_y/360*M_PI);
    340 
    341 	r_refdef.fvrectx = (float)r_refdef.vrect.x;
    342 	r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5;
    343 	r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1;
    344 	r_refdef.fvrecty = (float)r_refdef.vrect.y;
    345 	r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5;
    346 	r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
    347 	r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1;
    348 	r_refdef.fvrectright = (float)r_refdef.vrectright;
    349 	r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5;
    350 	r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99;
    351 	r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
    352 	r_refdef.fvrectbottom = (float)r_refdef.vrectbottom;
    353 	r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5;
    354 
    355 	r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale);
    356 	r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale);
    357 	r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale);
    358 	r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale);
    359 	r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
    360 			r_refdef.aliasvrect.width;
    361 	r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
    362 			r_refdef.aliasvrect.height;
    363 
    364 	xOrigin = r_refdef.xOrigin;
    365 	yOrigin = r_refdef.yOrigin;
    366 	
    367 // values for perspective projection
    368 // if math were exact, the values would range from 0.5 to to range+0.5
    369 // hopefully they wll be in the 0.000001 to range+.999999 and truncate
    370 // the polygon rasterization will never render in the first row or column
    371 // but will definately render in the [range] row and column, so adjust the
    372 // buffer origin to get an exact edge to edge fill
    373 	xcenter = ((float)r_refdef.vrect.width * XCENTERING) +
    374 			r_refdef.vrect.x - 0.5;
    375 	aliasxcenter = xcenter * r_aliasuvscale;
    376 	ycenter = ((float)r_refdef.vrect.height * YCENTERING) +
    377 			r_refdef.vrect.y - 0.5;
    378 	aliasycenter = ycenter * r_aliasuvscale;
    379 
    380 	xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
    381 	aliasxscale = xscale * r_aliasuvscale;
    382 	xscaleinv = 1.0 / xscale;
    383 
    384 	yscale = xscale;
    385 	aliasyscale = yscale * r_aliasuvscale;
    386 	yscaleinv = 1.0 / yscale;
    387 	xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView;
    388 	yscaleshrink = xscaleshrink;
    389 
    390 // left side clip
    391 	screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView);
    392 	screenedge[0].normal[1] = 0;
    393 	screenedge[0].normal[2] = 1;
    394 	screenedge[0].type = PLANE_ANYZ;
    395 	
    396 // right side clip
    397 	screenedge[1].normal[0] =
    398 			1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView);
    399 	screenedge[1].normal[1] = 0;
    400 	screenedge[1].normal[2] = 1;
    401 	screenedge[1].type = PLANE_ANYZ;
    402 	
    403 // top side clip
    404 	screenedge[2].normal[0] = 0;
    405 	screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
    406 	screenedge[2].normal[2] = 1;
    407 	screenedge[2].type = PLANE_ANYZ;
    408 	
    409 // bottom side clip
    410 	screenedge[3].normal[0] = 0;
    411 	screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
    412 	screenedge[3].normal[2] = 1;	
    413 	screenedge[3].type = PLANE_ANYZ;
    414 	
    415 	for (i=0 ; i<4 ; i++)
    416 		VectorNormalize (screenedge[i].normal);
    417 
    418 	D_ViewChanged ();
    419 }
    420 
    421 
    422 /*
    423 ===============
    424 R_SetupFrame
    425 ===============
    426 */
    427 void R_SetupFrame (void)
    428 {
    429 	int			i;
    430 	vrect_t		vrect;
    431 
    432 	if (r_fullbright->modified)
    433 	{
    434 		r_fullbright->modified = false;
    435 		D_FlushCaches ();	// so all lighting changes
    436 	}
    437 	
    438 	r_framecount++;
    439 
    440 
    441 // build the transformation matrix for the given view angles
    442 	VectorCopy (r_refdef.vieworg, modelorg);
    443 	VectorCopy (r_refdef.vieworg, r_origin);
    444 
    445 	AngleVectors (r_refdef.viewangles, vpn, vright, vup);
    446 
    447 // current viewleaf
    448 	if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
    449 	{
    450 		r_viewleaf = Mod_PointInLeaf (r_origin, r_worldmodel);
    451 		r_viewcluster = r_viewleaf->cluster;
    452 	}
    453 
    454 	if (sw_waterwarp->value && (r_newrefdef.rdflags & RDF_UNDERWATER) )
    455 		r_dowarp = true;
    456 	else
    457 		r_dowarp = false;
    458 
    459 	if (r_dowarp)
    460 	{	// warp into off screen buffer
    461 		vrect.x = 0;
    462 		vrect.y = 0;
    463 		vrect.width = r_newrefdef.width < WARP_WIDTH ? r_newrefdef.width : WARP_WIDTH;
    464 		vrect.height = r_newrefdef.height < WARP_HEIGHT ? r_newrefdef.height : WARP_HEIGHT;
    465 
    466 		d_viewbuffer = r_warpbuffer;
    467 		r_screenwidth = WARP_WIDTH;
    468 	}
    469 	else
    470 	{
    471 		vrect.x = r_newrefdef.x;
    472 		vrect.y = r_newrefdef.y;
    473 		vrect.width = r_newrefdef.width;
    474 		vrect.height = r_newrefdef.height;
    475 
    476 		d_viewbuffer = (void *)vid.buffer;
    477 		r_screenwidth = vid.rowbytes;
    478 	}
    479 	
    480 	R_ViewChanged (&vrect);
    481 
    482 // start off with just the four screen edge clip planes
    483 	R_TransformFrustum ();
    484 	R_SetUpFrustumIndexes ();
    485 
    486 // save base values
    487 	VectorCopy (vpn, base_vpn);
    488 	VectorCopy (vright, base_vright);
    489 	VectorCopy (vup, base_vup);
    490 
    491 // clear frame counts
    492 	c_faceclip = 0;
    493 	d_spanpixcount = 0;
    494 	r_polycount = 0;
    495 	r_drawnpolycount = 0;
    496 	r_wholepolycount = 0;
    497 	r_amodels_drawn = 0;
    498 	r_outofsurfaces = 0;
    499 	r_outofedges = 0;
    500 
    501 // d_setup
    502 	d_roverwrapped = false;
    503 	d_initial_rover = sc_rover;
    504 
    505 	d_minmip = sw_mipcap->value;
    506 	if (d_minmip > 3)
    507 		d_minmip = 3;
    508 	else if (d_minmip < 0)
    509 		d_minmip = 0;
    510 
    511 	for (i=0 ; i<(NUM_MIPS-1) ; i++)
    512 		d_scalemip[i] = basemip[i] * sw_mipscale->value;
    513 
    514 	d_aflatcolor = 0;
    515 }
    516 
    517 
    518 #if	!id386
    519 
    520 /*
    521 ================
    522 R_SurfacePatch
    523 ================
    524 */
    525 void R_SurfacePatch (void)
    526 {
    527 	// we only patch code on Intel
    528 }
    529 
    530 #endif	// !id386
    531 
    532 
    533 /* 
    534 ============================================================================== 
    535  
    536 						SCREEN SHOTS 
    537  
    538 ============================================================================== 
    539 */ 
    540 
    541 
    542 /* 
    543 ============== 
    544 WritePCXfile 
    545 ============== 
    546 */ 
    547 void WritePCXfile (char *filename, byte *data, int width, int height,
    548 	int rowbytes, byte *palette) 
    549 {
    550 	int			i, j, length;
    551 	pcx_t		*pcx;
    552 	byte		*pack;
    553 	FILE		*f;
    554 
    555 	pcx = (pcx_t *)malloc (width*height*2+1000);
    556 	if (!pcx)
    557 		return;
    558 
    559 	pcx->manufacturer = 0x0a;	// PCX id
    560 	pcx->version = 5;			// 256 color
    561  	pcx->encoding = 1;		// uncompressed
    562 	pcx->bits_per_pixel = 8;		// 256 color
    563 	pcx->xmin = 0;
    564 	pcx->ymin = 0;
    565 	pcx->xmax = LittleShort((short)(width-1));
    566 	pcx->ymax = LittleShort((short)(height-1));
    567 	pcx->hres = LittleShort((short)width);
    568 	pcx->vres = LittleShort((short)height);
    569 	memset (pcx->palette,0,sizeof(pcx->palette));
    570 	pcx->color_planes = 1;		// chunky image
    571 	pcx->bytes_per_line = LittleShort((short)width);
    572 	pcx->palette_type = LittleShort(2);		// not a grey scale
    573 	memset (pcx->filler,0,sizeof(pcx->filler));
    574 
    575 // pack the image
    576 	pack = &pcx->data;
    577 	
    578 	for (i=0 ; i<height ; i++)
    579 	{
    580 		for (j=0 ; j<width ; j++)
    581 		{
    582 			if ( (*data & 0xc0) != 0xc0)
    583 				*pack++ = *data++;
    584 			else
    585 			{
    586 				*pack++ = 0xc1;
    587 				*pack++ = *data++;
    588 			}
    589 		}
    590 
    591 		data += rowbytes - width;
    592 	}
    593 			
    594 // write the palette
    595 	*pack++ = 0x0c;	// palette ID byte
    596 	for (i=0 ; i<768 ; i++)
    597 		*pack++ = *palette++;
    598 		
    599 // write output file 
    600 	length = pack - (byte *)pcx;
    601 	f = fopen (filename, "wb");
    602 	if (!f)
    603 		ri.Con_Printf (PRINT_ALL, "Failed to open to %s\n", filename);
    604 	else
    605 	{
    606 		fwrite ((void *)pcx, 1, length, f);
    607 		fclose (f);
    608 	}
    609 
    610 	free (pcx);
    611 } 
    612  
    613 
    614 
    615 /* 
    616 ================== 
    617 R_ScreenShot_f
    618 ================== 
    619 */  
    620 void R_ScreenShot_f (void) 
    621 { 
    622 	int			i; 
    623 	char		pcxname[80]; 
    624 	char		checkname[MAX_OSPATH];
    625 	FILE		*f;
    626 	byte		palette[768];
    627 
    628 	// create the scrnshots directory if it doesn't exist
    629 	Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot", ri.FS_Gamedir());
    630 	Sys_Mkdir (checkname);
    631 
    632 // 
    633 // find a file name to save it to 
    634 // 
    635 	strcpy(pcxname,"quake00.pcx");
    636 		
    637 	for (i=0 ; i<=99 ; i++) 
    638 	{ 
    639 		pcxname[5] = i/10 + '0'; 
    640 		pcxname[6] = i%10 + '0'; 
    641 		Com_sprintf (checkname, sizeof(checkname), "%s/scrnshot/%s", ri.FS_Gamedir(), pcxname);
    642 		f = fopen (checkname, "r");
    643 		if (!f)
    644 			break;	// file doesn't exist
    645 		fclose (f);
    646 	} 
    647 	if (i==100) 
    648 	{
    649 		ri.Con_Printf (PRINT_ALL, "R_ScreenShot_f: Couldn't create a PCX"); 
    650 		return;
    651 	}
    652 
    653 	// turn the current 32 bit palette into a 24 bit palette
    654 	for (i=0 ; i<256 ; i++)
    655 	{
    656 		palette[i*3+0] = sw_state.currentpalette[i*4+0];
    657 		palette[i*3+1] = sw_state.currentpalette[i*4+1];
    658 		palette[i*3+2] = sw_state.currentpalette[i*4+2];
    659 	}
    660 
    661 // 
    662 // save the pcx file 
    663 // 
    664 
    665 	WritePCXfile (checkname, vid.buffer, vid.width, vid.height, vid.rowbytes,
    666 				  palette);
    667 
    668 	ri.Con_Printf (PRINT_ALL, "Wrote %s\n", checkname);
    669 } 
    670