Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

r_main.c (29507B)


      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_main.c
     21 
     22 #include "r_local.h"
     23 
     24 viddef_t	vid;
     25 refimport_t	ri;
     26 
     27 unsigned	d_8to24table[256];
     28 
     29 entity_t	r_worldentity;
     30 
     31 char		skyname[MAX_QPATH];
     32 float		skyrotate;
     33 vec3_t		skyaxis;
     34 image_t		*sky_images[6];
     35 
     36 refdef_t	r_newrefdef;
     37 model_t		*currentmodel;
     38 
     39 model_t		*r_worldmodel;
     40 
     41 byte		r_warpbuffer[WARP_WIDTH * WARP_HEIGHT];
     42 
     43 swstate_t sw_state;
     44 
     45 void		*colormap;
     46 vec3_t		viewlightvec;
     47 alight_t	r_viewlighting = {128, 192, viewlightvec};
     48 float		r_time1;
     49 int			r_numallocatededges;
     50 float		r_aliasuvscale = 1.0;
     51 int			r_outofsurfaces;
     52 int			r_outofedges;
     53 
     54 qboolean	r_dowarp;
     55 
     56 mvertex_t	*r_pcurrentvertbase;
     57 
     58 int			c_surf;
     59 int			r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
     60 qboolean	r_surfsonstack;
     61 int			r_clipflags;
     62 
     63 //
     64 // view origin
     65 //
     66 vec3_t	vup, base_vup;
     67 vec3_t	vpn, base_vpn;
     68 vec3_t	vright, base_vright;
     69 vec3_t	r_origin;
     70 
     71 //
     72 // screen size info
     73 //
     74 oldrefdef_t	r_refdef;
     75 float		xcenter, ycenter;
     76 float		xscale, yscale;
     77 float		xscaleinv, yscaleinv;
     78 float		xscaleshrink, yscaleshrink;
     79 float		aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
     80 
     81 int		r_screenwidth;
     82 
     83 float	verticalFieldOfView;
     84 float	xOrigin, yOrigin;
     85 
     86 mplane_t	screenedge[4];
     87 
     88 //
     89 // refresh flags
     90 //
     91 int		r_framecount = 1;	// so frame counts initialized to 0 don't match
     92 int		r_visframecount;
     93 int		d_spanpixcount;
     94 int		r_polycount;
     95 int		r_drawnpolycount;
     96 int		r_wholepolycount;
     97 
     98 int			*pfrustum_indexes[4];
     99 int			r_frustum_indexes[4*6];
    100 
    101 mleaf_t		*r_viewleaf;
    102 int			r_viewcluster, r_oldviewcluster;
    103 
    104 image_t  	*r_notexture_mip;
    105 
    106 float	da_time1, da_time2, dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
    107 float	se_time1, se_time2, de_time1, de_time2;
    108 
    109 void R_MarkLeaves (void);
    110 
    111 cvar_t	*r_lefthand;
    112 cvar_t	*sw_aliasstats;
    113 cvar_t	*sw_allow_modex;
    114 cvar_t	*sw_clearcolor;
    115 cvar_t	*sw_drawflat;
    116 cvar_t	*sw_draworder;
    117 cvar_t	*sw_maxedges;
    118 cvar_t	*sw_maxsurfs;
    119 cvar_t  *sw_mode;
    120 cvar_t	*sw_reportedgeout;
    121 cvar_t	*sw_reportsurfout;
    122 cvar_t  *sw_stipplealpha;
    123 cvar_t	*sw_surfcacheoverride;
    124 cvar_t	*sw_waterwarp;
    125 
    126 cvar_t	*r_drawworld;
    127 cvar_t	*r_drawentities;
    128 cvar_t	*r_dspeeds;
    129 cvar_t	*r_fullbright;
    130 cvar_t  *r_lerpmodels;
    131 cvar_t  *r_novis;
    132 
    133 cvar_t	*r_speeds;
    134 cvar_t	*r_lightlevel;	//FIXME HACK
    135 
    136 cvar_t	*vid_fullscreen;
    137 cvar_t	*vid_gamma;
    138 
    139 //PGM
    140 cvar_t	*sw_lockpvs;
    141 //PGM
    142 
    143 #define	STRINGER(x) "x"
    144 
    145 
    146 #if	!id386
    147 
    148 // r_vars.c
    149 
    150 // all global and static refresh variables are collected in a contiguous block
    151 // to avoid cache conflicts.
    152 
    153 //-------------------------------------------------------
    154 // global refresh variables
    155 //-------------------------------------------------------
    156 
    157 // FIXME: make into one big structure, like cl or sv
    158 // FIXME: do separately for refresh engine and driver
    159 
    160 
    161 // d_vars.c
    162 
    163 // all global and static refresh variables are collected in a contiguous block
    164 // to avoid cache conflicts.
    165 
    166 //-------------------------------------------------------
    167 // global refresh variables
    168 //-------------------------------------------------------
    169 
    170 // FIXME: make into one big structure, like cl or sv
    171 // FIXME: do separately for refresh engine and driver
    172 
    173 float	d_sdivzstepu, d_tdivzstepu, d_zistepu;
    174 float	d_sdivzstepv, d_tdivzstepv, d_zistepv;
    175 float	d_sdivzorigin, d_tdivzorigin, d_ziorigin;
    176 
    177 fixed16_t	sadjust, tadjust, bbextents, bbextentt;
    178 
    179 pixel_t			*cacheblock;
    180 int				cachewidth;
    181 pixel_t			*d_viewbuffer;
    182 short			*d_pzbuffer;
    183 unsigned int	d_zrowbytes;
    184 unsigned int	d_zwidth;
    185 
    186 
    187 #endif	// !id386
    188 
    189 byte	r_notexture_buffer[1024];
    190 
    191 /*
    192 ==================
    193 R_InitTextures
    194 ==================
    195 */
    196 void	R_InitTextures (void)
    197 {
    198 	int		x,y, m;
    199 	byte	*dest;
    200 	
    201 // create a simple checkerboard texture for the default
    202 	r_notexture_mip = (image_t *)&r_notexture_buffer;
    203 	
    204 	r_notexture_mip->width = r_notexture_mip->height = 16;
    205 	r_notexture_mip->pixels[0] = &r_notexture_buffer[sizeof(image_t)];
    206 	r_notexture_mip->pixels[1] = r_notexture_mip->pixels[0] + 16*16;
    207 	r_notexture_mip->pixels[2] = r_notexture_mip->pixels[1] + 8*8;
    208 	r_notexture_mip->pixels[3] = r_notexture_mip->pixels[2] + 4*4;
    209 	
    210 	for (m=0 ; m<4 ; m++)
    211 	{
    212 		dest = r_notexture_mip->pixels[m];
    213 		for (y=0 ; y< (16>>m) ; y++)
    214 			for (x=0 ; x< (16>>m) ; x++)
    215 			{
    216 				if (  (y< (8>>m) ) ^ (x< (8>>m) ) )
    217 
    218 					*dest++ = 0;
    219 				else
    220 					*dest++ = 0xff;
    221 			}
    222 	}	
    223 }
    224 
    225 
    226 /*
    227 ================
    228 R_InitTurb
    229 ================
    230 */
    231 void R_InitTurb (void)
    232 {
    233 	int		i;
    234 	
    235 	for (i=0 ; i<1280 ; i++)
    236 	{
    237 		sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
    238 		intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2;	// AMP2, not 20
    239 		blanktable[i] = 0;			//PGM
    240 	}
    241 }
    242 
    243 void R_ImageList_f( void );
    244 
    245 void R_Register (void)
    246 {
    247 	sw_aliasstats = ri.Cvar_Get ("sw_polymodelstats", "0", 0);
    248 	sw_allow_modex = ri.Cvar_Get( "sw_allow_modex", "1", CVAR_ARCHIVE );
    249 	sw_clearcolor = ri.Cvar_Get ("sw_clearcolor", "2", 0);
    250 	sw_drawflat = ri.Cvar_Get ("sw_drawflat", "0", 0);
    251 	sw_draworder = ri.Cvar_Get ("sw_draworder", "0", 0);
    252 	sw_maxedges = ri.Cvar_Get ("sw_maxedges", STRINGER(MAXSTACKSURFACES), 0);
    253 	sw_maxsurfs = ri.Cvar_Get ("sw_maxsurfs", "0", 0);
    254 	sw_mipcap = ri.Cvar_Get ("sw_mipcap", "0", 0);
    255 	sw_mipscale = ri.Cvar_Get ("sw_mipscale", "1", 0);
    256 	sw_reportedgeout = ri.Cvar_Get ("sw_reportedgeout", "0", 0);
    257 	sw_reportsurfout = ri.Cvar_Get ("sw_reportsurfout", "0", 0);
    258 	sw_stipplealpha = ri.Cvar_Get( "sw_stipplealpha", "0", CVAR_ARCHIVE );
    259 	sw_surfcacheoverride = ri.Cvar_Get ("sw_surfcacheoverride", "0", 0);
    260 	sw_waterwarp = ri.Cvar_Get ("sw_waterwarp", "1", 0);
    261 	sw_mode = ri.Cvar_Get( "sw_mode", "0", CVAR_ARCHIVE );
    262 
    263 	r_lefthand = ri.Cvar_Get( "hand", "0", CVAR_USERINFO | CVAR_ARCHIVE );
    264 	r_speeds = ri.Cvar_Get ("r_speeds", "0", 0);
    265 	r_fullbright = ri.Cvar_Get ("r_fullbright", "0", 0);
    266 	r_drawentities = ri.Cvar_Get ("r_drawentities", "1", 0);
    267 	r_drawworld = ri.Cvar_Get ("r_drawworld", "1", 0);
    268 	r_dspeeds = ri.Cvar_Get ("r_dspeeds", "0", 0);
    269 	r_lightlevel = ri.Cvar_Get ("r_lightlevel", "0", 0);
    270 	r_lerpmodels = ri.Cvar_Get( "r_lerpmodels", "1", 0 );
    271 	r_novis = ri.Cvar_Get( "r_novis", "0", 0 );
    272 
    273 	vid_fullscreen = ri.Cvar_Get( "vid_fullscreen", "0", CVAR_ARCHIVE );
    274 	vid_gamma = ri.Cvar_Get( "vid_gamma", "1.0", CVAR_ARCHIVE );
    275 
    276 	ri.Cmd_AddCommand ("modellist", Mod_Modellist_f);
    277 	ri.Cmd_AddCommand( "screenshot", R_ScreenShot_f );
    278 	ri.Cmd_AddCommand( "imagelist", R_ImageList_f );
    279 
    280 	sw_mode->modified = true; // force us to do mode specific stuff later
    281 	vid_gamma->modified = true; // force us to rebuild the gamma table later
    282 
    283 //PGM
    284 	sw_lockpvs = ri.Cvar_Get ("sw_lockpvs", "0", 0);
    285 //PGM
    286 }
    287 
    288 void R_UnRegister (void)
    289 {
    290 	ri.Cmd_RemoveCommand( "screenshot" );
    291 	ri.Cmd_RemoveCommand ("modellist");
    292 	ri.Cmd_RemoveCommand( "imagelist" );
    293 }
    294 
    295 /*
    296 ===============
    297 R_Init
    298 ===============
    299 */
    300 qboolean R_Init( void *hInstance, void *wndProc )
    301 {
    302 	R_InitImages ();
    303 	Mod_Init ();
    304 	Draw_InitLocal ();
    305 	R_InitTextures ();
    306 
    307 	R_InitTurb ();
    308 
    309 	view_clipplanes[0].leftedge = true;
    310 	view_clipplanes[1].rightedge = true;
    311 	view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
    312 			view_clipplanes[3].leftedge = false;
    313 	view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
    314 			view_clipplanes[3].rightedge = false;
    315 
    316 	r_refdef.xOrigin = XCENTERING;
    317 	r_refdef.yOrigin = YCENTERING;
    318 
    319 // TODO: collect 386-specific code in one place
    320 #if	id386
    321 	Sys_MakeCodeWriteable ((long)R_EdgeCodeStart,
    322 					     (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart);
    323 	Sys_SetFPCW ();		// get bit masks for FPCW	(FIXME: is this id386?)
    324 #endif	// id386
    325 
    326 	r_aliasuvscale = 1.0;
    327 
    328 	R_Register ();
    329 	Draw_GetPalette ();
    330 	SWimp_Init( hInstance, wndProc );
    331 
    332 	// create the window
    333 	R_BeginFrame( 0 );
    334 
    335 	ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
    336 
    337 	return true;
    338 }
    339 
    340 /*
    341 ===============
    342 R_Shutdown
    343 ===============
    344 */
    345 void R_Shutdown (void)
    346 {
    347 	// free z buffer
    348 	if (d_pzbuffer)
    349 	{
    350 		free (d_pzbuffer);
    351 		d_pzbuffer = NULL;
    352 	}
    353 	// free surface cache
    354 	if (sc_base)
    355 	{
    356 		D_FlushCaches ();
    357 		free (sc_base);
    358 		sc_base = NULL;
    359 	}
    360 
    361 	// free colormap
    362 	if (vid.colormap)
    363 	{
    364 		free (vid.colormap);
    365 		vid.colormap = NULL;
    366 	}
    367 	R_UnRegister ();
    368 	Mod_FreeAll ();
    369 	R_ShutdownImages ();
    370 
    371 	SWimp_Shutdown();
    372 }
    373 
    374 /*
    375 ===============
    376 R_NewMap
    377 ===============
    378 */
    379 void R_NewMap (void)
    380 {
    381 	r_viewcluster = -1;
    382 
    383 	r_cnumsurfs = sw_maxsurfs->value;
    384 
    385 	if (r_cnumsurfs <= MINSURFACES)
    386 		r_cnumsurfs = MINSURFACES;
    387 
    388 	if (r_cnumsurfs > NUMSTACKSURFACES)
    389 	{
    390 		surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
    391 		surface_p = surfaces;
    392 		surf_max = &surfaces[r_cnumsurfs];
    393 		r_surfsonstack = false;
    394 	// surface 0 doesn't really exist; it's just a dummy because index 0
    395 	// is used to indicate no edge attached to surface
    396 		surfaces--;
    397 		R_SurfacePatch ();
    398 	}
    399 	else
    400 	{
    401 		r_surfsonstack = true;
    402 	}
    403 
    404 	r_maxedgesseen = 0;
    405 	r_maxsurfsseen = 0;
    406 
    407 	r_numallocatededges = sw_maxedges->value;
    408 
    409 	if (r_numallocatededges < MINEDGES)
    410 		r_numallocatededges = MINEDGES;
    411 
    412 	if (r_numallocatededges <= NUMSTACKEDGES)
    413 	{
    414 		auxedges = NULL;
    415 	}
    416 	else
    417 	{
    418 		auxedges = malloc (r_numallocatededges * sizeof(edge_t));
    419 	}
    420 }
    421 
    422 
    423 /*
    424 ===============
    425 R_MarkLeaves
    426 
    427 Mark the leaves and nodes that are in the PVS for the current
    428 cluster
    429 ===============
    430 */
    431 void R_MarkLeaves (void)
    432 {
    433 	byte	*vis;
    434 	mnode_t	*node;
    435 	int		i;
    436 	mleaf_t	*leaf;
    437 	int		cluster;
    438 
    439 	if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
    440 		return;
    441 	
    442 	// development aid to let you run around and see exactly where
    443 	// the pvs ends
    444 	if (sw_lockpvs->value)
    445 		return;
    446 
    447 	r_visframecount++;
    448 	r_oldviewcluster = r_viewcluster;
    449 
    450 	if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
    451 	{
    452 		// mark everything
    453 		for (i=0 ; i<r_worldmodel->numleafs ; i++)
    454 			r_worldmodel->leafs[i].visframe = r_visframecount;
    455 		for (i=0 ; i<r_worldmodel->numnodes ; i++)
    456 			r_worldmodel->nodes[i].visframe = r_visframecount;
    457 		return;
    458 	}
    459 
    460 	vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
    461 	
    462 	for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
    463 	{
    464 		cluster = leaf->cluster;
    465 		if (cluster == -1)
    466 			continue;
    467 		if (vis[cluster>>3] & (1<<(cluster&7)))
    468 		{
    469 			node = (mnode_t *)leaf;
    470 			do
    471 			{
    472 				if (node->visframe == r_visframecount)
    473 					break;
    474 				node->visframe = r_visframecount;
    475 				node = node->parent;
    476 			} while (node);
    477 		}
    478 	}
    479 
    480 #if 0
    481 	for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
    482 	{
    483 		if (vis[i>>3] & (1<<(i&7)))
    484 		{
    485 			node = (mnode_t *)&r_worldmodel->leafs[i];	// FIXME: cluster
    486 			do
    487 			{
    488 				if (node->visframe == r_visframecount)
    489 					break;
    490 				node->visframe = r_visframecount;
    491 				node = node->parent;
    492 			} while (node);
    493 		}
    494 	}
    495 #endif
    496 }
    497 
    498 /*
    499 ** R_DrawNullModel
    500 **
    501 ** IMPLEMENT THIS!
    502 */
    503 void R_DrawNullModel( void )
    504 {
    505 }
    506 
    507 /*
    508 =============
    509 R_DrawEntitiesOnList
    510 =============
    511 */
    512 void R_DrawEntitiesOnList (void)
    513 {
    514 	int			i;
    515 	qboolean	translucent_entities = false;
    516 
    517 	if (!r_drawentities->value)
    518 		return;
    519 
    520 	// all bmodels have already been drawn by the edge list
    521 	for (i=0 ; i<r_newrefdef.num_entities ; i++)
    522 	{
    523 		currententity = &r_newrefdef.entities[i];
    524 
    525 		if ( currententity->flags & RF_TRANSLUCENT )
    526 		{
    527 			translucent_entities = true;
    528 			continue;
    529 		}
    530 
    531 		if ( currententity->flags & RF_BEAM )
    532 		{
    533 			modelorg[0] = -r_origin[0];
    534 			modelorg[1] = -r_origin[1];
    535 			modelorg[2] = -r_origin[2];
    536 			VectorCopy( vec3_origin, r_entorigin );
    537 			R_DrawBeam( currententity );
    538 		}
    539 		else
    540 		{
    541 			currentmodel = currententity->model;
    542 			if (!currentmodel)
    543 			{
    544 				R_DrawNullModel();
    545 				continue;
    546 			}
    547 			VectorCopy (currententity->origin, r_entorigin);
    548 			VectorSubtract (r_origin, r_entorigin, modelorg);
    549 
    550 			switch (currentmodel->type)
    551 			{
    552 			case mod_sprite:
    553 				R_DrawSprite ();
    554 				break;
    555 
    556 			case mod_alias:
    557 				R_AliasDrawModel ();
    558 				break;
    559 
    560 			default:
    561 				break;
    562 			}
    563 		}
    564 	}
    565 
    566 	if ( !translucent_entities )
    567 		return;
    568 
    569 	for (i=0 ; i<r_newrefdef.num_entities ; i++)
    570 	{
    571 		currententity = &r_newrefdef.entities[i];
    572 
    573 		if ( !( currententity->flags & RF_TRANSLUCENT ) )
    574 			continue;
    575 
    576 		if ( currententity->flags & RF_BEAM )
    577 		{
    578 			modelorg[0] = -r_origin[0];
    579 			modelorg[1] = -r_origin[1];
    580 			modelorg[2] = -r_origin[2];
    581 			VectorCopy( vec3_origin, r_entorigin );
    582 			R_DrawBeam( currententity );
    583 		}
    584 		else
    585 		{
    586 			currentmodel = currententity->model;
    587 			if (!currentmodel)
    588 			{
    589 				R_DrawNullModel();
    590 				continue;
    591 			}
    592 			VectorCopy (currententity->origin, r_entorigin);
    593 			VectorSubtract (r_origin, r_entorigin, modelorg);
    594 
    595 			switch (currentmodel->type)
    596 			{
    597 			case mod_sprite:
    598 				R_DrawSprite ();
    599 				break;
    600 
    601 			case mod_alias:
    602 				R_AliasDrawModel ();
    603 				break;
    604 
    605 			default:
    606 				break;
    607 			}
    608 		}
    609 	}
    610 }
    611 
    612 
    613 /*
    614 =============
    615 R_BmodelCheckBBox
    616 =============
    617 */
    618 int R_BmodelCheckBBox (float *minmaxs)
    619 {
    620 	int			i, *pindex, clipflags;
    621 	vec3_t		acceptpt, rejectpt;
    622 	float		d;
    623 
    624 	clipflags = 0;
    625 
    626 	for (i=0 ; i<4 ; i++)
    627 	{
    628 	// generate accept and reject points
    629 	// FIXME: do with fast look-ups or integer tests based on the sign bit
    630 	// of the floating point values
    631 
    632 		pindex = pfrustum_indexes[i];
    633 
    634 		rejectpt[0] = minmaxs[pindex[0]];
    635 		rejectpt[1] = minmaxs[pindex[1]];
    636 		rejectpt[2] = minmaxs[pindex[2]];
    637 		
    638 		d = DotProduct (rejectpt, view_clipplanes[i].normal);
    639 		d -= view_clipplanes[i].dist;
    640 
    641 		if (d <= 0)
    642 			return BMODEL_FULLY_CLIPPED;
    643 
    644 		acceptpt[0] = minmaxs[pindex[3+0]];
    645 		acceptpt[1] = minmaxs[pindex[3+1]];
    646 		acceptpt[2] = minmaxs[pindex[3+2]];
    647 
    648 		d = DotProduct (acceptpt, view_clipplanes[i].normal);
    649 		d -= view_clipplanes[i].dist;
    650 
    651 		if (d <= 0)
    652 			clipflags |= (1<<i);
    653 	}
    654 
    655 	return clipflags;
    656 }
    657 
    658 
    659 /*
    660 ===================
    661 R_FindTopnode
    662 
    663 Find the first node that splits the given box
    664 ===================
    665 */
    666 mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
    667 {
    668 	mplane_t	*splitplane;
    669 	int			sides;
    670 	mnode_t *node;
    671 
    672 	node = r_worldmodel->nodes;
    673 
    674 	while (1)
    675 	{
    676 		if (node->visframe != r_visframecount)
    677 			return NULL;		// not visible at all
    678 		
    679 		if (node->contents != CONTENTS_NODE)
    680 		{
    681 			if (node->contents != CONTENTS_SOLID)
    682 				return	node; // we've reached a non-solid leaf, so it's
    683 							//  visible and not BSP clipped
    684 			return NULL;	// in solid, so not visible
    685 		}
    686 		
    687 		splitplane = node->plane;
    688 		sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
    689 		
    690 		if (sides == 3)
    691 			return node;	// this is the splitter
    692 		
    693 	// not split yet; recurse down the contacted side
    694 		if (sides & 1)
    695 			node = node->children[0];
    696 		else
    697 			node = node->children[1];
    698 	}
    699 }
    700 
    701 
    702 /*
    703 =============
    704 RotatedBBox
    705 
    706 Returns an axially aligned box that contains the input box at the given rotation
    707 =============
    708 */
    709 void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
    710 {
    711 	vec3_t	tmp, v;
    712 	int		i, j;
    713 	vec3_t	forward, right, up;
    714 
    715 	if (!angles[0] && !angles[1] && !angles[2])
    716 	{
    717 		VectorCopy (mins, tmins);
    718 		VectorCopy (maxs, tmaxs);
    719 		return;
    720 	}
    721 
    722 	for (i=0 ; i<3 ; i++)
    723 	{
    724 		tmins[i] = 99999;
    725 		tmaxs[i] = -99999;
    726 	}
    727 
    728 	AngleVectors (angles, forward, right, up);
    729 
    730 	for ( i = 0; i < 8; i++ )
    731 	{
    732 		if ( i & 1 )
    733 			tmp[0] = mins[0];
    734 		else
    735 			tmp[0] = maxs[0];
    736 
    737 		if ( i & 2 )
    738 			tmp[1] = mins[1];
    739 		else
    740 			tmp[1] = maxs[1];
    741 
    742 		if ( i & 4 )
    743 			tmp[2] = mins[2];
    744 		else
    745 			tmp[2] = maxs[2];
    746 
    747 
    748 		VectorScale (forward, tmp[0], v);
    749 		VectorMA (v, -tmp[1], right, v);
    750 		VectorMA (v, tmp[2], up, v);
    751 
    752 		for (j=0 ; j<3 ; j++)
    753 		{
    754 			if (v[j] < tmins[j])
    755 				tmins[j] = v[j];
    756 			if (v[j] > tmaxs[j])
    757 				tmaxs[j] = v[j];
    758 		}
    759 	}
    760 }
    761 
    762 /*
    763 =============
    764 R_DrawBEntitiesOnList
    765 =============
    766 */
    767 void R_DrawBEntitiesOnList (void)
    768 {
    769 	int			i, clipflags;
    770 	vec3_t		oldorigin;
    771 	vec3_t		mins, maxs;
    772 	float		minmaxs[6];
    773 	mnode_t		*topnode;
    774 
    775 	if (!r_drawentities->value)
    776 		return;
    777 
    778 	VectorCopy (modelorg, oldorigin);
    779 	insubmodel = true;
    780 	r_dlightframecount = r_framecount;
    781 
    782 	for (i=0 ; i<r_newrefdef.num_entities ; i++)
    783 	{
    784 		currententity = &r_newrefdef.entities[i];
    785 		currentmodel = currententity->model;
    786 		if (!currentmodel)
    787 			continue;
    788 		if (currentmodel->nummodelsurfaces == 0)
    789 			continue;	// clip brush only
    790 		if ( currententity->flags & RF_BEAM )
    791 			continue;
    792 		if (currentmodel->type != mod_brush)
    793 			continue;
    794 	// see if the bounding box lets us trivially reject, also sets
    795 	// trivial accept status
    796 		RotatedBBox (currentmodel->mins, currentmodel->maxs,
    797 			currententity->angles, mins, maxs);
    798 		VectorAdd (mins, currententity->origin, minmaxs);
    799 		VectorAdd (maxs, currententity->origin, (minmaxs+3));
    800 
    801 		clipflags = R_BmodelCheckBBox (minmaxs);
    802 		if (clipflags == BMODEL_FULLY_CLIPPED)
    803 			continue;	// off the edge of the screen
    804 
    805 		topnode = R_FindTopnode (minmaxs, minmaxs+3);
    806 		if (!topnode)
    807 			continue;	// no part in a visible leaf
    808 
    809 		VectorCopy (currententity->origin, r_entorigin);
    810 		VectorSubtract (r_origin, r_entorigin, modelorg);
    811 
    812 		r_pcurrentvertbase = currentmodel->vertexes;
    813 
    814 	// FIXME: stop transforming twice
    815 		R_RotateBmodel ();
    816 
    817 	// calculate dynamic lighting for bmodel
    818 		R_PushDlights (currentmodel);
    819 
    820 		if (topnode->contents == CONTENTS_NODE)
    821 		{
    822 		// not a leaf; has to be clipped to the world BSP
    823 			r_clipflags = clipflags;
    824 			R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
    825 		}
    826 		else
    827 		{
    828 		// falls entirely in one leaf, so we just put all the
    829 		// edges in the edge list and let 1/z sorting handle
    830 		// drawing order
    831 			R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
    832 		}
    833 
    834 	// put back world rotation and frustum clipping		
    835 	// FIXME: R_RotateBmodel should just work off base_vxx
    836 		VectorCopy (base_vpn, vpn);
    837 		VectorCopy (base_vup, vup);
    838 		VectorCopy (base_vright, vright);
    839 		VectorCopy (oldorigin, modelorg);
    840 		R_TransformFrustum ();
    841 	}
    842 
    843 	insubmodel = false;
    844 }
    845 
    846 
    847 /*
    848 ================
    849 R_EdgeDrawing
    850 ================
    851 */
    852 void R_EdgeDrawing (void)
    853 {
    854 	edge_t	ledges[NUMSTACKEDGES +
    855 				((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
    856 	surf_t	lsurfs[NUMSTACKSURFACES +
    857 				((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
    858 
    859 	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
    860 		return;
    861 
    862 	if (auxedges)
    863 	{
    864 		r_edges = auxedges;
    865 	}
    866 	else
    867 	{
    868 		r_edges =  (edge_t *)
    869 				(((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
    870 	}
    871 
    872 	if (r_surfsonstack)
    873 	{
    874 		surfaces =  (surf_t *)
    875 				(((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
    876 		surf_max = &surfaces[r_cnumsurfs];
    877 	// surface 0 doesn't really exist; it's just a dummy because index 0
    878 	// is used to indicate no edge attached to surface
    879 		surfaces--;
    880 		R_SurfacePatch ();
    881 	}
    882 
    883 	R_BeginEdgeFrame ();
    884 
    885 	if (r_dspeeds->value)
    886 	{
    887 		rw_time1 = Sys_Milliseconds ();
    888 	}
    889 
    890 	R_RenderWorld ();
    891 
    892 	if (r_dspeeds->value)
    893 	{
    894 		rw_time2 = Sys_Milliseconds ();
    895 		db_time1 = rw_time2;
    896 	}
    897 
    898 	R_DrawBEntitiesOnList ();
    899 
    900 	if (r_dspeeds->value)
    901 	{
    902 		db_time2 = Sys_Milliseconds ();
    903 		se_time1 = db_time2;
    904 	}
    905 
    906 	R_ScanEdges ();
    907 }
    908 
    909 //=======================================================================
    910 
    911 
    912 /*
    913 =============
    914 R_CalcPalette
    915 
    916 =============
    917 */
    918 void R_CalcPalette (void)
    919 {
    920 	static qboolean modified;
    921 	byte	palette[256][4], *in, *out;
    922 	int		i, j;
    923 	float	alpha, one_minus_alpha;
    924 	vec3_t	premult;
    925 	int		v;
    926 
    927 	alpha = r_newrefdef.blend[3];
    928 	if (alpha <= 0)
    929 	{
    930 		if (modified)
    931 		{	// set back to default
    932 			modified = false;
    933 			R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
    934 			return;
    935 		}
    936 		return;
    937 	}
    938 
    939 	modified = true;
    940 	if (alpha > 1)
    941 		alpha = 1;
    942 
    943 	premult[0] = r_newrefdef.blend[0]*alpha*255;
    944 	premult[1] = r_newrefdef.blend[1]*alpha*255;
    945 	premult[2] = r_newrefdef.blend[2]*alpha*255;
    946 
    947 	one_minus_alpha = (1.0 - alpha);
    948 
    949 	in = (byte *)d_8to24table;
    950 	out = palette[0];
    951 	for (i=0 ; i<256 ; i++, in+=4, out+=4)
    952 	{
    953 		for (j=0 ; j<3 ; j++)
    954 		{
    955 			v = premult[j] + one_minus_alpha * in[j];
    956 			if (v > 255)
    957 				v = 255;
    958 			out[j] = v;
    959 		}
    960 		out[3] = 255;
    961 	}
    962 
    963 	R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] );
    964 //	SWimp_SetPalette( palette[0] );
    965 }
    966 
    967 //=======================================================================
    968 
    969 void R_SetLightLevel (void)
    970 {
    971 	vec3_t		light;
    972 
    973 	if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
    974 	{
    975 		r_lightlevel->value = 150.0;
    976 		return;
    977 	}
    978 
    979 	// save off light value for server to look at (BIG HACK!)
    980 	R_LightPoint (r_newrefdef.vieworg, light);
    981 	r_lightlevel->value = 150.0 * light[0];
    982 }
    983 
    984 
    985 /*
    986 @@@@@@@@@@@@@@@@
    987 R_RenderFrame
    988 
    989 @@@@@@@@@@@@@@@@
    990 */
    991 void R_RenderFrame (refdef_t *fd)
    992 {
    993 	r_newrefdef = *fd;
    994 
    995 	if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
    996 		ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
    997 
    998 	VectorCopy (fd->vieworg, r_refdef.vieworg);
    999 	VectorCopy (fd->viewangles, r_refdef.viewangles);
   1000 
   1001 	if (r_speeds->value || r_dspeeds->value)
   1002 		r_time1 = Sys_Milliseconds ();
   1003 
   1004 	R_SetupFrame ();
   1005 
   1006 	R_MarkLeaves ();	// done here so we know if we're in water
   1007 
   1008 	R_PushDlights (r_worldmodel);
   1009 
   1010 	R_EdgeDrawing ();
   1011 
   1012 	if (r_dspeeds->value)
   1013 	{
   1014 		se_time2 = Sys_Milliseconds ();
   1015 		de_time1 = se_time2;
   1016 	}
   1017 
   1018 	R_DrawEntitiesOnList ();
   1019 
   1020 	if (r_dspeeds->value)
   1021 	{
   1022 		de_time2 = Sys_Milliseconds ();
   1023 		dp_time1 = Sys_Milliseconds ();
   1024 	}
   1025 
   1026 	R_DrawParticles ();
   1027 
   1028 	if (r_dspeeds->value)
   1029 		dp_time2 = Sys_Milliseconds ();
   1030 
   1031 	R_DrawAlphaSurfaces();
   1032 
   1033 	R_SetLightLevel ();
   1034 
   1035 	if (r_dowarp)
   1036 		D_WarpScreen ();
   1037 
   1038 	if (r_dspeeds->value)
   1039 		da_time1 = Sys_Milliseconds ();
   1040 
   1041 	if (r_dspeeds->value)
   1042 		da_time2 = Sys_Milliseconds ();
   1043 
   1044 	R_CalcPalette ();
   1045 
   1046 	if (sw_aliasstats->value)
   1047 		R_PrintAliasStats ();
   1048 		
   1049 	if (r_speeds->value)
   1050 		R_PrintTimes ();
   1051 
   1052 	if (r_dspeeds->value)
   1053 		R_PrintDSpeeds ();
   1054 
   1055 	if (sw_reportsurfout->value && r_outofsurfaces)
   1056 		ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
   1057 
   1058 	if (sw_reportedgeout->value && r_outofedges)
   1059 		ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
   1060 }
   1061 
   1062 /*
   1063 ** R_InitGraphics
   1064 */
   1065 void R_InitGraphics( int width, int height )
   1066 {
   1067 	vid.width  = width;
   1068 	vid.height = height;
   1069 
   1070 	// free z buffer
   1071 	if ( d_pzbuffer )
   1072 	{
   1073 		free( d_pzbuffer );
   1074 		d_pzbuffer = NULL;
   1075 	}
   1076 
   1077 	// free surface cache
   1078 	if ( sc_base )
   1079 	{
   1080 		D_FlushCaches ();
   1081 		free( sc_base );
   1082 		sc_base = NULL;
   1083 	}
   1084 
   1085 	d_pzbuffer = malloc(vid.width*vid.height*2);
   1086 
   1087 	R_InitCaches ();
   1088 
   1089 	R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table );
   1090 }
   1091 
   1092 /*
   1093 ** R_BeginFrame
   1094 */
   1095 void R_BeginFrame( float camera_separation )
   1096 {
   1097 	extern void Draw_BuildGammaTable( void );
   1098 
   1099 	/*
   1100 	** rebuild the gamma correction palette if necessary
   1101 	*/
   1102 	if ( vid_gamma->modified )
   1103 	{
   1104 		Draw_BuildGammaTable();
   1105 		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
   1106 
   1107 		vid_gamma->modified = false;
   1108 	}
   1109 
   1110 	while ( sw_mode->modified || vid_fullscreen->modified )
   1111 	{
   1112 		rserr_t err;
   1113 
   1114 		/*
   1115 		** if this returns rserr_invalid_fullscreen then it set the mode but not as a
   1116 		** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
   1117 		*/
   1118 		if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
   1119 		{
   1120 			R_InitGraphics( vid.width, vid.height );
   1121 
   1122 			sw_state.prev_mode = sw_mode->value;
   1123 			vid_fullscreen->modified = false;
   1124 			sw_mode->modified = false;
   1125 		}
   1126 		else
   1127 		{
   1128 			if ( err == rserr_invalid_mode )
   1129 			{
   1130 				ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
   1131 				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
   1132 			}
   1133 			else if ( err == rserr_invalid_fullscreen )
   1134 			{
   1135 				R_InitGraphics( vid.width, vid.height );
   1136 
   1137 				ri.Cvar_SetValue( "vid_fullscreen", 0);
   1138 				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
   1139 				sw_state.prev_mode = sw_mode->value;
   1140 //				vid_fullscreen->modified = false;
   1141 //				sw_mode->modified = false;
   1142 			}
   1143 			else
   1144 			{
   1145 				ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
   1146 			}
   1147 		}
   1148 	}
   1149 }
   1150 
   1151 /*
   1152 ** R_GammaCorrectAndSetPalette
   1153 */
   1154 void R_GammaCorrectAndSetPalette( const unsigned char *palette )
   1155 {
   1156 	int i;
   1157 
   1158 	for ( i = 0; i < 256; i++ )
   1159 	{
   1160 		sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
   1161 		sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
   1162 		sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
   1163 	}
   1164 
   1165 	SWimp_SetPalette( sw_state.currentpalette );
   1166 }
   1167 
   1168 /*
   1169 ** R_CinematicSetPalette
   1170 */
   1171 void R_CinematicSetPalette( const unsigned char *palette )
   1172 {
   1173 	byte palette32[1024];
   1174 	int		i, j, w;
   1175 	int		*d;
   1176 
   1177 	// clear screen to black to avoid any palette flash
   1178 	w = abs(vid.rowbytes)>>2;	// stupid negative pitch win32 stuff...
   1179 	for (i=0 ; i<vid.height ; i++, d+=w)
   1180 	{
   1181 		d = (int *)(vid.buffer + i*vid.rowbytes);
   1182 		for (j=0 ; j<w ; j++)
   1183 			d[j] = 0;
   1184 	}
   1185 	// flush it to the screen
   1186 	SWimp_EndFrame ();
   1187 
   1188 	if ( palette )
   1189 	{
   1190 		for ( i = 0; i < 256; i++ )
   1191 		{
   1192 			palette32[i*4+0] = palette[i*3+0];
   1193 			palette32[i*4+1] = palette[i*3+1];
   1194 			palette32[i*4+2] = palette[i*3+2];
   1195 			palette32[i*4+3] = 0xFF;
   1196 		}
   1197 
   1198 		R_GammaCorrectAndSetPalette( palette32 );
   1199 	}
   1200 	else
   1201 	{
   1202 		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
   1203 	}
   1204 }
   1205 
   1206 /*
   1207 ================
   1208 Draw_BuildGammaTable
   1209 ================
   1210 */
   1211 void Draw_BuildGammaTable (void)
   1212 {
   1213 	int		i, inf;
   1214 	float	g;
   1215 
   1216 	g = vid_gamma->value;
   1217 
   1218 	if (g == 1.0)
   1219 	{
   1220 		for (i=0 ; i<256 ; i++)
   1221 			sw_state.gammatable[i] = i;
   1222 		return;
   1223 	}
   1224 	
   1225 	for (i=0 ; i<256 ; i++)
   1226 	{
   1227 		inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
   1228 		if (inf < 0)
   1229 			inf = 0;
   1230 		if (inf > 255)
   1231 			inf = 255;
   1232 		sw_state.gammatable[i] = inf;
   1233 	}
   1234 }
   1235 
   1236 /*
   1237 ** R_DrawBeam
   1238 */
   1239 void R_DrawBeam( entity_t *e )
   1240 {
   1241 #define NUM_BEAM_SEGS 6
   1242 
   1243 	int	i;
   1244 
   1245 	vec3_t perpvec;
   1246 	vec3_t direction, normalized_direction;
   1247 	vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
   1248 	vec3_t oldorigin, origin;
   1249 
   1250 	oldorigin[0] = e->oldorigin[0];
   1251 	oldorigin[1] = e->oldorigin[1];
   1252 	oldorigin[2] = e->oldorigin[2];
   1253 
   1254 	origin[0] = e->origin[0];
   1255 	origin[1] = e->origin[1];
   1256 	origin[2] = e->origin[2];
   1257 
   1258 	normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
   1259 	normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
   1260 	normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
   1261 
   1262 	if ( VectorNormalize( normalized_direction ) == 0 )
   1263 		return;
   1264 
   1265 	PerpendicularVector( perpvec, normalized_direction );
   1266 	VectorScale( perpvec, e->frame / 2, perpvec );
   1267 
   1268 	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
   1269 	{
   1270 		RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
   1271 		VectorAdd( start_points[i], origin, start_points[i] );
   1272 		VectorAdd( start_points[i], direction, end_points[i] );
   1273 	}
   1274 
   1275 	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
   1276 	{
   1277 		R_IMFlatShadedQuad( start_points[i],
   1278 		                    end_points[i],
   1279 							end_points[(i+1)%NUM_BEAM_SEGS],
   1280 							start_points[(i+1)%NUM_BEAM_SEGS],
   1281 							e->skinnum & 0xFF,
   1282 							e->alpha );
   1283 	}
   1284 }
   1285 
   1286 
   1287 //===================================================================
   1288 
   1289 /*
   1290 ============
   1291 R_SetSky
   1292 ============
   1293 */
   1294 // 3dstudio environment map names
   1295 char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
   1296 int	r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
   1297 extern	mtexinfo_t		r_skytexinfo[6];
   1298 void R_SetSky (char *name, float rotate, vec3_t axis)
   1299 {
   1300 	int		i;
   1301 	char	pathname[MAX_QPATH];
   1302 
   1303 	strncpy (skyname, name, sizeof(skyname)-1);
   1304 	skyrotate = rotate;
   1305 	VectorCopy (axis, skyaxis);
   1306 
   1307 	for (i=0 ; i<6 ; i++)
   1308 	{
   1309 		Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
   1310 		r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
   1311 	}
   1312 }
   1313 
   1314 
   1315 /*
   1316 ===============
   1317 Draw_GetPalette
   1318 ===============
   1319 */
   1320 void Draw_GetPalette (void)
   1321 {
   1322 	byte	*pal, *out;
   1323 	int		i;
   1324 	int		r, g, b;
   1325 
   1326 	// get the palette and colormap
   1327 	LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
   1328 	if (!vid.colormap)
   1329 		ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
   1330 	vid.alphamap = vid.colormap + 64*256;
   1331 
   1332 	out = (byte *)d_8to24table;
   1333 	for (i=0 ; i<256 ; i++, out+=4)
   1334 	{
   1335 		r = pal[i*3+0];
   1336 		g = pal[i*3+1];
   1337 		b = pal[i*3+2];
   1338 
   1339         out[0] = r;
   1340         out[1] = g;
   1341         out[2] = b;
   1342 	}
   1343 
   1344 	free (pal);
   1345 }
   1346 
   1347 struct image_s *R_RegisterSkin (char *name);
   1348 
   1349 /*
   1350 @@@@@@@@@@@@@@@@@@@@@
   1351 GetRefAPI
   1352 
   1353 @@@@@@@@@@@@@@@@@@@@@
   1354 */
   1355 refexport_t GetRefAPI (refimport_t rimp)
   1356 {
   1357 	refexport_t	re;
   1358 
   1359 	ri = rimp;
   1360 
   1361 	re.api_version = API_VERSION;
   1362 
   1363 	re.BeginRegistration = R_BeginRegistration;
   1364     re.RegisterModel = R_RegisterModel;
   1365     re.RegisterSkin = R_RegisterSkin;
   1366 	re.RegisterPic = Draw_FindPic;
   1367 	re.SetSky = R_SetSky;
   1368 	re.EndRegistration = R_EndRegistration;
   1369 
   1370 	re.RenderFrame = R_RenderFrame;
   1371 
   1372 	re.DrawGetPicSize = Draw_GetPicSize;
   1373 	re.DrawPic = Draw_Pic;
   1374 	re.DrawStretchPic = Draw_StretchPic;
   1375 	re.DrawChar = Draw_Char;
   1376 	re.DrawTileClear = Draw_TileClear;
   1377 	re.DrawFill = Draw_Fill;
   1378 	re.DrawFadeScreen= Draw_FadeScreen;
   1379 
   1380 	re.DrawStretchRaw = Draw_StretchRaw;
   1381 
   1382 	re.Init = R_Init;
   1383 	re.Shutdown = R_Shutdown;
   1384 
   1385 	re.CinematicSetPalette = R_CinematicSetPalette;
   1386 	re.BeginFrame = R_BeginFrame;
   1387 	re.EndFrame = SWimp_EndFrame;
   1388 
   1389 	re.AppActivate = SWimp_AppActivate;
   1390 
   1391 	Swap_Init ();
   1392 
   1393 	return re;
   1394 }
   1395 
   1396 #ifndef REF_HARD_LINKED
   1397 // this is only here so the functions in q_shared.c and q_shwin.c can link
   1398 void Sys_Error (char *error, ...)
   1399 {
   1400 	va_list		argptr;
   1401 	char		text[1024];
   1402 
   1403 	va_start (argptr, error);
   1404 	vsprintf (text, error, argptr);
   1405 	va_end (argptr);
   1406 
   1407 	ri.Sys_Error (ERR_FATAL, "%s", text);
   1408 }
   1409 
   1410 void Com_Printf (char *fmt, ...)
   1411 {
   1412 	va_list		argptr;
   1413 	char		text[1024];
   1414 
   1415 	va_start (argptr, fmt);
   1416 	vsprintf (text, fmt, argptr);
   1417 	va_end (argptr);
   1418 
   1419 	ri.Con_Printf (PRINT_ALL, "%s", text);
   1420 }
   1421 
   1422 #endif