1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer 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 multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP 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 MP 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 MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP 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 MP 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 
62 //----(SA)
63 /*
64 ==============
65 R_SetFog
66 
67   if fogvar == FOG_CMD_SWITCHFOG {
68 	fogvar is the command
69 	var1 is the fog to switch to
70 	var2 is the time to transition
71   }
72   else {
73 	fogvar is the fog that's being set
74 	var1 is the near fog z value
75 	var2 is the far fog z value
76 	rgb = color
77 	density is density, and is used to derive the values of 'mode', 'drawsky', and 'clearscreen'
78   }
79 ==============
80 */
R_SetFog(int fogvar,int var1,int var2,float r,float g,float b,float density)81 void R_SetFog( int fogvar, int var1, int var2, float r, float g, float b, float density ) {
82 	if ( fogvar != FOG_CMD_SWITCHFOG ) {   // just set the parameters and return
83 
84 		if ( var1 == 0 && var2 == 0 ) {    // clear this fog
85 			glfogsettings[fogvar].registered = qfalse;
86 			return;
87 		}
88 
89 		glfogsettings[fogvar].color[0]      = r;
90 		glfogsettings[fogvar].color[1]      = g;
91 		glfogsettings[fogvar].color[2]      = b;
92 		glfogsettings[fogvar].color[3]      = 1;
93 		glfogsettings[fogvar].start         = var1;
94 		glfogsettings[fogvar].end           = var2;
95 		if ( density > 1 ) {
96 			glfogsettings[fogvar].mode          = GL_LINEAR;
97 			glfogsettings[fogvar].drawsky       = qfalse;
98 			glfogsettings[fogvar].clearscreen   = qtrue;
99 			glfogsettings[fogvar].density       = 1.0;
100 		} else
101 		{
102 			glfogsettings[fogvar].mode          = GL_EXP;
103 			glfogsettings[fogvar].drawsky       = qtrue;
104 			glfogsettings[fogvar].clearscreen   = qfalse;
105 			glfogsettings[fogvar].density       = density;
106 		}
107 		glfogsettings[fogvar].hint          = GL_DONT_CARE;
108 		glfogsettings[fogvar].registered    = qtrue;
109 
110 		return;
111 	}
112 
113 	// don't switch to invalid fogs
114 	if ( glfogsettings[var1].registered != qtrue ) {
115 		return;
116 	}
117 
118 	glfogNum = var1;
119 
120 	// transitioning to new fog, store the current values as the 'from'
121 
122 	if ( glfogsettings[FOG_CURRENT].registered ) {
123 		memcpy( &glfogsettings[FOG_LAST], &glfogsettings[FOG_CURRENT], sizeof( glfog_t ) );
124 	} else {
125 		// if no current fog fall back to world fog
126 		// FIXME: handle transition if there is no FOG_MAP fog
127 		memcpy( &glfogsettings[FOG_LAST], &glfogsettings[FOG_MAP], sizeof( glfog_t ) );
128 	}
129 
130 	memcpy( &glfogsettings[FOG_TARGET], &glfogsettings[glfogNum], sizeof( glfog_t ) );
131 
132 	// setup transition times
133 	glfogsettings[FOG_TARGET].startTime = tr.refdef.time;
134 	glfogsettings[FOG_TARGET].finishTime = tr.refdef.time + var2;
135 }
136 
137 //----(SA) end
138 
139 /*
140 ================
141 R_CompareVert
142 ================
143 */
R_CompareVert(srfVert_t * v1,srfVert_t * v2,qboolean checkST)144 qboolean R_CompareVert(srfVert_t * v1, srfVert_t * v2, qboolean checkST)
145 {
146 	int             i;
147 
148 	for(i = 0; i < 3; i++)
149 	{
150 		if(floor(v1->xyz[i] + 0.1) != floor(v2->xyz[i] + 0.1))
151 		{
152 			return qfalse;
153 		}
154 
155 		if(checkST && ((v1->st[0] != v2->st[0]) || (v1->st[1] != v2->st[1])))
156 		{
157 			return qfalse;
158 		}
159 	}
160 
161 	return qtrue;
162 }
163 
164 
165 /*
166 =============
167 R_CalcTexDirs
168 
169 Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
170 =============
171 */
R_CalcTexDirs(vec3_t sdir,vec3_t tdir,const vec3_t v1,const vec3_t v2,const vec3_t v3,const vec2_t w1,const vec2_t w2,const vec2_t w3)172 void R_CalcTexDirs(vec3_t sdir, vec3_t tdir, const vec3_t v1, const vec3_t v2,
173 				   const vec3_t v3, const vec2_t w1, const vec2_t w2, const vec2_t w3)
174 {
175 	float			x1, x2, y1, y2, z1, z2;
176 	float			s1, s2, t1, t2, r;
177 
178 	x1 = v2[0] - v1[0];
179 	x2 = v3[0] - v1[0];
180 	y1 = v2[1] - v1[1];
181 	y2 = v3[1] - v1[1];
182 	z1 = v2[2] - v1[2];
183 	z2 = v3[2] - v1[2];
184 
185 	s1 = w2[0] - w1[0];
186 	s2 = w3[0] - w1[0];
187 	t1 = w2[1] - w1[1];
188 	t2 = w3[1] - w1[1];
189 
190 	r = s1 * t2 - s2 * t1;
191 	if (r) r = 1.0f / r;
192 
193 	VectorSet(sdir, (t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, (t2 * z1 - t1 * z2) * r);
194 	VectorSet(tdir, (s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, (s1 * z2 - s2 * z1) * r);
195 }
196 
197 /*
198 =============
199 R_CalcTangentSpace
200 
201 Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
202 =============
203 */
R_CalcTangentSpace(vec3_t tangent,vec3_t bitangent,const vec3_t normal,const vec3_t sdir,const vec3_t tdir)204 vec_t R_CalcTangentSpace(vec3_t tangent, vec3_t bitangent, const vec3_t normal, const vec3_t sdir, const vec3_t tdir)
205 {
206 	vec3_t n_cross_t;
207 	vec_t n_dot_t, handedness;
208 
209 	// Gram-Schmidt orthogonalize
210 	n_dot_t = DotProduct(normal, sdir);
211 	VectorMA(sdir, -n_dot_t, normal, tangent);
212 	VectorNormalize(tangent);
213 
214 	// Calculate handedness
215 	CrossProduct(normal, sdir, n_cross_t);
216 	handedness = (DotProduct(n_cross_t, tdir) < 0.0f) ? -1.0f : 1.0f;
217 
218 	// Calculate orthogonal bitangent, if necessary
219 	if (bitangent)
220 		CrossProduct(normal, tangent, bitangent);
221 
222 	return handedness;
223 }
224 
225 
R_CalcTangentVectors(srfVert_t * dv[3])226 qboolean R_CalcTangentVectors(srfVert_t * dv[3])
227 {
228 	int             i;
229 	float           bb, s, t;
230 	vec3_t          bary;
231 
232 
233 	/* calculate barycentric basis for the triangle */
234 	bb = (dv[1]->st[0] - dv[0]->st[0]) * (dv[2]->st[1] - dv[0]->st[1]) - (dv[2]->st[0] - dv[0]->st[0]) * (dv[1]->st[1] - dv[0]->st[1]);
235 	if(fabs(bb) < 0.00000001f)
236 		return qfalse;
237 
238 	/* do each vertex */
239 	for(i = 0; i < 3; i++)
240 	{
241 		vec4_t tangent;
242 		vec3_t normal, bitangent, nxt;
243 
244 		// calculate s tangent vector
245 		s = dv[i]->st[0] + 10.0f;
246 		t = dv[i]->st[1];
247 		bary[0] = ((dv[1]->st[0] - s) * (dv[2]->st[1] - t) - (dv[2]->st[0] - s) * (dv[1]->st[1] - t)) / bb;
248 		bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb;
249 		bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb;
250 
251 		tangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0];
252 		tangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1];
253 		tangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2];
254 
255 		VectorSubtract(tangent, dv[i]->xyz, tangent);
256 		VectorNormalize(tangent);
257 
258 		// calculate t tangent vector
259 		s = dv[i]->st[0];
260 		t = dv[i]->st[1] + 10.0f;
261 		bary[0] = ((dv[1]->st[0] - s) * (dv[2]->st[1] - t) - (dv[2]->st[0] - s) * (dv[1]->st[1] - t)) / bb;
262 		bary[1] = ((dv[2]->st[0] - s) * (dv[0]->st[1] - t) - (dv[0]->st[0] - s) * (dv[2]->st[1] - t)) / bb;
263 		bary[2] = ((dv[0]->st[0] - s) * (dv[1]->st[1] - t) - (dv[1]->st[0] - s) * (dv[0]->st[1] - t)) / bb;
264 
265 		bitangent[0] = bary[0] * dv[0]->xyz[0] + bary[1] * dv[1]->xyz[0] + bary[2] * dv[2]->xyz[0];
266 		bitangent[1] = bary[0] * dv[0]->xyz[1] + bary[1] * dv[1]->xyz[1] + bary[2] * dv[2]->xyz[1];
267 		bitangent[2] = bary[0] * dv[0]->xyz[2] + bary[1] * dv[1]->xyz[2] + bary[2] * dv[2]->xyz[2];
268 
269 		VectorSubtract(bitangent, dv[i]->xyz, bitangent);
270 		VectorNormalize(bitangent);
271 
272 		// store bitangent handedness
273 		R_VaoUnpackNormal(normal, dv[i]->normal);
274 		CrossProduct(normal, tangent, nxt);
275 		tangent[3] = (DotProduct(nxt, bitangent) < 0.0f) ? -1.0f : 1.0f;
276 
277 		R_VaoPackTangent(dv[i]->tangent, tangent);
278 
279 		// debug code
280 		//% Sys_FPrintf( SYS_VRB, "%d S: (%f %f %f) T: (%f %f %f)\n", i,
281 		//%     stv[ i ][ 0 ], stv[ i ][ 1 ], stv[ i ][ 2 ], ttv[ i ][ 0 ], ttv[ i ][ 1 ], ttv[ i ][ 2 ] );
282 	}
283 
284 	return qtrue;
285 }
286 
287 /*
288 =================
289 R_CullLocalBox
290 
291 Returns CULL_IN, CULL_CLIP, or CULL_OUT
292 =================
293 */
R_CullLocalBox(vec3_t localBounds[2])294 int R_CullLocalBox(vec3_t localBounds[2]) {
295 #if 0
296 	int i, j;
297 	vec3_t transformed[8];
298 	float dists[8];
299 	vec3_t v;
300 	cplane_t    *frust;
301 	int anyBack;
302 	int front, back;
303 
304 	if ( r_nocull->integer ) {
305 		return CULL_CLIP;
306 	}
307 
308 	// transform into world space
309 	for ( i = 0 ; i < 8 ; i++ ) {
310 		v[0] = bounds[i & 1][0];
311 		v[1] = bounds[( i >> 1 ) & 1][1];
312 		v[2] = bounds[( i >> 2 ) & 1][2];
313 
314 		VectorCopy( tr.or.origin, transformed[i] );
315 		VectorMA( transformed[i], v[0], tr.or.axis[0], transformed[i] );
316 		VectorMA( transformed[i], v[1], tr.or.axis[1], transformed[i] );
317 		VectorMA( transformed[i], v[2], tr.or.axis[2], transformed[i] );
318 	}
319 
320 	// check against frustum planes
321 	anyBack = 0;
322 	for ( i = 0 ; i < 4 ; i++ ) {
323 		frust = &tr.viewParms.frustum[i];
324 
325 		front = back = 0;
326 		for ( j = 0 ; j < 8 ; j++ ) {
327 			dists[j] = DotProduct( transformed[j], frust->normal );
328 			if ( dists[j] > frust->dist ) {
329 				front = 1;
330 				if ( back ) {
331 					break;      // a point is in front
332 				}
333 			} else {
334 				back = 1;
335 			}
336 		}
337 		if ( !front ) {
338 			// all points were behind one of the planes
339 			return CULL_OUT;
340 		}
341 		anyBack |= back;
342 	}
343 
344 	if ( !anyBack ) {
345 		return CULL_IN;     // completely inside frustum
346 	}
347 
348 	return CULL_CLIP;       // partially clipped
349 
350 #else
351 	int             j;
352 	vec3_t          transformed;
353 	vec3_t          v;
354 	vec3_t          worldBounds[2];
355 
356 	if(r_nocull->integer)
357 	{
358 		return CULL_CLIP;
359 	}
360 
361 	// transform into world space
362 	ClearBounds(worldBounds[0], worldBounds[1]);
363 
364 	for(j = 0; j < 8; j++)
365 	{
366 		v[0] = localBounds[j & 1][0];
367 		v[1] = localBounds[(j >> 1) & 1][1];
368 		v[2] = localBounds[(j >> 2) & 1][2];
369 
370 		R_LocalPointToWorld(v, transformed);
371 
372 		AddPointToBounds(transformed, worldBounds[0], worldBounds[1]);
373 	}
374 
375 	return R_CullBox(worldBounds);
376 #endif
377 }
378 
379 /*
380 =================
381 R_CullBox
382 
383 Returns CULL_IN, CULL_CLIP, or CULL_OUT
384 =================
385 */
R_CullBox(vec3_t worldBounds[2])386 int R_CullBox(vec3_t worldBounds[2]) {
387 	int             i;
388 	cplane_t       *frust;
389 	qboolean        anyClip;
390 	int             r, numPlanes;
391 
392 	numPlanes = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4;
393 
394 	// check against frustum planes
395 	anyClip = qfalse;
396 	for(i = 0; i < numPlanes; i++)
397 	{
398 		frust = &tr.viewParms.frustum[i];
399 
400 		r = BoxOnPlaneSide(worldBounds[0], worldBounds[1], frust);
401 
402 		if(r == 2)
403 		{
404 			// completely outside frustum
405 			return CULL_OUT;
406 		}
407 		if(r == 3)
408 		{
409 			anyClip = qtrue;
410 		}
411 	}
412 
413 	if(!anyClip)
414 	{
415 		// completely inside frustum
416 		return CULL_IN;
417 	}
418 
419 	// partially clipped
420 	return CULL_CLIP;
421 }
422 
423 /*
424 ** R_CullLocalPointAndRadius
425 */
R_CullLocalPointAndRadius(const vec3_t pt,float radius)426 int R_CullLocalPointAndRadius( const vec3_t pt, float radius ) {
427 	vec3_t transformed;
428 
429 	R_LocalPointToWorld( pt, transformed );
430 
431 	return R_CullPointAndRadius( transformed, radius );
432 }
433 
434 /*
435 ** R_CullPointAndRadius
436 */
R_CullPointAndRadiusEx(const vec3_t pt,float radius,const cplane_t * frustum,int numPlanes)437 int R_CullPointAndRadiusEx( const vec3_t pt, float radius, const cplane_t* frustum, int numPlanes ) {
438 	int i;
439 	float dist;
440 	const cplane_t	*frust;
441 	qboolean mightBeClipped = qfalse;
442 
443 	if ( r_nocull->integer ) {
444 		return CULL_CLIP;
445 	}
446 
447 	// check against frustum planes
448 	for (i = 0 ; i < numPlanes ; i++)
449 	{
450 		frust = &frustum[i];
451 
452 		dist = DotProduct( pt, frust->normal ) - frust->dist;
453 		if ( dist < -radius ) {
454 			return CULL_OUT;
455 		} else if ( dist <= radius )   {
456 			mightBeClipped = qtrue;
457 		}
458 	}
459 
460 	if ( mightBeClipped ) {
461 		return CULL_CLIP;
462 	}
463 
464 	return CULL_IN;     // completely inside frustum
465 }
466 
467 /*
468 ** R_CullPointAndRadius
469 */
R_CullPointAndRadius(const vec3_t pt,float radius)470 int R_CullPointAndRadius( const vec3_t pt, float radius )
471 {
472 	return R_CullPointAndRadiusEx(pt, radius, tr.viewParms.frustum, (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 5 : 4);
473 }
474 
475 /*
476 =================
477 R_LocalNormalToWorld
478 
479 =================
480 */
R_LocalNormalToWorld(const vec3_t local,vec3_t world)481 void R_LocalNormalToWorld (const vec3_t local, vec3_t world) {
482 	world[0] = local[0] * tr.or.axis[0][0] + local[1] * tr.or.axis[1][0] + local[2] * tr.or.axis[2][0];
483 	world[1] = local[0] * tr.or.axis[0][1] + local[1] * tr.or.axis[1][1] + local[2] * tr.or.axis[2][1];
484 	world[2] = local[0] * tr.or.axis[0][2] + local[1] * tr.or.axis[1][2] + local[2] * tr.or.axis[2][2];
485 }
486 
487 /*
488 =================
489 R_LocalPointToWorld
490 
491 =================
492 */
R_LocalPointToWorld(const vec3_t local,vec3_t world)493 void R_LocalPointToWorld (const vec3_t local, vec3_t world) {
494 	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];
495 	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];
496 	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];
497 }
498 
499 /*
500 =================
501 R_WorldToLocal
502 
503 =================
504 */
R_WorldToLocal(const vec3_t world,vec3_t local)505 void R_WorldToLocal (const vec3_t world, vec3_t local) {
506 	local[0] = DotProduct( world, tr.or.axis[0] );
507 	local[1] = DotProduct( world, tr.or.axis[1] );
508 	local[2] = DotProduct( world, tr.or.axis[2] );
509 }
510 
511 /*
512 ==========================
513 R_TransformModelToClip
514 
515 ==========================
516 */
R_TransformModelToClip(const vec3_t src,const float * modelMatrix,const float * projectionMatrix,vec4_t eye,vec4_t dst)517 void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
518 							 vec4_t eye, vec4_t dst ) {
519 	int i;
520 
521 	for ( i = 0 ; i < 4 ; i++ ) {
522 		eye[i] =
523 			src[0] * modelMatrix[ i + 0 * 4 ] +
524 			src[1] * modelMatrix[ i + 1 * 4 ] +
525 			src[2] * modelMatrix[ i + 2 * 4 ] +
526 			1 * modelMatrix[ i + 3 * 4 ];
527 	}
528 
529 	for ( i = 0 ; i < 4 ; i++ ) {
530 		dst[i] =
531 			eye[0] * projectionMatrix[ i + 0 * 4 ] +
532 			eye[1] * projectionMatrix[ i + 1 * 4 ] +
533 			eye[2] * projectionMatrix[ i + 2 * 4 ] +
534 			eye[3] * projectionMatrix[ i + 3 * 4 ];
535 	}
536 }
537 
538 /*
539 ==========================
540 R_TransformClipToWindow
541 
542 ==========================
543 */
R_TransformClipToWindow(const vec4_t clip,const viewParms_t * view,vec4_t normalized,vec4_t window)544 void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) {
545 	normalized[0] = clip[0] / clip[3];
546 	normalized[1] = clip[1] / clip[3];
547 	normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
548 
549 	window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth;
550 	window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight;
551 	window[2] = normalized[2];
552 
553 	window[0] = (int) ( window[0] + 0.5 );
554 	window[1] = (int) ( window[1] + 0.5 );
555 }
556 
557 
558 /*
559 ==========================
560 myGlMultMatrix
561 
562 ==========================
563 */
myGlMultMatrix(const float * a,const float * b,float * out)564 void myGlMultMatrix( const float *a, const float *b, float *out ) {
565 	int i, j;
566 
567 	for ( i = 0 ; i < 4 ; i++ ) {
568 		for ( j = 0 ; j < 4 ; j++ ) {
569 			out[ i * 4 + j ] =
570 				a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
571 				+ a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
572 				+ a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
573 				+ a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
574 		}
575 	}
576 }
577 
578 /*
579 =================
580 R_RotateForEntity
581 
582 Generates an orientation for an entity and viewParms
583 Does NOT produce any GL calls
584 Called by both the front end and the back end
585 =================
586 */
R_RotateForEntity(const trRefEntity_t * ent,const viewParms_t * viewParms,orientationr_t * or)587 void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
588 						orientationr_t *or ) {
589 	float glMatrix[16];
590 	vec3_t delta;
591 	float axisLength;
592 
593 	if ( ent->e.reType != RT_MODEL ) {
594 		*or = viewParms->world;
595 		return;
596 	}
597 
598 	VectorCopy( ent->e.origin, or->origin );
599 
600 	VectorCopy( ent->e.axis[0], or->axis[0] );
601 	VectorCopy( ent->e.axis[1], or->axis[1] );
602 	VectorCopy( ent->e.axis[2], or->axis[2] );
603 
604 	glMatrix[0] = or->axis[0][0];
605 	glMatrix[4] = or->axis[1][0];
606 	glMatrix[8] = or->axis[2][0];
607 	glMatrix[12] = or->origin[0];
608 
609 	glMatrix[1] = or->axis[0][1];
610 	glMatrix[5] = or->axis[1][1];
611 	glMatrix[9] = or->axis[2][1];
612 	glMatrix[13] = or->origin[1];
613 
614 	glMatrix[2] = or->axis[0][2];
615 	glMatrix[6] = or->axis[1][2];
616 	glMatrix[10] = or->axis[2][2];
617 	glMatrix[14] = or->origin[2];
618 
619 	glMatrix[3] = 0;
620 	glMatrix[7] = 0;
621 	glMatrix[11] = 0;
622 	glMatrix[15] = 1;
623 
624 	Mat4Copy(glMatrix, or->transformMatrix);
625 	myGlMultMatrix( glMatrix, viewParms->world.modelMatrix, or->modelMatrix );
626 
627 	// calculate the viewer origin in the model's space
628 	// needed for fog, specular, and environment mapping
629 	VectorSubtract( viewParms->or.origin, or->origin, delta );
630 
631 	// compensate for scale in the axes if necessary
632 	if ( ent->e.nonNormalizedAxes ) {
633 		axisLength = VectorLength( ent->e.axis[0] );
634 		if ( !axisLength ) {
635 			axisLength = 0;
636 		} else {
637 			axisLength = 1.0f / axisLength;
638 		}
639 	} else {
640 		axisLength = 1.0f;
641 	}
642 
643 	or->viewOrigin[0] = DotProduct( delta, or->axis[0] ) * axisLength;
644 	or->viewOrigin[1] = DotProduct( delta, or->axis[1] ) * axisLength;
645 	or->viewOrigin[2] = DotProduct( delta, or->axis[2] ) * axisLength;
646 }
647 
648 /*
649 =================
650 R_RotateForViewer
651 
652 Sets up the modelview matrix for a given viewParm
653 =================
654 */
R_RotateForViewer(void)655 void R_RotateForViewer( void ) {
656 	float viewerMatrix[16];
657 	vec3_t origin;
658 
659 	memset( &tr.or, 0, sizeof( tr.or ) );
660 	tr.or.axis[0][0] = 1;
661 	tr.or.axis[1][1] = 1;
662 	tr.or.axis[2][2] = 1;
663 	VectorCopy( tr.viewParms.or.origin, tr.or.viewOrigin );
664 
665 	// transform by the camera placement
666 	VectorCopy( tr.viewParms.or.origin, origin );
667 
668 	viewerMatrix[0] = tr.viewParms.or.axis[0][0];
669 	viewerMatrix[4] = tr.viewParms.or.axis[0][1];
670 	viewerMatrix[8] = tr.viewParms.or.axis[0][2];
671 	viewerMatrix[12] = -origin[0] * viewerMatrix[0] + - origin[1] * viewerMatrix[4] + - origin[2] * viewerMatrix[8];
672 
673 	viewerMatrix[1] = tr.viewParms.or.axis[1][0];
674 	viewerMatrix[5] = tr.viewParms.or.axis[1][1];
675 	viewerMatrix[9] = tr.viewParms.or.axis[1][2];
676 	viewerMatrix[13] = -origin[0] * viewerMatrix[1] + - origin[1] * viewerMatrix[5] + - origin[2] * viewerMatrix[9];
677 
678 	viewerMatrix[2] = tr.viewParms.or.axis[2][0];
679 	viewerMatrix[6] = tr.viewParms.or.axis[2][1];
680 	viewerMatrix[10] = tr.viewParms.or.axis[2][2];
681 	viewerMatrix[14] = -origin[0] * viewerMatrix[2] + - origin[1] * viewerMatrix[6] + - origin[2] * viewerMatrix[10];
682 
683 	viewerMatrix[3] = 0;
684 	viewerMatrix[7] = 0;
685 	viewerMatrix[11] = 0;
686 	viewerMatrix[15] = 1;
687 
688 	// convert from our coordinate system (looking down X)
689 	// to OpenGL's coordinate system (looking down -Z)
690 	myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.or.modelMatrix );
691 
692 	tr.viewParms.world = tr.or;
693 
694 }
695 
696 
697 
698 /*
699 ==============
700 R_SetFrameFog
701 ==============
702 */
R_SetFrameFog(void)703 void R_SetFrameFog( void ) {
704 
705 	if ( r_speeds->integer == 5 ) {
706 		if ( !glfogsettings[FOG_TARGET].registered ) {
707 			ri.Printf( PRINT_ALL, "no fog - calc zFar: %0.1f\n", tr.viewParms.zFar );
708 			return;
709 		}
710 	}
711 
712 	// DHM - Nerve :: If fog is not valid, don't use it
713 	if ( !glfogsettings[FOG_TARGET].registered ) {
714 		return;
715 	}
716 
717 	// still fading
718 	if ( glfogsettings[FOG_TARGET].finishTime && glfogsettings[FOG_TARGET].finishTime >= tr.refdef.time ) {
719 		float lerpPos;
720 		int fadeTime;
721 
722 		// transitioning from density to distance
723 		if ( glfogsettings[FOG_LAST].mode == GL_EXP && glfogsettings[FOG_TARGET].mode == GL_LINEAR ) {
724 			// for now just fast transition to the target when dissimilar fogs are
725 			memcpy( &glfogsettings[FOG_CURRENT], &glfogsettings[FOG_TARGET], sizeof( glfog_t ) );
726 			glfogsettings[FOG_TARGET].finishTime = 0;
727 		}
728 		// transitioning from distance to density
729 		else if ( glfogsettings[FOG_LAST].mode == GL_LINEAR && glfogsettings[FOG_TARGET].mode == GL_EXP ) {
730 			memcpy( &glfogsettings[FOG_CURRENT], &glfogsettings[FOG_TARGET], sizeof( glfog_t ) );
731 			glfogsettings[FOG_TARGET].finishTime = 0;
732 		}
733 		// transitioning like fog modes
734 		else {
735 
736 			fadeTime = glfogsettings[FOG_TARGET].finishTime - glfogsettings[FOG_TARGET].startTime;
737 			if ( fadeTime <= 0 ) {
738 				fadeTime = 1;   // avoid divide by zero
739 
740 
741 			}
742 			lerpPos = (float)( tr.refdef.time - glfogsettings[FOG_TARGET].startTime ) / (float)fadeTime;
743 			if ( lerpPos > 1 ) {
744 				lerpPos = 1;
745 			}
746 
747 			// lerp near/far
748 			glfogsettings[FOG_CURRENT].start        = glfogsettings[FOG_LAST].start + ( ( glfogsettings[FOG_TARGET].start - glfogsettings[FOG_LAST].start ) * lerpPos );
749 			glfogsettings[FOG_CURRENT].end          = glfogsettings[FOG_LAST].end + ( ( glfogsettings[FOG_TARGET].end - glfogsettings[FOG_LAST].end ) * lerpPos );
750 
751 			// lerp color
752 			glfogsettings[FOG_CURRENT].color[0]     = glfogsettings[FOG_LAST].color[0] + ( ( glfogsettings[FOG_TARGET].color[0] - glfogsettings[FOG_LAST].color[0] ) * lerpPos );
753 			glfogsettings[FOG_CURRENT].color[1]     = glfogsettings[FOG_LAST].color[1] + ( ( glfogsettings[FOG_TARGET].color[1] - glfogsettings[FOG_LAST].color[1] ) * lerpPos );
754 			glfogsettings[FOG_CURRENT].color[2]     = glfogsettings[FOG_LAST].color[2] + ( ( glfogsettings[FOG_TARGET].color[2] - glfogsettings[FOG_LAST].color[2] ) * lerpPos );
755 
756 			glfogsettings[FOG_CURRENT].density      = glfogsettings[FOG_TARGET].density;
757 			glfogsettings[FOG_CURRENT].mode         = glfogsettings[FOG_TARGET].mode;
758 			glfogsettings[FOG_CURRENT].registered   = qtrue;
759 
760 			// if either fog in the transition clears the screen, clear the background this frame to avoid hall of mirrors
761 			glfogsettings[FOG_CURRENT].clearscreen  = ( glfogsettings[FOG_TARGET].clearscreen || glfogsettings[FOG_LAST].clearscreen );
762 		}
763 	} else {
764 		// probably usually not necessary to copy the whole thing.
765 		// potential FIXME: since this is the most common occurance, diff first and only set changes
766 		memcpy( &glfogsettings[FOG_CURRENT], &glfogsettings[FOG_TARGET], sizeof( glfog_t ) );
767 	}
768 
769 
770 	// shorten the far clip if the fog opaque distance is closer than the procedural farcip dist
771 
772 	if ( glfogsettings[FOG_CURRENT].mode == GL_LINEAR ) {
773 		if ( glfogsettings[FOG_CURRENT].end < tr.viewParms.zFar ) {
774 			tr.viewParms.zFar = glfogsettings[FOG_CURRENT].end;
775 		}
776 	}
777 //	else
778 //		glfogsettings[FOG_CURRENT].end = 5;
779 
780 
781 	if ( r_speeds->integer == 5 ) {
782 		if ( glfogsettings[FOG_CURRENT].mode == GL_LINEAR ) {
783 			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 );
784 		} else {
785 			ri.Printf( PRINT_ALL, "density fog - den: %0.4f  calc zFar: %0.1f  fog zFar: %0.1f\n", glfogsettings[FOG_CURRENT].density, tr.viewParms.zFar, glfogsettings[FOG_CURRENT].end );
786 		}
787 	}
788 }
789 
790 
791 /*
792 ==============
793 SetFarClip
794 ==============
795 */
R_SetFarClip(void)796 static void R_SetFarClip( void ) {
797 	float farthestCornerDistance = 0;
798 	int i;
799 
800 	// if not rendering the world (icons, menus, etc)
801 	// set a 2k far clip plane
802 	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
803 		tr.viewParms.zFar = 2048;
804 		return;
805 	}
806 
807 	//----(SA)	this lets you use r_zfar from the command line to experiment with different
808 	//			distances, but setting it back to 0 uses the map (or procedurally generated) default
809 	if ( r_zfar->value ) {
810 
811 		tr.viewParms.zFar = r_zfar->integer;
812 		R_SetFrameFog();
813 
814 		if ( r_speeds->integer == 5 ) {
815 			ri.Printf( PRINT_ALL, "r_zfar value forcing farclip at: %f\n", tr.viewParms.zFar );
816 		}
817 
818 		return;
819 	}
820 
821 	//
822 	// set far clipping planes dynamically
823 	//
824 	farthestCornerDistance = 0;
825 	for ( i = 0; i < 8; i++ )
826 	{
827 		vec3_t v;
828 		vec3_t vecTo;
829 		float distance;
830 
831 		if ( i & 1 ) {
832 			v[0] = tr.viewParms.visBounds[0][0];
833 		} else
834 		{
835 			v[0] = tr.viewParms.visBounds[1][0];
836 		}
837 
838 		if ( i & 2 ) {
839 			v[1] = tr.viewParms.visBounds[0][1];
840 		} else
841 		{
842 			v[1] = tr.viewParms.visBounds[1][1];
843 		}
844 
845 		if ( i & 4 ) {
846 			v[2] = tr.viewParms.visBounds[0][2];
847 		} else
848 		{
849 			v[2] = tr.viewParms.visBounds[1][2];
850 		}
851 
852 		VectorSubtract( v, tr.viewParms.or.origin, vecTo );
853 
854 		distance = vecTo[0] * vecTo[0] + vecTo[1] * vecTo[1] + vecTo[2] * vecTo[2];
855 
856 		if ( distance > farthestCornerDistance ) {
857 			farthestCornerDistance = distance;
858 		}
859 	}
860 
861 	tr.viewParms.zFar = sqrt( farthestCornerDistance );
862 	R_SetFrameFog();
863 }
864 
865 /*
866 =================
867 R_SetupFrustum
868 
869 Set up the culling frustum planes for the current view using the results we got from computing the first two rows of
870 the projection matrix.
871 =================
872 */
R_SetupFrustum(viewParms_t * dest,float xmin,float xmax,float ymax,float zProj,float zFar,float stereoSep)873 void R_SetupFrustum (viewParms_t *dest, float xmin, float xmax, float ymax, float zProj, float zFar, float stereoSep)
874 {
875 	vec3_t ofsorigin;
876 	float oppleg, adjleg, length;
877 	int i;
878 
879 	if(stereoSep == 0 && xmin == -xmax)
880 	{
881 		// symmetric case can be simplified
882 		VectorCopy(dest->or.origin, ofsorigin);
883 
884 		length = sqrt(xmax * xmax + zProj * zProj);
885 		oppleg = xmax / length;
886 		adjleg = zProj / length;
887 
888 		VectorScale(dest->or.axis[0], oppleg, dest->frustum[0].normal);
889 		VectorMA(dest->frustum[0].normal, adjleg, dest->or.axis[1], dest->frustum[0].normal);
890 
891 		VectorScale(dest->or.axis[0], oppleg, dest->frustum[1].normal);
892 		VectorMA(dest->frustum[1].normal, -adjleg, dest->or.axis[1], dest->frustum[1].normal);
893 	}
894 	else
895 	{
896 		// In stereo rendering, due to the modification of the projection matrix, dest->or.origin is not the
897 		// actual origin that we're rendering so offset the tip of the view pyramid.
898 		VectorMA(dest->or.origin, stereoSep, dest->or.axis[1], ofsorigin);
899 
900 		oppleg = xmax + stereoSep;
901 		length = sqrt(oppleg * oppleg + zProj * zProj);
902 		VectorScale(dest->or.axis[0], oppleg / length, dest->frustum[0].normal);
903 		VectorMA(dest->frustum[0].normal, zProj / length, dest->or.axis[1], dest->frustum[0].normal);
904 
905 		oppleg = xmin + stereoSep;
906 		length = sqrt(oppleg * oppleg + zProj * zProj);
907 		VectorScale(dest->or.axis[0], -oppleg / length, dest->frustum[1].normal);
908 		VectorMA(dest->frustum[1].normal, -zProj / length, dest->or.axis[1], dest->frustum[1].normal);
909 	}
910 
911 	length = sqrt(ymax * ymax + zProj * zProj);
912 	oppleg = ymax / length;
913 	adjleg = zProj / length;
914 
915 	VectorScale(dest->or.axis[0], oppleg, dest->frustum[2].normal);
916 	VectorMA(dest->frustum[2].normal, adjleg, dest->or.axis[2], dest->frustum[2].normal);
917 
918 	VectorScale(dest->or.axis[0], oppleg, dest->frustum[3].normal);
919 	VectorMA(dest->frustum[3].normal, -adjleg, dest->or.axis[2], dest->frustum[3].normal);
920 
921 	for (i=0 ; i<4 ; i++) {
922 		dest->frustum[i].type = PLANE_NON_AXIAL;
923 		dest->frustum[i].dist = DotProduct (ofsorigin, dest->frustum[i].normal);
924 		SetPlaneSignbits( &dest->frustum[i] );
925 	}
926 
927 	if (zFar != 0.0f)
928 	{
929 		vec3_t farpoint;
930 
931 		VectorMA(ofsorigin, zFar, dest->or.axis[0], farpoint);
932 		VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal);
933 
934 		dest->frustum[4].type = PLANE_NON_AXIAL;
935 		dest->frustum[4].dist = DotProduct (farpoint, dest->frustum[4].normal);
936 		SetPlaneSignbits( &dest->frustum[4] );
937 		dest->flags |= VPF_FARPLANEFRUSTUM;
938 	}
939 }
940 
941 /*
942 ===============
943 R_SetupProjection
944 ===============
945 */
R_SetupProjection(viewParms_t * dest,float zProj,float zFar,qboolean computeFrustum)946 void R_SetupProjection(viewParms_t *dest, float zProj, float zFar, qboolean computeFrustum)
947 {
948 	float	xmin, xmax, ymin, ymax;
949 	float	width, height, stereoSep = r_stereoSeparation->value;
950 
951 	/*
952 	 * offset the view origin of the viewer for stereo rendering
953 	 * by setting the projection matrix appropriately.
954 	 */
955 
956 	if(stereoSep != 0)
957 	{
958 		if(dest->stereoFrame == STEREO_LEFT)
959 			stereoSep = zProj / stereoSep;
960 		else if(dest->stereoFrame == STEREO_RIGHT)
961 			stereoSep = zProj / -stereoSep;
962 		else
963 			stereoSep = 0;
964 	}
965 
966 	ymax = zProj * tan(dest->fovY * M_PI / 360.0f);
967 	ymin = -ymax;
968 
969 	xmax = zProj * tan(dest->fovX * M_PI / 360.0f);
970 	xmin = -xmax;
971 
972 	width = xmax - xmin;
973 	height = ymax - ymin;
974 
975 	dest->projectionMatrix[0] = 2 * zProj / width;
976 	dest->projectionMatrix[4] = 0;
977 	dest->projectionMatrix[8] = (xmax + xmin + 2 * stereoSep) / width;
978 	dest->projectionMatrix[12] = 2 * zProj * stereoSep / width;
979 
980 	dest->projectionMatrix[1] = 0;
981 	dest->projectionMatrix[5] = 2 * zProj / height;
982 	dest->projectionMatrix[9] = ( ymax + ymin ) / height;	// normally 0
983 	dest->projectionMatrix[13] = 0;
984 
985 	dest->projectionMatrix[3] = 0;
986 	dest->projectionMatrix[7] = 0;
987 	dest->projectionMatrix[11] = -1;
988 	dest->projectionMatrix[15] = 0;
989 
990 	// Now that we have all the data for the projection matrix we can also setup the view frustum.
991 	if(computeFrustum)
992 		R_SetupFrustum(dest, xmin, xmax, ymax, zProj, zFar, stereoSep);
993 }
994 
995 /*
996 ===============
997 R_SetupProjectionZ
998 
999 Sets the z-component transformation part in the projection matrix
1000 ===============
1001 */
R_SetupProjectionZ(viewParms_t * dest)1002 void R_SetupProjectionZ(viewParms_t *dest)
1003 {
1004 	float zNear, zFar, depth;
1005 
1006 	zNear = r_znear->value;
1007 	zFar	= dest->zFar;
1008 
1009 	depth	= zFar - zNear;
1010 
1011 	dest->projectionMatrix[2] = 0;
1012 	dest->projectionMatrix[6] = 0;
1013 	dest->projectionMatrix[10] = -( zFar + zNear ) / depth;
1014 	dest->projectionMatrix[14] = -2 * zFar * zNear / depth;
1015 
1016 	if (dest->isPortal)
1017 	{
1018 		float	plane[4];
1019 		float	plane2[4];
1020 		vec4_t q, c;
1021 
1022 		// transform portal plane into camera space
1023 		plane[0] = dest->portalPlane.normal[0];
1024 		plane[1] = dest->portalPlane.normal[1];
1025 		plane[2] = dest->portalPlane.normal[2];
1026 		plane[3] = dest->portalPlane.dist;
1027 
1028 		plane2[0] = -DotProduct (dest->or.axis[1], plane);
1029 		plane2[1] = DotProduct (dest->or.axis[2], plane);
1030 		plane2[2] = -DotProduct (dest->or.axis[0], plane);
1031 		plane2[3] = DotProduct (plane, dest->or.origin) - plane[3];
1032 
1033 		// Lengyel, Eric. "Modifying the Projection Matrix to Perform Oblique Near-plane Clipping".
1034 		// Terathon Software 3D Graphics Library, 2004. http://www.terathon.com/code/oblique.html
1035 		q[0] = (SGN(plane2[0]) + dest->projectionMatrix[8]) / dest->projectionMatrix[0];
1036 		q[1] = (SGN(plane2[1]) + dest->projectionMatrix[9]) / dest->projectionMatrix[5];
1037 		q[2] = -1.0f;
1038 		q[3] = (1.0f + dest->projectionMatrix[10]) / dest->projectionMatrix[14];
1039 
1040 		VectorScale4(plane2, 2.0f / DotProduct4(plane2, q), c);
1041 
1042 		dest->projectionMatrix[2]  = c[0];
1043 		dest->projectionMatrix[6]  = c[1];
1044 		dest->projectionMatrix[10] = c[2] + 1.0f;
1045 		dest->projectionMatrix[14] = c[3];
1046 
1047 	}
1048 }
1049 
1050 /*
1051 ===============
1052 R_SetupProjectionOrtho
1053 ===============
1054 */
R_SetupProjectionOrtho(viewParms_t * dest,vec3_t viewBounds[2])1055 void R_SetupProjectionOrtho(viewParms_t *dest, vec3_t viewBounds[2])
1056 {
1057 	float xmin, xmax, ymin, ymax, znear, zfar;
1058 	//viewParms_t *dest = &tr.viewParms;
1059 	int i;
1060 	vec3_t pop;
1061 
1062 	// Quake3:   Projection:
1063 	//
1064 	//    Z  X   Y  Z
1065 	//    | /    | /
1066 	//    |/     |/
1067 	// Y--+      +--X
1068 
1069 	xmin  =  viewBounds[0][1];
1070 	xmax  =  viewBounds[1][1];
1071 	ymin  = -viewBounds[1][2];
1072 	ymax  = -viewBounds[0][2];
1073 	znear =  viewBounds[0][0];
1074 	zfar  =  viewBounds[1][0];
1075 
1076 	dest->projectionMatrix[0]  = 2 / (xmax - xmin);
1077 	dest->projectionMatrix[4]  = 0;
1078 	dest->projectionMatrix[8]  = 0;
1079 	dest->projectionMatrix[12] = (xmax + xmin) / (xmax - xmin);
1080 
1081 	dest->projectionMatrix[1]  = 0;
1082 	dest->projectionMatrix[5]  = 2 / (ymax - ymin);
1083 	dest->projectionMatrix[9]  = 0;
1084 	dest->projectionMatrix[13] = (ymax + ymin) / (ymax - ymin);
1085 
1086 	dest->projectionMatrix[2]  = 0;
1087 	dest->projectionMatrix[6]  = 0;
1088 	dest->projectionMatrix[10] = -2 / (zfar - znear);
1089 	dest->projectionMatrix[14] = -(zfar + znear) / (zfar - znear);
1090 
1091 	dest->projectionMatrix[3]  = 0;
1092 	dest->projectionMatrix[7]  = 0;
1093 	dest->projectionMatrix[11] = 0;
1094 	dest->projectionMatrix[15] = 1;
1095 
1096 	VectorScale(dest->or.axis[1],  1.0f, dest->frustum[0].normal);
1097 	VectorMA(dest->or.origin, viewBounds[0][1], dest->frustum[0].normal, pop);
1098 	dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal);
1099 
1100 	VectorScale(dest->or.axis[1], -1.0f, dest->frustum[1].normal);
1101 	VectorMA(dest->or.origin, -viewBounds[1][1], dest->frustum[1].normal, pop);
1102 	dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal);
1103 
1104 	VectorScale(dest->or.axis[2],  1.0f, dest->frustum[2].normal);
1105 	VectorMA(dest->or.origin, viewBounds[0][2], dest->frustum[2].normal, pop);
1106 	dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal);
1107 
1108 	VectorScale(dest->or.axis[2], -1.0f, dest->frustum[3].normal);
1109 	VectorMA(dest->or.origin, -viewBounds[1][2], dest->frustum[3].normal, pop);
1110 	dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal);
1111 
1112 	VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal);
1113 	VectorMA(dest->or.origin, -viewBounds[1][0], dest->frustum[4].normal, pop);
1114 	dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal);
1115 
1116 	for (i = 0; i < 5; i++)
1117 	{
1118 		dest->frustum[i].type = PLANE_NON_AXIAL;
1119 		SetPlaneSignbits (&dest->frustum[i]);
1120 	}
1121 
1122 	dest->flags |= VPF_FARPLANEFRUSTUM;
1123 }
1124 
1125 /*
1126 =================
1127 R_MirrorPoint
1128 =================
1129 */
R_MirrorPoint(vec3_t in,orientation_t * surface,orientation_t * camera,vec3_t out)1130 void R_MirrorPoint( vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out ) {
1131 	int i;
1132 	vec3_t local;
1133 	vec3_t transformed;
1134 	float d;
1135 
1136 	VectorSubtract( in, surface->origin, local );
1137 
1138 	VectorClear( transformed );
1139 	for ( i = 0 ; i < 3 ; i++ ) {
1140 		d = DotProduct( local, surface->axis[i] );
1141 		VectorMA( transformed, d, camera->axis[i], transformed );
1142 	}
1143 
1144 	VectorAdd( transformed, camera->origin, out );
1145 }
1146 
R_MirrorVector(vec3_t in,orientation_t * surface,orientation_t * camera,vec3_t out)1147 void R_MirrorVector( vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out ) {
1148 	int i;
1149 	float d;
1150 
1151 	VectorClear( out );
1152 	for ( i = 0 ; i < 3 ; i++ ) {
1153 		d = DotProduct( in, surface->axis[i] );
1154 		VectorMA( out, d, camera->axis[i], out );
1155 	}
1156 }
1157 
1158 
1159 /*
1160 =============
1161 R_PlaneForSurface
1162 =============
1163 */
R_PlaneForSurface(surfaceType_t * surfType,cplane_t * plane)1164 void R_PlaneForSurface( surfaceType_t *surfType, cplane_t *plane ) {
1165 	srfBspSurface_t	*tri;
1166 	srfPoly_t       *poly;
1167 	srfVert_t		*v1, *v2, *v3;
1168 	vec4_t plane4;
1169 
1170 	if ( !surfType ) {
1171 		memset( plane, 0, sizeof( *plane ) );
1172 		plane->normal[0] = 1;
1173 		return;
1174 	}
1175 	switch ( *surfType ) {
1176 	case SF_FACE:
1177 		*plane = ((srfBspSurface_t *)surfType)->cullPlane;
1178 		return;
1179 	case SF_TRIANGLES:
1180 		tri = (srfBspSurface_t *)surfType;
1181 		v1 = tri->verts + tri->indexes[0];
1182 		v2 = tri->verts + tri->indexes[1];
1183 		v3 = tri->verts + tri->indexes[2];
1184 		PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz );
1185 		VectorCopy( plane4, plane->normal );
1186 		plane->dist = plane4[3];
1187 		return;
1188 	case SF_POLY:
1189 		poly = (srfPoly_t *)surfType;
1190 		PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz );
1191 		VectorCopy( plane4, plane->normal );
1192 		plane->dist = plane4[3];
1193 		return;
1194 	default:
1195 		memset( plane, 0, sizeof( *plane ) );
1196 		plane->normal[0] = 1;
1197 		return;
1198 	}
1199 }
1200 
1201 /*
1202 =================
1203 R_GetPortalOrientation
1204 
1205 entityNum is the entity that the portal surface is a part of, which may
1206 be moving and rotating.
1207 
1208 Returns qtrue if it should be mirrored
1209 =================
1210 */
R_GetPortalOrientations(drawSurf_t * drawSurf,int entityNum,orientation_t * surface,orientation_t * camera,vec3_t pvsOrigin,qboolean * mirror)1211 qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum,
1212 								  orientation_t *surface, orientation_t *camera,
1213 								  vec3_t pvsOrigin, qboolean *mirror ) {
1214 	int i;
1215 	cplane_t originalPlane, plane;
1216 	trRefEntity_t   *e;
1217 	float d;
1218 	vec3_t transformed;
1219 
1220 	// create plane axis for the portal we are seeing
1221 	R_PlaneForSurface( drawSurf->surface, &originalPlane );
1222 
1223 	// rotate the plane if necessary
1224 	if ( entityNum != REFENTITYNUM_WORLD ) {
1225 		tr.currentEntityNum = entityNum;
1226 		tr.currentEntity = &tr.refdef.entities[entityNum];
1227 
1228 		// get the orientation of the entity
1229 		R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or );
1230 
1231 		// rotate the plane, but keep the non-rotated version for matching
1232 		// against the portalSurface entities
1233 		R_LocalNormalToWorld( originalPlane.normal, plane.normal );
1234 		plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin );
1235 
1236 		// translate the original plane
1237 		originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin );
1238 	} else {
1239 		plane = originalPlane;
1240 	}
1241 
1242 	VectorCopy( plane.normal, surface->axis[0] );
1243 	PerpendicularVector( surface->axis[1], surface->axis[0] );
1244 	CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] );
1245 
1246 	// locate the portal entity closest to this plane.
1247 	// origin will be the origin of the portal, origin2 will be
1248 	// the origin of the camera
1249 	for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) {
1250 		e = &tr.refdef.entities[i];
1251 		if ( e->e.reType != RT_PORTALSURFACE ) {
1252 			continue;
1253 		}
1254 
1255 		d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
1256 		if ( d > 64 || d < -64 ) {
1257 			continue;
1258 		}
1259 
1260 		// get the pvsOrigin from the entity
1261 		VectorCopy( e->e.oldorigin, pvsOrigin );
1262 
1263 		// if the entity is just a mirror, don't use as a camera point
1264 		if ( e->e.oldorigin[0] == e->e.origin[0] &&
1265 			 e->e.oldorigin[1] == e->e.origin[1] &&
1266 			 e->e.oldorigin[2] == e->e.origin[2] ) {
1267 			VectorScale( plane.normal, plane.dist, surface->origin );
1268 			VectorCopy( surface->origin, camera->origin );
1269 			VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] );
1270 			VectorCopy( surface->axis[1], camera->axis[1] );
1271 			VectorCopy( surface->axis[2], camera->axis[2] );
1272 
1273 			*mirror = qtrue;
1274 			return qtrue;
1275 		}
1276 
1277 		// project the origin onto the surface plane to get
1278 		// an origin point we can rotate around
1279 		d = DotProduct( e->e.origin, plane.normal ) - plane.dist;
1280 		VectorMA( e->e.origin, -d, surface->axis[0], surface->origin );
1281 
1282 		// now get the camera origin and orientation
1283 		VectorCopy( e->e.oldorigin, camera->origin );
1284 		AxisCopy( e->e.axis, camera->axis );
1285 		VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] );
1286 		VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] );
1287 
1288 		// optionally rotate
1289 		if ( e->e.oldframe ) {
1290 			// if a speed is specified
1291 			if ( e->e.frame ) {
1292 				// continuous rotate
1293 				d = ( tr.refdef.time / 1000.0f ) * e->e.frame;
1294 				VectorCopy( camera->axis[1], transformed );
1295 				RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
1296 				CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
1297 			} else {
1298 				// bobbing rotate, with skinNum being the rotation offset
1299 				d = sin( tr.refdef.time * 0.003f );
1300 				d = e->e.skinNum + d * 4;
1301 				VectorCopy( camera->axis[1], transformed );
1302 				RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
1303 				CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
1304 			}
1305 		} else if ( e->e.skinNum )   {
1306 			d = e->e.skinNum;
1307 			VectorCopy( camera->axis[1], transformed );
1308 			RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
1309 			CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
1310 		}
1311 		*mirror = qfalse;
1312 		return qtrue;
1313 	}
1314 
1315 	// if we didn't locate a portal entity, don't render anything.
1316 	// We don't want to just treat it as a mirror, because without a
1317 	// portal entity the server won't have communicated a proper entity set
1318 	// in the snapshot
1319 
1320 	// unfortunately, with local movement prediction it is easily possible
1321 	// to see a surface before the server has communicated the matching
1322 	// portal surface entity, so we don't want to print anything here...
1323 
1324 	//ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" );
1325 
1326 	return qfalse;
1327 }
1328 
IsMirror(const drawSurf_t * drawSurf,int entityNum)1329 static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum ) {
1330 	int i;
1331 	cplane_t originalPlane, plane;
1332 	trRefEntity_t   *e;
1333 	float d;
1334 
1335 	// create plane axis for the portal we are seeing
1336 	R_PlaneForSurface( drawSurf->surface, &originalPlane );
1337 
1338 	// rotate the plane if necessary
1339 	if ( entityNum != REFENTITYNUM_WORLD ) {
1340 		tr.currentEntityNum = entityNum;
1341 		tr.currentEntity = &tr.refdef.entities[entityNum];
1342 
1343 		// get the orientation of the entity
1344 		R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.or );
1345 
1346 		// rotate the plane, but keep the non-rotated version for matching
1347 		// against the portalSurface entities
1348 		R_LocalNormalToWorld( originalPlane.normal, plane.normal );
1349 		plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.or.origin );
1350 
1351 		// translate the original plane
1352 		originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.or.origin );
1353 	}
1354 
1355 	// locate the portal entity closest to this plane.
1356 	// origin will be the origin of the portal, origin2 will be
1357 	// the origin of the camera
1358 	for ( i = 0 ; i < tr.refdef.num_entities ; i++ )
1359 	{
1360 		e = &tr.refdef.entities[i];
1361 		if ( e->e.reType != RT_PORTALSURFACE ) {
1362 			continue;
1363 		}
1364 
1365 		d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
1366 		if ( d > 64 || d < -64 ) {
1367 			continue;
1368 		}
1369 
1370 		// if the entity is just a mirror, don't use as a camera point
1371 		if ( e->e.oldorigin[0] == e->e.origin[0] &&
1372 			 e->e.oldorigin[1] == e->e.origin[1] &&
1373 			 e->e.oldorigin[2] == e->e.origin[2] ) {
1374 			return qtrue;
1375 		}
1376 
1377 		return qfalse;
1378 	}
1379 	return qfalse;
1380 }
1381 
1382 /*
1383 ** SurfIsOffscreen
1384 **
1385 ** Determines if a surface is completely offscreen.
1386 */
SurfIsOffscreen(const drawSurf_t * drawSurf,vec4_t clipDest[128])1387 static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
1388 	float shortest = 100000000;
1389 	int entityNum;
1390 	int numTriangles;
1391 	shader_t *shader;
1392 	int fogNum;
1393 	int dlighted;
1394 	int pshadowed;
1395 	vec4_t clip, eye;
1396 	int i;
1397 	unsigned int pointOr = 0;
1398 	unsigned int pointAnd = (unsigned int)~0;
1399 
1400 	R_RotateForViewer();
1401 
1402 	R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed );
1403 	RB_BeginSurface( shader, fogNum, drawSurf->cubemapIndex );
1404 	rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
1405 
1406 	assert( tess.numVertexes < 128 );
1407 
1408 	for ( i = 0; i < tess.numVertexes; i++ )
1409 	{
1410 		int j;
1411 		unsigned int pointFlags = 0;
1412 
1413 		R_TransformModelToClip( tess.xyz[i], tr.or.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );
1414 
1415 		for ( j = 0; j < 3; j++ )
1416 		{
1417 			if ( clip[j] >= clip[3] ) {
1418 				pointFlags |= ( 1 << ( j * 2 ) );
1419 			} else if ( clip[j] <= -clip[3] )   {
1420 				pointFlags |= ( 1 << ( j * 2 + 1 ) );
1421 			}
1422 		}
1423 		pointAnd &= pointFlags;
1424 		pointOr |= pointFlags;
1425 	}
1426 
1427 	// trivially reject
1428 	if ( pointAnd ) {
1429 		return qtrue;
1430 	}
1431 
1432 	// determine if this surface is backfaced and also determine the distance
1433 	// to the nearest vertex so we can cull based on portal range.  Culling
1434 	// based on vertex distance isn't 100% correct (we should be checking for
1435 	// range to the surface), but it's good enough for the types of portals
1436 	// we have in the game right now.
1437 	numTriangles = tess.numIndexes / 3;
1438 
1439 	for ( i = 0; i < tess.numIndexes; i += 3 )
1440 	{
1441 		vec3_t normal, tNormal;
1442 
1443 		float len;
1444 
1445 		VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.or.origin, normal );
1446 
1447 		len = VectorLengthSquared( normal );            // lose the sqrt
1448 		if ( len < shortest ) {
1449 			shortest = len;
1450 		}
1451 
1452 		R_VaoUnpackNormal(tNormal, tess.normal[tess.indexes[i]]);
1453 
1454 		if ( DotProduct( normal, tNormal ) >= 0 )
1455  		{
1456 			numTriangles--;
1457 		}
1458 	}
1459 	if ( !numTriangles ) {
1460 		return qtrue;
1461 	}
1462 
1463 	// mirrors can early out at this point, since we don't do a fade over distance
1464 	// with them (although we could)
1465 	if ( IsMirror( drawSurf, entityNum ) ) {
1466 		return qfalse;
1467 	}
1468 
1469 	if ( shortest > ( tess.shader->portalRange * tess.shader->portalRange ) ) {
1470 		return qtrue;
1471 	}
1472 
1473 	return qfalse;
1474 }
1475 
1476 /*
1477 ========================
1478 R_MirrorViewBySurface
1479 
1480 Returns qtrue if another view has been rendered
1481 ========================
1482 */
R_MirrorViewBySurface(drawSurf_t * drawSurf,int entityNum)1483 qboolean R_MirrorViewBySurface( drawSurf_t *drawSurf, int entityNum ) {
1484 	vec4_t clipDest[128];
1485 	viewParms_t newParms;
1486 	viewParms_t oldParms;
1487 	orientation_t surface, camera;
1488 
1489 	// don't recursively mirror
1490 	if ( tr.viewParms.isPortal ) {
1491 		ri.Printf( PRINT_DEVELOPER, "WARNING: recursive mirror/portal found\n" );
1492 		return qfalse;
1493 	}
1494 
1495 //	if ( r_noportals->integer || r_fastsky->integer || tr.levelGLFog) {
1496 	if ( r_noportals->integer || r_fastsky->integer ) {
1497 		return qfalse;
1498 	}
1499 
1500 	// trivially reject portal/mirror
1501 	if ( SurfIsOffscreen( drawSurf, clipDest ) ) {
1502 		return qfalse;
1503 	}
1504 
1505 	// save old viewParms so we can return to it after the mirror view
1506 	oldParms = tr.viewParms;
1507 
1508 	newParms = tr.viewParms;
1509 	newParms.isPortal = qtrue;
1510 	newParms.zFar = 0.0f;
1511 	newParms.flags &= ~VPF_FARPLANEFRUSTUM;
1512 	if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera,
1513 								   newParms.pvsOrigin, &newParms.isMirror ) ) {
1514 		return qfalse;      // bad portal, no portalentity
1515 	}
1516 
1517 	// Never draw viewmodels in portal or mirror views.
1518 	newParms.flags |= VPF_NOVIEWMODEL;
1519 
1520 	R_MirrorPoint( oldParms.or.origin, &surface, &camera, newParms.or.origin );
1521 
1522 	VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal );
1523 	newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal );
1524 
1525 	R_MirrorVector( oldParms.or.axis[0], &surface, &camera, newParms.or.axis[0] );
1526 	R_MirrorVector( oldParms.or.axis[1], &surface, &camera, newParms.or.axis[1] );
1527 	R_MirrorVector( oldParms.or.axis[2], &surface, &camera, newParms.or.axis[2] );
1528 
1529 	// OPTIMIZE: restrict the viewport on the mirrored view
1530 
1531 	// render the mirror view
1532 	R_RenderView( &newParms );
1533 
1534 	tr.viewParms = oldParms;
1535 
1536 	return qtrue;
1537 }
1538 
1539 /*
1540 =================
1541 R_SpriteFogNum
1542 
1543 See if a sprite is inside a fog volume
1544 =================
1545 */
R_SpriteFogNum(trRefEntity_t * ent)1546 int R_SpriteFogNum( trRefEntity_t *ent ) {
1547 	int i, j;
1548 	fog_t           *fog;
1549 
1550 	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
1551 		return 0;
1552 	}
1553 
1554 	if ( ent->e.renderfx & RF_CROSSHAIR ) {
1555 		return 0;
1556 	}
1557 
1558 	for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
1559 		fog = &tr.world->fogs[i];
1560 		for ( j = 0 ; j < 3 ; j++ ) {
1561 			if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) {
1562 				break;
1563 			}
1564 			if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) {
1565 				break;
1566 			}
1567 		}
1568 		if ( j == 3 ) {
1569 			return i;
1570 		}
1571 	}
1572 
1573 	return 0;
1574 }
1575 
1576 /*
1577 ==========================================================================================
1578 
1579 DRAWSURF SORTING
1580 
1581 ==========================================================================================
1582 */
1583 
1584 /*
1585 ===============
1586 R_Radix
1587 ===============
1588 */
R_Radix(int byte,int size,drawSurf_t * source,drawSurf_t * dest)1589 static ID_INLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest )
1590 {
1591   int           count[ 256 ] = { 0 };
1592   int           index[ 256 ];
1593   int           i;
1594   unsigned char *sortKey = NULL;
1595   unsigned char *end = NULL;
1596 
1597   sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
1598   end = sortKey + ( size * sizeof( drawSurf_t ) );
1599   for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) )
1600     ++count[ *sortKey ];
1601 
1602   index[ 0 ] = 0;
1603 
1604   for( i = 1; i < 256; ++i )
1605     index[ i ] = index[ i - 1 ] + count[ i - 1 ];
1606 
1607   sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
1608   for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) )
1609     dest[ index[ *sortKey ]++ ] = source[ i ];
1610 }
1611 
1612 /*
1613 ===============
1614 R_RadixSort
1615 
1616 Radix sort with 4 byte size buckets
1617 ===============
1618 */
R_RadixSort(drawSurf_t * source,int size)1619 static void R_RadixSort( drawSurf_t *source, int size )
1620 {
1621   static drawSurf_t scratch[ MAX_DRAWSURFS ];
1622 #ifdef Q3_LITTLE_ENDIAN
1623   R_Radix( 0, size, source, scratch );
1624   R_Radix( 1, size, scratch, source );
1625   R_Radix( 2, size, source, scratch );
1626   R_Radix( 3, size, scratch, source );
1627 #else
1628   R_Radix( 3, size, source, scratch );
1629   R_Radix( 2, size, scratch, source );
1630   R_Radix( 1, size, source, scratch );
1631   R_Radix( 0, size, scratch, source );
1632 #endif //Q3_LITTLE_ENDIAN
1633 }
1634 
1635 //==========================================================================================
1636 
1637 /*
1638 =================
1639 R_AddDrawSurf
1640 =================
1641 */
R_AddDrawSurf(surfaceType_t * surface,shader_t * shader,int fogIndex,int dlightMap,int pshadowMap,int cubemap)1642 void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
1643 			int fogIndex, int dlightMap, int pshadowMap, int cubemap ) {
1644 	int index;
1645 
1646 	// instead of checking for overflow, we just mask the index
1647 	// so it wraps around
1648 	index = tr.refdef.numDrawSurfs & DRAWSURF_MASK;
1649 	// the sort data is packed into a single 32 bit value so it can be
1650 	// compared quickly during the qsorting process
1651 	tr.refdef.drawSurfs[index].sort = ( shader->sortedIndex << QSORT_SHADERNUM_SHIFT )
1652 		| tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT )
1653 		| ((int)pshadowMap << QSORT_PSHADOW_SHIFT) | (int)dlightMap;
1654 	tr.refdef.drawSurfs[index].cubemapIndex = cubemap;
1655 	tr.refdef.drawSurfs[index].surface = surface;
1656 	tr.refdef.numDrawSurfs++;
1657 }
1658 
1659 /*
1660 =================
1661 R_DecomposeSort
1662 =================
1663 */
R_DecomposeSort(unsigned sort,int * entityNum,shader_t ** shader,int * fogNum,int * dlightMap,int * pshadowMap)1664 void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
1665 					int *fogNum, int *dlightMap, int *pshadowMap ) {
1666 	*fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31;
1667 	*shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & ( MAX_SHADERS - 1 ) ];
1668 //	*entityNum = ( sort >> QSORT_ENTITYNUM_SHIFT ) & ( MAX_GENTITIES - 1 );   // (SA) uppded entity count for Wolf to 11 bits
1669 	*entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK;
1670 	*pshadowMap = (sort >> QSORT_PSHADOW_SHIFT ) & 1;
1671 	*dlightMap = sort & 1;
1672 }
1673 
1674 /*
1675 =================
1676 R_SortDrawSurfs
1677 =================
1678 */
R_SortDrawSurfs(drawSurf_t * drawSurfs,int numDrawSurfs)1679 void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
1680 	shader_t        *shader;
1681 	int fogNum;
1682 	int entityNum;
1683 	int dlighted;
1684 	int             pshadowed;
1685 	int i;
1686 
1687 	//ri.Printf(PRINT_ALL, "firstDrawSurf %d numDrawSurfs %d\n", (int)(drawSurfs - tr.refdef.drawSurfs), numDrawSurfs);
1688 
1689 	// it is possible for some views to not have any surfaces
1690 	if ( numDrawSurfs < 1 ) {
1691 		// we still need to add it for hyperspace cases
1692 		R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
1693 		return;
1694 	}
1695 
1696 	// sort the drawsurfs by sort type, then orientation, then shader
1697 	R_RadixSort( drawSurfs, numDrawSurfs );
1698 
1699 	// skip pass through drawing if rendering a shadow map
1700 	if (tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW))
1701 	{
1702 		R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
1703 		return;
1704 	}
1705 
1706 	// check for any pass through drawing, which
1707 	// may cause another view to be rendered first
1708 	for ( i = 0 ; i < numDrawSurfs ; i++ ) {
1709 		R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted, &pshadowed );
1710 
1711 		if ( shader->sort > SS_PORTAL ) {
1712 			break;
1713 		}
1714 
1715 		// no shader should ever have this sort type
1716 		if ( shader->sort == SS_BAD ) {
1717 			ri.Error( ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name );
1718 		}
1719 
1720 		// if the mirror was completely clipped away, we may need to check another surface
1721 		if ( R_MirrorViewBySurface( ( drawSurfs + i ), entityNum ) ) {
1722 			// this is a debug option to see exactly what is being mirrored
1723 			if ( r_portalOnly->integer ) {
1724 				return;
1725 			}
1726 			break;      // only one mirror view at a time
1727 		}
1728 	}
1729 
1730 	R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
1731 }
1732 
1733 /*
1734 =============
1735 R_AddEntitySurfaces
1736 =============
1737 */
R_AddEntitySurface(int entityNum)1738 static void R_AddEntitySurface (int entityNum)
1739 {
1740 	trRefEntity_t   *ent;
1741 	shader_t        *shader;
1742 
1743 	tr.currentEntityNum = entityNum;
1744 
1745 	ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum];
1746 
1747 	ent->needDlights = qfalse;
1748 
1749 	// preshift the value we are going to OR into the drawsurf sort
1750 	tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
1751 
1752 	//
1753 	// the weapon model must be handled special --
1754 	// we don't want the hacked weapon position showing in
1755 	// mirrors, because the true body position will already be drawn
1756 	//
1757 	if ( (ent->e.renderfx & RF_FIRST_PERSON) && (tr.viewParms.flags & VPF_NOVIEWMODEL)) {
1758 		return;
1759 	}
1760 
1761 	// simple generated models, like sprites and beams, are not culled
1762 	switch ( ent->e.reType ) {
1763 	case RT_PORTALSURFACE:
1764 		break;      // don't draw anything
1765 	case RT_SPRITE:
1766 	case RT_SPLASH:
1767 	case RT_BEAM:
1768 	case RT_LIGHTNING:
1769 	case RT_RAIL_CORE:
1770 	case RT_RAIL_CORE_TAPER:
1771 	case RT_RAIL_RINGS:
1772 		// self blood sprites, talk balloons, etc should not be drawn in the primary
1773 		// view.  We can't just do this check for all entities, because md3
1774 		// entities may still want to cast shadows from them
1775 		if ( ( ent->e.renderfx & RF_THIRD_PERSON ) && !tr.viewParms.isPortal ) {
1776 				return;
1777 		}
1778 		shader = R_GetShaderByHandle( ent->e.customShader );
1779 		R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0, 0, 0 /*cubeMap*/ );
1780 		break;
1781 
1782 	case RT_MODEL:
1783 		// we must set up parts of tr.or for model culling
1784 		R_RotateForEntity( ent, &tr.viewParms, &tr.or );
1785 
1786 		tr.currentModel = R_GetModelByHandle( ent->e.hModel );
1787 		if ( !tr.currentModel ) {
1788 			R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 /*cubeMap*/  );
1789 		} else {
1790 			switch ( tr.currentModel->type ) {
1791 			case MOD_MESH:
1792 				R_AddMD3Surfaces( ent );
1793 				break;
1794 			case MOD_MDS:
1795 				R_AddAnimSurfaces( ent );
1796 				break;
1797 			case MOD_MDR:
1798 				R_MDRAddAnimSurfaces( ent );
1799 				break;
1800 			case MOD_IQM:
1801 				R_AddIQMSurfaces( ent );
1802 				break;
1803 			case MOD_BRUSH:
1804 				R_AddBrushModelSurfaces( ent );
1805 				break;
1806 			case MOD_BAD:       // null model axis
1807 				if ( ( ent->e.renderfx & RF_THIRD_PERSON ) && !tr.viewParms.isPortal ) {
1808 					break;
1809 				}
1810 				R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0, 0, 0 );
1811 				break;
1812 			default:
1813 				ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
1814 				break;
1815 			}
1816 		}
1817 		break;
1818 	default:
1819 		ri.Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" );
1820 	}
1821 }
1822 
1823 /*
1824 =============
1825 R_AddEntitySurfaces
1826 =============
1827 */
R_AddEntitySurfaces(void)1828 void R_AddEntitySurfaces (void) {
1829 	int i;
1830 
1831 	if ( !r_drawentities->integer ) {
1832 		return;
1833 	}
1834 
1835 	for ( i = 0; i < tr.refdef.num_entities; i++)
1836 		R_AddEntitySurface(i);
1837 }
1838 
1839 /*
1840 ====================
1841 R_GenerateDrawSurfs
1842 ====================
1843 */
R_GenerateDrawSurfs(void)1844 void R_GenerateDrawSurfs( void ) {
1845 	R_AddWorldSurfaces();
1846 
1847 	R_AddPolygonSurfaces();
1848 
1849 	// set the projection matrix with the minimum zfar
1850 	// now that we have the world bounded
1851 	// this needs to be done before entities are
1852 	// added, because they use the projection
1853 	// matrix for lod calculation
1854 
1855 	// dynamically compute far clip plane distance
1856 	if (!(tr.viewParms.flags & VPF_SHADOWMAP))
1857 	{
1858 		R_SetFarClip();
1859 	}
1860 
1861 	// we know the size of the clipping volume. Now set the rest of the projection matrix.
1862 	R_SetupProjectionZ (&tr.viewParms);
1863 
1864 	R_AddEntitySurfaces();
1865 }
1866 
1867 /*
1868 ================
1869 R_DebugPolygon
1870 ================
1871 */
R_DebugPolygon(int color,int numPoints,float * points)1872 void R_DebugPolygon( int color, int numPoints, float *points ) {
1873 	// FIXME: implement this
1874 #if 0
1875 	int i;
1876 
1877 	GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
1878 
1879 	// draw solid shade
1880 
1881 	qglColor3f( color & 1, ( color >> 1 ) & 1, ( color >> 2 ) & 1 );
1882 	qglBegin( GL_POLYGON );
1883 	for ( i = 0 ; i < numPoints ; i++ ) {
1884 		qglVertex3fv( points + i * 3 );
1885 	}
1886 	qglEnd();
1887 
1888 	// draw wireframe outline
1889 	GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
1890 	qglDepthRange( 0, 0 );
1891 	qglColor3f( 1, 1, 1 );
1892 	qglBegin( GL_POLYGON );
1893 	for ( i = 0 ; i < numPoints ; i++ ) {
1894 		qglVertex3fv( points + i * 3 );
1895 	}
1896 	qglEnd();
1897 	qglDepthRange( 0, 1 );
1898 #endif
1899 }
1900 
1901 /*
1902 ====================
1903 R_DebugGraphics
1904 
1905 Visualization aid for movement clipping debugging
1906 ====================
1907 */
R_DebugGraphics(void)1908 void R_DebugGraphics( void ) {
1909 	if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
1910 		return;
1911 	}
1912 	if ( !r_debugSurface->integer ) {
1913 		return;
1914 	}
1915 
1916 	R_IssuePendingRenderCommands();
1917 
1918 	GL_BindToTMU(tr.whiteImage, TB_COLORMAP);
1919 	GL_Cull( CT_FRONT_SIDED );
1920 	ri.CM_DrawDebugSurface( R_DebugPolygon );
1921 }
1922 
1923 
1924 /*
1925 ================
1926 R_RenderView
1927 
1928 A view may be either the actual camera view,
1929 or a mirror / remote location
1930 ================
1931 */
R_RenderView(viewParms_t * parms)1932 void R_RenderView( viewParms_t *parms ) {
1933 	int firstDrawSurf;
1934 	int numDrawSurfs;
1935 
1936 	if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
1937 		return;
1938 	}
1939 
1940 	tr.viewCount++;
1941 
1942 	tr.viewParms = *parms;
1943 	tr.viewParms.frameSceneNum = tr.frameSceneNum;
1944 	tr.viewParms.frameCount = tr.frameCount;
1945 
1946 	firstDrawSurf = tr.refdef.numDrawSurfs;
1947 
1948 	tr.viewCount++;
1949 
1950 	// set viewParms.world
1951 	R_RotateForViewer();
1952 
1953 	R_SetupProjection(&tr.viewParms, r_zproj->value, tr.viewParms.zFar, qtrue);
1954 
1955 	R_GenerateDrawSurfs();
1956 
1957 	// if we overflowed MAX_DRAWSURFS, the drawsurfs
1958 	// wrapped around in the buffer and we will be missing
1959 	// the first surfaces, not the last ones
1960 	numDrawSurfs = tr.refdef.numDrawSurfs;
1961 	if ( numDrawSurfs > MAX_DRAWSURFS ) {
1962 		numDrawSurfs = MAX_DRAWSURFS;
1963 	}
1964 
1965 	R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, numDrawSurfs - firstDrawSurf );
1966 
1967 	// draw main system development information (surface outlines, etc)
1968 	R_DebugGraphics();
1969 }
1970 
1971 
R_RenderDlightCubemaps(const refdef_t * fd)1972 void R_RenderDlightCubemaps(const refdef_t *fd)
1973 {
1974 	int i;
1975 
1976 	for (i = 0; i < tr.refdef.num_dlights; i++)
1977 	{
1978 		viewParms_t		shadowParms;
1979 		int j;
1980 
1981 		// use previous frame to determine visible dlights
1982 		if ((1 << i) & tr.refdef.dlightMask)
1983 			continue;
1984 
1985 		Com_Memset( &shadowParms, 0, sizeof( shadowParms ) );
1986 
1987 		shadowParms.viewportX = tr.refdef.x;
1988 		shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + PSHADOW_MAP_SIZE );
1989 		shadowParms.viewportWidth = PSHADOW_MAP_SIZE;
1990 		shadowParms.viewportHeight = PSHADOW_MAP_SIZE;
1991 		shadowParms.isPortal = qfalse;
1992 		shadowParms.isMirror = qtrue; // because it is
1993 
1994 		shadowParms.fovX = 90;
1995 		shadowParms.fovY = 90;
1996 
1997 		shadowParms.flags = VPF_SHADOWMAP | VPF_DEPTHSHADOW | VPF_NOVIEWMODEL;
1998 		shadowParms.zFar = tr.refdef.dlights[i].radius;
1999 
2000 		VectorCopy( tr.refdef.dlights[i].origin, shadowParms.or.origin );
2001 
2002 		for (j = 0; j < 6; j++)
2003 		{
2004 			switch(j)
2005 			{
2006 				case 0:
2007 					// -X
2008 					VectorSet( shadowParms.or.axis[0], -1,  0,  0);
2009 					VectorSet( shadowParms.or.axis[1],  0,  0, -1);
2010 					VectorSet( shadowParms.or.axis[2],  0,  1,  0);
2011 					break;
2012 				case 1:
2013 					// +X
2014 					VectorSet( shadowParms.or.axis[0],  1,  0,  0);
2015 					VectorSet( shadowParms.or.axis[1],  0,  0,  1);
2016 					VectorSet( shadowParms.or.axis[2],  0,  1,  0);
2017 					break;
2018 				case 2:
2019 					// -Y
2020 					VectorSet( shadowParms.or.axis[0],  0, -1,  0);
2021 					VectorSet( shadowParms.or.axis[1],  1,  0,  0);
2022 					VectorSet( shadowParms.or.axis[2],  0,  0, -1);
2023 					break;
2024 				case 3:
2025 					// +Y
2026 					VectorSet( shadowParms.or.axis[0],  0,  1,  0);
2027 					VectorSet( shadowParms.or.axis[1],  1,  0,  0);
2028 					VectorSet( shadowParms.or.axis[2],  0,  0,  1);
2029 					break;
2030 				case 4:
2031 					// -Z
2032 					VectorSet( shadowParms.or.axis[0],  0,  0, -1);
2033 					VectorSet( shadowParms.or.axis[1],  1,  0,  0);
2034 					VectorSet( shadowParms.or.axis[2],  0,  1,  0);
2035 					break;
2036 				case 5:
2037 					// +Z
2038 					VectorSet( shadowParms.or.axis[0],  0,  0,  1);
2039 					VectorSet( shadowParms.or.axis[1], -1,  0,  0);
2040 					VectorSet( shadowParms.or.axis[2],  0,  1,  0);
2041 					break;
2042 			}
2043 
2044 			R_RenderView(&shadowParms);
2045 			R_AddCapShadowmapCmd( i, j );
2046 		}
2047 	}
2048 }
2049 
2050 
R_RenderPshadowMaps(const refdef_t * fd)2051 void R_RenderPshadowMaps(const refdef_t *fd)
2052 {
2053 	viewParms_t		shadowParms;
2054 	int i;
2055 
2056 	// first, make a list of shadows
2057 	for ( i = 0; i < tr.refdef.num_entities; i++)
2058 	{
2059 		trRefEntity_t *ent = &tr.refdef.entities[i];
2060 
2061 		if((ent->e.renderfx & (RF_FIRST_PERSON | RF_NOSHADOW)))
2062 			continue;
2063 
2064 		//if((ent->e.renderfx & RF_THIRD_PERSON))
2065 			//continue;
2066 
2067 		if (ent->e.reType == RT_MODEL)
2068 		{
2069 			model_t *model = R_GetModelByHandle( ent->e.hModel );
2070 			pshadow_t shadow;
2071 			float radius = 0.0f;
2072 			float scale = 1.0f;
2073 			vec3_t diff;
2074 			int j;
2075 
2076 			if (!model)
2077 				continue;
2078 
2079 			if (ent->e.nonNormalizedAxes)
2080 			{
2081 				scale = VectorLength( ent->e.axis[0] );
2082 			}
2083 
2084 			switch (model->type)
2085 			{
2086 				case MOD_MESH:
2087 				{
2088 					mdvFrame_t *frame = &model->mdv[0]->frames[ent->e.frame];
2089 
2090 					radius = frame->radius * scale;
2091 				}
2092 				break;
2093 				case MOD_MDS:
2094 				{
2095 					mdsHeader_t *header = model->mds;
2096 					int frameSize = (size_t)( &((mdsFrame_t *)0)->bones[ header->numBones ] );
2097 					mdsFrame_t *frame = ( mdsFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
2098 
2099 					radius = frame->radius;
2100 				}
2101 				break;
2102 				case MOD_MDR:
2103 				{
2104 					// FIXME: never actually tested this
2105 					mdrHeader_t *header = model->modelData;
2106 					int frameSize = (size_t)( &((mdrFrame_t *)0)->bones[ header->numBones ] );
2107 					mdrFrame_t *frame = ( mdrFrame_t * ) ( ( byte * ) header + header->ofsFrames + frameSize * ent->e.frame);
2108 
2109 					radius = frame->radius;
2110 				}
2111 				break;
2112 				case MOD_IQM:
2113 				{
2114 					// FIXME: never actually tested this
2115 					iqmData_t *data = model->modelData;
2116 					vec3_t diag;
2117 					float *framebounds;
2118 
2119 					framebounds = data->bounds + 6*ent->e.frame;
2120 					VectorSubtract( framebounds+3, framebounds, diag );
2121 					radius = 0.5f * VectorLength( diag );
2122 				}
2123 				break;
2124 
2125 				default:
2126 					break;
2127 			}
2128 
2129 			if (!radius)
2130 				continue;
2131 
2132 			// Cull entities that are behind the viewer by more than lightRadius
2133 			VectorSubtract(ent->e.origin, fd->vieworg, diff);
2134 			if (DotProduct(diff, fd->viewaxis[0]) < -r_pshadowDist->value)
2135 				continue;
2136 
2137 			memset(&shadow, 0, sizeof(shadow));
2138 
2139 			shadow.numEntities = 1;
2140 			shadow.entityNums[0] = i;
2141 			shadow.viewRadius = radius;
2142 			shadow.lightRadius = r_pshadowDist->value;
2143 			VectorCopy(ent->e.origin, shadow.viewOrigin);
2144 			shadow.sort = DotProduct(diff, diff) / (radius * radius);
2145 			VectorCopy(ent->e.origin, shadow.entityOrigins[0]);
2146 			shadow.entityRadiuses[0] = radius;
2147 
2148 			for (j = 0; j < MAX_CALC_PSHADOWS; j++)
2149 			{
2150 				pshadow_t swap;
2151 
2152 				if (j + 1 > tr.refdef.num_pshadows)
2153 				{
2154 					tr.refdef.num_pshadows = j + 1;
2155 					tr.refdef.pshadows[j] = shadow;
2156 					break;
2157 				}
2158 
2159 				// sort shadows by distance from camera divided by radius
2160 				// FIXME: sort better
2161 				if (tr.refdef.pshadows[j].sort <= shadow.sort)
2162 					continue;
2163 
2164 				swap = tr.refdef.pshadows[j];
2165 				tr.refdef.pshadows[j] = shadow;
2166 				shadow = swap;
2167 			}
2168 		}
2169 	}
2170 
2171 	// next, merge touching pshadows
2172 	for ( i = 0; i < tr.refdef.num_pshadows; i++)
2173 	{
2174 		pshadow_t *ps1 = &tr.refdef.pshadows[i];
2175 		int j;
2176 
2177 		for (j = i + 1; j < tr.refdef.num_pshadows; j++)
2178 		{
2179 			pshadow_t *ps2 = &tr.refdef.pshadows[j];
2180 			int k;
2181 			qboolean touch;
2182 
2183 			if (ps1->numEntities == 8)
2184 				break;
2185 
2186 			touch = qfalse;
2187 			if (SpheresIntersect(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius))
2188 			{
2189 				for (k = 0; k < ps1->numEntities; k++)
2190 				{
2191 					if (SpheresIntersect(ps1->entityOrigins[k], ps1->entityRadiuses[k], ps2->viewOrigin, ps2->viewRadius))
2192 					{
2193 						touch = qtrue;
2194 						break;
2195 					}
2196 				}
2197 			}
2198 
2199 			if (touch)
2200 			{
2201 				vec3_t newOrigin;
2202 				float newRadius;
2203 
2204 				BoundingSphereOfSpheres(ps1->viewOrigin, ps1->viewRadius, ps2->viewOrigin, ps2->viewRadius, newOrigin, &newRadius);
2205 				VectorCopy(newOrigin, ps1->viewOrigin);
2206 				ps1->viewRadius = newRadius;
2207 
2208 				ps1->entityNums[ps1->numEntities] = ps2->entityNums[0];
2209 				VectorCopy(ps2->viewOrigin, ps1->entityOrigins[ps1->numEntities]);
2210 				ps1->entityRadiuses[ps1->numEntities] = ps2->viewRadius;
2211 
2212 				ps1->numEntities++;
2213 
2214 				for (k = j; k < tr.refdef.num_pshadows - 1; k++)
2215 				{
2216 					tr.refdef.pshadows[k] = tr.refdef.pshadows[k + 1];
2217 				}
2218 
2219 				j--;
2220 				tr.refdef.num_pshadows--;
2221 			}
2222 		}
2223 	}
2224 
2225 	// cap number of drawn pshadows
2226 	if (tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS)
2227 	{
2228 		tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS;
2229 	}
2230 
2231 	// next, fill up the rest of the shadow info
2232 	for ( i = 0; i < tr.refdef.num_pshadows; i++)
2233 	{
2234 		pshadow_t *shadow = &tr.refdef.pshadows[i];
2235 		vec3_t up;
2236 		vec3_t ambientLight, directedLight, lightDir;
2237 
2238 		VectorSet(lightDir, 0.57735f, 0.57735f, 0.57735f);
2239 #if 1
2240 		R_LightForPoint(shadow->viewOrigin, ambientLight, directedLight, lightDir);
2241 
2242 		// sometimes there's no light
2243 		if (DotProduct(lightDir, lightDir) < 0.9f)
2244 			VectorSet(lightDir, 0.0f, 0.0f, 1.0f);
2245 #endif
2246 
2247 		if (shadow->viewRadius * 3.0f > shadow->lightRadius)
2248 		{
2249 			shadow->lightRadius = shadow->viewRadius * 3.0f;
2250 		}
2251 
2252 		VectorMA(shadow->viewOrigin, shadow->viewRadius, lightDir, shadow->lightOrigin);
2253 
2254 		// make up a projection, up doesn't matter
2255 		VectorScale(lightDir, -1.0f, shadow->lightViewAxis[0]);
2256 		VectorSet(up, 0, 0, -1);
2257 
2258 		if ( fabs(DotProduct(up, shadow->lightViewAxis[0])) > 0.9f )
2259 		{
2260 			VectorSet(up, -1, 0, 0);
2261 		}
2262 
2263 		CrossProduct(shadow->lightViewAxis[0], up, shadow->lightViewAxis[1]);
2264 		VectorNormalize(shadow->lightViewAxis[1]);
2265 		CrossProduct(shadow->lightViewAxis[0], shadow->lightViewAxis[1], shadow->lightViewAxis[2]);
2266 
2267 		VectorCopy(shadow->lightViewAxis[0], shadow->cullPlane.normal);
2268 		shadow->cullPlane.dist = DotProduct(shadow->cullPlane.normal, shadow->lightOrigin);
2269 		shadow->cullPlane.type = PLANE_NON_AXIAL;
2270 		SetPlaneSignbits(&shadow->cullPlane);
2271 	}
2272 
2273 	// next, render shadowmaps
2274 	for ( i = 0; i < tr.refdef.num_pshadows; i++)
2275 	{
2276 		int firstDrawSurf;
2277 		pshadow_t *shadow = &tr.refdef.pshadows[i];
2278 		int j;
2279 
2280 		Com_Memset( &shadowParms, 0, sizeof( shadowParms ) );
2281 
2282 		if (glRefConfig.framebufferObject)
2283 		{
2284 			shadowParms.viewportX = 0;
2285 			shadowParms.viewportY = 0;
2286 		}
2287 		else
2288 		{
2289 			shadowParms.viewportX = tr.refdef.x;
2290 			shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + PSHADOW_MAP_SIZE );
2291 		}
2292 		shadowParms.viewportWidth = PSHADOW_MAP_SIZE;
2293 		shadowParms.viewportHeight = PSHADOW_MAP_SIZE;
2294 		shadowParms.isPortal = qfalse;
2295 		shadowParms.isMirror = qfalse;
2296 
2297 		shadowParms.fovX = 90;
2298 		shadowParms.fovY = 90;
2299 
2300 		if (glRefConfig.framebufferObject)
2301 			shadowParms.targetFbo = tr.pshadowFbos[i];
2302 
2303 		shadowParms.flags = VPF_DEPTHSHADOW | VPF_NOVIEWMODEL;
2304 		shadowParms.zFar = shadow->lightRadius;
2305 
2306 		VectorCopy(shadow->lightOrigin, shadowParms.or.origin);
2307 
2308 		VectorCopy(shadow->lightViewAxis[0], shadowParms.or.axis[0]);
2309 		VectorCopy(shadow->lightViewAxis[1], shadowParms.or.axis[1]);
2310 		VectorCopy(shadow->lightViewAxis[2], shadowParms.or.axis[2]);
2311 
2312 		{
2313 			tr.viewCount++;
2314 
2315 			tr.viewParms = shadowParms;
2316 			tr.viewParms.frameSceneNum = tr.frameSceneNum;
2317 			tr.viewParms.frameCount = tr.frameCount;
2318 
2319 			firstDrawSurf = tr.refdef.numDrawSurfs;
2320 
2321 			tr.viewCount++;
2322 
2323 			// set viewParms.world
2324 			R_RotateForViewer ();
2325 
2326 			{
2327 				float xmin, xmax, ymin, ymax, znear, zfar;
2328 				viewParms_t *dest = &tr.viewParms;
2329 				vec3_t pop;
2330 
2331 				xmin = ymin = -shadow->viewRadius;
2332 				xmax = ymax = shadow->viewRadius;
2333 				znear = 0;
2334 				zfar = shadow->lightRadius;
2335 
2336 				dest->projectionMatrix[0] = 2 / (xmax - xmin);
2337 				dest->projectionMatrix[4] = 0;
2338 				dest->projectionMatrix[8] = (xmax + xmin) / (xmax - xmin);
2339 				dest->projectionMatrix[12] =0;
2340 
2341 				dest->projectionMatrix[1] = 0;
2342 				dest->projectionMatrix[5] = 2 / (ymax - ymin);
2343 				dest->projectionMatrix[9] = ( ymax + ymin ) / (ymax - ymin);	// normally 0
2344 				dest->projectionMatrix[13] = 0;
2345 
2346 				dest->projectionMatrix[2] = 0;
2347 				dest->projectionMatrix[6] = 0;
2348 				dest->projectionMatrix[10] = 2 / (zfar - znear);
2349 				dest->projectionMatrix[14] = 0;
2350 
2351 				dest->projectionMatrix[3] = 0;
2352 				dest->projectionMatrix[7] = 0;
2353 				dest->projectionMatrix[11] = 0;
2354 				dest->projectionMatrix[15] = 1;
2355 
2356 				VectorScale(dest->or.axis[1],  1.0f, dest->frustum[0].normal);
2357 				VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[0].normal, pop);
2358 				dest->frustum[0].dist = DotProduct(pop, dest->frustum[0].normal);
2359 
2360 				VectorScale(dest->or.axis[1], -1.0f, dest->frustum[1].normal);
2361 				VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[1].normal, pop);
2362 				dest->frustum[1].dist = DotProduct(pop, dest->frustum[1].normal);
2363 
2364 				VectorScale(dest->or.axis[2],  1.0f, dest->frustum[2].normal);
2365 				VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[2].normal, pop);
2366 				dest->frustum[2].dist = DotProduct(pop, dest->frustum[2].normal);
2367 
2368 				VectorScale(dest->or.axis[2], -1.0f, dest->frustum[3].normal);
2369 				VectorMA(dest->or.origin, -shadow->viewRadius, dest->frustum[3].normal, pop);
2370 				dest->frustum[3].dist = DotProduct(pop, dest->frustum[3].normal);
2371 
2372 				VectorScale(dest->or.axis[0], -1.0f, dest->frustum[4].normal);
2373 				VectorMA(dest->or.origin, -shadow->lightRadius, dest->frustum[4].normal, pop);
2374 				dest->frustum[4].dist = DotProduct(pop, dest->frustum[4].normal);
2375 
2376 				for (j = 0; j < 5; j++)
2377 				{
2378 					dest->frustum[j].type = PLANE_NON_AXIAL;
2379 					SetPlaneSignbits (&dest->frustum[j]);
2380 				}
2381 
2382 				dest->flags |= VPF_FARPLANEFRUSTUM;
2383 			}
2384 
2385 			for (j = 0; j < shadow->numEntities; j++)
2386 			{
2387 				R_AddEntitySurface(shadow->entityNums[j]);
2388 			}
2389 
2390 			R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
2391 
2392 			if (!glRefConfig.framebufferObject)
2393 				R_AddCapShadowmapCmd( i, -1 );
2394 		}
2395 	}
2396 }
2397 
CalcSplit(float n,float f,float i,float m)2398 static float CalcSplit(float n, float f, float i, float m)
2399 {
2400 	return (n * pow(f / n, i / m) + (f - n) * i / m) / 2.0f;
2401 }
2402 
2403 
R_RenderSunShadowMaps(const refdef_t * fd,int level)2404 void R_RenderSunShadowMaps(const refdef_t *fd, int level)
2405 {
2406 	viewParms_t		shadowParms;
2407 	vec4_t lightDir, lightCol;
2408 	vec3_t lightViewAxis[3];
2409 	vec3_t lightOrigin;
2410 	float splitZNear, splitZFar, splitBias;
2411 	float viewZNear, viewZFar;
2412 	vec3_t lightviewBounds[2];
2413 	qboolean lightViewIndependentOfCameraView = qfalse;
2414 
2415 	if (r_forceSun->integer == 2)
2416 	{
2417 		int scale = 32768;
2418 		float angle = (fd->time % scale) / (float)scale * M_PI;
2419 		lightDir[0] = cos(angle);
2420 		lightDir[1] = sin(35.0f * M_PI / 180.0f);
2421 		lightDir[2] = sin(angle) * cos(35.0f * M_PI / 180.0f);
2422 		lightDir[3] = 0.0f;
2423 
2424 		if (1) //((fd->time % (scale * 2)) < scale)
2425 		{
2426 			lightCol[0] =
2427 			lightCol[1] =
2428 			lightCol[2] = CLAMP(sin(angle) * 2.0f, 0.0f, 1.0f) * 2.0f;
2429 			lightCol[3] = 1.0f;
2430 		}
2431 		else
2432 		{
2433 			lightCol[0] =
2434 			lightCol[1] =
2435 			lightCol[2] = CLAMP(sin(angle) * 2.0f * 0.1f, 0.0f, 0.1f);
2436 			lightCol[3] = 1.0f;
2437 		}
2438 
2439 		VectorCopy4(lightDir, tr.refdef.sunDir);
2440 		VectorCopy4(lightCol, tr.refdef.sunCol);
2441 		VectorScale4(lightCol, 0.2f, tr.refdef.sunAmbCol);
2442 	}
2443 	else
2444 	{
2445 		VectorCopy4(tr.refdef.sunDir, lightDir);
2446 	}
2447 
2448 	viewZNear = r_shadowCascadeZNear->value;
2449 	viewZFar = r_shadowCascadeZFar->value;
2450 	splitBias = r_shadowCascadeZBias->value;
2451 
2452 	switch(level)
2453 	{
2454 		case 0:
2455 		default:
2456 			//splitZNear = r_znear->value;
2457 			//splitZFar  = 256;
2458 			splitZNear = viewZNear;
2459 			splitZFar = CalcSplit(viewZNear, viewZFar, 1, 3) + splitBias;
2460 			break;
2461 		case 1:
2462 			splitZNear = CalcSplit(viewZNear, viewZFar, 1, 3) + splitBias;
2463 			splitZFar = CalcSplit(viewZNear, viewZFar, 2, 3) + splitBias;
2464 			//splitZNear = 256;
2465 			//splitZFar  = 896;
2466 			break;
2467 		case 2:
2468 			splitZNear = CalcSplit(viewZNear, viewZFar, 2, 3) + splitBias;
2469 			splitZFar = viewZFar;
2470 			//splitZNear = 896;
2471 			//splitZFar  = 3072;
2472 			break;
2473 	}
2474 
2475 	if (level != 3)
2476 		VectorCopy(fd->vieworg, lightOrigin);
2477 	else
2478 		VectorCopy(tr.world->lightGridOrigin, lightOrigin);
2479 
2480 	// Make up a projection
2481 	VectorScale(lightDir, -1.0f, lightViewAxis[0]);
2482 
2483 	if (level == 3 || lightViewIndependentOfCameraView)
2484 	{
2485 		// Use world up as light view up
2486 		VectorSet(lightViewAxis[2], 0, 0, 1);
2487 	}
2488 	else if (level == 0)
2489 	{
2490 		// Level 0 tries to use a diamond texture orientation relative to camera view
2491 		// Use halfway between camera view forward and left for light view up
2492 		VectorAdd(fd->viewaxis[0], fd->viewaxis[1], lightViewAxis[2]);
2493 	}
2494 	else
2495 	{
2496 		// Use camera view up as light view up
2497 		VectorCopy(fd->viewaxis[2], lightViewAxis[2]);
2498 	}
2499 
2500 	// Check if too close to parallel to light direction
2501 	if (fabs(DotProduct(lightViewAxis[2], lightViewAxis[0])) > 0.9f)
2502 	{
2503 		if (level == 3 || lightViewIndependentOfCameraView)
2504 		{
2505 			// Use world left as light view up
2506 			VectorSet(lightViewAxis[2], 0, 1, 0);
2507 		}
2508 		else if (level == 0)
2509 		{
2510 			// Level 0 tries to use a diamond texture orientation relative to camera view
2511 			// Use halfway between camera view forward and up for light view up
2512 			VectorAdd(fd->viewaxis[0], fd->viewaxis[2], lightViewAxis[2]);
2513 		}
2514 		else
2515 		{
2516 			// Use camera view left as light view up
2517 			VectorCopy(fd->viewaxis[1], lightViewAxis[2]);
2518 		}
2519 	}
2520 
2521 	// clean axes
2522 	CrossProduct(lightViewAxis[2], lightViewAxis[0], lightViewAxis[1]);
2523 	VectorNormalize(lightViewAxis[1]);
2524 	CrossProduct(lightViewAxis[0], lightViewAxis[1], lightViewAxis[2]);
2525 
2526 	// Create bounds for light projection using slice of view projection
2527 	{
2528 		mat4_t lightViewMatrix;
2529 		vec4_t point, base, lightViewPoint;
2530 		float lx, ly;
2531 
2532 		base[3] = 1;
2533 		point[3] = 1;
2534 		lightViewPoint[3] = 1;
2535 
2536 		Mat4View(lightViewAxis, lightOrigin, lightViewMatrix);
2537 
2538 		ClearBounds(lightviewBounds[0], lightviewBounds[1]);
2539 
2540 		if (level != 3)
2541 		{
2542 			// add view near plane
2543 			lx = splitZNear * tan(fd->fov_x * M_PI / 360.0f);
2544 			ly = splitZNear * tan(fd->fov_y * M_PI / 360.0f);
2545 			VectorMA(fd->vieworg, splitZNear, fd->viewaxis[0], base);
2546 
2547 			VectorMA(base,   lx, fd->viewaxis[1], point);
2548 			VectorMA(point,  ly, fd->viewaxis[2], point);
2549 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2550 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2551 
2552 			VectorMA(base,  -lx, fd->viewaxis[1], point);
2553 			VectorMA(point,  ly, fd->viewaxis[2], point);
2554 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2555 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2556 
2557 			VectorMA(base,   lx, fd->viewaxis[1], point);
2558 			VectorMA(point, -ly, fd->viewaxis[2], point);
2559 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2560 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2561 
2562 			VectorMA(base,  -lx, fd->viewaxis[1], point);
2563 			VectorMA(point, -ly, fd->viewaxis[2], point);
2564 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2565 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2566 
2567 			// add view far plane
2568 			lx = splitZFar * tan(fd->fov_x * M_PI / 360.0f);
2569 			ly = splitZFar * tan(fd->fov_y * M_PI / 360.0f);
2570 			VectorMA(fd->vieworg, splitZFar, fd->viewaxis[0], base);
2571 
2572 			VectorMA(base,   lx, fd->viewaxis[1], point);
2573 			VectorMA(point,  ly, fd->viewaxis[2], point);
2574 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2575 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2576 
2577 			VectorMA(base,  -lx, fd->viewaxis[1], point);
2578 			VectorMA(point,  ly, fd->viewaxis[2], point);
2579 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2580 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2581 
2582 			VectorMA(base,   lx, fd->viewaxis[1], point);
2583 			VectorMA(point, -ly, fd->viewaxis[2], point);
2584 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2585 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2586 
2587 			VectorMA(base,  -lx, fd->viewaxis[1], point);
2588 			VectorMA(point, -ly, fd->viewaxis[2], point);
2589 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2590 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2591 		}
2592 		else
2593 		{
2594 			// use light grid size as level size
2595 			// FIXME: could be tighter
2596 			vec3_t bounds;
2597 
2598 			bounds[0] = tr.world->lightGridSize[0] * tr.world->lightGridBounds[0];
2599 			bounds[1] = tr.world->lightGridSize[1] * tr.world->lightGridBounds[1];
2600 			bounds[2] = tr.world->lightGridSize[2] * tr.world->lightGridBounds[2];
2601 
2602 			point[0] = tr.world->lightGridOrigin[0];
2603 			point[1] = tr.world->lightGridOrigin[1];
2604 			point[2] = tr.world->lightGridOrigin[2];
2605 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2606 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2607 
2608 			point[0] = tr.world->lightGridOrigin[0] + bounds[0];
2609 			point[1] = tr.world->lightGridOrigin[1];
2610 			point[2] = tr.world->lightGridOrigin[2];
2611 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2612 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2613 
2614 			point[0] = tr.world->lightGridOrigin[0];
2615 			point[1] = tr.world->lightGridOrigin[1] + bounds[1];
2616 			point[2] = tr.world->lightGridOrigin[2];
2617 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2618 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2619 
2620 			point[0] = tr.world->lightGridOrigin[0] + bounds[0];
2621 			point[1] = tr.world->lightGridOrigin[1] + bounds[1];
2622 			point[2] = tr.world->lightGridOrigin[2];
2623 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2624 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2625 
2626 			point[0] = tr.world->lightGridOrigin[0];
2627 			point[1] = tr.world->lightGridOrigin[1];
2628 			point[2] = tr.world->lightGridOrigin[2] + bounds[2];
2629 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2630 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2631 
2632 			point[0] = tr.world->lightGridOrigin[0] + bounds[0];
2633 			point[1] = tr.world->lightGridOrigin[1];
2634 			point[2] = tr.world->lightGridOrigin[2] + bounds[2];
2635 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2636 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2637 
2638 			point[0] = tr.world->lightGridOrigin[0];
2639 			point[1] = tr.world->lightGridOrigin[1] + bounds[1];
2640 			point[2] = tr.world->lightGridOrigin[2] + bounds[2];
2641 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2642 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2643 
2644 			point[0] = tr.world->lightGridOrigin[0] + bounds[0];
2645 			point[1] = tr.world->lightGridOrigin[1] + bounds[1];
2646 			point[2] = tr.world->lightGridOrigin[2] + bounds[2];
2647 			Mat4Transform(lightViewMatrix, point, lightViewPoint);
2648 			AddPointToBounds(lightViewPoint, lightviewBounds[0], lightviewBounds[1]);
2649 		}
2650 
2651 		if (!glRefConfig.depthClamp)
2652 			lightviewBounds[0][0] = lightviewBounds[1][0] - 8192;
2653 
2654 		// Moving the Light in Texel-Sized Increments
2655 		// from http://msdn.microsoft.com/en-us/library/windows/desktop/ee416324%28v=vs.85%29.aspx
2656 		//
2657 		if (lightViewIndependentOfCameraView)
2658 		{
2659 			float cascadeBound, worldUnitsPerTexel, invWorldUnitsPerTexel;
2660 
2661 			cascadeBound = MAX(lightviewBounds[1][0] - lightviewBounds[0][0], lightviewBounds[1][1] - lightviewBounds[0][1]);
2662 			cascadeBound = MAX(cascadeBound, lightviewBounds[1][2] - lightviewBounds[0][2]);
2663 			worldUnitsPerTexel = cascadeBound / tr.sunShadowFbo[level]->width;
2664 			invWorldUnitsPerTexel = 1.0f / worldUnitsPerTexel;
2665 
2666 			VectorScale(lightviewBounds[0], invWorldUnitsPerTexel, lightviewBounds[0]);
2667 			lightviewBounds[0][0] = floor(lightviewBounds[0][0]);
2668 			lightviewBounds[0][1] = floor(lightviewBounds[0][1]);
2669 			lightviewBounds[0][2] = floor(lightviewBounds[0][2]);
2670 			VectorScale(lightviewBounds[0], worldUnitsPerTexel, lightviewBounds[0]);
2671 
2672 			VectorScale(lightviewBounds[1], invWorldUnitsPerTexel, lightviewBounds[1]);
2673 			lightviewBounds[1][0] = floor(lightviewBounds[1][0]);
2674 			lightviewBounds[1][1] = floor(lightviewBounds[1][1]);
2675 			lightviewBounds[1][2] = floor(lightviewBounds[1][2]);
2676 			VectorScale(lightviewBounds[1], worldUnitsPerTexel, lightviewBounds[1]);
2677 		}
2678 
2679 		//ri.Printf(PRINT_ALL, "level %d znear %f zfar %f\n", level, lightviewBounds[0][0], lightviewBounds[1][0]);
2680 		//ri.Printf(PRINT_ALL, "xmin %f xmax %f ymin %f ymax %f\n", lightviewBounds[0][1], lightviewBounds[1][1], -lightviewBounds[1][2], -lightviewBounds[0][2]);
2681 	}
2682 
2683 
2684 	{
2685 		int firstDrawSurf;
2686 
2687 		Com_Memset( &shadowParms, 0, sizeof( shadowParms ) );
2688 
2689 		if (glRefConfig.framebufferObject)
2690 		{
2691 			shadowParms.viewportX = 0;
2692 			shadowParms.viewportY = 0;
2693 		}
2694 		else
2695 		{
2696 			shadowParms.viewportX = tr.refdef.x;
2697 			shadowParms.viewportY = glConfig.vidHeight - ( tr.refdef.y + tr.sunShadowFbo[level]->height );
2698 		}
2699 		shadowParms.viewportWidth  = tr.sunShadowFbo[level]->width;
2700 		shadowParms.viewportHeight = tr.sunShadowFbo[level]->height;
2701 		shadowParms.isPortal = qfalse;
2702 		shadowParms.isMirror = qfalse;
2703 
2704 		shadowParms.fovX = 90;
2705 		shadowParms.fovY = 90;
2706 
2707 		if (glRefConfig.framebufferObject)
2708 			shadowParms.targetFbo = tr.sunShadowFbo[level];
2709 
2710 		shadowParms.flags = VPF_DEPTHSHADOW | VPF_DEPTHCLAMP | VPF_ORTHOGRAPHIC | VPF_NOVIEWMODEL;
2711 		shadowParms.zFar = lightviewBounds[1][0];
2712 
2713 		VectorCopy(lightOrigin, shadowParms.or.origin);
2714 
2715 		VectorCopy(lightViewAxis[0], shadowParms.or.axis[0]);
2716 		VectorCopy(lightViewAxis[1], shadowParms.or.axis[1]);
2717 		VectorCopy(lightViewAxis[2], shadowParms.or.axis[2]);
2718 
2719 		VectorCopy(lightOrigin, shadowParms.pvsOrigin );
2720 
2721 		{
2722 			tr.viewCount++;
2723 
2724 			tr.viewParms = shadowParms;
2725 			tr.viewParms.frameSceneNum = tr.frameSceneNum;
2726 			tr.viewParms.frameCount = tr.frameCount;
2727 
2728 			firstDrawSurf = tr.refdef.numDrawSurfs;
2729 
2730 			tr.viewCount++;
2731 
2732 			// set viewParms.world
2733 			R_RotateForViewer ();
2734 
2735 			R_SetupProjectionOrtho(&tr.viewParms, lightviewBounds);
2736 
2737 			R_AddWorldSurfaces ();
2738 
2739 			R_AddPolygonSurfaces();
2740 
2741 			R_AddEntitySurfaces ();
2742 
2743 			R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
2744 		}
2745 
2746 		Mat4Multiply(tr.viewParms.projectionMatrix, tr.viewParms.world.modelMatrix, tr.refdef.sunShadowMvp[level]);
2747 	}
2748 }
2749 
R_RenderCubemapSide(int cubemapIndex,int cubemapSide,qboolean subscene)2750 void R_RenderCubemapSide( int cubemapIndex, int cubemapSide, qboolean subscene )
2751 {
2752 	refdef_t refdef;
2753 	viewParms_t	parms;
2754 
2755 	memset( &refdef, 0, sizeof( refdef ) );
2756 	refdef.rdflags = 0;
2757 	VectorCopy(tr.cubemaps[cubemapIndex].origin, refdef.vieworg);
2758 
2759 	switch(cubemapSide)
2760 	{
2761 		case 0:
2762 			// -X
2763 			VectorSet( refdef.viewaxis[0], -1,  0,  0);
2764 			VectorSet( refdef.viewaxis[1],  0,  0, -1);
2765 			VectorSet( refdef.viewaxis[2],  0,  1,  0);
2766 			break;
2767 		case 1:
2768 			// +X
2769 			VectorSet( refdef.viewaxis[0],  1,  0,  0);
2770 			VectorSet( refdef.viewaxis[1],  0,  0,  1);
2771 			VectorSet( refdef.viewaxis[2],  0,  1,  0);
2772 			break;
2773 		case 2:
2774 			// -Y
2775 			VectorSet( refdef.viewaxis[0],  0, -1,  0);
2776 			VectorSet( refdef.viewaxis[1],  1,  0,  0);
2777 			VectorSet( refdef.viewaxis[2],  0,  0, -1);
2778 			break;
2779 		case 3:
2780 			// +Y
2781 			VectorSet( refdef.viewaxis[0],  0,  1,  0);
2782 			VectorSet( refdef.viewaxis[1],  1,  0,  0);
2783 			VectorSet( refdef.viewaxis[2],  0,  0,  1);
2784 			break;
2785 		case 4:
2786 			// -Z
2787 			VectorSet( refdef.viewaxis[0],  0,  0, -1);
2788 			VectorSet( refdef.viewaxis[1],  1,  0,  0);
2789 			VectorSet( refdef.viewaxis[2],  0,  1,  0);
2790 			break;
2791 		case 5:
2792 			// +Z
2793 			VectorSet( refdef.viewaxis[0],  0,  0,  1);
2794 			VectorSet( refdef.viewaxis[1], -1,  0,  0);
2795 			VectorSet( refdef.viewaxis[2],  0,  1,  0);
2796 			break;
2797 	}
2798 
2799 	refdef.fov_x = 90;
2800 	refdef.fov_y = 90;
2801 
2802 	refdef.x = 0;
2803 	refdef.y = 0;
2804 	refdef.width = tr.renderCubeFbo->width;
2805 	refdef.height = tr.renderCubeFbo->height;
2806 
2807 	refdef.time = 0;
2808 
2809 	if (!subscene)
2810 	{
2811 		RE_BeginScene(&refdef);
2812 
2813 		// FIXME: sun shadows aren't rendered correctly in cubemaps
2814 		// fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first
2815 		if(0) //(glRefConfig.framebufferObject && r_sunlightMode->integer && (r_forceSun->integer || tr.sunShadows))
2816 		{
2817 			R_RenderSunShadowMaps(&refdef, 0);
2818 			R_RenderSunShadowMaps(&refdef, 1);
2819 			R_RenderSunShadowMaps(&refdef, 2);
2820 			R_RenderSunShadowMaps(&refdef, 3);
2821 		}
2822 	}
2823 
2824 	{
2825 		vec3_t ambient, directed, lightDir;
2826 		float scale;
2827 
2828 		R_LightForPoint(tr.refdef.vieworg, ambient, directed, lightDir);
2829 		scale = directed[0] + directed[1] + directed[2] + ambient[0] + ambient[1] + ambient[2] + 1.0f;
2830 
2831 		// only print message for first side
2832 		if (scale < 1.0001f && cubemapSide == 0)
2833 		{
2834 			ri.Printf(PRINT_ALL, "cubemap %d %s (%f, %f, %f) is outside the lightgrid or inside a wall!\n", cubemapIndex, tr.cubemaps[cubemapIndex].name, tr.refdef.vieworg[0], tr.refdef.vieworg[1], tr.refdef.vieworg[2]);
2835 		}
2836 	}
2837 
2838 	Com_Memset( &parms, 0, sizeof( parms ) );
2839 
2840 	parms.viewportX = 0;
2841 	parms.viewportY = 0;
2842 	parms.viewportWidth = tr.renderCubeFbo->width;
2843 	parms.viewportHeight = tr.renderCubeFbo->height;
2844 	parms.isPortal = qfalse;
2845 	parms.isMirror = qtrue;
2846 	parms.flags =  VPF_NOVIEWMODEL | VPF_NOCUBEMAPS;
2847 
2848 	parms.fovX = 90;
2849 	parms.fovY = 90;
2850 
2851 	VectorCopy( refdef.vieworg, parms.or.origin );
2852 	VectorCopy( refdef.viewaxis[0], parms.or.axis[0] );
2853 	VectorCopy( refdef.viewaxis[1], parms.or.axis[1] );
2854 	VectorCopy( refdef.viewaxis[2], parms.or.axis[2] );
2855 
2856 	VectorCopy( refdef.vieworg, parms.pvsOrigin );
2857 
2858 	// FIXME: sun shadows aren't rendered correctly in cubemaps
2859 	// fix involves changing r_FBufScale to fit smaller cubemap image size, or rendering cubemap to framebuffer first
2860 	if (0) //(r_depthPrepass->value && ((r_forceSun->integer) || tr.sunShadows))
2861 	{
2862 		parms.flags = VPF_USESUNLIGHT;
2863 	}
2864 
2865 	parms.targetFbo = tr.renderCubeFbo;
2866 	parms.targetFboLayer = cubemapSide;
2867 	parms.targetFboCubemapIndex = cubemapIndex;
2868 
2869 	R_RenderView(&parms);
2870 
2871 	if (!subscene)
2872 		RE_EndScene();
2873 }
2874 
2875