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