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 */
R_InitTextures(void)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 */
R_InitTurb(void)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 
R_Register(void)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 
R_UnRegister(void)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 */
R_Init(void * hInstance,void * wndProc)300 int 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 	if (SWimp_Init( hInstance, wndProc ) == false)
331 		return -1;
332 
333 	// create the window
334 	R_BeginFrame( 0 );
335 
336 	ri.Con_Printf (PRINT_ALL, "ref_soft version: "REF_VERSION"\n");
337 
338 	return true;
339 }
340 
341 /*
342 ===============
343 R_Shutdown
344 ===============
345 */
R_Shutdown(void)346 void R_Shutdown (void)
347 {
348 	// free z buffer
349 	if (d_pzbuffer)
350 	{
351 		free (d_pzbuffer);
352 		d_pzbuffer = NULL;
353 	}
354 	// free surface cache
355 	if (sc_base)
356 	{
357 		D_FlushCaches ();
358 		free (sc_base);
359 		sc_base = NULL;
360 	}
361 
362 	// free colormap
363 	if (vid.colormap)
364 	{
365 		free (vid.colormap);
366 		vid.colormap = NULL;
367 	}
368 	R_UnRegister ();
369 	Mod_FreeAll ();
370 	R_ShutdownImages ();
371 
372 	SWimp_Shutdown();
373 }
374 
375 /*
376 ===============
377 R_NewMap
378 ===============
379 */
R_NewMap(void)380 void R_NewMap (void)
381 {
382 	r_viewcluster = -1;
383 
384 	r_cnumsurfs = sw_maxsurfs->value;
385 
386 	if (r_cnumsurfs <= MINSURFACES)
387 		r_cnumsurfs = MINSURFACES;
388 
389 	if (r_cnumsurfs > NUMSTACKSURFACES)
390 	{
391 		surfaces = malloc (r_cnumsurfs * sizeof(surf_t));
392 		surface_p = surfaces;
393 		surf_max = &surfaces[r_cnumsurfs];
394 		r_surfsonstack = false;
395 	// surface 0 doesn't really exist; it's just a dummy because index 0
396 	// is used to indicate no edge attached to surface
397 		surfaces--;
398 		R_SurfacePatch ();
399 	}
400 	else
401 	{
402 		r_surfsonstack = true;
403 	}
404 
405 	r_maxedgesseen = 0;
406 	r_maxsurfsseen = 0;
407 
408 	r_numallocatededges = sw_maxedges->value;
409 
410 	if (r_numallocatededges < MINEDGES)
411 		r_numallocatededges = MINEDGES;
412 
413 	if (r_numallocatededges <= NUMSTACKEDGES)
414 	{
415 		auxedges = NULL;
416 	}
417 	else
418 	{
419 		auxedges = malloc (r_numallocatededges * sizeof(edge_t));
420 	}
421 }
422 
423 
424 /*
425 ===============
426 R_MarkLeaves
427 
428 Mark the leaves and nodes that are in the PVS for the current
429 cluster
430 ===============
431 */
R_MarkLeaves(void)432 void R_MarkLeaves (void)
433 {
434 	byte	*vis;
435 	mnode_t	*node;
436 	int		i;
437 	mleaf_t	*leaf;
438 	int		cluster;
439 
440 	if (r_oldviewcluster == r_viewcluster && !r_novis->value && r_viewcluster != -1)
441 		return;
442 
443 	// development aid to let you run around and see exactly where
444 	// the pvs ends
445 	if (sw_lockpvs->value)
446 		return;
447 
448 	r_visframecount++;
449 	r_oldviewcluster = r_viewcluster;
450 
451 	if (r_novis->value || r_viewcluster == -1 || !r_worldmodel->vis)
452 	{
453 		// mark everything
454 		for (i=0 ; i<r_worldmodel->numleafs ; i++)
455 			r_worldmodel->leafs[i].visframe = r_visframecount;
456 		for (i=0 ; i<r_worldmodel->numnodes ; i++)
457 			r_worldmodel->nodes[i].visframe = r_visframecount;
458 		return;
459 	}
460 
461 	vis = Mod_ClusterPVS (r_viewcluster, r_worldmodel);
462 
463 	for (i=0,leaf=r_worldmodel->leafs ; i<r_worldmodel->numleafs ; i++, leaf++)
464 	{
465 		cluster = leaf->cluster;
466 		if (cluster == -1)
467 			continue;
468 		if (vis[cluster>>3] & (1<<(cluster&7)))
469 		{
470 			node = (mnode_t *)leaf;
471 			do
472 			{
473 				if (node->visframe == r_visframecount)
474 					break;
475 				node->visframe = r_visframecount;
476 				node = node->parent;
477 			} while (node);
478 		}
479 	}
480 
481 #if 0
482 	for (i=0 ; i<r_worldmodel->vis->numclusters ; i++)
483 	{
484 		if (vis[i>>3] & (1<<(i&7)))
485 		{
486 			node = (mnode_t *)&r_worldmodel->leafs[i];	// FIXME: cluster
487 			do
488 			{
489 				if (node->visframe == r_visframecount)
490 					break;
491 				node->visframe = r_visframecount;
492 				node = node->parent;
493 			} while (node);
494 		}
495 	}
496 #endif
497 }
498 
499 /*
500 ** R_DrawNullModel
501 **
502 ** IMPLEMENT THIS!
503 */
R_DrawNullModel(void)504 void R_DrawNullModel( void )
505 {
506 }
507 
508 /*
509 =============
510 R_DrawEntitiesOnList
511 =============
512 */
R_DrawEntitiesOnList(void)513 void R_DrawEntitiesOnList (void)
514 {
515 	int			i;
516 	qboolean	translucent_entities = false;
517 
518 	if (!r_drawentities->value)
519 		return;
520 
521 	// all bmodels have already been drawn by the edge list
522 	for (i=0 ; i<r_newrefdef.num_entities ; i++)
523 	{
524 		currententity = &r_newrefdef.entities[i];
525 
526 		if ( currententity->flags & RF_TRANSLUCENT )
527 		{
528 			translucent_entities = true;
529 			continue;
530 		}
531 
532 		if ( currententity->flags & RF_BEAM )
533 		{
534 			modelorg[0] = -r_origin[0];
535 			modelorg[1] = -r_origin[1];
536 			modelorg[2] = -r_origin[2];
537 			VectorCopy( vec3_origin, r_entorigin );
538 			R_DrawBeam( currententity );
539 		}
540 		else
541 		{
542 			currentmodel = currententity->model;
543 			if (!currentmodel)
544 			{
545 				R_DrawNullModel();
546 				continue;
547 			}
548 			VectorCopy (currententity->origin, r_entorigin);
549 			VectorSubtract (r_origin, r_entorigin, modelorg);
550 
551 			switch (currentmodel->type)
552 			{
553 			case mod_sprite:
554 				R_DrawSprite ();
555 				break;
556 
557 			case mod_alias:
558 				R_AliasDrawModel ();
559 				break;
560 
561 			default:
562 				break;
563 			}
564 		}
565 	}
566 
567 	if ( !translucent_entities )
568 		return;
569 
570 	for (i=0 ; i<r_newrefdef.num_entities ; i++)
571 	{
572 		currententity = &r_newrefdef.entities[i];
573 
574 		if ( !( currententity->flags & RF_TRANSLUCENT ) )
575 			continue;
576 
577 		if ( currententity->flags & RF_BEAM )
578 		{
579 			modelorg[0] = -r_origin[0];
580 			modelorg[1] = -r_origin[1];
581 			modelorg[2] = -r_origin[2];
582 			VectorCopy( vec3_origin, r_entorigin );
583 			R_DrawBeam( currententity );
584 		}
585 		else
586 		{
587 			currentmodel = currententity->model;
588 			if (!currentmodel)
589 			{
590 				R_DrawNullModel();
591 				continue;
592 			}
593 			VectorCopy (currententity->origin, r_entorigin);
594 			VectorSubtract (r_origin, r_entorigin, modelorg);
595 
596 			switch (currentmodel->type)
597 			{
598 			case mod_sprite:
599 				R_DrawSprite ();
600 				break;
601 
602 			case mod_alias:
603 				R_AliasDrawModel ();
604 				break;
605 
606 			default:
607 				break;
608 			}
609 		}
610 	}
611 }
612 
613 
614 /*
615 =============
616 R_BmodelCheckBBox
617 =============
618 */
R_BmodelCheckBBox(float * minmaxs)619 int R_BmodelCheckBBox (float *minmaxs)
620 {
621 	int			i, *pindex, clipflags;
622 	vec3_t		acceptpt, rejectpt;
623 	float		d;
624 
625 	clipflags = 0;
626 
627 	for (i=0 ; i<4 ; i++)
628 	{
629 	// generate accept and reject points
630 	// FIXME: do with fast look-ups or integer tests based on the sign bit
631 	// of the floating point values
632 
633 		pindex = pfrustum_indexes[i];
634 
635 		rejectpt[0] = minmaxs[pindex[0]];
636 		rejectpt[1] = minmaxs[pindex[1]];
637 		rejectpt[2] = minmaxs[pindex[2]];
638 
639 		d = DotProduct (rejectpt, view_clipplanes[i].normal);
640 		d -= view_clipplanes[i].dist;
641 
642 		if (d <= 0)
643 			return BMODEL_FULLY_CLIPPED;
644 
645 		acceptpt[0] = minmaxs[pindex[3+0]];
646 		acceptpt[1] = minmaxs[pindex[3+1]];
647 		acceptpt[2] = minmaxs[pindex[3+2]];
648 
649 		d = DotProduct (acceptpt, view_clipplanes[i].normal);
650 		d -= view_clipplanes[i].dist;
651 
652 		if (d <= 0)
653 			clipflags |= (1<<i);
654 	}
655 
656 	return clipflags;
657 }
658 
659 
660 /*
661 ===================
662 R_FindTopnode
663 
664 Find the first node that splits the given box
665 ===================
666 */
R_FindTopnode(vec3_t mins,vec3_t maxs)667 mnode_t *R_FindTopnode (vec3_t mins, vec3_t maxs)
668 {
669 	mplane_t	*splitplane;
670 	int			sides;
671 	mnode_t *node;
672 
673 	node = r_worldmodel->nodes;
674 
675 	while (1)
676 	{
677 		if (node->visframe != r_visframecount)
678 			return NULL;		// not visible at all
679 
680 		if (node->contents != CONTENTS_NODE)
681 		{
682 			if (node->contents != CONTENTS_SOLID)
683 				return	node; // we've reached a non-solid leaf, so it's
684 							//  visible and not BSP clipped
685 			return NULL;	// in solid, so not visible
686 		}
687 
688 		splitplane = node->plane;
689 		sides = BOX_ON_PLANE_SIDE(mins, maxs, (cplane_t *)splitplane);
690 
691 		if (sides == 3)
692 			return node;	// this is the splitter
693 
694 	// not split yet; recurse down the contacted side
695 		if (sides & 1)
696 			node = node->children[0];
697 		else
698 			node = node->children[1];
699 	}
700 }
701 
702 
703 /*
704 =============
705 RotatedBBox
706 
707 Returns an axially aligned box that contains the input box at the given rotation
708 =============
709 */
RotatedBBox(vec3_t mins,vec3_t maxs,vec3_t angles,vec3_t tmins,vec3_t tmaxs)710 void RotatedBBox (vec3_t mins, vec3_t maxs, vec3_t angles, vec3_t tmins, vec3_t tmaxs)
711 {
712 	vec3_t	tmp, v;
713 	int		i, j;
714 	vec3_t	forward, right, up;
715 
716 	if (!angles[0] && !angles[1] && !angles[2])
717 	{
718 		VectorCopy (mins, tmins);
719 		VectorCopy (maxs, tmaxs);
720 		return;
721 	}
722 
723 	for (i=0 ; i<3 ; i++)
724 	{
725 		tmins[i] = 99999;
726 		tmaxs[i] = -99999;
727 	}
728 
729 	AngleVectors (angles, forward, right, up);
730 
731 	for ( i = 0; i < 8; i++ )
732 	{
733 		if ( i & 1 )
734 			tmp[0] = mins[0];
735 		else
736 			tmp[0] = maxs[0];
737 
738 		if ( i & 2 )
739 			tmp[1] = mins[1];
740 		else
741 			tmp[1] = maxs[1];
742 
743 		if ( i & 4 )
744 			tmp[2] = mins[2];
745 		else
746 			tmp[2] = maxs[2];
747 
748 
749 		VectorScale (forward, tmp[0], v);
750 		VectorMA (v, -tmp[1], right, v);
751 		VectorMA (v, tmp[2], up, v);
752 
753 		for (j=0 ; j<3 ; j++)
754 		{
755 			if (v[j] < tmins[j])
756 				tmins[j] = v[j];
757 			if (v[j] > tmaxs[j])
758 				tmaxs[j] = v[j];
759 		}
760 	}
761 }
762 
763 /*
764 =============
765 R_DrawBEntitiesOnList
766 =============
767 */
R_DrawBEntitiesOnList(void)768 void R_DrawBEntitiesOnList (void)
769 {
770 	int			i, clipflags;
771 	vec3_t		oldorigin;
772 	vec3_t		mins, maxs;
773 	float		minmaxs[6];
774 	mnode_t		*topnode;
775 
776 	if (!r_drawentities->value)
777 		return;
778 
779 	VectorCopy (modelorg, oldorigin);
780 	insubmodel = true;
781 	r_dlightframecount = r_framecount;
782 
783 	for (i=0 ; i<r_newrefdef.num_entities ; i++)
784 	{
785 		currententity = &r_newrefdef.entities[i];
786 		currentmodel = currententity->model;
787 		if (!currentmodel)
788 			continue;
789 		if (currentmodel->nummodelsurfaces == 0)
790 			continue;	// clip brush only
791 		if ( currententity->flags & RF_BEAM )
792 			continue;
793 		if (currentmodel->type != mod_brush)
794 			continue;
795 	// see if the bounding box lets us trivially reject, also sets
796 	// trivial accept status
797 		RotatedBBox (currentmodel->mins, currentmodel->maxs,
798 			currententity->angles, mins, maxs);
799 		VectorAdd (mins, currententity->origin, minmaxs);
800 		VectorAdd (maxs, currententity->origin, (minmaxs+3));
801 
802 		clipflags = R_BmodelCheckBBox (minmaxs);
803 		if (clipflags == BMODEL_FULLY_CLIPPED)
804 			continue;	// off the edge of the screen
805 
806 		topnode = R_FindTopnode (minmaxs, minmaxs+3);
807 		if (!topnode)
808 			continue;	// no part in a visible leaf
809 
810 		VectorCopy (currententity->origin, r_entorigin);
811 		VectorSubtract (r_origin, r_entorigin, modelorg);
812 
813 		r_pcurrentvertbase = currentmodel->vertexes;
814 
815 	// FIXME: stop transforming twice
816 		R_RotateBmodel ();
817 
818 	// calculate dynamic lighting for bmodel
819 		R_PushDlights (currentmodel);
820 
821 		if (topnode->contents == CONTENTS_NODE)
822 		{
823 		// not a leaf; has to be clipped to the world BSP
824 			r_clipflags = clipflags;
825 			R_DrawSolidClippedSubmodelPolygons (currentmodel, topnode);
826 		}
827 		else
828 		{
829 		// falls entirely in one leaf, so we just put all the
830 		// edges in the edge list and let 1/z sorting handle
831 		// drawing order
832 			R_DrawSubmodelPolygons (currentmodel, clipflags, topnode);
833 		}
834 
835 	// put back world rotation and frustum clipping
836 	// FIXME: R_RotateBmodel should just work off base_vxx
837 		VectorCopy (base_vpn, vpn);
838 		VectorCopy (base_vup, vup);
839 		VectorCopy (base_vright, vright);
840 		VectorCopy (oldorigin, modelorg);
841 		R_TransformFrustum ();
842 	}
843 
844 	insubmodel = false;
845 }
846 
847 
848 /*
849 ================
850 R_EdgeDrawing
851 ================
852 */
R_EdgeDrawing(void)853 void R_EdgeDrawing (void)
854 {
855 	edge_t	ledges[NUMSTACKEDGES +
856 				((CACHE_SIZE - 1) / sizeof(edge_t)) + 1];
857 	surf_t	lsurfs[NUMSTACKSURFACES +
858 				((CACHE_SIZE - 1) / sizeof(surf_t)) + 1];
859 
860 	if ( r_newrefdef.rdflags & RDF_NOWORLDMODEL )
861 		return;
862 
863 	if (auxedges)
864 	{
865 		r_edges = auxedges;
866 	}
867 	else
868 	{
869 		r_edges =  (edge_t *)
870 				(((long)&ledges[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
871 	}
872 
873 	if (r_surfsonstack)
874 	{
875 		surfaces =  (surf_t *)
876 				(((long)&lsurfs[0] + CACHE_SIZE - 1) & ~(CACHE_SIZE - 1));
877 		surf_max = &surfaces[r_cnumsurfs];
878 	// surface 0 doesn't really exist; it's just a dummy because index 0
879 	// is used to indicate no edge attached to surface
880 		surfaces--;
881 		R_SurfacePatch ();
882 	}
883 
884 	R_BeginEdgeFrame ();
885 
886 	if (r_dspeeds->value)
887 	{
888 		rw_time1 = Sys_Milliseconds ();
889 	}
890 
891 	R_RenderWorld ();
892 
893 	if (r_dspeeds->value)
894 	{
895 		rw_time2 = Sys_Milliseconds ();
896 		db_time1 = rw_time2;
897 	}
898 
899 	R_DrawBEntitiesOnList ();
900 
901 	if (r_dspeeds->value)
902 	{
903 		db_time2 = Sys_Milliseconds ();
904 		se_time1 = db_time2;
905 	}
906 
907 	R_ScanEdges ();
908 }
909 
910 //=======================================================================
911 
912 
913 /*
914 =============
915 R_CalcPalette
916 
917 =============
918 */
R_CalcPalette(void)919 void R_CalcPalette (void)
920 {
921 	static qboolean modified;
922 	byte	palette[256][4], *in, *out;
923 	int		i, j;
924 	float	alpha, one_minus_alpha;
925 	vec3_t	premult;
926 	int		v;
927 
928 	alpha = r_newrefdef.blend[3];
929 	if (alpha <= 0)
930 	{
931 		if (modified)
932 		{	// set back to default
933 			modified = false;
934 			R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
935 			return;
936 		}
937 		return;
938 	}
939 
940 	modified = true;
941 	if (alpha > 1)
942 		alpha = 1;
943 
944 	premult[0] = r_newrefdef.blend[0]*alpha*255;
945 	premult[1] = r_newrefdef.blend[1]*alpha*255;
946 	premult[2] = r_newrefdef.blend[2]*alpha*255;
947 
948 	one_minus_alpha = (1.0 - alpha);
949 
950 	in = (byte *)d_8to24table;
951 	out = palette[0];
952 	for (i=0 ; i<256 ; i++, in+=4, out+=4)
953 	{
954 		for (j=0 ; j<3 ; j++)
955 		{
956 			v = premult[j] + one_minus_alpha * in[j];
957 			if (v > 255)
958 				v = 255;
959 			out[j] = v;
960 		}
961 		out[3] = 255;
962 	}
963 
964 	R_GammaCorrectAndSetPalette( ( const unsigned char * ) palette[0] );
965 //	SWimp_SetPalette( palette[0] );
966 }
967 
968 //=======================================================================
969 
R_SetLightLevel(void)970 void R_SetLightLevel (void)
971 {
972 	vec3_t		light;
973 
974 	if ((r_newrefdef.rdflags & RDF_NOWORLDMODEL) || (!r_drawentities->value) || (!currententity))
975 	{
976 		r_lightlevel->value = 150.0;
977 		return;
978 	}
979 
980 	// save off light value for server to look at (BIG HACK!)
981 	R_LightPoint (r_newrefdef.vieworg, light);
982 	r_lightlevel->value = 150.0 * light[0];
983 }
984 
985 
986 /*
987 @@@@@@@@@@@@@@@@
988 R_RenderFrame
989 
990 @@@@@@@@@@@@@@@@
991 */
R_RenderFrame(refdef_t * fd)992 void R_RenderFrame (refdef_t *fd)
993 {
994 	r_newrefdef = *fd;
995 
996 	if (!r_worldmodel && !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) )
997 		ri.Sys_Error (ERR_FATAL,"R_RenderView: NULL worldmodel");
998 
999 	VectorCopy (fd->vieworg, r_refdef.vieworg);
1000 	VectorCopy (fd->viewangles, r_refdef.viewangles);
1001 
1002 	if (r_speeds->value || r_dspeeds->value)
1003 		r_time1 = Sys_Milliseconds ();
1004 
1005 	R_SetupFrame ();
1006 
1007 	R_MarkLeaves ();	// done here so we know if we're in water
1008 
1009 	R_PushDlights (r_worldmodel);
1010 
1011 	R_EdgeDrawing ();
1012 
1013 	if (r_dspeeds->value)
1014 	{
1015 		se_time2 = Sys_Milliseconds ();
1016 		de_time1 = se_time2;
1017 	}
1018 
1019 	R_DrawEntitiesOnList ();
1020 
1021 	if (r_dspeeds->value)
1022 	{
1023 		de_time2 = Sys_Milliseconds ();
1024 		dp_time1 = Sys_Milliseconds ();
1025 	}
1026 
1027 	R_DrawParticles ();
1028 
1029 	if (r_dspeeds->value)
1030 		dp_time2 = Sys_Milliseconds ();
1031 
1032 	R_DrawAlphaSurfaces();
1033 
1034 	R_SetLightLevel ();
1035 
1036 	if (r_dowarp)
1037 		D_WarpScreen ();
1038 
1039 	if (r_dspeeds->value)
1040 		da_time1 = Sys_Milliseconds ();
1041 
1042 	if (r_dspeeds->value)
1043 		da_time2 = Sys_Milliseconds ();
1044 
1045 	R_CalcPalette ();
1046 
1047 	if (sw_aliasstats->value)
1048 		R_PrintAliasStats ();
1049 
1050 	if (r_speeds->value)
1051 		R_PrintTimes ();
1052 
1053 	if (r_dspeeds->value)
1054 		R_PrintDSpeeds ();
1055 
1056 	if (sw_reportsurfout->value && r_outofsurfaces)
1057 		ri.Con_Printf (PRINT_ALL,"Short %d surfaces\n", r_outofsurfaces);
1058 
1059 	if (sw_reportedgeout->value && r_outofedges)
1060 		ri.Con_Printf (PRINT_ALL,"Short roughly %d edges\n", r_outofedges * 2 / 3);
1061 }
1062 
1063 /*
1064 ** R_InitGraphics
1065 */
R_InitGraphics(int width,int height)1066 void R_InitGraphics( int width, int height )
1067 {
1068 	vid.width  = width;
1069 	vid.height = height;
1070 
1071 	// free z buffer
1072 	if ( d_pzbuffer )
1073 	{
1074 		free( d_pzbuffer );
1075 		d_pzbuffer = NULL;
1076 	}
1077 
1078 	// free surface cache
1079 	if ( sc_base )
1080 	{
1081 		D_FlushCaches ();
1082 		free( sc_base );
1083 		sc_base = NULL;
1084 	}
1085 
1086 	d_pzbuffer = malloc(vid.width*vid.height*2);
1087 
1088 	R_InitCaches ();
1089 
1090 	R_GammaCorrectAndSetPalette( ( const unsigned char *) d_8to24table );
1091 }
1092 
1093 #ifdef REDBLUE
1094 void SetStereoBuffer(int buf);
1095 #endif
1096 /*
1097 ** R_BeginFrame
1098 */
R_BeginFrame(float camera_separation)1099 void R_BeginFrame( float camera_separation )
1100 {
1101 	extern void Draw_BuildGammaTable( void );
1102 #ifdef REDBLUE
1103 	SetStereoBuffer((camera_separation <= 0.0) ? 0 : 1);
1104 #endif
1105 	/*
1106 	** rebuild the gamma correction palette if necessary
1107 	*/
1108 	if ( vid_gamma->modified )
1109 	{
1110 		Draw_BuildGammaTable();
1111 		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
1112 
1113 		vid_gamma->modified = false;
1114 	}
1115 
1116 	while ( sw_mode->modified || vid_fullscreen->modified )
1117 	{
1118 		rserr_t err;
1119 
1120 		/*
1121 		** if this returns rserr_invalid_fullscreen then it set the mode but not as a
1122 		** fullscreen mode, e.g. 320x200 on a system that doesn't support that res
1123 		*/
1124 		if ( ( err = SWimp_SetMode( &vid.width, &vid.height, sw_mode->value, vid_fullscreen->value ) ) == rserr_ok )
1125 		{
1126 			R_InitGraphics( vid.width, vid.height );
1127 
1128 			sw_state.prev_mode = sw_mode->value;
1129 			vid_fullscreen->modified = false;
1130 			sw_mode->modified = false;
1131 		}
1132 		else
1133 		{
1134 			if ( err == rserr_invalid_mode )
1135 			{
1136 				ri.Cvar_SetValue( "sw_mode", sw_state.prev_mode );
1137 				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - could not set mode\n" );
1138 			}
1139 			else if ( err == rserr_invalid_fullscreen )
1140 			{
1141 				R_InitGraphics( vid.width, vid.height );
1142 
1143 				ri.Cvar_SetValue( "vid_fullscreen", 0);
1144 				ri.Con_Printf( PRINT_ALL, "ref_soft::R_BeginFrame() - fullscreen unavailable in this mode\n" );
1145 				sw_state.prev_mode = sw_mode->value;
1146 //				vid_fullscreen->modified = false;
1147 //				sw_mode->modified = false;
1148 			}
1149 			else
1150 			{
1151 				ri.Sys_Error( ERR_FATAL, "ref_soft::R_BeginFrame() - catastrophic mode change failure\n" );
1152 			}
1153 		}
1154 	}
1155 }
1156 
1157 /*
1158 ** R_GammaCorrectAndSetPalette
1159 */
R_GammaCorrectAndSetPalette(const unsigned char * palette)1160 void R_GammaCorrectAndSetPalette( const unsigned char *palette )
1161 {
1162 	int i;
1163 
1164 	for ( i = 0; i < 256; i++ )
1165 	{
1166 		sw_state.currentpalette[i*4+0] = sw_state.gammatable[palette[i*4+0]];
1167 		sw_state.currentpalette[i*4+1] = sw_state.gammatable[palette[i*4+1]];
1168 		sw_state.currentpalette[i*4+2] = sw_state.gammatable[palette[i*4+2]];
1169 	}
1170 
1171 	SWimp_SetPalette( sw_state.currentpalette );
1172 }
1173 
1174 /*
1175 ** R_CinematicSetPalette
1176 */
R_CinematicSetPalette(const unsigned char * palette)1177 void R_CinematicSetPalette( const unsigned char *palette )
1178 {
1179 	byte palette32[1024];
1180 	int		i, j, w;
1181 	int		*d;
1182 
1183 	// clear screen to black to avoid any palette flash
1184 	w = abs(vid.rowbytes)>>2;	// stupid negative pitch win32 stuff...
1185 	for (i=0 ; i<vid.height ; i++, d+=w)
1186 	{
1187 		d = (int *)(vid.buffer + i*vid.rowbytes);
1188 		for (j=0 ; j<w ; j++)
1189 			d[j] = 0;
1190 	}
1191 	// flush it to the screen
1192 	SWimp_EndFrame ();
1193 
1194 	if ( palette )
1195 	{
1196 		for ( i = 0; i < 256; i++ )
1197 		{
1198 			palette32[i*4+0] = palette[i*3+0];
1199 			palette32[i*4+1] = palette[i*3+1];
1200 			palette32[i*4+2] = palette[i*3+2];
1201 			palette32[i*4+3] = 0xFF;
1202 		}
1203 
1204 		R_GammaCorrectAndSetPalette( palette32 );
1205 	}
1206 	else
1207 	{
1208 		R_GammaCorrectAndSetPalette( ( const unsigned char * ) d_8to24table );
1209 	}
1210 }
1211 
1212 /*
1213 ================
1214 Draw_BuildGammaTable
1215 ================
1216 */
Draw_BuildGammaTable(void)1217 void Draw_BuildGammaTable (void)
1218 {
1219 	int		i, inf;
1220 	float	g;
1221 
1222 	g = vid_gamma->value;
1223 
1224 	if (g == 1.0)
1225 	{
1226 		for (i=0 ; i<256 ; i++)
1227 			sw_state.gammatable[i] = i;
1228 		return;
1229 	}
1230 
1231 	for (i=0 ; i<256 ; i++)
1232 	{
1233 		inf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;
1234 		if (inf < 0)
1235 			inf = 0;
1236 		if (inf > 255)
1237 			inf = 255;
1238 		sw_state.gammatable[i] = inf;
1239 	}
1240 }
1241 
1242 /*
1243 ** R_DrawBeam
1244 */
R_DrawBeam(entity_t * e)1245 void R_DrawBeam( entity_t *e )
1246 {
1247 #define NUM_BEAM_SEGS 6
1248 
1249 	int	i;
1250 
1251 	vec3_t perpvec;
1252 	vec3_t direction, normalized_direction;
1253 	vec3_t start_points[NUM_BEAM_SEGS], end_points[NUM_BEAM_SEGS];
1254 	vec3_t oldorigin, origin;
1255 
1256 	oldorigin[0] = e->oldorigin[0];
1257 	oldorigin[1] = e->oldorigin[1];
1258 	oldorigin[2] = e->oldorigin[2];
1259 
1260 	origin[0] = e->origin[0];
1261 	origin[1] = e->origin[1];
1262 	origin[2] = e->origin[2];
1263 
1264 	normalized_direction[0] = direction[0] = oldorigin[0] - origin[0];
1265 	normalized_direction[1] = direction[1] = oldorigin[1] - origin[1];
1266 	normalized_direction[2] = direction[2] = oldorigin[2] - origin[2];
1267 
1268 	if ( VectorNormalize( normalized_direction ) == 0 )
1269 		return;
1270 
1271 	PerpendicularVector( perpvec, normalized_direction );
1272 	VectorScale( perpvec, e->frame / 2, perpvec );
1273 
1274 	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
1275 	{
1276 		RotatePointAroundVector( start_points[i], normalized_direction, perpvec, (360.0/NUM_BEAM_SEGS)*i );
1277 		VectorAdd( start_points[i], origin, start_points[i] );
1278 		VectorAdd( start_points[i], direction, end_points[i] );
1279 	}
1280 
1281 	for ( i = 0; i < NUM_BEAM_SEGS; i++ )
1282 	{
1283 		R_IMFlatShadedQuad( start_points[i],
1284 		                    end_points[i],
1285 							end_points[(i+1)%NUM_BEAM_SEGS],
1286 							start_points[(i+1)%NUM_BEAM_SEGS],
1287 							e->skinnum & 0xFF,
1288 							e->alpha );
1289 	}
1290 }
1291 
1292 
1293 //===================================================================
1294 
1295 /*
1296 ============
1297 R_SetSky
1298 ============
1299 */
1300 // 3dstudio environment map names
1301 char	*suf[6] = {"rt", "bk", "lf", "ft", "up", "dn"};
1302 int	r_skysideimage[6] = {5, 2, 4, 1, 0, 3};
1303 extern	mtexinfo_t		r_skytexinfo[6];
R_SetSky(char * name,float rotate,vec3_t axis)1304 void R_SetSky (char *name, float rotate, vec3_t axis)
1305 {
1306 	int		i;
1307 	char	pathname[MAX_QPATH];
1308 
1309 	strncpy (skyname, name, sizeof(skyname)-1);
1310 	skyrotate = rotate;
1311 	VectorCopy (axis, skyaxis);
1312 
1313 	for (i=0 ; i<6 ; i++)
1314 	{
1315 		Com_sprintf (pathname, sizeof(pathname), "env/%s%s.pcx", skyname, suf[r_skysideimage[i]]);
1316 		r_skytexinfo[i].image = R_FindImage (pathname, it_sky);
1317 	}
1318 }
1319 
1320 
1321 /*
1322 ===============
1323 Draw_GetPalette
1324 ===============
1325 */
Draw_GetPalette(void)1326 void Draw_GetPalette (void)
1327 {
1328 	byte	*pal, *out;
1329 	int		i;
1330 	int		r, g, b;
1331 
1332 	// get the palette and colormap
1333 	LoadPCX ("pics/colormap.pcx", &vid.colormap, &pal, NULL, NULL);
1334 	if (!vid.colormap)
1335 		ri.Sys_Error (ERR_FATAL, "Couldn't load pics/colormap.pcx");
1336 	vid.alphamap = vid.colormap + 64*256;
1337 
1338 	out = (byte *)d_8to24table;
1339 	for (i=0 ; i<256 ; i++, out+=4)
1340 	{
1341 		r = pal[i*3+0];
1342 		g = pal[i*3+1];
1343 		b = pal[i*3+2];
1344 
1345         out[0] = r;
1346         out[1] = g;
1347         out[2] = b;
1348 	}
1349 
1350 	free (pal);
1351 }
1352 
1353 struct image_s *R_RegisterSkin (char *name);
1354 
1355 /*
1356 @@@@@@@@@@@@@@@@@@@@@
1357 GetRefAPI
1358 
1359 @@@@@@@@@@@@@@@@@@@@@
1360 */
GetRefAPI(refimport_t rimp)1361 refexport_t GetRefAPI (refimport_t rimp)
1362 {
1363 	refexport_t	re;
1364 
1365 	ri = rimp;
1366 
1367 	re.api_version = API_VERSION;
1368 
1369 	re.BeginRegistration = R_BeginRegistration;
1370     re.RegisterModel = R_RegisterModel;
1371     re.RegisterSkin = R_RegisterSkin;
1372 	re.RegisterPic = Draw_FindPic;
1373 	re.SetSky = R_SetSky;
1374 	re.EndRegistration = R_EndRegistration;
1375 
1376 	re.RenderFrame = R_RenderFrame;
1377 
1378 	re.DrawGetPicSize = Draw_GetPicSize;
1379 
1380 
1381 #ifdef QMAX
1382 	re.DrawScaledPic = Draw_ScaledPic;
1383 	re.AddStain = R_AddStain;
1384 #endif
1385 
1386 	re.DrawPic = Draw_Pic;
1387 	re.DrawStretchPic = Draw_StretchPic;
1388 	re.DrawChar = Draw_Char;
1389 	re.DrawTileClear = Draw_TileClear;
1390 	re.DrawFill = Draw_Fill;
1391 	re.DrawFadeScreen= Draw_FadeScreen;
1392 
1393 	re.DrawStretchRaw = Draw_StretchRaw;
1394 
1395 	re.Init = R_Init;
1396 	re.Shutdown = R_Shutdown;
1397 
1398 	re.CinematicSetPalette = R_CinematicSetPalette;
1399 	re.BeginFrame = R_BeginFrame;
1400 	re.EndFrame = SWimp_EndFrame;
1401 
1402 	re.AppActivate = SWimp_AppActivate;
1403 
1404 	Swap_Init ();
1405 
1406 	return re;
1407 }
1408 
1409 #ifndef REF_HARD_LINKED
1410 // this is only here so the functions in q_shared.c and q_shwin.c can link
Sys_Error(char * error,...)1411 void Sys_Error (char *error, ...)
1412 {
1413 	va_list		argptr;
1414 	char		text[1024];
1415 
1416 	va_start (argptr, error);
1417 	vsprintf (text, error, argptr);
1418 	va_end (argptr);
1419 
1420 	ri.Sys_Error (ERR_FATAL, "%s", text);
1421 }
1422 
Com_Printf(char * fmt,...)1423 void Com_Printf (char *fmt, ...)
1424 {
1425 	va_list		argptr;
1426 	char		text[1024];
1427 
1428 	va_start (argptr, fmt);
1429 	vsprintf (text, fmt, argptr);
1430 	va_end (argptr);
1431 
1432 	ri.Con_Printf (PRINT_ALL, "%s", text);
1433 }
1434 
1435 #endif
1436 
1437 #ifdef QMAX
R_AddStain(vec3_t org,float intensity,float r,float g,float b)1438 void	R_AddStain (vec3_t org, float intensity, float r, float g, float b) {
1439 }
1440 
Draw_ScaledPic(int x,int y,float scale,float alpha,char * pic)1441 void	Draw_ScaledPic (int x, int y, float scale, float alpha, char *pic) {
1442 }
1443 #endif
1444