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