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