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