1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein single player GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein single player GPL Source Code (“RTCW SP Source Code”).
8 
9 RTCW SP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW SP Source Code 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 RTCW SP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 /*
30  * name:		tr_main.c
31  *
32  * desc:		main control flow for each frame
33  *
34 */
35 
36 #include "tr_local.h"
37 
38 #include <string.h> // memcpy
39 
40 trGlobals_t tr;
41 
42 static float s_flipMatrix[16] = {
43 	// convert from our coordinate system (looking down X)
44 	// to OpenGL's coordinate system (looking down -Z)
45 	0, 0, -1, 0,
46 	-1, 0, 0, 0,
47 	0, 1, 0, 0,
48 	0, 0, 0, 1
49 };
50 
51 
52 refimport_t ri;
53 
54 // entities that will have procedurally generated surfaces will just
55 // point at this for their sorting surface
56 surfaceType_t entitySurface = SF_ENTITY;
57 
58 // fog stuff
59 glfog_t glfogsettings[NUM_FOGS];
60 glfogType_t glfogNum = FOG_NONE;
61 qboolean fogIsOn = qfalse;
62 
63 
64 /*
65 =================
66 R_Fog (void)
67 =================
68 */
R_Fog(glfog_t * curfog)69 void R_Fog( glfog_t *curfog ) {
70 
71 	if ( !r_wolffog->integer ) {
72 		R_FogOff();
73 		return;
74 	}
75 
76 	if ( !curfog->registered ) {   //----(SA)
77 		R_FogOff();
78 		return;
79 	}
80 
81 	//----(SA) assme values of '0' for these parameters means 'use default'
82 	if ( !curfog->density ) {
83 		curfog->density = 1;
84 	}
85 	if ( !curfog->hint ) {
86 		curfog->hint = GL_DONT_CARE;
87 	}
88 	if ( !curfog->mode ) {
89 		curfog->mode = GL_LINEAR;
90 	}
91 	//----(SA)	end
92 
93 
94 	R_FogOn();
95 
96 	qglFogi( GL_FOG_MODE, curfog->mode );
97 	qglFogfv( GL_FOG_COLOR, curfog->color );
98 	qglFogf( GL_FOG_DENSITY, curfog->density );
99 	qglHint( GL_FOG_HINT, curfog->hint );
100 
101 	if ( backEnd.refdef.rdflags & RDF_SNOOPERVIEW ) {
102 		qglFogf( GL_FOG_START, curfog->end );       // snooper starts GL fog out further
103 	} else {
104 		qglFogf( GL_FOG_START, curfog->start );
105 	}
106 
107 	if ( r_zfar->value ) {             // (SA) allow override for helping level designers test fog distances
108 		qglFogf( GL_FOG_END, r_zfar->value );
109 	} else {
110 		if ( backEnd.refdef.rdflags & RDF_SNOOPERVIEW ) {
111 			qglFogf( GL_FOG_END, curfog->end + 1000 );      // snooper ends GL fog out further.  this works fine with our maps, but could be 'funky' with later maps
112 		}
113 		else {
114 			qglFogf( GL_FOG_END, curfog->end );
115 		}
116 	}
117 
118 #ifndef USE_OPENGLES
119 //----(SA)	added
120 	// NV fog mode
121 	if ( glConfig.NVFogAvailable ) {
122 		qglFogi( GL_FOG_DISTANCE_MODE_NV, glConfig.NVFogMode );
123 	}
124 //----(SA)	end
125 #endif
126 
127 	qglClearColor( curfog->color[0], curfog->color[1], curfog->color[2], curfog->color[3] );
128 
129 
130 }
131 
132 // Ridah, allow disabling fog temporarily
R_FogOff(void)133 void R_FogOff( void ) {
134 	if ( !fogIsOn ) {
135 		return;
136 	}
137 	qglDisable( GL_FOG );
138 	fogIsOn = qfalse;
139 }
140 
R_FogOn(void)141 void R_FogOn( void ) {
142 	if ( fogIsOn ) {
143 		return;
144 	}
145 
146 //	if(r_uiFullScreen->integer) {	// don't fog in the menu
147 //		R_FogOff();
148 //		return;
149 //	}
150 
151 	if ( backEnd.projection2D ) {  // no fog in 2d
152 		R_FogOff();
153 		return;
154 	}
155 
156 	if ( !r_wolffog->integer ) {
157 		return;
158 	}
159 
160 //	if(backEnd.viewParms.isGLFogged) {
161 //		if(!(backEnd.viewParms.glFog.registered))
162 //			return;
163 //	}
164 
165 	if ( backEnd.refdef.rdflags & RDF_SKYBOXPORTAL ) { // don't force world fog on portal sky
166 		if ( !( glfogsettings[FOG_PORTALVIEW].registered ) ) {
167 			return;
168 		}
169 	} else if ( !glfogNum )     {
170 		return;
171 	}
172 
173 	qglEnable( GL_FOG );
174 	fogIsOn = qtrue;
175 }
176 // done.
177 
178 
179 
180 //----(SA)
181 /*
182 ==============
183 R_SetFog
184 
185   if fogvar == FOG_CMD_SWITCHFOG {
186 	fogvar is the command
187 	var1 is the fog to switch to
188 	var2 is the time to transition
189   }
190   else {
191 	fogvar is the fog that's being set
192 	var1 is the near fog z value
193 	var2 is the far fog z value
194 	rgb = color
195 	density is density, and is used to derive the values of 'mode', 'drawsky', and 'clearscreen'
196   }
197 ==============
198 */
R_SetFog(int fogvar,int var1,int var2,float r,float g,float b,float density)199 void R_SetFog( int fogvar, int var1, int var2, float r, float g, float b, float density ) {
200 	if ( fogvar != FOG_CMD_SWITCHFOG ) {   // just set the parameters and return
201 
202 		if ( var1 == 0 && var2 == 0 ) {    // clear this fog
203 			glfogsettings[fogvar].registered = qfalse;
204 			return;
205 		}
206 
207 		glfogsettings[fogvar].color[0]      = r;
208 		glfogsettings[fogvar].color[1]      = g;
209 		glfogsettings[fogvar].color[2]      = b;
210 		glfogsettings[fogvar].color[3]      = 1;
211 		glfogsettings[fogvar].start         = var1;
212 		glfogsettings[fogvar].end           = var2;
213 		if ( density >= 1 ) {
214 			glfogsettings[fogvar].mode          = GL_LINEAR;
215 			glfogsettings[fogvar].drawsky       = qfalse;
216 			glfogsettings[fogvar].clearscreen   = qtrue;
217 			glfogsettings[fogvar].density       = 1.0;
218 		} else
219 		{
220 			glfogsettings[fogvar].mode          = GL_EXP;
221 			glfogsettings[fogvar].drawsky       = qtrue;
222 			glfogsettings[fogvar].clearscreen   = qfalse;
223 			glfogsettings[fogvar].density       = density;
224 		}
225 		glfogsettings[fogvar].hint          = GL_DONT_CARE;
226 		glfogsettings[fogvar].registered    = qtrue;
227 
228 		return;
229 	}
230 
231 	// FOG_MAP now used to mean 'no fog'
232 	if ( var1 == FOG_MAP ) {
233 
234 		// transitioning from...
235 		if ( glfogsettings[FOG_CURRENT].registered ) {
236 			memcpy( &glfogsettings[FOG_LAST], &glfogsettings[FOG_CURRENT], sizeof( glfog_t ) );
237 		}
238 
239 		memcpy( &glfogsettings[FOG_TARGET], &glfogsettings[glfogNum], sizeof( glfog_t ) );
240 
241 
242 		// clear, clear, clear
243 		memset( &glfogsettings[FOG_MAP], 0, sizeof( glfog_t ) );
244 //		memset(&glfogsettings[FOG_CURRENT], 0, sizeof(glfog_t));
245 		memset( &glfogsettings[FOG_TARGET], 0, sizeof( glfog_t ) );
246 //		glfogsettings[FOG_CURRENT].registered = qfalse;
247 //		glfogsettings[FOG_TARGET].registered = qfalse;
248 		glfogNum = FOG_NONE;
249 		return;
250 	}
251 
252 	// don't switch to invalid fogs
253 	if ( glfogsettings[var1].registered != qtrue ) {
254 		return;
255 	}
256 
257 
258 	glfogNum = var1;
259 
260 	// transitioning to new fog, store the current values as the 'from'
261 
262 	if ( glfogsettings[FOG_CURRENT].registered ) {
263 		memcpy( &glfogsettings[FOG_LAST], &glfogsettings[FOG_CURRENT], sizeof( glfog_t ) );
264 	} else {
265 		// if no current fog fall back to world fog
266 		// FIXME: handle transition if there is no FOG_MAP fog
267 //		memcpy(&glfogsettings[FOG_LAST], &glfogsettings[FOG_MAP], sizeof(glfog_t));
268 		memcpy( &glfogsettings[FOG_LAST], &glfogsettings[glfogNum], sizeof( glfog_t ) );
269 	}
270 
271 	memcpy( &glfogsettings[FOG_TARGET], &glfogsettings[glfogNum], sizeof( glfog_t ) );
272 
273 	if ( !var2 ) { // instant
274 		glfogsettings[FOG_TARGET].startTime = 0;
275 		glfogsettings[FOG_TARGET].finishTime = 0;
276 		glfogsettings[FOG_TARGET].dirty = 1;
277 		glfogsettings[FOG_CURRENT].dirty = 1;
278 	} else {
279 		// setup transition times
280 		glfogsettings[FOG_TARGET].startTime = tr.refdef.time;
281 		glfogsettings[FOG_TARGET].finishTime = tr.refdef.time + var2;
282 	}
283 }
284 
285 //----(SA) end
286 
287 /*
288 =================
289 R_CullLocalBox
290 
291 Returns CULL_IN, CULL_CLIP, or CULL_OUT
292 =================
293 */
R_CullLocalBox(vec3_t bounds[2])294 int R_CullLocalBox( vec3_t bounds[2] ) {
295 	int i, j;
296 	vec3_t transformed[8];
297 	float dists[8];
298 	vec3_t v;
299 	cplane_t    *frust;
300 	int anyBack;
301 	int front, back;
302 
303 	if ( r_nocull->integer ) {
304 		return CULL_CLIP;
305 	}
306 
307 	// transform into world space
308 	for ( i = 0 ; i < 8 ; i++ ) {
309 		v[0] = bounds[i & 1][0];
310 		v[1] = bounds[( i >> 1 ) & 1][1];
311 		v[2] = bounds[( i >> 2 ) & 1][2];
312 
313 		VectorCopy( tr.or.origin, transformed[i] );
314 		VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] );
315 		VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] );
316 		VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] );
317 	}
318 
319 	// check against frustum planes
320 	anyBack = 0;
321 	for ( i = 0 ; i < 4 ; i++ ) {
322 		frust = &tr.viewParms.frustum[i];
323 
324 		front = back = 0;
325 		for ( j = 0 ; j < 8 ; j++ ) {
326 			dists[j] = DotProduct( transformed[j], frust->normal );
327 			if ( dists[j] > frust->dist ) {
328 				front = 1;
329 				if ( back ) {
330 					break;      // a point is in front
331 				}
332 			} else {
333 				back = 1;
334 			}
335 		}
336 		if ( !front ) {
337 			// all points were behind one of the planes
338 			return CULL_OUT;
339 		}
340 		anyBack |= back;
341 	}
342 
343 	if ( !anyBack ) {
344 		return CULL_IN;     // completely inside frustum
345 	}
346 
347 	return CULL_CLIP;       // partially clipped
348 }
349 
350 /*
351 ** R_CullLocalPointAndRadius
352 */
R_CullLocalPointAndRadius(vec3_t pt,float radius)353 int R_CullLocalPointAndRadius( vec3_t pt, float radius ) {
354 	vec3_t transformed;
355 
356 	R_LocalPointToWorld( pt, transformed );
357 
358 	return R_CullPointAndRadius( transformed, radius );
359 }
360 
361 /*
362 ** R_CullPointAndRadius
363 */
R_CullPointAndRadius(vec3_t pt,float radius)364 int R_CullPointAndRadius( vec3_t pt, float radius ) {
365 	int i;
366 	float dist;
367 	cplane_t    *frust;
368 	qboolean mightBeClipped = qfalse;
369 
370 	if ( r_nocull->integer ) {
371 		return CULL_CLIP;
372 	}
373 
374 	// check against frustum planes
375 	for ( i = 0 ; i < 4 ; i++ )
376 	{
377 		frust = &tr.viewParms.frustum[i];
378 
379 		dist = DotProduct( pt, frust->normal ) - frust->dist;
380 		if ( dist < -radius ) {
381 			return CULL_OUT;
382 		} else if ( dist <= radius )   {
383 			mightBeClipped = qtrue;
384 		}
385 	}
386 
387 	if ( mightBeClipped ) {
388 		return CULL_CLIP;
389 	}
390 
391 	return CULL_IN;     // completely inside frustum
392 }
393 
394 
395 /*
396 =================
397 R_LocalNormalToWorld
398 
399 =================
400 */
R_LocalNormalToWorld(vec3_t local,vec3_t world)401 void R_LocalNormalToWorld( vec3_t local, vec3_t world ) {
402 	world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0];
403 	world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1];
404 	world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2];
405 }
406 
407 /*
408 =================
409 R_LocalPointToWorld
410 
411 =================
412 */
R_LocalPointToWorld(vec3_t local,vec3_t world)413 void R_LocalPointToWorld( vec3_t local, vec3_t world ) {
414 	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];
415 	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];
416 	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];
417 }
418 
419 /*
420 =================
421 R_WorldToLocal
422 
423 =================
424 */
R_WorldToLocal(vec3_t world,vec3_t local)425 void R_WorldToLocal( vec3_t world, vec3_t local ) {
426 	local[0] = DotProduct( world, tr.or.axis[0] );
427 	local[1] = DotProduct( world, tr.or.axis[1] );
428 	local[2] = DotProduct( world, tr.or.axis[2] );
429 }
430 
431 /*
432 ==========================
433 R_TransformModelToClip
434 
435 ==========================
436 */
R_TransformModelToClip(const vec3_t src,const float * modelMatrix,const float * projectionMatrix,vec4_t eye,vec4_t dst)437 void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
438 							 vec4_t eye, vec4_t dst ) {
439 	int i;
440 
441 	for ( i = 0 ; i < 4 ; i++ ) {
442 		eye[i] =
443 			src[0] * modelMatrix[ i + 0 * 4 ] +
444 			src[1] * modelMatrix[ i + 1 * 4 ] +
445 			src[2] * modelMatrix[ i + 2 * 4 ] +
446 			1 * modelMatrix[ i + 3 * 4 ];
447 	}
448 
449 	for ( i = 0 ; i < 4 ; i++ ) {
450 		dst[i] =
451 			eye[0] * projectionMatrix[ i + 0 * 4 ] +
452 			eye[1] * projectionMatrix[ i + 1 * 4 ] +
453 			eye[2] * projectionMatrix[ i + 2 * 4 ] +
454 			eye[3] * projectionMatrix[ i + 3 * 4 ];
455 	}
456 }
457 
458 /*
459 ==========================
460 R_TransformClipToWindow
461 
462 ==========================
463 */
R_TransformClipToWindow(const vec4_t clip,const viewParms_t * view,vec4_t normalized,vec4_t window)464 void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) {
465 	normalized[0] = clip[0] / clip[3];
466 	normalized[1] = clip[1] / clip[3];
467 	normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
468 
469 	window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth;
470 	window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight;
471 	window[2] = normalized[2];
472 
473 	window[0] = (int) ( window[0] + 0.5 );
474 	window[1] = (int) ( window[1] + 0.5 );
475 }
476 
477 
478 /*
479 ==========================
480 myGlMultMatrix
481 
482 ==========================
483 */
myGlMultMatrix(const float * a,const float * b,float * out)484 void myGlMultMatrix( const float *a, const float *b, float *out ) {
485 	int i, j;
486 
487 	for ( i = 0 ; i < 4 ; i++ ) {
488 		for ( j = 0 ; j < 4 ; j++ ) {
489 			out[ i * 4 + j ] =
490 				a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
491 				+ a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
492 				+ a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
493 				+ a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
494 		}
495 	}
496 }
497 
498 /*
499 =================
500 R_RotateForEntity
501 
502 Generates an orientation for an entity and viewParms
503 Does NOT produce any GL calls
504 Called by both the front end and the back end
505 =================
506 */
R_RotateForEntity(const trRefEntity_t * ent,const viewParms_t * viewParms,orientationr_t * or)507 void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
508 						orientationr_t *or ) {
509 	float glMatrix[16];
510 	vec3_t delta;
511 	float axisLength;
512 
513 	if ( ent->e.reType != RT_MODEL ) {
514 		*or = viewParms->world;
515 		return;
516 	}
517 
518 	VectorCopy( ent->e.origin, or->origin );
519 
520 	VectorCopy( ent->e.axis[0], or->axis[0] );
521 	VectorCopy( ent->e.axis[1], or->axis[1] );
522 	VectorCopy( ent->e.axis[2], or->axis[2] );
523 
524 	glMatrix[0] = or->axis[0][0];
525 	glMatrix[4] = or->axis[1][0];
526 	glMatrix[8] = or->axis[2][0];
527 	glMatrix[12] = or->origin[0];
528 
529 	glMatrix[1] = or->axis[0][1];
530 	glMatrix[5] = or->axis[1][1];
531 	glMatrix[9] = or->axis[2][1];
532 	glMatrix[13] = or->origin[1];
533 
534 	glMatrix[2] = or->axis[0][2];
535 	glMatrix[6] = or->axis[1][2];
536 	glMatrix[10] = or->axis[2][2];
537 	glMatrix[14] = or->origin[2];
538 
539 	glMatrix[3] = 0;
540 	glMatrix[7] = 0;
541 	glMatrix[11] = 0;
542 	glMatrix[15] = 1;
543 
544 	myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix );
545 
546 	// calculate the viewer origin in the model's space
547 	// needed for fog, specular, and environment mapping
548 	VectorSubtract( viewParms->or.origin, or->origin, delta );
549 
550 	// compensate for scale in the axes if necessary
551 	if ( ent->e.nonNormalizedAxes ) {
552 		axisLength = VectorLength( ent->e.axis[0] );
553 		if ( !axisLength ) {
554 			axisLength = 0;
555 		} else {
556 			axisLength = 1.0f / axisLength;
557 		}
558 	} else {
559 		axisLength = 1.0f;
560 	}
561 
562 	or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength;
563 	or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength;
564 	or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength;
565 }
566 
567 /*
568 =================
569 R_RotateForViewer
570 
571 Sets up the modelview matrix for a given viewParm
572 =================
573 */
R_RotateForViewer(void)574 void R_RotateForViewer( void ) {
575 	float viewerMatrix[16];
576 	vec3_t origin;
577 
578 	memset( &tr.or, 0, sizeof( tr.or ) );
579 	tr.or.axis[0][0] = 1;
580 	tr.or.axis[1][1] = 1;
581 	tr.or.axis[2][2] = 1;
582 	VectorCopy( tr.viewParms.or.origin, tr.or.viewOrigin );
583 
584 	// transform by the camera placement
585 	VectorCopy( tr.viewParms.or.origin, origin );
586 
587 	viewerMatrix[0] = tr.viewParms.or.axis[0][0];
588 	viewerMatrix[4] = tr.viewParms.or.axis[0][1];
589 	viewerMatrix[8] = tr.viewParms.or.axis[0][2];
590 	viewerMatrix[12] = -origin[0] * viewerMatrix[0] + - origin[1] * viewerMatrix[4] + - origin[2] * viewerMatrix[8];
591 
592 	viewerMatrix[1] = tr.viewParms.or.axis[1][0];
593 	viewerMatrix[5] = tr.viewParms.or.axis[1][1];
594 	viewerMatrix[9] = tr.viewParms.or.axis[1][2];
595 	viewerMatrix[13] = -origin[0] * viewerMatrix[1] + - origin[1] * viewerMatrix[5] + - origin[2] * viewerMatrix[9];
596 
597 	viewerMatrix[2] = tr.viewParms.or.axis[2][0];
598 	viewerMatrix[6] = tr.viewParms.or.axis[2][1];
599 	viewerMatrix[10] = tr.viewParms.or.axis[2][2];
600 	viewerMatrix[14] = -origin[0] * viewerMatrix[2] + - origin[1] * viewerMatrix[6] + - origin[2] * viewerMatrix[10];
601 
602 	viewerMatrix[3] = 0;
603 	viewerMatrix[7] = 0;
604 	viewerMatrix[11] = 0;
605 	viewerMatrix[15] = 1;
606 
607 	// convert from our coordinate system (looking down X)
608 	// to OpenGL's coordinate system (looking down -Z)
609 	myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix );
610 
611 	tr.viewParms.world = tr.or;
612 
613 }
614 
615 
616 
617 /*
618 ==============
619 R_SetFrameFog
620 ==============
621 */
R_SetFrameFog(void)622 void R_SetFrameFog( void ) {
623 
624 	if ( r_speeds->integer == 5 ) {
625 		if ( !glfogsettings[FOG_TARGET].registered ) {
626 			ri.Printf( PRINT_ALL, "no fog - calc zFar: %0.1f\n", tr.viewParms.zFar );
627 			return;
628 		}
629 	}
630 
631 	// still fading
632 	if ( glfogsettings[FOG_TARGET].finishTime && glfogsettings[FOG_TARGET].finishTime >= tr.refdef.time ) {
633 		float lerpPos;
634 		int fadeTime;
635 
636 		// transitioning from density to distance
637 		if ( glfogsettings[FOG_LAST].mode == GL_EXP && glfogsettings[FOG_TARGET].mode == GL_LINEAR ) {
638 			// for now just fast transition to the target when dissimilar fogs are
639 			memcpy( &glfogsettings[FOG_CURRENT], &glfogsettings[FOG_TARGET], sizeof( glfog_t ) );
640 			glfogsettings[FOG_TARGET].finishTime = 0;
641 		}
642 		// transitioning from distance to density
643 		else if ( glfogsettings[FOG_LAST].mode == GL_LINEAR && glfogsettings[FOG_TARGET].mode == GL_EXP ) {
644 			memcpy( &glfogsettings[FOG_CURRENT], &glfogsettings[FOG_TARGET], sizeof( glfog_t ) );
645 			glfogsettings[FOG_TARGET].finishTime = 0;
646 		}
647 		// transitioning like fog modes
648 		else {
649 
650 			fadeTime = glfogsettings[FOG_TARGET].finishTime - glfogsettings[FOG_TARGET].startTime;
651 			if ( fadeTime <= 0 ) {
652 				fadeTime = 1;   // avoid divide by zero
653 
654 
655 			}
656 			lerpPos = (float)( tr.refdef.time - glfogsettings[FOG_TARGET].startTime ) / (float)fadeTime;
657 			if ( lerpPos > 1 ) {
658 				lerpPos = 1;
659 			}
660 
661 			// lerp near/far
662 			glfogsettings[FOG_CURRENT].start        = glfogsettings[FOG_LAST].start + ( ( glfogsettings[FOG_TARGET].start - glfogsettings[FOG_LAST].start ) * lerpPos );
663 			glfogsettings[FOG_CURRENT].end          = glfogsettings[FOG_LAST].end + ( ( glfogsettings[FOG_TARGET].end - glfogsettings[FOG_LAST].end ) * lerpPos );
664 
665 			// lerp color
666 			glfogsettings[FOG_CURRENT].color[0]     = glfogsettings[FOG_LAST].color[0] + ( ( glfogsettings[FOG_TARGET].color[0] - glfogsettings[FOG_LAST].color[0] ) * lerpPos );
667 			glfogsettings[FOG_CURRENT].color[1]     = glfogsettings[FOG_LAST].color[1] + ( ( glfogsettings[FOG_TARGET].color[1] - glfogsettings[FOG_LAST].color[1] ) * lerpPos );
668 			glfogsettings[FOG_CURRENT].color[2]     = glfogsettings[FOG_LAST].color[2] + ( ( glfogsettings[FOG_TARGET].color[2] - glfogsettings[FOG_LAST].color[2] ) * lerpPos );
669 
670 			glfogsettings[FOG_CURRENT].density      = glfogsettings[FOG_TARGET].density;
671 			glfogsettings[FOG_CURRENT].mode         = glfogsettings[FOG_TARGET].mode;
672 			glfogsettings[FOG_CURRENT].registered   = qtrue;
673 
674 			// if either fog in the transition clears the screen, clear the background this frame to avoid hall of mirrors
675 			glfogsettings[FOG_CURRENT].clearscreen  = ( glfogsettings[FOG_TARGET].clearscreen || glfogsettings[FOG_LAST].clearscreen );
676 		}
677 
678 		glfogsettings[FOG_CURRENT].dirty = 1;
679 	} else {
680 		// potential FIXME: since this is the most common occurance, diff first and only set changes
681 //		if(glfogsettings[FOG_CURRENT].dirty) {
682 		memcpy( &glfogsettings[FOG_CURRENT], &glfogsettings[FOG_TARGET], sizeof( glfog_t ) );
683 		glfogsettings[FOG_CURRENT].dirty = 0;
684 //		}
685 	}
686 
687 
688 	// shorten the far clip if the fog opaque distance is closer than the procedural farcip dist
689 
690 	if ( glfogsettings[FOG_CURRENT].mode == GL_LINEAR ) {
691 		if ( glfogsettings[FOG_CURRENT].end < tr.viewParms.zFar ) {
692 			tr.viewParms.zFar = glfogsettings[FOG_CURRENT].end;
693 		}
694 		if ( backEnd.refdef.rdflags & RDF_SNOOPERVIEW ) {
695 			tr.viewParms.zFar += 1000;  // zfar out slightly further for snooper.  this works fine with our maps, but could be 'funky' with later maps
696 
697 		}
698 	}
699 //	else
700 //		glfogsettings[FOG_CURRENT].end = 5;
701 
702 
703 	if ( r_speeds->integer == 5 ) {
704 		if ( glfogsettings[FOG_CURRENT].mode == GL_LINEAR ) {
705 			ri.Printf( PRINT_ALL, "farclip fog - den: %0.1f  calc zFar: %0.1f  fog zfar: %0.1f\n", glfogsettings[FOG_CURRENT].density, tr.viewParms.zFar, glfogsettings[FOG_CURRENT].end );
706 		} else {
707 			ri.Printf( PRINT_ALL, "density fog - den: %0.6f  calc zFar: %0.1f  fog zFar: %0.1f\n", glfogsettings[FOG_CURRENT].density, tr.viewParms.zFar, glfogsettings[FOG_CURRENT].end );
708 		}
709 	}
710 }
711 
712 
713 /*
714 ==============
715 R_SetFarClip
716 ==============
717 */
R_SetFarClip(void)718 static void R_SetFarClip( void ) {
719 	float farthestCornerDistance = 0;
720 	int i;
721 
722 	// if not rendering the world (icons, menus, etc)
723 	// set a 2k far clip plane
724 	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
725 		tr.viewParms.zFar = 2048;
726 		return;
727 	}
728 
729 	//----(SA)	this lets you use r_zfar from the command line to experiment with different
730 	//			distances, but setting it back to 0 uses the map (or procedurally generated) default
731 	if ( r_zfar->value ) {
732 
733 		tr.viewParms.zFar = r_zfar->integer;
734 		R_SetFrameFog();
735 
736 		if ( r_speeds->integer == 5 ) {
737 			ri.Printf( PRINT_ALL, "r_zfar value forcing farclip at: %f\n", tr.viewParms.zFar );
738 		}
739 
740 		return;
741 	}
742 
743 	//
744 	// set far clipping planes dynamically
745 	//
746 	farthestCornerDistance = 0;
747 	for ( i = 0; i < 8; i++ )
748 	{
749 		vec3_t v;
750 		vec3_t vecTo;
751 		float distance;
752 
753 		if ( i & 1 ) {
754 			v[0] = tr.viewParms.visBounds[0][0];
755 		} else
756 		{
757 			v[0] = tr.viewParms.visBounds[1][0];
758 		}
759 
760 		if ( i & 2 ) {
761 			v[1] = tr.viewParms.visBounds[0][1];
762 		} else
763 		{
764 			v[1] = tr.viewParms.visBounds[1][1];
765 		}
766 
767 		if ( i & 4 ) {
768 			v[2] = tr.viewParms.visBounds[0][2];
769 		} else
770 		{
771 			v[2] = tr.viewParms.visBounds[1][2];
772 		}
773 
774 		VectorSubtract( v, tr.viewParms.or.origin, vecTo );
775 
776 		distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2];
777 
778 		if ( distance > farthestCornerDistance ) {
779 			farthestCornerDistance = distance;
780 		}
781 	}
782 
783 	tr.viewParms.zFar = sqrt( farthestCornerDistance );
784 	R_SetFrameFog();
785 }
786 
787 /*
788 =================
789 R_SetupFrustum
790 
791 Set up the culling frustum planes for the current view using the results we got from computing the first two rows of
792 the projection matrix.
793 =================
794 */
R_SetupFrustum(viewParms_t * dest,float xmin,float xmax,float ymax,float zProj,float stereoSep)795 void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float stereoSep)
796 {
797 	vec3_t ofsorigin;
798 	float oppleg, adjleg, length;
799 	int i;
800 
801 	if(stereoSep == 0 && xmin == -xmax)
802 	{
803 		// symmetric case can be simplified
804 		VectorCopy(dest->or.origin, ofsorigin);
805 
806 		length = sqrt(xmax * xmax + zProj * zProj);
807 		oppleg = xmax / length;
808 		adjleg = zProj / length;
809 
810 		VectorScale(dest->or.axis[0], oppleg, dest->frustum[0].normal);
811 		VectorMA(dest->frustum[0].normal, adjleg, dest->or.axis[1], dest->frustum[0].normal);
812 
813 		VectorScale(dest->or.axis[0], oppleg, dest->frustum[1].normal);
814 		VectorMA(dest->frustum[1].normal, -adjleg, dest->or.axis[1], dest->frustum[1].normal);
815 	}
816 	else
817 	{
818 		// In stereo rendering, due to the modification of the projection matrix, dest->or.origin is not the
819 		// actual origin that we're rendering so offset the tip of the view pyramid.
820 		VectorMA(dest->or.origin, stereoSep, dest->or.axis[1], ofsorigin);
821 
822 		oppleg = xmax + stereoSep;
823 		length = sqrt(oppleg * oppleg + zProj * zProj);
824 		VectorScale(dest->or.axis[0], oppleg / length, dest->frustum[0].normal);
825 		VectorMA(dest->frustum[0].normal, zProj / length, dest->or.axis[1], dest->frustum[0].normal);
826 
827 		oppleg = xmin + stereoSep;
828 		length = sqrt(oppleg * oppleg + zProj * zProj);
829 		VectorScale(dest->or.axis[0], -oppleg / length, dest->frustum[1].normal);
830 		VectorMA(dest->frustum[1].normal, -zProj / length, dest->or.axis[1], dest->frustum[1].normal);
831 	}
832 
833 	length = sqrt(ymax * ymax + zProj * zProj);
834 	oppleg = ymax / length;
835 	adjleg = zProj / length;
836 
837 	VectorScale(dest->or.axis[0], oppleg, dest->frustum[2].normal);
838 	VectorMA(dest->frustum[2].normal, adjleg, dest->or.axis[2], dest->frustum[2].normal);
839 
840 	VectorScale(dest->or.axis[0], oppleg, dest->frustum[3].normal);
841 	VectorMA(dest->frustum[3].normal, -adjleg, dest->or.axis[2], dest->frustum[3].normal);
842 
843 	for (i=0 ; i<4 ; i++) {
844 		dest->frustum[i].type = PLANE_NON_AXIAL;
845 		dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal);
846 		SetPlaneSignbits( &dest->frustum[i] );
847 	}
848 }
849 
850 /*
851 ===============
852 R_SetupProjection
853 ===============
854 */
R_SetupProjection(viewParms_t * dest,float zProj,qboolean computeFrustum)855 void R_SetupProjection(viewParms_t *dest, float zProj, qboolean computeFrustum)
856 {
857 	float	xmin, xmax, ymin, ymax;
858 	float	width, height, stereoSep = r_stereoSeparation->value;
859 
860 	/*
861 	 * offset the view origin of the viewer for stereo rendering
862 	 * by setting the projection matrix appropriately.
863 	 */
864 
865 	if(stereoSep != 0)
866 	{
867 		if(dest->stereoFrame == STEREO_LEFT)
868 			stereoSep = zProj / stereoSep;
869 		else if(dest->stereoFrame == STEREO_RIGHT)
870 			stereoSep = zProj / -stereoSep;
871 		else
872 			stereoSep = 0;
873 	}
874 
875 	ymax = zProj * tan(dest->fovY * M_PI / 360.0f);
876 	ymin = -ymax;
877 
878 	xmax = zProj * tan(dest->fovX * M_PI / 360.0f);
879 	xmin = -xmax;
880 
881 	width = xmax - xmin;
882 	height = ymax - ymin;
883 
884 	dest->projectionMatrix[0] = 2 * zProj / width;
885 	dest->projectionMatrix[4] = 0;
886 	dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width;
887 	dest->projectionMatrix[12] = 2 * zProj * stereoSep / width;
888 
889 	dest->projectionMatrix[1] = 0;
890 	dest->projectionMatrix[5] = 2 * zProj / height;
891 	dest->projectionMatrix[9] = ( ymax + ymin ) / height;	// normally 0
892 	dest->projectionMatrix[13] = 0;
893 
894 	dest->projectionMatrix[3] = 0;
895 	dest->projectionMatrix[7] = 0;
896 	dest->projectionMatrix[11] = -1;
897 	dest->projectionMatrix[15] = 0;
898 
899 	// Now that we have all the data for the projection matrix we can also setup the view frustum.
900 	if(computeFrustum)
901 		R_SetupFrustum(dest, xmin, xmax, ymax, zProj, stereoSep);
902 }
903 
904 /*
905 ===============
906 R_SetupProjectionZ
907 
908 Sets the z-component transformation part in the projection matrix
909 ===============
910 */
R_SetupProjectionZ(viewParms_t * dest)911 void R_SetupProjectionZ(viewParms_t *dest)
912 {
913 	float zNear, zFar, depth;
914 
915 	zNear	= r_znear->value;
916 	zFar	= dest->zFar;
917 	depth	= zFar - zNear;
918 
919 	dest->projectionMatrix[2] = 0;
920 	dest->projectionMatrix[6] = 0;
921 	dest->projectionMatrix[10] = -( zFar + zNear ) / depth;
922 	dest->projectionMatrix[14] = -2 * zFar * zNear / depth;
923 }
924 
925 
926 /*
927 =================
928 R_MirrorPoint
929 =================
930 */
R_MirrorPoint(vec3_t in,orientation_t * surface,orientation_t * camera,vec3_t out)931 void R_MirrorPoint( vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out ) {
932 	int i;
933 	vec3_t local;
934 	vec3_t transformed;
935 	float d;
936 
937 	VectorSubtract( in, surface->origin, local );
938 
939 	VectorClear( transformed );
940 	for ( i = 0 ; i < 3 ; i++ ) {
941 		d = DotProduct( local, surface->axis[i] );
942 		VectorMA( transformed, d, camera->axis[i], transformed );
943 	}
944 
945 	VectorAdd( transformed, camera->origin, out );
946 }
947 
R_MirrorVector(vec3_t in,orientation_t * surface,orientation_t * camera,vec3_t out)948 void R_MirrorVector( vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out ) {
949 	int i;
950 	float d;
951 
952 	VectorClear( out );
953 	for ( i = 0 ; i < 3 ; i++ ) {
954 		d = DotProduct( in, surface->axis[i] );
955 		VectorMA( out, d, camera->axis[i], out );
956 	}
957 }
958 
959 
960 /*
961 =============
962 R_PlaneForSurface
963 =============
964 */
R_PlaneForSurface(surfaceType_t * surfType,cplane_t * plane)965 void R_PlaneForSurface( surfaceType_t *surfType, cplane_t *plane ) {
966 	srfTriangles_t  *tri;
967 	srfPoly_t       *poly;
968 	drawVert_t      *v1, *v2, *v3;
969 	vec4_t plane4;
970 
971 	if ( !surfType ) {
972 		memset( plane, 0, sizeof( *plane ) );
973 		plane->normal[0] = 1;
974 		return;
975 	}
976 	switch ( *surfType ) {
977 	case SF_FACE:
978 		*plane = ( (srfSurfaceFace_t *)surfType )->plane;
979 		return;
980 	case SF_TRIANGLES:
981 		tri = (srfTriangles_t *)surfType;
982 		v1 = tri->verts + tri->indexes[0];
983 		v2 = tri->verts + tri->indexes[1];
984 		v3 = tri->verts + tri->indexes[2];
985 		PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz );
986 		VectorCopy( plane4, plane->normal );
987 		plane->dist = plane4[3];
988 		return;
989 	case SF_POLY:
990 		poly = (srfPoly_t *)surfType;
991 		PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz );
992 		VectorCopy( plane4, plane->normal );
993 		plane->dist = plane4[3];
994 		return;
995 	default:
996 		memset( plane, 0, sizeof( *plane ) );
997 		plane->normal[0] = 1;
998 		return;
999 	}
1000 }
1001 
1002 /*
1003 =================
1004 R_GetPortalOrientation
1005 
1006 entityNum is the entity that the portal surface is a part of, which may
1007 be moving and rotating.
1008 
1009 Returns qtrue if it should be mirrored
1010 =================
1011 */
R_GetPortalOrientations(drawSurf_t * drawSurf,int entityNum,orientation_t * surface,orientation_t * camera,vec3_t pvsOrigin,qboolean * mirror)1012 qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum,
1013 								  orientation_t *surface, orientation_t *camera,
1014 								  vec3_t pvsOrigin, qboolean *mirror ) {
1015 	int i;
1016 	cplane_t originalPlane, plane;
1017 	trRefEntity_t   *e;
1018 	float d;
1019 	vec3_t transformed;
1020 
1021 	// create plane axis for the portal we are seeing
1022 	R_PlaneForSurface( drawSurf->surface, &originalPlane );
1023 
1024 	// rotate the plane if necessary
1025 	if ( entityNum != REFENTITYNUM_WORLD ) {
1026 		tr.currentEntityNum = entityNum;
1027 		tr.currentEntity = &tr.refdef.entities[entityNum];
1028 
1029 		// get the orientation of the entity
1030 		R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or );
1031 
1032 		// rotate the plane, but keep the non-rotated version for matching
1033 		// against the portalSurface entities
1034 		R_LocalNormalToWorld( originalPlane.normal, plane.normal );
1035 		plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin );
1036 
1037 		// translate the original plane
1038 		originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin );
1039 	} else {
1040 		plane = originalPlane;
1041 	}
1042 
1043 	VectorCopy( plane.normal, surface->axis[0] );
1044 	PerpendicularVector( surface->axis[1], surface->axis[0] );
1045 	CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] );
1046 
1047 	// locate the portal entity closest to this plane.
1048 	// origin will be the origin of the portal, origin2 will be
1049 	// the origin of the camera
1050 	for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) {
1051 		e = &tr.refdef.entities[i];
1052 		if ( e->e.reType != RT_PORTALSURFACE ) {
1053 			continue;
1054 		}
1055 
1056 		d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
1057 		if ( d > 64 || d < -64 ) {
1058 			continue;
1059 		}
1060 
1061 		// get the pvsOrigin from the entity
1062 		VectorCopy( e->e.oldorigin, pvsOrigin );
1063 
1064 		// if the entity is just a mirror, don't use as a camera point
1065 		if ( e->e.oldorigin[0] == e->e.origin[0] &&
1066 			 e->e.oldorigin[1] == e->e.origin[1] &&
1067 			 e->e.oldorigin[2] == e->e.origin[2] ) {
1068 			VectorScale( plane.normal, plane.dist, surface->origin );
1069 			VectorCopy( surface->origin, camera->origin );
1070 			VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] );
1071 			VectorCopy( surface->axis[1], camera->axis[1] );
1072 			VectorCopy( surface->axis[2], camera->axis[2] );
1073 
1074 			*mirror = qtrue;
1075 			return qtrue;
1076 		}
1077 
1078 		// project the origin onto the surface plane to get
1079 		// an origin point we can rotate around
1080 		d = DotProduct( e->e.origin, plane.normal ) - plane.dist;
1081 		VectorMA( e->e.origin, -d, surface->axis[0], surface->origin );
1082 
1083 		// now get the camera origin and orientation
1084 		VectorCopy( e->e.oldorigin, camera->origin );
1085 		AxisCopy( e->e.axis, camera->axis );
1086 		VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] );
1087 		VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] );
1088 
1089 		// optionally rotate
1090 		if ( e->e.oldframe ) {
1091 			// if a speed is specified
1092 			if ( e->e.frame ) {
1093 				// continuous rotate
1094 				d = ( tr.refdef.time / 1000.0f ) * e->e.frame;
1095 				VectorCopy( camera->axis[1], transformed );
1096 				RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
1097 				CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
1098 			} else {
1099 				// bobbing rotate, with skinNum being the rotation offset
1100 				d = sin( tr.refdef.time * 0.003f );
1101 				d = e->e.skinNum + d * 4;
1102 				VectorCopy( camera->axis[1], transformed );
1103 				RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
1104 				CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
1105 			}
1106 		} else if ( e->e.skinNum )   {
1107 			d = e->e.skinNum;
1108 			VectorCopy( camera->axis[1], transformed );
1109 			RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
1110 			CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
1111 		}
1112 		*mirror = qfalse;
1113 		return qtrue;
1114 	}
1115 
1116 	// if we didn't locate a portal entity, don't render anything.
1117 	// We don't want to just treat it as a mirror, because without a
1118 	// portal entity the server won't have communicated a proper entity set
1119 	// in the snapshot
1120 
1121 	// unfortunately, with local movement prediction it is easily possible
1122 	// to see a surface before the server has communicated the matching
1123 	// portal surface entity, so we don't want to print anything here...
1124 
1125 	//ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" );
1126 
1127 	return qfalse;
1128 }
1129 
IsMirror(const drawSurf_t * drawSurf,int entityNum)1130 static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) {
1131 	int i;
1132 	cplane_t originalPlane, plane;
1133 	trRefEntity_t   *e;
1134 	float d;
1135 
1136 	// create plane axis for the portal we are seeing
1137 	R_PlaneForSurface( drawSurf->surface, &originalPlane );
1138 
1139 	// rotate the plane if necessary
1140 	if ( entityNum != REFENTITYNUM_WORLD ) {
1141 		tr.currentEntityNum = entityNum;
1142 		tr.currentEntity = &tr.refdef.entities[entityNum];
1143 
1144 		// get the orientation of the entity
1145 		R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or );
1146 
1147 		// rotate the plane, but keep the non-rotated version for matching
1148 		// against the portalSurface entities
1149 		R_LocalNormalToWorld( originalPlane.normal, plane.normal );
1150 		plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin );
1151 
1152 		// translate the original plane
1153 		originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin );
1154 	}
1155 
1156 	// locate the portal entity closest to this plane.
1157 	// origin will be the origin of the portal, origin2 will be
1158 	// the origin of the camera
1159 	for ( i = 0 ; i < tr.refdef.num_entities ; i++ )
1160 	{
1161 		e = &tr.refdef.entities[i];
1162 		if ( e->e.reType != RT_PORTALSURFACE ) {
1163 			continue;
1164 		}
1165 
1166 		d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
1167 		if ( d > 64 || d < -64 ) {
1168 			continue;
1169 		}
1170 
1171 		// if the entity is just a mirror, don't use as a camera point
1172 		if ( e->e.oldorigin[0] == e->e.origin[0] &&
1173 			 e->e.oldorigin[1] == e->e.origin[1] &&
1174 			 e->e.oldorigin[2] == e->e.origin[2] ) {
1175 			return qtrue;
1176 		}
1177 
1178 		return qfalse;
1179 	}
1180 	return qfalse;
1181 }
1182 
1183 /*
1184 ** SurfIsOffscreen
1185 **
1186 ** Determines if a surface is completely offscreen.
1187 */
SurfIsOffscreen(const drawSurf_t * drawSurf,vec4_t clipDest[128])1188 static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
1189 	float shortest = 100000000;
1190 	int entityNum;
1191 	int numTriangles;
1192 	shader_t *shader;
1193 	int fogNum;
1194 	int dlighted;
1195 // GR - tessellation flag
1196 	int atiTess;
1197 	vec4_t clip, eye;
1198 	int i;
1199 	unsigned int pointOr = 0;
1200 	unsigned int pointAnd = (unsigned int)~0;
1201 
1202 	R_RotateForViewer();
1203 
1204 // GR - decompose with tessellation flag
1205 	R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &atiTess );
1206 	RB_BeginSurface( shader, fogNum );
1207 	rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
1208 
1209 	assert( tess.numVertexes < 128 );
1210 
1211 	for ( i = 0; i < tess.numVertexes; i++ )
1212 	{
1213 		int j;
1214 		unsigned int pointFlags = 0;
1215 
1216 		R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );
1217 
1218 		for ( j = 0; j < 3; j++ )
1219 		{
1220 			if ( clip[j] >= clip[3] ) {
1221 				pointFlags |= ( 1 << ( j * 2 ) );
1222 			} else if ( clip[j] <= -clip[3] )   {
1223 				pointFlags |= ( 1 << ( j * 2 + 1 ) );
1224 			}
1225 		}
1226 		pointAnd &= pointFlags;
1227 		pointOr |= pointFlags;
1228 	}
1229 
1230 	// trivially reject
1231 	if ( pointAnd ) {
1232 		return qtrue;
1233 	}
1234 
1235 	// determine if this surface is backfaced and also determine the distance
1236 	// to the nearest vertex so we can cull based on portal range.  Culling
1237 	// based on vertex distance isn't 100% correct (we should be checking for
1238 	// range to the surface), but it's good enough for the types of portals
1239 	// we have in the game right now.
1240 	numTriangles = tess.numIndexes / 3;
1241 
1242 	for ( i = 0; i < tess.numIndexes; i += 3 )
1243 	{
1244 		vec3_t normal;
1245 		float len;
1246 
1247 		VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal );
1248 
1249 		len = VectorLengthSquared( normal );            // lose the sqrt
1250 		if ( len < shortest ) {
1251 			shortest = len;
1252 		}
1253 
1254 		if ( DotProduct( normal, tess.normal[tess.indexes[i]] ) >= 0 )
1255  		{
1256 			numTriangles--;
1257 		}
1258 	}
1259 	if ( !numTriangles ) {
1260 		return qtrue;
1261 	}
1262 
1263 	// mirrors can early out at this point, since we don't do a fade over distance
1264 	// with them (although we could)
1265 	if ( IsMirror( drawSurf, entityNum ) ) {
1266 		return qfalse;
1267 	}
1268 
1269 	if ( shortest > ( tess.shader->portalRange * tess.shader->portalRange ) ) {
1270 		return qtrue;
1271 	}
1272 
1273 	return qfalse;
1274 }
1275 
1276 /*
1277 ========================
1278 R_MirrorViewBySurface
1279 
1280 Returns qtrue if another view has been rendered
1281 ========================
1282 */
R_MirrorViewBySurface(drawSurf_t * drawSurf,int entityNum)1283 qboolean R_MirrorViewBySurface( drawSurf_t *drawSurf, int entityNum ) {
1284 	vec4_t clipDest[128];
1285 	viewParms_t newParms;
1286 	viewParms_t oldParms;
1287 	orientation_t surface, camera;
1288 
1289 	// don't recursively mirror
1290 	if ( tr.viewParms.isPortal ) {
1291 		ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" );
1292 		return qfalse;
1293 	}
1294 
1295 //	if ( r_noportals->integer || r_fastsky->integer || tr.levelGLFog) {
1296 	if ( r_noportals->integer || r_fastsky->integer ) {
1297 		return qfalse;
1298 	}
1299 
1300 	// trivially reject portal/mirror
1301 	if ( SurfIsOffscreen( drawSurf, clipDest ) ) {
1302 		return qfalse;
1303 	}
1304 
1305 	// save old viewParms so we can return to it after the mirror view
1306 	oldParms = tr.viewParms;
1307 
1308 	newParms = tr.viewParms;
1309 	newParms.isPortal = qtrue;
1310 	if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera,
1311 								   newParms.pvsOrigin, &newParms.isMirror ) ) {
1312 		return qfalse;      // bad portal, no portalentity
1313 	}
1314 
1315 	R_MirrorPoint( oldParms.or.origin, &surface, &camera, newParms.or.origin );
1316 
1317 	VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal );
1318 	newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal );
1319 
1320 	R_MirrorVector( oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0] );
1321 	R_MirrorVector( oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1] );
1322 	R_MirrorVector( oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2] );
1323 
1324 	// OPTIMIZE: restrict the viewport on the mirrored view
1325 
1326 	// render the mirror view
1327 	R_RenderView( &newParms );
1328 
1329 	tr.viewParms = oldParms;
1330 
1331 	return qtrue;
1332 }
1333 
1334 /*
1335 =================
1336 R_SpriteFogNum
1337 
1338 See if a sprite is inside a fog volume
1339 =================
1340 */
R_SpriteFogNum(trRefEntity_t * ent)1341 int R_SpriteFogNum( trRefEntity_t *ent ) {
1342 	int i, j;
1343 	fog_t           *fog;
1344 
1345 	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
1346 		return 0;
1347 	}
1348 
1349 	if ( ent->e.renderfx & RF_CROSSHAIR ) {
1350 		return 0;
1351 	}
1352 
1353 	for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
1354 		fog = &tr.world->fogs[i];
1355 		for ( j = 0 ; j < 3 ; j++ ) {
1356 			if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) {
1357 				break;
1358 			}
1359 			if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) {
1360 				break;
1361 			}
1362 		}
1363 		if ( j == 3 ) {
1364 			return i;
1365 		}
1366 	}
1367 
1368 	return 0;
1369 }
1370 
1371 /*
1372 ==========================================================================================
1373 
1374 DRAWSURF SORTING
1375 
1376 ==========================================================================================
1377 */
1378 
1379 /*
1380 ===============
1381 R_Radix
1382 ===============
1383 */
R_Radix(int byte,int size,drawSurf_t * source,drawSurf_t * dest)1384 static ID_INLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest )
1385 {
1386   int           count[ 256 ] = { 0 };
1387   int           index[ 256 ];
1388   int           i;
1389   unsigned char *sortKey = NULL;
1390   unsigned char *end = NULL;
1391 
1392   sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
1393   end = sortKey + ( size * sizeof( drawSurf_t ) );
1394   for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) )
1395     ++count[ *sortKey ];
1396 
1397   index[ 0 ] = 0;
1398 
1399   for( i = 1; i < 256; ++i )
1400     index[ i ] = index[ i - 1 ] + count[ i - 1 ];
1401 
1402   sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
1403   for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) )
1404     dest[ index[ *sortKey ]++ ] = source[ i ];
1405 }
1406 
1407 /*
1408 ===============
1409 R_RadixSort
1410 
1411 Radix sort with 4 byte size buckets
1412 ===============
1413 */
R_RadixSort(drawSurf_t * source,int size)1414 static void R_RadixSort( drawSurf_t *source, int size )
1415 {
1416   static drawSurf_t scratch[ MAX_DRAWSURFS ];
1417 #ifdef Q3_LITTLE_ENDIAN
1418   R_Radix( 0, size, source, scratch );
1419   R_Radix( 1, size, scratch, source );
1420   R_Radix( 2, size, source, scratch );
1421   R_Radix( 3, size, scratch, source );
1422 #else
1423   R_Radix( 3, size, source, scratch );
1424   R_Radix( 2, size, scratch, source );
1425   R_Radix( 1, size, source, scratch );
1426   R_Radix( 0, size, scratch, source );
1427 #endif //Q3_LITTLE_ENDIAN
1428 }
1429 
1430 //==========================================================================================
1431 
1432 /*
1433 =================
1434 R_AddDrawSurf
1435 =================
1436 */
R_AddDrawSurf(surfaceType_t * surface,shader_t * shader,int fogIndex,int dlightMap,int atiTess)1437 void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
1438 					int fogIndex, int dlightMap, int atiTess ) {
1439 	int index;
1440 
1441 	// instead of checking for overflow, we just mask the index
1442 	// so it wraps around
1443 	index = tr.refdef.numDrawSurfs & DRAWSURF_MASK;
1444 	// the sort data is packed into a single 32 bit value so it can be
1445 	// compared quickly during the qsorting process
1446 // GR - add tesselation flag to the sort
1447 	tr.refdef.drawSurfs[index].sort = ( shader->sortedIndex << QSORT_SHADERNUM_SHIFT )
1448 									  | ( atiTess << QSORT_ATI_TESS_SHIFT )
1449 									  | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
1450 	tr.refdef.drawSurfs[index].surface = surface;
1451 	tr.refdef.numDrawSurfs++;
1452 }
1453 
1454 /*
1455 =================
1456 R_DecomposeSort
1457 =================
1458 */
1459 // GR - decompose  with tessellation flag
R_DecomposeSort(unsigned sort,int * entityNum,shader_t ** shader,int * fogNum,int * dlightMap,int * atiTess)1460 void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
1461 					  int *fogNum, int *dlightMap, int *atiTess ) {
1462 	*fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31;
1463 	*shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & ( MAX_SHADERS - 1 ) ];
1464 //	*entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & ( MAX_GENTITIES - 1 );   // (SA) uppded entity count for Wolf to 11 bits
1465 	*entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK;
1466 	*dlightMap = sort & 3;
1467 //GR - extract tessellation flag
1468 	*atiTess = ( sort >> QSORT_ATI_TESS_SHIFT ) & 1;
1469 }
1470 
1471 /*
1472 =================
1473 R_SortDrawSurfs
1474 =================
1475 */
R_SortDrawSurfs(drawSurf_t * drawSurfs,int numDrawSurfs)1476 void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
1477 	shader_t        *shader;
1478 	int fogNum;
1479 	int entityNum;
1480 	int dlighted;
1481 	int i;
1482 // GR - tessellation flag
1483 	int atiTess;
1484 
1485 	// it is possible for some views to not have any surfaces
1486 	if ( numDrawSurfs < 1 ) {
1487 		// we still need to add it for hyperspace cases
1488 		R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
1489 		return;
1490 	}
1491 
1492 	// sort the drawsurfs by sort type, then orientation, then shader
1493 	R_RadixSort( drawSurfs, numDrawSurfs );
1494 
1495 	// check for any pass through drawing, which
1496 	// may cause another view to be rendered first
1497 	for ( i = 0 ; i < numDrawSurfs ; i++ ) {
1498 // GR - decompose with tessellation flag
1499 		R_DecomposeSort( ( drawSurfs + i )->sort, &entityNum, &shader, &fogNum, &dlighted, &atiTess );
1500 
1501 		if ( shader->sort > SS_PORTAL ) {
1502 			break;
1503 		}
1504 
1505 		// no shader should ever have this sort type
1506 		if ( shader->sort == SS_BAD ) {
1507 			ri.Error( ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name );
1508 		}
1509 
1510 		// if the mirror was completely clipped away, we may need to check another surface
1511 		if ( R_MirrorViewBySurface( ( drawSurfs + i ), entityNum ) ) {
1512 			// this is a debug option to see exactly what is being mirrored
1513 			if ( r_portalOnly->integer ) {
1514 				return;
1515 			}
1516 			break;      // only one mirror view at a time
1517 		}
1518 	}
1519 
1520 	R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
1521 }
1522 
1523 /*
1524 =============
1525 R_AddEntitySurfaces
1526 =============
1527 */
R_AddEntitySurfaces(void)1528 void R_AddEntitySurfaces( void ) {
1529 	trRefEntity_t   *ent;
1530 	shader_t        *shader;
1531 
1532 	if ( !r_drawentities->integer ) {
1533 		return;
1534 	}
1535 
1536 	for ( tr.currentEntityNum = 0;
1537 		  tr.currentEntityNum < tr.refdef.num_entities;
1538 		  tr.currentEntityNum++ ) {
1539 		ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum];
1540 
1541 		ent->needDlights = qfalse;
1542 
1543 		// preshift the value we are going to OR into the drawsurf sort
1544 		tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
1545 
1546 		//
1547 		// the weapon model must be handled special --
1548 		// we don't want the hacked weapon position showing in
1549 		// mirrors, because the true body position will already be drawn
1550 		//
1551 		if ( ( ent->e.renderfx & RF_FIRST_PERSON ) && tr.viewParms.isPortal ) {
1552 			continue;
1553 		}
1554 
1555 		// simple generated models, like sprites and beams, are not culled
1556 		switch ( ent->e.reType ) {
1557 		case RT_PORTALSURFACE:
1558 			break;      // don't draw anything
1559 		case RT_SPRITE:
1560 		case RT_SPLASH:
1561 		case RT_BEAM:
1562 		case RT_LIGHTNING:
1563 		case RT_RAIL_CORE:
1564 		case RT_RAIL_CORE_TAPER:
1565 		case RT_RAIL_RINGS:
1566 			// self blood sprites, talk balloons, etc should not be drawn in the primary
1567 			// view.  We can't just do this check for all entities, because md3
1568 			// entities may still want to cast shadows from them
1569 			if ( ( ent->e.renderfx & RF_THIRD_PERSON ) && !tr.viewParms.isPortal ) {
1570 				continue;
1571 			}
1572 			shader = R_GetShaderByHandle( ent->e.customShader );
1573 // GR - these entities are not tessellated
1574 			R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, ATI_TESS_NONE );
1575 			break;
1576 
1577 		case RT_MODEL:
1578 			// we must set up parts of tr.or for model culling
1579 			R_RotateForEntity( ent, &tr.viewParms, &tr.or );
1580 
1581 			tr.currentModel = R_GetModelByHandle( ent->e.hModel );
1582 			if ( !tr.currentModel ) {
1583 // GR - not tessellated
1584 				R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, ATI_TESS_NONE );
1585 			} else {
1586 				switch ( tr.currentModel->type ) {
1587 				case MOD_MESH:
1588 					R_AddMD3Surfaces( ent );
1589 					break;
1590 					// Ridah
1591 				case MOD_MDC:
1592 					R_AddMDCSurfaces( ent );
1593 					break;
1594 					// done.
1595 				case MOD_MDS:
1596 					R_AddAnimSurfaces( ent );
1597 					break;
1598 				case MOD_MDR:
1599 					R_MDRAddAnimSurfaces( ent );
1600 					break;
1601 				case MOD_IQM:
1602 					R_AddIQMSurfaces( ent );
1603 					break;
1604 				case MOD_BRUSH:
1605 					R_AddBrushModelSurfaces( ent );
1606 					break;
1607 				case MOD_BAD:       // null model axis
1608 					if ( ( ent->e.renderfx & RF_THIRD_PERSON ) && !tr.viewParms.isPortal ) {
1609 						break;
1610 					}
1611 					R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, ATI_TESS_NONE );
1612 					break;
1613 				default:
1614 					ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
1615 					break;
1616 				}
1617 			}
1618 			break;
1619 		default:
1620 			ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" );
1621 		}
1622 	}
1623 
1624 }
1625 
1626 
1627 /*
1628 ====================
1629 R_GenerateDrawSurfs
1630 ====================
1631 */
R_GenerateDrawSurfs(void)1632 void R_GenerateDrawSurfs( void ) {
1633 	R_AddWorldSurfaces();
1634 
1635 	R_AddPolygonSurfaces();
1636 
1637 	// set the projection matrix with the minimum zfar
1638 	// now that we have the world bounded
1639 	// this needs to be done before entities are
1640 	// added, because they use the projection
1641 	// matrix for lod calculation
1642 
1643 	// dynamically compute far clip plane distance
1644 	R_SetFarClip();
1645 
1646 	// we know the size of the clipping volume. Now set the rest of the projection matrix.
1647 	R_SetupProjectionZ (&tr.viewParms);
1648 
1649 	R_AddEntitySurfaces();
1650 }
1651 
1652 /*
1653 ================
1654 R_DebugPolygon
1655 ================
1656 */
R_DebugPolygon(int color,int numPoints,float * points)1657 void R_DebugPolygon( int color, int numPoints, float *points ) {
1658 #ifndef USE_OPENGLES
1659 	int i;
1660 #endif
1661 
1662 	GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
1663 
1664 	// draw solid shade
1665 
1666 #ifdef USE_OPENGLES
1667 	qglColor4f( color&1, (color>>1)&1, (color>>2)&1, 1.0f );
1668 	qglVertexPointer  ( 3, GL_FLOAT, 0, points );
1669 	qglDrawArrays( GL_TRIANGLE_FAN, 0, numPoints );
1670 #else
1671 	qglColor3f( color & 1, ( color >> 1 ) & 1, ( color >> 2 ) & 1 );
1672 	qglBegin( GL_POLYGON );
1673 	for ( i = 0 ; i < numPoints ; i++ ) {
1674 		qglVertex3fv( points + i * 3 );
1675 	}
1676 	qglEnd();
1677 #endif
1678 
1679 	// draw wireframe outline
1680 #ifndef USE_OPENGLES
1681 	GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
1682 #endif
1683 	qglDepthRange( 0, 0 );
1684 #ifdef USE_OPENGLES
1685 	qglColor4f( 1.0f, 1.0f, 1.0f, 1.0f );
1686 	qglVertexPointer  ( 3, GL_FLOAT, 0, points );
1687 	qglDrawArrays( GL_LINES, 0, numPoints );
1688 #else
1689 	qglColor3f( 1, 1, 1 );
1690 	qglBegin( GL_POLYGON );
1691 	for ( i = 0 ; i < numPoints ; i++ ) {
1692 		qglVertex3fv( points + i * 3 );
1693 	}
1694 	qglEnd();
1695 #endif
1696 	qglDepthRange( 0, 1 );
1697 }
1698 
1699 /*
1700 ====================
1701 R_DebugGraphics
1702 
1703 Visualization aid for movement clipping debugging
1704 ====================
1705 */
R_DebugGraphics(void)1706 void R_DebugGraphics( void ) {
1707 	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
1708 		return;
1709 	}
1710 	if ( !r_debugSurface->integer ) {
1711 		return;
1712 	}
1713 
1714 	R_FogOff(); // moved this in here to keep from /always/ doing the fog state change
1715 
1716 	R_IssuePendingRenderCommands();
1717 
1718 	GL_Bind( tr.whiteImage );
1719 	GL_Cull( CT_FRONT_SIDED );
1720 	ri.CM_DrawDebugSurface( R_DebugPolygon );
1721 }
1722 
1723 
1724 /*
1725 ================
1726 R_RenderView
1727 
1728 A view may be either the actual camera view,
1729 or a mirror / remote location
1730 ================
1731 */
R_RenderView(viewParms_t * parms)1732 void R_RenderView( viewParms_t *parms ) {
1733 	int firstDrawSurf;
1734 	int numDrawSurfs;
1735 
1736 	if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
1737 		return;
1738 	}
1739 
1740 	tr.viewCount++;
1741 
1742 	tr.viewParms = *parms;
1743 	tr.viewParms.frameSceneNum = tr.frameSceneNum;
1744 	tr.viewParms.frameCount = tr.frameCount;
1745 
1746 	firstDrawSurf = tr.refdef.numDrawSurfs;
1747 
1748 	tr.viewCount++;
1749 
1750 	// set viewParms.world
1751 	R_RotateForViewer();
1752 
1753 	R_SetupProjection(&tr.viewParms, r_zproj->value, qtrue);
1754 
1755 	R_GenerateDrawSurfs();
1756 
1757 	// if we overflowed MAX_DRAWSURFS, the drawsurfs
1758 	// wrapped around in the buffer and we will be missing
1759 	// the first surfaces, not the last ones
1760 	numDrawSurfs = tr.refdef.numDrawSurfs;
1761 	if ( numDrawSurfs > MAX_DRAWSURFS ) {
1762 		numDrawSurfs = MAX_DRAWSURFS;
1763 	}
1764 
1765 	R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, numDrawSurfs - firstDrawSurf );
1766 
1767 	// draw main system development information (surface outlines, etc)
1768 	R_FogOff();
1769 	R_DebugGraphics();
1770 	R_FogOn();
1771 
1772 }
1773