Home | History | Annotate | Download | only in client
      1 /*
      2 Copyright (C) 1996-1997 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 "quakedef.h"
     23 #include "r_local.h"
     24 
     25 //define	PASSAGES
     26 
     27 void		*colormap;
     28 vec3_t		viewlightvec;
     29 alight_t	r_viewlighting = {128, 192, viewlightvec};
     30 float		r_time1;
     31 int			r_numallocatededges;
     32 qboolean	r_drawpolys;
     33 qboolean	r_drawculledpolys;
     34 qboolean	r_worldpolysbacktofront;
     35 qboolean	r_recursiveaffinetriangles = true;
     36 int			r_pixbytes = 1;
     37 float		r_aliasuvscale = 1.0;
     38 int			r_outofsurfaces;
     39 int			r_outofedges;
     40 
     41 qboolean	r_dowarp, r_dowarpold, r_viewchanged;
     42 
     43 int			numbtofpolys;
     44 btofpoly_t	*pbtofpolys;
     45 mvertex_t	*r_pcurrentvertbase;
     46 
     47 int			c_surf;
     48 int			r_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;
     49 qboolean	r_surfsonstack;
     50 int			r_clipflags;
     51 
     52 byte		*r_warpbuffer;
     53 
     54 byte		*r_stack_start;
     55 
     56 qboolean	r_fov_greater_than_90;
     57 
     58 entity_t	r_worldentity;
     59 
     60 //
     61 // view origin
     62 //
     63 vec3_t	vup, base_vup;
     64 vec3_t	vpn, base_vpn;
     65 vec3_t	vright, base_vright;
     66 vec3_t	r_origin;
     67 
     68 //
     69 // screen size info
     70 //
     71 refdef_t	r_refdef;
     72 float		xcenter, ycenter;
     73 float		xscale, yscale;
     74 float		xscaleinv, yscaleinv;
     75 float		xscaleshrink, yscaleshrink;
     76 float		aliasxscale, aliasyscale, aliasxcenter, aliasycenter;
     77 
     78 int		screenwidth;
     79 
     80 float	pixelAspect;
     81 float	screenAspect;
     82 float	verticalFieldOfView;
     83 float	xOrigin, yOrigin;
     84 
     85 mplane_t	screenedge[4];
     86 
     87 //
     88 // refresh flags
     89 //
     90 int		r_framecount = 1;	// so frame counts initialized to 0 don't match
     91 int		r_visframecount;
     92 int		d_spanpixcount;
     93 int		r_polycount;
     94 int		r_drawnpolycount;
     95 int		r_wholepolycount;
     96 
     97 int			*pfrustum_indexes[4];
     98 int			r_frustum_indexes[4*6];
     99 
    100 int		reinit_surfcache = 1;	// if 1, surface cache is currently empty and
    101 								// must be reinitialized for current cache size
    102 
    103 mleaf_t		*r_viewleaf, *r_oldviewleaf;
    104 
    105 texture_t	*r_notexture_mip;
    106 
    107 float		r_aliastransition, r_resfudge;
    108 
    109 int		d_lightstylevalue[256];	// 8.8 fraction of base light value
    110 
    111 float	dp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;
    112 float	se_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;
    113 
    114 void R_MarkLeaves (void);
    115 
    116 cvar_t	r_draworder = {"r_draworder","0"};
    117 cvar_t	r_speeds = {"r_speeds","0"};
    118 cvar_t	r_timegraph = {"r_timegraph","0"};
    119 cvar_t	r_netgraph = {"r_netgraph","0"};
    120 cvar_t	r_zgraph = {"r_zgraph","0"};
    121 cvar_t	r_graphheight = {"r_graphheight","15"};
    122 cvar_t	r_clearcolor = {"r_clearcolor","2"};
    123 cvar_t	r_waterwarp = {"r_waterwarp","1"};
    124 cvar_t	r_fullbright = {"r_fullbright","0"};
    125 cvar_t	r_drawentities = {"r_drawentities","1"};
    126 cvar_t	r_drawviewmodel = {"r_drawviewmodel","1"};
    127 cvar_t	r_aliasstats = {"r_polymodelstats","0"};
    128 cvar_t	r_dspeeds = {"r_dspeeds","0"};
    129 cvar_t	r_drawflat = {"r_drawflat", "0"};
    130 cvar_t	r_ambient = {"r_ambient", "0"};
    131 cvar_t	r_reportsurfout = {"r_reportsurfout", "0"};
    132 cvar_t	r_maxsurfs = {"r_maxsurfs", "0"};
    133 cvar_t	r_numsurfs = {"r_numsurfs", "0"};
    134 cvar_t	r_reportedgeout = {"r_reportedgeout", "0"};
    135 cvar_t	r_maxedges = {"r_maxedges", "0"};
    136 cvar_t	r_numedges = {"r_numedges", "0"};
    137 cvar_t	r_aliastransbase = {"r_aliastransbase", "200"};
    138 cvar_t	r_aliastransadj = {"r_aliastransadj", "100"};
    139 
    140 extern cvar_t	scr_fov;
    141 
    142 void CreatePassages (void);
    143 void SetVisibilityByPassages (void);
    144 
    145 void R_NetGraph (void);
    146 void R_ZGraph (void);
    147 
    148 /*
    149 ==================
    150 R_InitTextures
    151 ==================
    152 */
    153 void	R_InitTextures (void)
    154 {
    155 	int		x,y, m;
    156 	byte	*dest;
    157 
    158 // create a simple checkerboard texture for the default
    159 	r_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, "notexture");
    160 
    161 	r_notexture_mip->width = r_notexture_mip->height = 16;
    162 	r_notexture_mip->offsets[0] = sizeof(texture_t);
    163 	r_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16;
    164 	r_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8;
    165 	r_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4;
    166 
    167 	for (m=0 ; m<4 ; m++)
    168 	{
    169 		dest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];
    170 		for (y=0 ; y< (16>>m) ; y++)
    171 			for (x=0 ; x< (16>>m) ; x++)
    172 			{
    173 				if (  (y< (8>>m) ) ^ (x< (8>>m) ) )
    174 					*dest++ = 0;
    175 				else
    176 					*dest++ = 0xff;
    177 			}
    178 	}
    179 }
    180 
    181 /*
    182 ===============
    183 R_Init
    184 ===============
    185 */
    186 void R_Init (void)
    187 {
    188 	int		dummy;
    189 
    190 // get stack position so we can guess if we are going to overflow
    191 	r_stack_start = (byte *)&dummy;
    192 
    193 	R_InitTurb ();
    194 
    195 	Cmd_AddCommand ("timerefresh", R_TimeRefresh_f);
    196 	Cmd_AddCommand ("pointfile", R_ReadPointFile_f);
    197 
    198 	Cvar_RegisterVariable (&r_draworder);
    199 	Cvar_RegisterVariable (&r_speeds);
    200 	Cvar_RegisterVariable (&r_timegraph);
    201 	Cvar_RegisterVariable (&r_netgraph);
    202 	Cvar_RegisterVariable (&r_zgraph);
    203 	Cvar_RegisterVariable (&r_graphheight);
    204 	Cvar_RegisterVariable (&r_drawflat);
    205 	Cvar_RegisterVariable (&r_ambient);
    206 	Cvar_RegisterVariable (&r_clearcolor);
    207 	Cvar_RegisterVariable (&r_waterwarp);
    208 	Cvar_RegisterVariable (&r_fullbright);
    209 	Cvar_RegisterVariable (&r_drawentities);
    210 	Cvar_RegisterVariable (&r_drawviewmodel);
    211 	Cvar_RegisterVariable (&r_aliasstats);
    212 	Cvar_RegisterVariable (&r_dspeeds);
    213 	Cvar_RegisterVariable (&r_reportsurfout);
    214 	Cvar_RegisterVariable (&r_maxsurfs);
    215 	Cvar_RegisterVariable (&r_numsurfs);
    216 	Cvar_RegisterVariable (&r_reportedgeout);
    217 	Cvar_RegisterVariable (&r_maxedges);
    218 	Cvar_RegisterVariable (&r_numedges);
    219 	Cvar_RegisterVariable (&r_aliastransbase);
    220 	Cvar_RegisterVariable (&r_aliastransadj);
    221 
    222 	Cvar_SetValue ("r_maxedges", (float)NUMSTACKEDGES);
    223 	Cvar_SetValue ("r_maxsurfs", (float)NUMSTACKSURFACES);
    224 
    225 	view_clipplanes[0].leftedge = true;
    226 	view_clipplanes[1].rightedge = true;
    227 	view_clipplanes[1].leftedge = view_clipplanes[2].leftedge =
    228 			view_clipplanes[3].leftedge = false;
    229 	view_clipplanes[0].rightedge = view_clipplanes[2].rightedge =
    230 			view_clipplanes[3].rightedge = false;
    231 
    232 	r_refdef.xOrigin = XCENTERING;
    233 	r_refdef.yOrigin = YCENTERING;
    234 
    235 	R_InitParticles ();
    236 
    237 // TODO: collect 386-specific code in one place
    238 #if	id386
    239 	Sys_MakeCodeWriteable ((long)R_EdgeCodeStart,
    240 					     (long)R_EdgeCodeEnd - (long)R_EdgeCodeStart);
    241 #endif	// id386
    242 
    243 	D_Init ();
    244 }
    245 
    246 /*
    247 ===============
    248 R_NewMap
    249 ===============
    250 */
    251 void R_NewMap (void)
    252 {
    253 	int		i;
    254 
    255 	memset (&r_worldentity, 0, sizeof(r_worldentity));
    256 	r_worldentity.model = cl.worldmodel;
    257 
    258 // clear out efrags in case the level hasn't been reloaded
    259 // FIXME: is this one short?
    260 	for (i=0 ; i<cl.worldmodel->numleafs ; i++)
    261 		cl.worldmodel->leafs[i].efrags = NULL;
    262 
    263 	r_viewleaf = NULL;
    264 	R_ClearParticles ();
    265 
    266 	r_cnumsurfs = r_maxsurfs.value;
    267 
    268 	if (r_cnumsurfs <= MINSURFACES)
    269 		r_cnumsurfs = MINSURFACES;
    270 
    271 	if (r_cnumsurfs > NUMSTACKSURFACES)
    272 	{
    273 		surfaces = Hunk_AllocName (r_cnumsurfs * sizeof(surf_t), "surfaces");
    274 		surface_p = surfaces;
    275 		surf_max = &surfaces[r_cnumsurfs];
    276 		r_surfsonstack = false;
    277 	// surface 0 doesn't really exist; it's just a dummy because index 0
    278 	// is used to indicate no edge attached to surface
    279 		surfaces--;
    280 		R_SurfacePatch ();
    281 	}
    282 	else
    283 	{
    284 		r_surfsonstack = true;
    285 	}
    286 
    287 	r_maxedgesseen = 0;
    288 	r_maxsurfsseen = 0;
    289 
    290 	r_numallocatededges = r_maxedges.value;
    291 
    292 	if (r_numallocatededges < MINEDGES)
    293 		r_numallocatededges = MINEDGES;
    294 
    295 	if (r_numallocatededges <= NUMSTACKEDGES)
    296 	{
    297 		auxedges = NULL;
    298 	}
    299 	else
    300 	{
    301 		auxedges = Hunk_AllocName (r_numallocatededges * sizeof(edge_t),
    302 								   "edges");
    303 	}
    304 
    305 	r_dowarpold = false;
    306 	r_viewchanged = false;
    307 }
    308 
    309 
    310 /*
    311 ===============
    312 R_SetVrect
    313 ===============
    314 */
    315 void R_SetVrect (vrect_t *pvrectin, vrect_t *pvrect, int lineadj)
    316 {
    317 	int		h;
    318 	float	size;
    319 	qboolean full = false;
    320 
    321 	if (scr_viewsize.value >= 100.0) {
    322 		size = 100.0;
    323 		full = true;
    324 	} else
    325 		size = scr_viewsize.value;
    326 
    327 	if (cl.intermission)
    328 	{
    329 		full = true;
    330 		size = 100.0;
    331 		lineadj = 0;
    332 	}
    333 	size /= 100.0;
    334 
    335 	if (!cl_sbar.value && full)
    336 		h = pvrectin->height;
    337 	else
    338 		h = pvrectin->height - lineadj;
    339 
    340 //	h = (!cl_sbar.value && size==1.0) ? pvrectin->height : (pvrectin->height - lineadj);
    341 //	h = pvrectin->height - lineadj;
    342 	if (full)
    343 		pvrect->width = pvrectin->width;
    344 	else
    345 		pvrect->width = pvrectin->width * size;
    346 	if (pvrect->width < 96)
    347 	{
    348 		size = 96.0 / pvrectin->width;
    349 		pvrect->width = 96;	// min for icons
    350 	}
    351 	pvrect->width &= ~7;
    352 	pvrect->height = pvrectin->height * size;
    353 	if (cl_sbar.value || !full) {
    354 		if (pvrect->height > pvrectin->height - lineadj)
    355 			pvrect->height = pvrectin->height - lineadj;
    356 	} else
    357 		if (pvrect->height > pvrectin->height)
    358 			pvrect->height = pvrectin->height;
    359 
    360 	pvrect->height &= ~1;
    361 
    362 	pvrect->x = (pvrectin->width - pvrect->width)/2;
    363 	if (full)
    364 		pvrect->y = 0;
    365 	else
    366 		pvrect->y = (h - pvrect->height)/2;
    367 }
    368 
    369 
    370 /*
    371 ===============
    372 R_ViewChanged
    373 
    374 Called every time the vid structure or r_refdef changes.
    375 Guaranteed to be called before the first refresh
    376 ===============
    377 */
    378 void R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect)
    379 {
    380 	int		i;
    381 	float	res_scale;
    382 
    383 	r_viewchanged = true;
    384 
    385 	R_SetVrect (pvrect, &r_refdef.vrect, lineadj);
    386 
    387 	r_refdef.horizontalFieldOfView = 2.0 * tan (r_refdef.fov_x/360*M_PI);
    388 	r_refdef.fvrectx = (float)r_refdef.vrect.x;
    389 	r_refdef.fvrectx_adj = (float)r_refdef.vrect.x - 0.5;
    390 	r_refdef.vrect_x_adj_shift20 = (r_refdef.vrect.x<<20) + (1<<19) - 1;
    391 	r_refdef.fvrecty = (float)r_refdef.vrect.y;
    392 	r_refdef.fvrecty_adj = (float)r_refdef.vrect.y - 0.5;
    393 	r_refdef.vrectright = r_refdef.vrect.x + r_refdef.vrect.width;
    394 	r_refdef.vrectright_adj_shift20 = (r_refdef.vrectright<<20) + (1<<19) - 1;
    395 	r_refdef.fvrectright = (float)r_refdef.vrectright;
    396 	r_refdef.fvrectright_adj = (float)r_refdef.vrectright - 0.5;
    397 	r_refdef.vrectrightedge = (float)r_refdef.vrectright - 0.99;
    398 	r_refdef.vrectbottom = r_refdef.vrect.y + r_refdef.vrect.height;
    399 	r_refdef.fvrectbottom = (float)r_refdef.vrectbottom;
    400 	r_refdef.fvrectbottom_adj = (float)r_refdef.vrectbottom - 0.5;
    401 
    402 	r_refdef.aliasvrect.x = (int)(r_refdef.vrect.x * r_aliasuvscale);
    403 	r_refdef.aliasvrect.y = (int)(r_refdef.vrect.y * r_aliasuvscale);
    404 	r_refdef.aliasvrect.width = (int)(r_refdef.vrect.width * r_aliasuvscale);
    405 	r_refdef.aliasvrect.height = (int)(r_refdef.vrect.height * r_aliasuvscale);
    406 	r_refdef.aliasvrectright = r_refdef.aliasvrect.x +
    407 			r_refdef.aliasvrect.width;
    408 	r_refdef.aliasvrectbottom = r_refdef.aliasvrect.y +
    409 			r_refdef.aliasvrect.height;
    410 
    411 	pixelAspect = aspect;
    412 	xOrigin = r_refdef.xOrigin;
    413 	yOrigin = r_refdef.yOrigin;
    414 
    415 	screenAspect = r_refdef.vrect.width*pixelAspect /
    416 			r_refdef.vrect.height;
    417 // 320*200 1.0 pixelAspect = 1.6 screenAspect
    418 // 320*240 1.0 pixelAspect = 1.3333 screenAspect
    419 // proper 320*200 pixelAspect = 0.8333333
    420 
    421 	verticalFieldOfView = r_refdef.horizontalFieldOfView / screenAspect;
    422 
    423 // values for perspective projection
    424 // if math were exact, the values would range from 0.5 to to range+0.5
    425 // hopefully they wll be in the 0.000001 to range+.999999 and truncate
    426 // the polygon rasterization will never render in the first row or column
    427 // but will definately render in the [range] row and column, so adjust the
    428 // buffer origin to get an exact edge to edge fill
    429 	xcenter = ((float)r_refdef.vrect.width * XCENTERING) +
    430 			r_refdef.vrect.x - 0.5;
    431 	aliasxcenter = xcenter * r_aliasuvscale;
    432 	ycenter = ((float)r_refdef.vrect.height * YCENTERING) +
    433 			r_refdef.vrect.y - 0.5;
    434 	aliasycenter = ycenter * r_aliasuvscale;
    435 
    436 	xscale = r_refdef.vrect.width / r_refdef.horizontalFieldOfView;
    437 	aliasxscale = xscale * r_aliasuvscale;
    438 	xscaleinv = 1.0 / xscale;
    439 	yscale = xscale * pixelAspect;
    440 	aliasyscale = yscale * r_aliasuvscale;
    441 	yscaleinv = 1.0 / yscale;
    442 	xscaleshrink = (r_refdef.vrect.width-6)/r_refdef.horizontalFieldOfView;
    443 	yscaleshrink = xscaleshrink*pixelAspect;
    444 
    445 // left side clip
    446 	screenedge[0].normal[0] = -1.0 / (xOrigin*r_refdef.horizontalFieldOfView);
    447 	screenedge[0].normal[1] = 0;
    448 	screenedge[0].normal[2] = 1;
    449 	screenedge[0].type = PLANE_ANYZ;
    450 
    451 // right side clip
    452 	screenedge[1].normal[0] =
    453 			1.0 / ((1.0-xOrigin)*r_refdef.horizontalFieldOfView);
    454 	screenedge[1].normal[1] = 0;
    455 	screenedge[1].normal[2] = 1;
    456 	screenedge[1].type = PLANE_ANYZ;
    457 
    458 // top side clip
    459 	screenedge[2].normal[0] = 0;
    460 	screenedge[2].normal[1] = -1.0 / (yOrigin*verticalFieldOfView);
    461 	screenedge[2].normal[2] = 1;
    462 	screenedge[2].type = PLANE_ANYZ;
    463 
    464 // bottom side clip
    465 	screenedge[3].normal[0] = 0;
    466 	screenedge[3].normal[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView);
    467 	screenedge[3].normal[2] = 1;
    468 	screenedge[3].type = PLANE_ANYZ;
    469 
    470 	for (i=0 ; i<4 ; i++)
    471 		VectorNormalize (screenedge[i].normal);
    472 
    473 	res_scale = sqrt ((double)(r_refdef.vrect.width * r_refdef.vrect.height) /
    474 			          (320.0 * 152.0)) *
    475 			(2.0 / r_refdef.horizontalFieldOfView);
    476 	r_aliastransition = r_aliastransbase.value * res_scale;
    477 	r_resfudge = r_aliastransadj.value * res_scale;
    478 
    479 	if (scr_fov.value <= 90.0)
    480 		r_fov_greater_than_90 = false;
    481 	else
    482 		r_fov_greater_than_90 = true;
    483 
    484 // TODO: collect 386-specific code in one place
    485 #if id386
    486 	if (r_pixbytes == 1)
    487 	{
    488 		Sys_MakeCodeWriteable ((long)R_Surf8Start,
    489 						     (long)R_Surf8End - (long)R_Surf8Start);
    490 		colormap = vid.colormap;
    491 		R_Surf8Patch ();
    492 	}
    493 	else
    494 	{
    495 		Sys_MakeCodeWriteable ((long)R_Surf16Start,
    496 						     (long)R_Surf16End - (long)R_Surf16Start);
    497 		colormap = vid.colormap16;
    498 		R_Surf16Patch ();
    499 	}
    500 #endif	// id386
    501 
    502 	D_ViewChanged ();
    503 }
    504 
    505 
    506 /*
    507 ===============
    508 R_MarkLeaves
    509 ===============
    510 */
    511 void R_MarkLeaves (void)
    512 {
    513 	byte	*vis;
    514 	mnode_t	*node;
    515 	int		i;
    516 
    517 	if (r_oldviewleaf == r_viewleaf)
    518 		return;
    519 
    520 	r_visframecount++;
    521 	r_oldviewleaf = r_viewleaf;
    522 
    523 	vis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
    524 
    525 	for (i=0 ; i<cl.worldmodel->numleafs ; i++)
    526 	{
    527 		if (vis[i>>3] & (1<<(i&7)))
    528 		{
    529 			node = (mnode_t *)&cl.worldmodel->leafs[i+1];
    530 			do
    531 			{
    532 				if (node->visframe == r_visframecount)
    533 					break;
    534 				node->visframe = r_visframecount;
    535 				node = node->parent;
    536 			} while (node);
    537 		}
    538 	}
    539 }
    540 
    541 
    542 /*
    543 =============
    544 R_DrawEntitiesOnList
    545 =============
    546 */
    547 void R_DrawEntitiesOnList (void)
    548 {
    549 	int			i, j;
    550 	int			lnum;
    551 	alight_t	lighting;
    552 // FIXME: remove and do real lighting
    553 	float		lightvec[3] = {-1, 0, 0};
    554 	vec3_t		dist;
    555 	float		add;
    556 
    557 	if (!r_drawentities.value)
    558 		return;
    559 
    560 	for (i=0 ; i<cl_numvisedicts ; i++)
    561 	{
    562 		currententity = &cl_visedicts[i];
    563 
    564 		switch (currententity->model->type)
    565 		{
    566 		case mod_sprite:
    567 			VectorCopy (currententity->origin, r_entorigin);
    568 			VectorSubtract (r_origin, r_entorigin, modelorg);
    569 			R_DrawSprite ();
    570 			break;
    571 
    572 		case mod_alias:
    573 			VectorCopy (currententity->origin, r_entorigin);
    574 			VectorSubtract (r_origin, r_entorigin, modelorg);
    575 
    576 		// see if the bounding box lets us trivially reject, also sets
    577 		// trivial accept status
    578 			if (R_AliasCheckBBox ())
    579 			{
    580 				j = R_LightPoint (currententity->origin);
    581 
    582 				lighting.ambientlight = j;
    583 				lighting.shadelight = j;
    584 
    585 				lighting.plightvec = lightvec;
    586 
    587 				for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
    588 				{
    589 					if (cl_dlights[lnum].die >= cl.time)
    590 					{
    591 						VectorSubtract (currententity->origin,
    592 										cl_dlights[lnum].origin,
    593 										dist);
    594 						add = cl_dlights[lnum].radius - Length(dist);
    595 
    596 						if (add > 0)
    597 							lighting.ambientlight += add;
    598 					}
    599 				}
    600 
    601 			// clamp lighting so it doesn't overbright as much
    602 				if (lighting.ambientlight > 128)
    603 					lighting.ambientlight = 128;
    604 				if (lighting.ambientlight + lighting.shadelight > 192)
    605 					lighting.shadelight = 192 - lighting.ambientlight;
    606 
    607 				R_AliasDrawModel (&lighting);
    608 			}
    609 
    610 			break;
    611 
    612 		default:
    613 			break;
    614 		}
    615 	}
    616 }
    617 
    618 /*
    619 =============
    620 R_DrawViewModel
    621 =============
    622 */
    623 void R_DrawViewModel (void)
    624 {
    625 // FIXME: remove and do real lighting
    626 	float		lightvec[3] = {-1, 0, 0};
    627 	int			j;
    628 	int			lnum;
    629 	vec3_t		dist;
    630 	float		add;
    631 	dlight_t	*dl;
    632 
    633 	if (!r_drawviewmodel.value || r_fov_greater_than_90 || !Cam_DrawViewModel())
    634 		return;
    635 
    636 	if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY)
    637 		return;
    638 
    639 	if (cl.stats[STAT_HEALTH] <= 0)
    640 		return;
    641 
    642 	currententity = &cl.viewent;
    643 	if (!currententity->model)
    644 		return;
    645 
    646 	VectorCopy (currententity->origin, r_entorigin);
    647 	VectorSubtract (r_origin, r_entorigin, modelorg);
    648 
    649 	VectorCopy (vup, viewlightvec);
    650 	VectorInverse (viewlightvec);
    651 
    652 	j = R_LightPoint (currententity->origin);
    653 
    654 	if (j < 24)
    655 		j = 24;		// allways give some light on gun
    656 	r_viewlighting.ambientlight = j;
    657 	r_viewlighting.shadelight = j;
    658 
    659 // add dynamic lights
    660 	for (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)
    661 	{
    662 		dl = &cl_dlights[lnum];
    663 		if (!dl->radius)
    664 			continue;
    665 		if (!dl->radius)
    666 			continue;
    667 		if (dl->die < cl.time)
    668 			continue;
    669 
    670 		VectorSubtract (currententity->origin, dl->origin, dist);
    671 		add = dl->radius - Length(dist);
    672 		if (add > 0)
    673 			r_viewlighting.ambientlight += add;
    674 	}
    675 
    676 // clamp lighting so it doesn't overbright as much
    677 	if (r_viewlighting.ambientlight > 128)
    678 		r_viewlighting.ambientlight = 128;
    679 	if (r_viewlighting.ambientlight + r_viewlighting.shadelight > 192)
    680 		r_viewlighting.shadelight = 192 - r_viewlighting.ambientlight;
    681 
    682 	r_viewlighting.plightvec = lightvec;
    683 
    684 	R_AliasDrawModel (&r_viewlighting);
    685 }
    686 
    687 
    688 /*
    689 =============
    690 R_BmodelCheckBBox
    691 =============
    692 */
    693 int R_BmodelCheckBBox (model_t *clmodel, float *minmaxs)
    694 {
    695 	int			i, *pindex, clipflags;
    696 	vec3_t		acceptpt, rejectpt;
    697 	double		d;
    698 
    699 	clipflags = 0;
    700 
    701 	if (currententity->angles[0] || currententity->angles[1]
    702 		|| currententity->angles[2])
    703 	{
    704 		for (i=0 ; i<4 ; i++)
    705 		{
    706 			d = DotProduct (currententity->origin, view_clipplanes[i].normal);
    707 			d -= view_clipplanes[i].dist;
    708 
    709 			if (d <= -clmodel->radius)
    710 				return BMODEL_FULLY_CLIPPED;
    711 
    712 			if (d <= clmodel->radius)
    713 				clipflags |= (1<<i);
    714 		}
    715 	}
    716 	else
    717 	{
    718 		for (i=0 ; i<4 ; i++)
    719 		{
    720 		// generate accept and reject points
    721 		// FIXME: do with fast look-ups or integer tests based on the sign bit
    722 		// of the floating point values
    723 
    724 			pindex = pfrustum_indexes[i];
    725 
    726 			rejectpt[0] = minmaxs[pindex[0]];
    727 			rejectpt[1] = minmaxs[pindex[1]];
    728 			rejectpt[2] = minmaxs[pindex[2]];
    729 
    730 			d = DotProduct (rejectpt, view_clipplanes[i].normal);
    731 			d -= view_clipplanes[i].dist;
    732 
    733 			if (d <= 0)
    734 				return BMODEL_FULLY_CLIPPED;
    735 
    736 			acceptpt[0] = minmaxs[pindex[3+0]];
    737 			acceptpt[1] = minmaxs[pindex[3+1]];
    738 			acceptpt[2] = minmaxs[pindex[3+2]];
    739 
    740 			d = DotProduct (acceptpt, view_clipplanes[i].normal);
    741 			d -= view_clipplanes[i].dist;
    742 
    743 			if (d <= 0)
    744 				clipflags |= (1<<i);
    745 		}
    746 	}
    747 
    748 	return clipflags;
    749 }
    750 
    751 
    752 /*
    753 =============
    754 R_DrawBEntitiesOnList
    755 =============
    756 */
    757 void R_DrawBEntitiesOnList (void)
    758 {
    759 	int			i, j, k, clipflags;
    760 	vec3_t		oldorigin;
    761 	model_t		*clmodel;
    762 	float		minmaxs[6];
    763 
    764 	if (!r_drawentities.value)
    765 		return;
    766 
    767 	VectorCopy (modelorg, oldorigin);
    768 	insubmodel = true;
    769 	r_dlightframecount = r_framecount;
    770 
    771 	for (i=0 ; i<cl_numvisedicts ; i++)
    772 	{
    773 		currententity = &cl_visedicts[i];
    774 
    775 		switch (currententity->model->type)
    776 		{
    777 		case mod_brush:
    778 
    779 			clmodel = currententity->model;
    780 
    781 		// see if the bounding box lets us trivially reject, also sets
    782 		// trivial accept status
    783 			for (j=0 ; j<3 ; j++)
    784 			{
    785 				minmaxs[j] = currententity->origin[j] +
    786 						clmodel->mins[j];
    787 				minmaxs[3+j] = currententity->origin[j] +
    788 						clmodel->maxs[j];
    789 			}
    790 
    791 			clipflags = R_BmodelCheckBBox (clmodel, minmaxs);
    792 
    793 			if (clipflags != BMODEL_FULLY_CLIPPED)
    794 			{
    795 				VectorCopy (currententity->origin, r_entorigin);
    796 				VectorSubtract (r_origin, r_entorigin, modelorg);
    797 			// FIXME: is this needed?
    798 				VectorCopy (modelorg, r_worldmodelorg);
    799 
    800 				r_pcurrentvertbase = clmodel->vertexes;
    801 
    802 			// FIXME: stop transforming twice
    803 				R_RotateBmodel ();
    804 
    805 			// calculate dynamic lighting for bmodel if it's not an
    806 			// instanced model
    807 				if (clmodel->firstmodelsurface != 0)
    808 				{
    809 					for (k=0 ; k<MAX_DLIGHTS ; k++)
    810 					{
    811 						if ((cl_dlights[k].die < cl.time) ||
    812 							(!cl_dlights[k].radius))
    813 						{
    814 							continue;
    815 						}
    816 
    817 						R_MarkLights (&cl_dlights[k], 1<<k,
    818 							clmodel->nodes + clmodel->hulls[0].firstclipnode);
    819 					}
    820 				}
    821 
    822 			// if the driver wants polygons, deliver those. Z-buffering is on
    823 			// at this point, so no clipping to the world tree is needed, just
    824 			// frustum clipping
    825 				if (r_drawpolys | r_drawculledpolys)
    826 				{
    827 					R_ZDrawSubmodelPolys (clmodel);
    828 				}
    829 				else
    830 				{
    831 					r_pefragtopnode = NULL;
    832 
    833 					for (j=0 ; j<3 ; j++)
    834 					{
    835 						r_emins[j] = minmaxs[j];
    836 						r_emaxs[j] = minmaxs[3+j];
    837 					}
    838 
    839 					R_SplitEntityOnNode2 (cl.worldmodel->nodes);
    840 
    841 					if (r_pefragtopnode)
    842 					{
    843 						currententity->topnode = r_pefragtopnode;
    844 
    845 						if (r_pefragtopnode->contents >= 0)
    846 						{
    847 						// not a leaf; has to be clipped to the world BSP
    848 							r_clipflags = clipflags;
    849 							R_DrawSolidClippedSubmodelPolygons (clmodel);
    850 						}
    851 						else
    852 						{
    853 						// falls entirely in one leaf, so we just put all the
    854 						// edges in the edge list and let 1/z sorting handle
    855 						// drawing order
    856 							R_DrawSubmodelPolygons (clmodel, clipflags);
    857 						}
    858 
    859 						currententity->topnode = NULL;
    860 					}
    861 				}
    862 
    863 			// put back world rotation and frustum clipping
    864 			// FIXME: R_RotateBmodel should just work off base_vxx
    865 				VectorCopy (base_vpn, vpn);
    866 				VectorCopy (base_vup, vup);
    867 				VectorCopy (base_vright, vright);
    868 				VectorCopy (base_modelorg, modelorg);
    869 				VectorCopy (oldorigin, modelorg);
    870 				R_TransformFrustum ();
    871 			}
    872 
    873 			break;
    874 
    875 		default:
    876 			break;
    877 		}
    878 	}
    879 
    880 	insubmodel = false;
    881 }
    882 
    883 
    884 /*
    885 ================
    886 R_EdgeDrawing
    887 ================
    888 */
    889 void R_EdgeDrawing (void)
    890 {
    891 	edge_t	ledges[NUMSTACKEDGES +
    892 				((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
    893 	surf_t	lsurfs[NUMSTACKSURFACES +
    894 				((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
    895 
    896 	if (auxedges)
    897 	{
    898 		r_edges = auxedges;
    899 	}
    900 	else
    901 	{
    902 		r_edges =  (edge_t *)
    903 				(((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
    904 	}
    905 
    906 	if (r_surfsonstack)
    907 	{
    908 		surfaces =  (surf_t *)
    909 				(((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
    910 		surf_max = &surfaces[r_cnumsurfs];
    911 	// surface 0 doesn't really exist; it's just a dummy because index 0
    912 	// is used to indicate no edge attached to surface
    913 		surfaces--;
    914 		R_SurfacePatch ();
    915 	}
    916 
    917 	R_BeginEdgeFrame ();
    918 
    919 	if (r_dspeeds.value)
    920 	{
    921 		rw_time1 = Sys_DoubleTime ();
    922 	}
    923 
    924 	R_RenderWorld ();
    925 
    926 	if (r_drawculledpolys)
    927 		R_ScanEdges ();
    928 
    929 // only the world can be drawn back to front with no z reads or compares, just
    930 // z writes, so have the driver turn z compares on now
    931 	D_TurnZOn ();
    932 
    933 	if (r_dspeeds.value)
    934 	{
    935 		rw_time2 = Sys_DoubleTime ();
    936 		db_time1 = rw_time2;
    937 	}
    938 
    939 	R_DrawBEntitiesOnList ();
    940 
    941 	if (r_dspeeds.value)
    942 	{
    943 		db_time2 = Sys_DoubleTime ();
    944 		se_time1 = db_time2;
    945 	}
    946 
    947 	if (!r_dspeeds.value)
    948 	{
    949 		VID_UnlockBuffer ();
    950 		S_ExtraUpdate ();	// don't let sound get messed up if going slow
    951 		VID_LockBuffer ();
    952 	}
    953 
    954 	if (!(r_drawpolys | r_drawculledpolys))
    955 		R_ScanEdges ();
    956 }
    957 
    958 
    959 /*
    960 ================
    961 R_RenderView
    962 
    963 r_refdef must be set before the first call
    964 ================
    965 */
    966 void R_RenderView_ (void)
    967 {
    968 	byte	warpbuffer[WARP_WIDTH * WARP_HEIGHT];
    969 
    970 	r_warpbuffer = warpbuffer;
    971 
    972 	if (r_timegraph.value || r_speeds.value || r_dspeeds.value)
    973 		r_time1 = Sys_DoubleTime ();
    974 
    975 	R_SetupFrame ();
    976 
    977 #ifdef PASSAGES
    978 SetVisibilityByPassages ();
    979 #else
    980 	R_MarkLeaves ();	// done here so we know if we're in water
    981 #endif
    982 
    983 // make FDIV fast. This reduces timing precision after we've been running for a
    984 // while, so we don't do it globally.  This also sets chop mode, and we do it
    985 // here so that setup stuff like the refresh area calculations match what's
    986 // done in screen.c
    987 	Sys_LowFPPrecision ();
    988 
    989 	if (!r_worldentity.model || !cl.worldmodel)
    990 		Sys_Error ("R_RenderView: NULL worldmodel");
    991 
    992 	if (!r_dspeeds.value)
    993 	{
    994 		VID_UnlockBuffer ();
    995 		S_ExtraUpdate ();	// don't let sound get messed up if going slow
    996 		VID_LockBuffer ();
    997 	}
    998 
    999 	R_EdgeDrawing ();
   1000 
   1001 	if (!r_dspeeds.value)
   1002 	{
   1003 		VID_UnlockBuffer ();
   1004 		S_ExtraUpdate ();	// don't let sound get messed up if going slow
   1005 		VID_LockBuffer ();
   1006 	}
   1007 
   1008 	if (r_dspeeds.value)
   1009 	{
   1010 		se_time2 = Sys_DoubleTime ();
   1011 		de_time1 = se_time2;
   1012 	}
   1013 
   1014 	R_DrawEntitiesOnList ();
   1015 
   1016 	if (r_dspeeds.value)
   1017 	{
   1018 		de_time2 = Sys_DoubleTime ();
   1019 		dv_time1 = de_time2;
   1020 	}
   1021 
   1022 	R_DrawViewModel ();
   1023 
   1024 	if (r_dspeeds.value)
   1025 	{
   1026 		dv_time2 = Sys_DoubleTime ();
   1027 		dp_time1 = Sys_DoubleTime ();
   1028 	}
   1029 
   1030 	R_DrawParticles ();
   1031 
   1032 	if (r_dspeeds.value)
   1033 		dp_time2 = Sys_DoubleTime ();
   1034 
   1035 	if (r_dowarp)
   1036 		D_WarpScreen ();
   1037 
   1038 	V_SetContentsColor (r_viewleaf->contents);
   1039 
   1040 	if (r_timegraph.value)
   1041 		R_TimeGraph ();
   1042 
   1043 	if (r_netgraph.value)
   1044 		R_NetGraph ();
   1045 
   1046 	if (r_zgraph.value)
   1047 		R_ZGraph ();
   1048 
   1049 	if (r_aliasstats.value)
   1050 		R_PrintAliasStats ();
   1051 
   1052 	if (r_speeds.value)
   1053 		R_PrintTimes ();
   1054 
   1055 	if (r_dspeeds.value)
   1056 		R_PrintDSpeeds ();
   1057 
   1058 	if (r_reportsurfout.value && r_outofsurfaces)
   1059 		Con_Printf ("Short %d surfaces\n", r_outofsurfaces);
   1060 
   1061 	if (r_reportedgeout.value && r_outofedges)
   1062 		Con_Printf ("Short roughly %d edges\n", r_outofedges * 2 / 3);
   1063 
   1064 // back to high floating-point precision
   1065 	Sys_HighFPPrecision ();
   1066 }
   1067 
   1068 void R_RenderView (void)
   1069 {
   1070 	int		dummy;
   1071 	int		delta;
   1072 
   1073 	delta = (byte *)&dummy - r_stack_start;
   1074 	if (delta < -10000 || delta > 10000)
   1075 		Sys_Error ("R_RenderView: called without enough stack");
   1076 
   1077 	if ( Hunk_LowMark() & 3 )
   1078 		Sys_Error ("Hunk is missaligned");
   1079 
   1080 	if ( (long)(&dummy) & 3 )
   1081 		Sys_Error ("Stack is missaligned");
   1082 
   1083 	if ( (long)(&r_warpbuffer) & 3 )
   1084 		Sys_Error ("Globals are missaligned");
   1085 
   1086 	R_RenderView_ ();
   1087 }
   1088 
   1089 /*
   1090 ================
   1091 R_InitTurb
   1092 ================
   1093 */
   1094 void R_InitTurb (void)
   1095 {
   1096 	int		i;
   1097 
   1098 	for (i=0 ; i<1280 ; i++)
   1099 	{
   1100 		sintable[i] = AMP + sin(i*3.14159*2/CYCLE)*AMP;
   1101 		intsintable[i] = AMP2 + sin(i*3.14159*2/CYCLE)*AMP2;	// AMP2, not 20
   1102 	}
   1103 }
   1104 
   1105