1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7 
8 This file is part of the OpenJK source code.
9 
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23 
24 // tr_main.c -- main control flow for each frame
25 #include "tr_local.h"
26 #include "ghoul2/g2_local.h"
27 
28 trGlobals_t		tr;
29 
30 static float	s_flipMatrix[16] = {
31 	// convert from our coordinate system (looking down X)
32 	// to OpenGL's coordinate system (looking down -Z)
33 	0, 0, -1, 0,
34 	-1, 0, 0, 0,
35 	0, 1, 0, 0,
36 	0, 0, 0, 1
37 };
38 
39 refimport_t	ri;
40 
41 // entities that will have procedurally generated surfaces will just
42 // point at this for their sorting surface
43 surfaceType_t	entitySurface = SF_ENTITY;
44 
45 /*
46 =================
47 R_CullLocalBox
48 
49 Returns CULL_IN, CULL_CLIP, or CULL_OUT
50 =================
51 */
R_CullLocalBox(const vec3_t bounds[2])52 int R_CullLocalBox (const vec3_t bounds[2]) {
53 	int		i, j;
54 	vec3_t	transformed[8];
55 	float	dists[8];
56 	vec3_t	v;
57 	cplane_t	*frust;
58 	int			anyBack;
59 	int			front, back;
60 
61 	if ( r_nocull->integer==1 ) {
62 		return CULL_CLIP;
63 	}
64 
65 	// transform into world space
66 	for (i = 0 ; i < 8 ; i++) {
67 		v[0] = bounds[i&1][0];
68 		v[1] = bounds[(i>>1)&1][1];
69 		v[2] = bounds[(i>>2)&1][2];
70 
71 		VectorCopy( tr.ori.origin, transformed[i] );
72 		VectorMA( transformed[i], v[0], tr.ori.axis[0], transformed[i] );
73 		VectorMA( transformed[i], v[1], tr.ori.axis[1], transformed[i] );
74 		VectorMA( transformed[i], v[2], tr.ori.axis[2], transformed[i] );
75 	}
76 
77 	// check against frustum planes
78 	anyBack = 0;
79 	for (i = 0 ; i < 4 ; i++) {
80 		frust = &tr.viewParms.frustum[i];
81 
82 		front = back = 0;
83 		for (j = 0 ; j < 8 ; j++) {
84 			dists[j] = DotProduct(transformed[j], frust->normal);
85 			if ( dists[j] > frust->dist ) {
86 				front = 1;
87 				if ( back ) {
88 					break;		// a point is in front
89 				}
90 			} else {
91 				back = 1;
92 			}
93 		}
94 		if ( !front ) {
95 			// all points were behind one of the planes
96 			return CULL_OUT;
97 		}
98 		anyBack |= back;
99 	}
100 
101 	if ( !anyBack ) {
102 		return CULL_IN;		// completely inside frustum
103 	}
104 
105 	return CULL_CLIP;		// partially clipped
106 }
107 
108 /*
109 ** R_CullLocalPointAndRadius
110 */
R_CullLocalPointAndRadius(const vec3_t pt,float radius)111 int R_CullLocalPointAndRadius( const vec3_t pt, float radius )
112 {
113 	vec3_t transformed;
114 
115 	R_LocalPointToWorld( pt, transformed );
116 
117 	return R_CullPointAndRadius( transformed, radius );
118 }
119 
120 /*
121 ** R_CullPointAndRadius
122 */
R_CullPointAndRadius(const vec3_t pt,float radius)123 int R_CullPointAndRadius( const vec3_t pt, float radius )
124 {
125 	int		i;
126 	float	dist;
127 	cplane_t	*frust;
128 	qboolean mightBeClipped = qfalse;
129 
130 	if ( r_nocull->integer==1 ) {
131 		return CULL_CLIP;
132 	}
133 
134 	// check against frustum planes
135 	for (i = 0 ; i < 4 ; i++)
136 	{
137 		frust = &tr.viewParms.frustum[i];
138 
139 		dist = DotProduct( pt, frust->normal) - frust->dist;
140 		if ( dist < -radius )
141 		{
142 			return CULL_OUT;
143 		}
144 		else if ( dist <= radius )
145 		{
146 			mightBeClipped = qtrue;
147 		}
148 	}
149 
150 	if ( mightBeClipped )
151 	{
152 		return CULL_CLIP;
153 	}
154 
155 	return CULL_IN;		// completely inside frustum
156 }
157 
158 /*
159 =================
160 R_LocalNormalToWorld
161 
162 =================
163 */
R_LocalNormalToWorld(const vec3_t local,vec3_t world)164 void R_LocalNormalToWorld (const vec3_t local, vec3_t world) {
165 	world[0] = local[0] * tr.ori.axis[0][0] + local[1] * tr.ori.axis[1][0] + local[2] * tr.ori.axis[2][0];
166 	world[1] = local[0] * tr.ori.axis[0][1] + local[1] * tr.ori.axis[1][1] + local[2] * tr.ori.axis[2][1];
167 	world[2] = local[0] * tr.ori.axis[0][2] + local[1] * tr.ori.axis[1][2] + local[2] * tr.ori.axis[2][2];
168 }
169 
170 /*
171 =================
172 R_LocalPointToWorld
173 
174 =================
175 */
R_LocalPointToWorld(const vec3_t local,vec3_t world)176 void R_LocalPointToWorld (const vec3_t local, vec3_t world) {
177 	world[0] = local[0] * tr.ori.axis[0][0] + local[1] * tr.ori.axis[1][0] + local[2] * tr.ori.axis[2][0] + tr.ori.origin[0];
178 	world[1] = local[0] * tr.ori.axis[0][1] + local[1] * tr.ori.axis[1][1] + local[2] * tr.ori.axis[2][1] + tr.ori.origin[1];
179 	world[2] = local[0] * tr.ori.axis[0][2] + local[1] * tr.ori.axis[1][2] + local[2] * tr.ori.axis[2][2] + tr.ori.origin[2];
180 }
181 
182 float preTransEntMatrix[16];
183 
184 /*
185 =================
186 R_WorldNormalToEntity
187 
188 =================
189 */
R_WorldNormalToEntity(const vec3_t worldvec,vec3_t entvec)190 void R_WorldNormalToEntity (const vec3_t worldvec, vec3_t entvec)
191 {
192 	entvec[0] = -worldvec[0] * preTransEntMatrix[0] - worldvec[1] * preTransEntMatrix[4] + worldvec[2] * preTransEntMatrix[8];
193 	entvec[1] = -worldvec[0] * preTransEntMatrix[1] - worldvec[1] * preTransEntMatrix[5] + worldvec[2] * preTransEntMatrix[9];
194 	entvec[2] = -worldvec[0] * preTransEntMatrix[2] - worldvec[1] * preTransEntMatrix[6] + worldvec[2] * preTransEntMatrix[10];
195 }
196 
197 /*
198 =================
199 R_WorldPointToEntity
200 
201 =================
202 */
203 /*void R_WorldPointToEntity (vec3_t worldvec, vec3_t entvec)
204 {
205 	entvec[0] = worldvec[0] * preTransEntMatrix[0] + worldvec[1] * preTransEntMatrix[4] + worldvec[2] * preTransEntMatrix[8]+preTransEntMatrix[12];
206 	entvec[1] = worldvec[0] * preTransEntMatrix[1] + worldvec[1] * preTransEntMatrix[5] + worldvec[2] * preTransEntMatrix[9]+preTransEntMatrix[13];
207 	entvec[2] = worldvec[0] * preTransEntMatrix[2] + worldvec[1] * preTransEntMatrix[6] + worldvec[2] * preTransEntMatrix[10]+preTransEntMatrix[14];
208 }
209 */
210 
211 /*
212 =================
213 R_WorldToLocal
214 
215 =================
216 */
R_WorldToLocal(vec3_t world,vec3_t local)217 void R_WorldToLocal (vec3_t world, vec3_t local) {
218 	local[0] = DotProduct(world, tr.ori.axis[0]);
219 	local[1] = DotProduct(world, tr.ori.axis[1]);
220 	local[2] = DotProduct(world, tr.ori.axis[2]);
221 }
222 
223 /*
224 ==========================
225 R_TransformModelToClip
226 
227 ==========================
228 */
R_TransformModelToClip(const vec3_t src,const float * modelMatrix,const float * projectionMatrix,vec4_t eye,vec4_t dst)229 void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
230 							vec4_t eye, vec4_t dst ) {
231 	int i;
232 
233 	for ( i = 0 ; i < 4 ; i++ ) {
234 		eye[i] =
235 			src[0] * modelMatrix[ i + 0 * 4 ] +
236 			src[1] * modelMatrix[ i + 1 * 4 ] +
237 			src[2] * modelMatrix[ i + 2 * 4 ] +
238 			1 * modelMatrix[ i + 3 * 4 ];
239 	}
240 
241 	for ( i = 0 ; i < 4 ; i++ ) {
242 		dst[i] =
243 			eye[0] * projectionMatrix[ i + 0 * 4 ] +
244 			eye[1] * projectionMatrix[ i + 1 * 4 ] +
245 			eye[2] * projectionMatrix[ i + 2 * 4 ] +
246 			eye[3] * projectionMatrix[ i + 3 * 4 ];
247 	}
248 }
249 
250 /*
251 ==========================
252 R_TransformClipToWindow
253 
254 ==========================
255 */
R_TransformClipToWindow(const vec4_t clip,const viewParms_t * view,vec4_t normalized,vec4_t window)256 void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) {
257 	normalized[0] = clip[0] / clip[3];
258 	normalized[1] = clip[1] / clip[3];
259 	normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
260 
261 	window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth;
262 	window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight;
263 	window[2] = normalized[2];
264 
265 	window[0] = (int) ( window[0] + 0.5 );
266 	window[1] = (int) ( window[1] + 0.5 );
267 }
268 
269 
270 /*
271 ==========================
272 myGlMultMatrix
273 
274 ==========================
275 */
myGlMultMatrix(const float * a,const float * b,float * out)276 void myGlMultMatrix( const float *a, const float *b, float *out ) {
277 	int		i, j;
278 
279 	for ( i = 0 ; i < 4 ; i++ ) {
280 		for ( j = 0 ; j < 4 ; j++ ) {
281 			out[ i * 4 + j ] =
282 				a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
283 				+ a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
284 				+ a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
285 				+ a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
286 		}
287 	}
288 }
289 
290 /*
291 =================
292 R_RotateForEntity
293 
294 Generates an orientation for an entity and viewParms
295 Does NOT produce any GL calls
296 Called by both the front end and the back end
297 =================
298 */
R_RotateForEntity(const trRefEntity_t * ent,const viewParms_t * viewParms,orientationr_t * ori)299 void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
300 					   orientationr_t *ori ) {
301 //	float	glMatrix[16];
302 	vec3_t	delta;
303 	float	axisLength;
304 
305 	if ( ent->e.reType != RT_MODEL ) {
306 		*ori = viewParms->world;
307 		return;
308 	}
309 
310 	VectorCopy( ent->e.origin, ori->origin );
311 
312 	VectorCopy( ent->e.axis[0], ori->axis[0] );
313 	VectorCopy( ent->e.axis[1], ori->axis[1] );
314 	VectorCopy( ent->e.axis[2], ori->axis[2] );
315 
316 	preTransEntMatrix[0] = ori->axis[0][0];
317 	preTransEntMatrix[4] = ori->axis[1][0];
318 	preTransEntMatrix[8] = ori->axis[2][0];
319 	preTransEntMatrix[12] = ori->origin[0];
320 
321 	preTransEntMatrix[1] = ori->axis[0][1];
322 	preTransEntMatrix[5] = ori->axis[1][1];
323 	preTransEntMatrix[9] = ori->axis[2][1];
324 	preTransEntMatrix[13] = ori->origin[1];
325 
326 	preTransEntMatrix[2] = ori->axis[0][2];
327 	preTransEntMatrix[6] = ori->axis[1][2];
328 	preTransEntMatrix[10] = ori->axis[2][2];
329 	preTransEntMatrix[14] = ori->origin[2];
330 
331 	preTransEntMatrix[3] = 0;
332 	preTransEntMatrix[7] = 0;
333 	preTransEntMatrix[11] = 0;
334 	preTransEntMatrix[15] = 1;
335 
336 	myGlMultMatrix( preTransEntMatrix, viewParms->world.modelMatrix, ori->modelMatrix );
337 
338 	// calculate the viewer origin in the model's space
339 	// needed for fog, specular, and environment mapping
340 	VectorSubtract( viewParms->ori.origin, ori->origin, delta );
341 
342 	// compensate for scale in the axes if necessary
343 	if ( ent->e.nonNormalizedAxes ) {
344 		axisLength = VectorLength( ent->e.axis[0] );
345 		if ( !axisLength ) {
346 			axisLength = 0;
347 		} else {
348 			axisLength = 1.0f / axisLength;
349 		}
350 	} else {
351 		axisLength = 1.0f;
352 	}
353 
354 	ori->viewOrigin[0] = DotProduct( delta, ori->axis[0] ) * axisLength;
355 	ori->viewOrigin[1] = DotProduct( delta, ori->axis[1] ) * axisLength;
356 	ori->viewOrigin[2] = DotProduct( delta, ori->axis[2] ) * axisLength;
357 }
358 
359 /*
360 =================
361 R_RotateForViewer
362 
363 Sets up the modelview matrix for a given viewParm
364 =================
365 */
R_RotateForViewer(void)366 void R_RotateForViewer (void)
367 {
368 	float	viewerMatrix[16];
369 	vec3_t	origin;
370 
371 	memset (&tr.ori, 0, sizeof(tr.ori));
372 	tr.ori.axis[0][0] = 1;
373 	tr.ori.axis[1][1] = 1;
374 	tr.ori.axis[2][2] = 1;
375 	VectorCopy (tr.viewParms.ori.origin, tr.ori.viewOrigin);
376 
377 	// transform by the camera placement
378 	VectorCopy( tr.viewParms.ori.origin, origin );
379 
380 	viewerMatrix[0] = tr.viewParms.ori.axis[0][0];
381 	viewerMatrix[4] = tr.viewParms.ori.axis[0][1];
382 	viewerMatrix[8] = tr.viewParms.ori.axis[0][2];
383 	viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
384 
385 	viewerMatrix[1] = tr.viewParms.ori.axis[1][0];
386 	viewerMatrix[5] = tr.viewParms.ori.axis[1][1];
387 	viewerMatrix[9] = tr.viewParms.ori.axis[1][2];
388 	viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
389 
390 	viewerMatrix[2] = tr.viewParms.ori.axis[2][0];
391 	viewerMatrix[6] = tr.viewParms.ori.axis[2][1];
392 	viewerMatrix[10] = tr.viewParms.ori.axis[2][2];
393 	viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
394 
395 	viewerMatrix[3] = 0;
396 	viewerMatrix[7] = 0;
397 	viewerMatrix[11] = 0;
398 	viewerMatrix[15] = 1;
399 
400 	// convert from our coordinate system (looking down X)
401 	// to OpenGL's coordinate system (looking down -Z)
402 	myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.ori.modelMatrix );
403 
404 	tr.viewParms.world = tr.ori;
405 
406 }
407 
408 /*
409 ** SetFarClip
410 */
SetFarClip(void)411 static void SetFarClip( void )
412 {
413 	float	farthestCornerDistance = 0;
414 	int		i;
415 
416 	// if not rendering the world (icons, menus, etc)
417 	// set a 2k far clip plane
418 	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
419 		if (tr.refdef.rdflags & RDF_AUTOMAP)
420 		{ //override the zfar then
421 			tr.viewParms.zFar = 32768.0f;
422 		}
423 		else
424 		{
425 			tr.viewParms.zFar = 2048.0f;
426 		}
427 		return;
428 	}
429 
430 	//
431 	// set far clipping planes dynamically
432 	//
433 	for ( i = 0; i < 8; i++ )
434 	{
435 		vec3_t v;
436 		float distance;
437 
438 		if ( i & 1 )
439 		{
440 			v[0] = tr.viewParms.visBounds[0][0];
441 		}
442 		else
443 		{
444 			v[0] = tr.viewParms.visBounds[1][0];
445 		}
446 
447 		if ( i & 2 )
448 		{
449 			v[1] = tr.viewParms.visBounds[0][1];
450 		}
451 		else
452 		{
453 			v[1] = tr.viewParms.visBounds[1][1];
454 		}
455 
456 		if ( i & 4 )
457 		{
458 			v[2] = tr.viewParms.visBounds[0][2];
459 		}
460 		else
461 		{
462 			v[2] = tr.viewParms.visBounds[1][2];
463 		}
464 
465 		distance = DistanceSquared(tr.viewParms.ori.origin, v);
466 
467 		if ( distance > farthestCornerDistance )
468 		{
469 			farthestCornerDistance = distance;
470 		}
471 	}
472 	// Bring in the zFar to the distanceCull distance
473 	// The sky renders at zFar so need to move it out a little
474 	// ...and make sure there is a minimum zfar to prevent problems
475 	tr.viewParms.zFar = Com_Clamp(2048.0f, tr.distanceCull * (1.732), sqrtf( farthestCornerDistance ));
476 
477 	/*
478 	if (r_shadows->integer == 2)
479 	{ //volume caps need an "infinite" far clipping plane. So I'm using this semi-arbitrary massive number.
480 		tr.viewParms.zFar = 524288.0f;
481 	}
482 	*/
483 }
484 
485 
486 /*
487 ===============
488 R_SetupProjection
489 ===============
490 */
R_SetupProjection(void)491 void R_SetupProjection( void ) {
492 	float	xmin, xmax, ymin, ymax;
493 	float	width, height, depth;
494 	float	zNear, zFar;
495 
496 	// dynamically compute far clip plane distance
497 	SetFarClip();
498 
499 	//
500 	// set up projection matrix
501 	//
502 	zNear	= r_znear->value;
503 	zFar	= tr.viewParms.zFar;
504 
505 	ymax = zNear * tan( tr.refdef.fov_y * M_PI / 360.0f );
506 	ymin = -ymax;
507 
508 	xmax = zNear * tan( tr.refdef.fov_x * M_PI / 360.0f );
509 	xmin = -xmax;
510 
511 	width = xmax - xmin;
512 	height = ymax - ymin;
513 	depth = zFar - zNear;
514 
515 	tr.viewParms.projectionMatrix[0] = 2 * zNear / width;
516 	tr.viewParms.projectionMatrix[4] = 0;
517 	tr.viewParms.projectionMatrix[8] = ( xmax + xmin ) / width;	// normally 0
518 	tr.viewParms.projectionMatrix[12] = 0;
519 
520 	tr.viewParms.projectionMatrix[1] = 0;
521 	tr.viewParms.projectionMatrix[5] = 2 * zNear / height;
522 	tr.viewParms.projectionMatrix[9] = ( ymax + ymin ) / height;	// normally 0
523 	tr.viewParms.projectionMatrix[13] = 0;
524 
525 	tr.viewParms.projectionMatrix[2] = 0;
526 	tr.viewParms.projectionMatrix[6] = 0;
527 	tr.viewParms.projectionMatrix[10] = -( zFar + zNear ) / depth;
528 	tr.viewParms.projectionMatrix[14] = -2 * zFar * zNear / depth;
529 
530 	tr.viewParms.projectionMatrix[3] = 0;
531 	tr.viewParms.projectionMatrix[7] = 0;
532 	tr.viewParms.projectionMatrix[11] = -1;
533 	tr.viewParms.projectionMatrix[15] = 0;
534 }
535 
536 /*
537 =================
538 R_SetupFrustum
539 
540 Setup that culling frustum planes for the current view
541 =================
542 */
R_SetupFrustum(void)543 void R_SetupFrustum (void) {
544 	int		i;
545 	float	xs, xc;
546 	float	ang;
547 
548 	ang = tr.viewParms.fovX / 180 * M_PI * 0.5f;
549 	xs = sin( ang );
550 	xc = cos( ang );
551 
552 	VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[0].normal );
553 	VectorMA( tr.viewParms.frustum[0].normal, xc, tr.viewParms.ori.axis[1], tr.viewParms.frustum[0].normal );
554 
555 	VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[1].normal );
556 	VectorMA( tr.viewParms.frustum[1].normal, -xc, tr.viewParms.ori.axis[1], tr.viewParms.frustum[1].normal );
557 
558 	ang = tr.viewParms.fovY / 180 * M_PI * 0.5f;
559 	xs = sin( ang );
560 	xc = cos( ang );
561 
562 	VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[2].normal );
563 	VectorMA( tr.viewParms.frustum[2].normal, xc, tr.viewParms.ori.axis[2], tr.viewParms.frustum[2].normal );
564 
565 	VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[3].normal );
566 	VectorMA( tr.viewParms.frustum[3].normal, -xc, tr.viewParms.ori.axis[2], tr.viewParms.frustum[3].normal );
567 
568 	for (i=0 ; i<4 ; i++) {
569 		tr.viewParms.frustum[i].type = PLANE_NON_AXIAL;
570 		tr.viewParms.frustum[i].dist = DotProduct (tr.viewParms.ori.origin, tr.viewParms.frustum[i].normal);
571 		SetPlaneSignbits( &tr.viewParms.frustum[i] );
572 	}
573 }
574 
575 
576 /*
577 =================
578 R_MirrorPoint
579 =================
580 */
R_MirrorPoint(vec3_t in,orientation_t * surface,orientation_t * camera,vec3_t out)581 void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
582 	int		i;
583 	vec3_t	local;
584 	vec3_t	transformed;
585 	float	d;
586 
587 	VectorSubtract( in, surface->origin, local );
588 
589 	VectorClear( transformed );
590 	for ( i = 0 ; i < 3 ; i++ ) {
591 		d = DotProduct(local, surface->axis[i]);
592 		VectorMA( transformed, d, camera->axis[i], transformed );
593 	}
594 
595 	VectorAdd( transformed, camera->origin, out );
596 }
597 
R_MirrorVector(vec3_t in,orientation_t * surface,orientation_t * camera,vec3_t out)598 void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
599 	int		i;
600 	float	d;
601 
602 	VectorClear( out );
603 	for ( i = 0 ; i < 3 ; i++ ) {
604 		d = DotProduct(in, surface->axis[i]);
605 		VectorMA( out, d, camera->axis[i], out );
606 	}
607 }
608 
609 
610 /*
611 =============
612 R_PlaneForSurface
613 =============
614 */
R_PlaneForSurface(surfaceType_t * surfType,cplane_t * plane)615 void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) {
616 	srfTriangles_t	*tri;
617 	srfPoly_t		*poly;
618 	drawVert_t		*v1, *v2, *v3;
619 	vec4_t			plane4;
620 
621 	if (!surfType) {
622 		memset (plane, 0, sizeof(*plane));
623 		plane->normal[0] = 1;
624 		return;
625 	}
626 	switch (*surfType) {
627 	case SF_FACE:
628 		*plane = ((srfSurfaceFace_t *)surfType)->plane;
629 		return;
630 	case SF_TRIANGLES:
631 		tri = (srfTriangles_t *)surfType;
632 		v1 = tri->verts + tri->indexes[0];
633 		v2 = tri->verts + tri->indexes[1];
634 		v3 = tri->verts + tri->indexes[2];
635 		PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz );
636 		VectorCopy( plane4, plane->normal );
637 		plane->dist = plane4[3];
638 		return;
639 	case SF_POLY:
640 		poly = (srfPoly_t *)surfType;
641 		PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz );
642 		VectorCopy( plane4, plane->normal );
643 		plane->dist = plane4[3];
644 		return;
645 	default:
646 		memset (plane, 0, sizeof(*plane));
647 		plane->normal[0] = 1;
648 		return;
649 	}
650 }
651 
652 /*
653 =================
654 R_GetPortalOrientation
655 
656 entityNum is the entity that the portal surface is a part of, which may
657 be moving and rotating.
658 
659 Returns qtrue if it should be mirrored
660 =================
661 */
R_GetPortalOrientations(drawSurf_t * drawSurf,int entityNum,orientation_t * surface,orientation_t * camera,vec3_t pvsOrigin,qboolean * mirror)662 qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum,
663 							 orientation_t *surface, orientation_t *camera,
664 							 vec3_t pvsOrigin, qboolean *mirror ) {
665 	int			i;
666 	cplane_t	originalPlane, plane;
667 	trRefEntity_t	*e;
668 	float		d;
669 	vec3_t		transformed;
670 
671 	// create plane axis for the portal we are seeing
672 	R_PlaneForSurface( drawSurf->surface, &originalPlane );
673 
674 	// rotate the plane if necessary
675 	if ( entityNum != REFENTITYNUM_WORLD ) {
676 		tr.currentEntityNum = entityNum;
677 		tr.currentEntity = &tr.refdef.entities[entityNum];
678 
679 		// get the orientation of the entity
680 		R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.ori );
681 
682 		// rotate the plane, but keep the non-rotated version for matching
683 		// against the portalSurface entities
684 		R_LocalNormalToWorld( originalPlane.normal, plane.normal );
685 		plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.ori.origin );
686 
687 		// translate the original plane
688 		originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.ori.origin );
689 	} else {
690 		plane = originalPlane;
691 	}
692 
693 	VectorCopy( plane.normal, surface->axis[0] );
694 	PerpendicularVector( surface->axis[1], surface->axis[0] );
695 	CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] );
696 
697 	// locate the portal entity closest to this plane.
698 	// origin will be the origin of the portal, origin2 will be
699 	// the origin of the camera
700 	for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) {
701 		e = &tr.refdef.entities[i];
702 		if ( e->e.reType != RT_PORTALSURFACE ) {
703 			continue;
704 		}
705 
706 		d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
707 		if ( d > 64 || d < -64) {
708 			continue;
709 		}
710 
711 		// get the pvsOrigin from the entity
712 		VectorCopy( e->e.oldorigin, pvsOrigin );
713 
714 		// if the entity is just a mirror, don't use as a camera point
715 		if ( e->e.oldorigin[0] == e->e.origin[0] &&
716 			e->e.oldorigin[1] == e->e.origin[1] &&
717 			e->e.oldorigin[2] == e->e.origin[2] ) {
718 			VectorScale( plane.normal, plane.dist, surface->origin );
719 			VectorCopy( surface->origin, camera->origin );
720 			VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] );
721 			VectorCopy( surface->axis[1], camera->axis[1] );
722 			VectorCopy( surface->axis[2], camera->axis[2] );
723 
724 			*mirror = qtrue;
725 			return qtrue;
726 		}
727 
728 		// project the origin onto the surface plane to get
729 		// an origin point we can rotate around
730 		d = DotProduct( e->e.origin, plane.normal ) - plane.dist;
731 		VectorMA( e->e.origin, -d, surface->axis[0], surface->origin );
732 
733 		// now get the camera origin and orientation
734 		VectorCopy( e->e.oldorigin, camera->origin );
735 		AxisCopy( e->e.axis, camera->axis );
736 		VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] );
737 		VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] );
738 
739 		// optionally rotate
740 		if ( e->e.oldframe ) {
741 			// if a speed is specified
742 			if ( e->e.frame ) {
743 				// continuous rotate
744 				d = (tr.refdef.time/1000.0f) * e->e.frame;
745 				VectorCopy( camera->axis[1], transformed );
746 				RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
747 				CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
748 			} else {
749 				// bobbing rotate, with skinNum being the rotation offset
750 				d = sin( tr.refdef.time * 0.003f );
751 				d = e->e.skinNum + d * 4;
752 				VectorCopy( camera->axis[1], transformed );
753 				RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
754 				CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
755 			}
756 		}
757 		else if ( e->e.skinNum ) {
758 			d = e->e.skinNum;
759 			VectorCopy( camera->axis[1], transformed );
760 			RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
761 			CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
762 		}
763 		*mirror = qfalse;
764 		return qtrue;
765 	}
766 
767 	// if we didn't locate a portal entity, don't render anything.
768 	// We don't want to just treat it as a mirror, because without a
769 	// portal entity the server won't have communicated a proper entity set
770 	// in the snapshot
771 
772 	// unfortunately, with local movement prediction it is easily possible
773 	// to see a surface before the server has communicated the matching
774 	// portal surface entity, so we don't want to print anything here...
775 
776 	//ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" );
777 
778 	return qfalse;
779 }
780 
IsMirror(const drawSurf_t * drawSurf,int entityNum)781 static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum )
782 {
783 	int			i;
784 	cplane_t	originalPlane, plane;
785 	trRefEntity_t	*e;
786 	float		d;
787 
788 	// create plane axis for the portal we are seeing
789 	R_PlaneForSurface( drawSurf->surface, &originalPlane );
790 
791 	// rotate the plane if necessary
792 	if ( entityNum != REFENTITYNUM_WORLD )
793 	{
794 		tr.currentEntityNum = entityNum;
795 		tr.currentEntity = &tr.refdef.entities[entityNum];
796 
797 		// get the orientation of the entity
798 		R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.ori );
799 
800 		// rotate the plane, but keep the non-rotated version for matching
801 		// against the portalSurface entities
802 		R_LocalNormalToWorld( originalPlane.normal, plane.normal );
803 		plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.ori.origin );
804 
805 		// translate the original plane
806 		originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.ori.origin );
807 	}
808 	else
809 	{
810 		plane = originalPlane;
811 	}
812 
813 	// locate the portal entity closest to this plane.
814 	// origin will be the origin of the portal, origin2 will be
815 	// the origin of the camera
816 	for ( i = 0 ; i < tr.refdef.num_entities ; i++ )
817 	{
818 		e = &tr.refdef.entities[i];
819 		if ( e->e.reType != RT_PORTALSURFACE ) {
820 			continue;
821 		}
822 
823 		d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
824 		if ( d > 64 || d < -64) {
825 			continue;
826 		}
827 
828 		// if the entity is just a mirror, don't use as a camera point
829 		if ( e->e.oldorigin[0] == e->e.origin[0] &&
830 			e->e.oldorigin[1] == e->e.origin[1] &&
831 			e->e.oldorigin[2] == e->e.origin[2] )
832 		{
833 			return qtrue;
834 		}
835 
836 		return qfalse;
837 	}
838 	return qfalse;
839 }
840 
841 /*
842 ** SurfIsOffscreen
843 **
844 ** Determines if a surface is completely offscreen.
845 */
SurfIsOffscreen(const drawSurf_t * drawSurf,vec4_t clipDest[128])846 static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
847 	float shortest = 100000000;
848 	int entityNum;
849 	int numTriangles;
850 	shader_t *shader;
851 	int		fogNum;
852 	int dlighted;
853 	vec4_t clip, eye;
854 	int i;
855 	unsigned int pointOr = 0;
856 	unsigned int pointAnd = (unsigned int)~0;
857 
858 	R_RotateForViewer();
859 
860 	R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
861 	RB_BeginSurface( shader, fogNum );
862 	rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
863 	assert( tess.numVertexes < 128 );
864 	for ( i = 0; i < tess.numVertexes; i++ )
865 	{
866 		int j;
867 		unsigned int pointFlags = 0;
868 
869 		R_TransformModelToClip( tess.xyz[i], tr.ori.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );
870 
871 		for ( j = 0; j < 3; j++ )
872 		{
873 			if ( clip[j] >= clip[3] )
874 			{
875 				pointFlags |= (1 << (j*2));
876 			}
877 			else if ( clip[j] <= -clip[3] )
878 			{
879 				pointFlags |= ( 1 << (j*2+1));
880 			}
881 		}
882 		pointAnd &= pointFlags;
883 		pointOr |= pointFlags;
884 	}
885 
886 	// trivially reject
887 	if ( pointAnd )
888 	{
889 		return qtrue;
890 	}
891 
892 	// determine if this surface is backfaced and also determine the distance
893 	// to the nearest vertex so we can cull based on portal range.  Culling
894 	// based on vertex distance isn't 100% correct (we should be checking for
895 	// range to the surface), but it's good enough for the types of portals
896 	// we have in the game right now.
897 	numTriangles = tess.numIndexes / 3;
898 
899 	for ( i = 0; i < tess.numIndexes; i += 3 )
900 	{
901 		vec3_t normal;
902 		float dot;
903 		float len;
904 
905 		VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.ori.origin, normal );
906 
907 		len = VectorLengthSquared( normal );			// lose the sqrt
908 		if ( len < shortest )
909 		{
910 			shortest = len;
911 		}
912 
913 		if ( ( dot = DotProduct( normal, tess.normal[tess.indexes[i]] ) ) >= 0 )
914 		{
915 			numTriangles--;
916 		}
917 	}
918 	if ( !numTriangles )
919 	{
920 		return qtrue;
921 	}
922 
923 	// mirrors can early out at this point, since we don't do a fade over distance
924 	// with them (although we could)
925 	if ( IsMirror( drawSurf, entityNum ) )
926 	{
927 		return qfalse;
928 	}
929 
930 	if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) )
931 	{
932 		return qtrue;
933 	}
934 
935 	return qfalse;
936 }
937 
938 /*
939 ========================
940 R_MirrorViewBySurface
941 
942 Returns qtrue if another view has been rendered
943 ========================
944 */
R_MirrorViewBySurface(drawSurf_t * drawSurf,int entityNum)945 qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {
946 	vec4_t			clipDest[128];
947 	viewParms_t		newParms;
948 	viewParms_t		oldParms;
949 	orientation_t	surface, camera;
950 
951 	// don't recursively mirror
952 	if (tr.viewParms.isPortal) {
953 		ri.Printf( PRINT_DEVELOPER, S_COLOR_RED "WARNING: recursive mirror/portal found\n" );
954 		return qfalse;
955 	}
956 
957 	if ( r_noportals->integer || (r_fastsky->integer == 1) ) {
958 		return qfalse;
959 	}
960 
961 	// trivially reject portal/mirror
962 	if ( SurfIsOffscreen( drawSurf, clipDest ) ) {
963 		return qfalse;
964 	}
965 
966 	// save old viewParms so we can return to it after the mirror view
967 	oldParms = tr.viewParms;
968 
969 	newParms = tr.viewParms;
970 	newParms.isPortal = qtrue;
971 	if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera,
972 		newParms.pvsOrigin, &newParms.isMirror ) ) {
973 		return qfalse;		// bad portal, no portalentity
974 	}
975 
976 	R_MirrorPoint (oldParms.ori.origin, &surface, &camera, newParms.ori.origin );
977 
978 	VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal );
979 	newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal );
980 
981 	R_MirrorVector (oldParms.ori.axis[0], &surface, &camera, newParms.ori.axis[0]);
982 	R_MirrorVector (oldParms.ori.axis[1], &surface, &camera, newParms.ori.axis[1]);
983 	R_MirrorVector (oldParms.ori.axis[2], &surface, &camera, newParms.ori.axis[2]);
984 
985 	// OPTIMIZE: restrict the viewport on the mirrored view
986 
987 	// render the mirror view
988 	R_RenderView (&newParms);
989 
990 	tr.viewParms = oldParms;
991 
992 	return qtrue;
993 }
994 
995 /*
996 =================
997 R_SpriteFogNum
998 
999 See if a sprite is inside a fog volume
1000 =================
1001 */
R_SpriteFogNum(trRefEntity_t * ent)1002 int R_SpriteFogNum( trRefEntity_t *ent ) {
1003 	int				i, j;
1004 	fog_t			*fog;
1005 
1006 	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
1007 		return 0;
1008 	}
1009 
1010 	for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
1011 		fog = &tr.world->fogs[i];
1012 		for ( j = 0 ; j < 3 ; j++ ) {
1013 			if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) {
1014 				break;
1015 			}
1016 			if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) {
1017 				break;
1018 			}
1019 		}
1020 		if ( j == 3 ) {
1021 			return i;
1022 		}
1023 	}
1024 
1025 	return 0;
1026 }
1027 
1028 /*
1029 ==========================================================================================
1030 
1031 DRAWSURF SORTING
1032 
1033 ==========================================================================================
1034 */
1035 
1036 /*
1037 ===============
1038 R_Radix
1039 ===============
1040 */
R_Radix(int byte,int size,drawSurf_t * source,drawSurf_t * dest)1041 static QINLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest )
1042 {
1043   int           count[ 256 ] = { 0 };
1044   int           index[ 256 ];
1045   int           i;
1046   unsigned char *sortKey = NULL;
1047   unsigned char *end = NULL;
1048 
1049   sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
1050   end = sortKey + ( size * sizeof( drawSurf_t ) );
1051   for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) )
1052     ++count[ *sortKey ];
1053 
1054   index[ 0 ] = 0;
1055 
1056   for( i = 1; i < 256; ++i )
1057     index[ i ] = index[ i - 1 ] + count[ i - 1 ];
1058 
1059   sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
1060   for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) )
1061     dest[ index[ *sortKey ]++ ] = source[ i ];
1062 }
1063 
1064 /*
1065 ===============
1066 R_RadixSort
1067 
1068 Radix sort with 4 byte size buckets
1069 ===============
1070 */
R_RadixSort(drawSurf_t * source,int size)1071 static void R_RadixSort( drawSurf_t *source, int size )
1072 {
1073   static drawSurf_t scratch[ MAX_DRAWSURFS ];
1074 #ifdef Q3_LITTLE_ENDIAN
1075   R_Radix( 0, size, source, scratch );
1076   R_Radix( 1, size, scratch, source );
1077   R_Radix( 2, size, source, scratch );
1078   R_Radix( 3, size, scratch, source );
1079 #else
1080   R_Radix( 3, size, source, scratch );
1081   R_Radix( 2, size, scratch, source );
1082   R_Radix( 1, size, source, scratch );
1083   R_Radix( 0, size, scratch, source );
1084 #endif //Q3_LITTLE_ENDIAN
1085 }
1086 
1087 //==========================================================================================
1088 
1089 /*
1090 =================
1091 R_AddDrawSurf
1092 =================
1093 */
R_AddDrawSurf(surfaceType_t * surface,shader_t * shader,int fogIndex,int dlightMap)1094 void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
1095 				   int fogIndex, int dlightMap ) {
1096 	int			index;
1097 
1098 	if (tr.refdef.rdflags & RDF_NOFOG)
1099 	{
1100 		fogIndex = 0;
1101 	}
1102 
1103 	if ( (shader->surfaceFlags & SURF_FORCESIGHT) && !(tr.refdef.rdflags & RDF_ForceSightOn) )
1104 	{	//if shader is only seen with ForceSight and we don't have ForceSight on, then don't draw
1105 		return;
1106 	}
1107 
1108 	// instead of checking for overflow, we just mask the index
1109 	// so it wraps around
1110 	index = tr.refdef.numDrawSurfs & DRAWSURF_MASK;
1111 	// the sort data is packed into a single 32 bit value so it can be
1112 	// compared quickly during the qsorting process
1113 	tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT)
1114 		| tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
1115 	tr.refdef.drawSurfs[index].surface = surface;
1116 	tr.refdef.numDrawSurfs++;
1117 }
1118 
1119 /*
1120 =================
1121 R_DecomposeSort
1122 =================
1123 */
R_DecomposeSort(unsigned sort,int * entityNum,shader_t ** shader,int * fogNum,int * dlightMap)1124 void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
1125 					 int *fogNum, int *dlightMap ) {
1126 	*fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31;
1127 	*shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ];
1128 	*entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK;
1129 	*dlightMap = sort & 3;
1130 }
1131 
1132 /*
1133 =================
1134 R_SortDrawSurfs
1135 =================
1136 */
R_SortDrawSurfs(drawSurf_t * drawSurfs,int numDrawSurfs)1137 void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
1138 	shader_t		*shader;
1139 	int				fogNum;
1140 	int				entityNum;
1141 	int				dlighted;
1142 	int				i;
1143 
1144 	// it is possible for some views to not have any surfaces
1145 	if ( numDrawSurfs < 1 ) {
1146 		// we still need to add it for hyperspace cases
1147 		R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
1148 		return;
1149 	}
1150 
1151 	// if we overflowed MAX_DRAWSURFS, the drawsurfs
1152 	// wrapped around in the buffer and we will be missing
1153 	// the first surfaces, not the last ones
1154 	if ( numDrawSurfs > MAX_DRAWSURFS ) {
1155 		numDrawSurfs = MAX_DRAWSURFS;
1156 	}
1157 
1158 	// sort the drawsurfs by sort type, then orientation, then shader
1159 	R_RadixSort( drawSurfs, numDrawSurfs );
1160 
1161 	// check for any pass through drawing, which
1162 	// may cause another view to be rendered first
1163 	for ( i = 0 ; i < numDrawSurfs ; i++ ) {
1164 		R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted );
1165 
1166 		if ( shader->sort > SS_PORTAL ) {
1167 			break;
1168 		}
1169 
1170 		// no shader should ever have this sort type
1171 		if ( shader->sort == SS_BAD ) {
1172 			Com_Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name );
1173 		}
1174 
1175 		// if the mirror was completely clipped away, we may need to check another surface
1176 		if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) {
1177 			// this is a debug option to see exactly what is being mirrored
1178 			if ( r_portalOnly->integer ) {
1179 				return;
1180 			}
1181 			break;		// only one mirror view at a time
1182 		}
1183 	}
1184 
1185 	R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
1186 }
1187 
1188 /*
1189 =============
1190 R_AddEntitySurfaces
1191 =============
1192 */
R_AddEntitySurfaces(void)1193 void R_AddEntitySurfaces (void) {
1194 	trRefEntity_t	*ent;
1195 	shader_t		*shader;
1196 
1197 	if ( !r_drawentities->integer ) {
1198 		return;
1199 	}
1200 
1201 	for ( tr.currentEntityNum = 0;
1202 	      tr.currentEntityNum < tr.refdef.num_entities;
1203 		  tr.currentEntityNum++ ) {
1204 		ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum];
1205 
1206 		assert(ent->e.renderfx >= 0);
1207 
1208 		ent->needDlights = qfalse;
1209 
1210 		// preshift the value we are going to OR into the drawsurf sort
1211 		tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
1212 
1213 		//
1214 		// the weapon model must be handled special --
1215 		// we don't want the hacked weapon position showing in
1216 		// mirrors, because the true body position will already be drawn
1217 		//
1218 		if ( (ent->e.renderfx & RF_FIRST_PERSON) && tr.viewParms.isPortal) {
1219 			continue;
1220 		}
1221 
1222 		// simple generated models, like sprites and beams, are not culled
1223 		switch ( ent->e.reType ) {
1224 		case RT_PORTALSURFACE:
1225 			break;		// don't draw anything
1226 		case RT_SPRITE:
1227 		case RT_BEAM:
1228 		case RT_ORIENTED_QUAD:
1229 		case RT_ELECTRICITY:
1230 		case RT_LINE:
1231 		case RT_ORIENTEDLINE:
1232 		case RT_CYLINDER:
1233 		case RT_SABER_GLOW:
1234 			// self blood sprites, talk balloons, etc should not be drawn in the primary
1235 			// view.  We can't just do this check for all entities, because md3
1236 			// entities may still want to cast shadows from them
1237 			if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
1238 				continue;
1239 			}
1240 			shader = R_GetShaderByHandle( ent->e.customShader );
1241 			R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0 );
1242 			break;
1243 
1244 		case RT_MODEL:
1245 			// we must set up parts of tr.ori for model culling
1246 			R_RotateForEntity( ent, &tr.viewParms, &tr.ori );
1247 
1248 			tr.currentModel = R_GetModelByHandle( ent->e.hModel );
1249 			if (!tr.currentModel) {
1250 				R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 );
1251 			} else {
1252 				switch ( tr.currentModel->type ) {
1253 				case MOD_MESH:
1254 					R_AddMD3Surfaces( ent );
1255 					break;
1256 				case MOD_BRUSH:
1257 					R_AddBrushModelSurfaces( ent );
1258 					break;
1259 /*
1260 Ghoul2 Insert Start
1261 */
1262 				case MOD_MDXM:
1263   					//g2r
1264 					if (ent->e.ghoul2)
1265 					{
1266 						R_AddGhoulSurfaces( ent);
1267 					}
1268   					break;
1269 				case MOD_BAD:		// null model axis
1270 					if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal)
1271 					{
1272 						if (!(ent->e.renderfx & RF_SHADOW_ONLY))
1273 						{
1274 							break;
1275 						}
1276 					}
1277 
1278   					if (ent->e.ghoul2 && G2API_HaveWeGhoul2Models(*((CGhoul2Info_v *)ent->e.ghoul2)))
1279   					{
1280   						R_AddGhoulSurfaces( ent);
1281   						break;
1282   					}
1283 
1284 					R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, false );
1285 					break;
1286 /*
1287 Ghoul2 Insert End
1288 */
1289 				default:
1290 					Com_Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
1291 					break;
1292 				}
1293 			}
1294 			break;
1295 
1296 		case RT_ENT_CHAIN:
1297 			shader = R_GetShaderByHandle( ent->e.customShader );
1298 			R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), false );
1299 			break;
1300 
1301 		default:
1302 			Com_Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" );
1303 		}
1304 	}
1305 
1306 }
1307 
1308 
1309 /*
1310 ====================
1311 R_GenerateDrawSurfs
1312 ====================
1313 */
R_GenerateDrawSurfs(void)1314 void R_GenerateDrawSurfs( void ) {
1315 	R_AddWorldSurfaces ();
1316 
1317 	R_AddPolygonSurfaces();
1318 
1319 	// set the projection matrix with the minimum zfar
1320 	// now that we have the world bounded
1321 	// this needs to be done before entities are
1322 	// added, because they use the projection
1323 	// matrix for lod calculation
1324 	R_SetupProjection ();
1325 
1326 	R_AddEntitySurfaces ();
1327 }
1328 
1329 /*
1330 ================
1331 R_DebugPolygon
1332 ================
1333 */
R_DebugPolygon(int color,int numPoints,float * points)1334 void R_DebugPolygon( int color, int numPoints, float *points ) {
1335 	int		i;
1336 
1337 	GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
1338 
1339 	// draw solid shade
1340 
1341 	qglColor3f( color&1, (color>>1)&1, (color>>2)&1 );
1342 	qglBegin( GL_POLYGON );
1343 	for ( i = 0 ; i < numPoints ; i++ ) {
1344 		qglVertex3fv( points + i * 3 );
1345 	}
1346 	qglEnd();
1347 
1348 	// draw wireframe outline
1349 	GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
1350 	qglDepthRange( 0, 0 );
1351 	qglColor3f( 1, 1, 1 );
1352 	qglBegin( GL_POLYGON );
1353 	for ( i = 0 ; i < numPoints ; i++ ) {
1354 		qglVertex3fv( points + i * 3 );
1355 	}
1356 	qglEnd();
1357 	qglDepthRange( 0, 1 );
1358 }
1359 
1360 /*
1361 ====================
1362 R_DebugGraphics
1363 
1364 Visualization aid for movement clipping debugging
1365 ====================
1366 */
R_DebugGraphics(void)1367 void R_DebugGraphics( void ) {
1368 	if ( !r_debugSurface->integer ) {
1369 		return;
1370 	}
1371 
1372 	// the render thread can't make callbacks to the main thread
1373 	R_IssuePendingRenderCommands();
1374 
1375 	GL_Bind( tr.whiteImage);
1376 	GL_Cull( CT_FRONT_SIDED );
1377 	ri.CM_DrawDebugSurface( R_DebugPolygon );
1378 }
1379 
1380 
1381 /*
1382 ================
1383 R_RenderView
1384 
1385 A view may be either the actual camera view,
1386 or a mirror / remote location
1387 ================
1388 */
R_RenderView(viewParms_t * parms)1389 void R_RenderView (viewParms_t *parms) {
1390 	int		firstDrawSurf;
1391 
1392 	if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
1393 		return;
1394 	}
1395 
1396 	tr.viewCount++;
1397 
1398 	tr.viewParms = *parms;
1399 	tr.viewParms.frameSceneNum = tr.frameSceneNum;
1400 	tr.viewParms.frameCount = tr.frameCount;
1401 
1402 	firstDrawSurf = tr.refdef.numDrawSurfs;
1403 
1404 	tr.viewCount++;
1405 
1406 	// set viewParms.world
1407 	R_RotateForViewer ();
1408 
1409 	R_SetupFrustum ();
1410 
1411 	R_GenerateDrawSurfs();
1412 
1413 	R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
1414 
1415 	// draw main system development information (surface outlines, etc)
1416 	R_DebugGraphics();
1417 }
1418