1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7
8 This file is part of the OpenJK source code.
9
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13
14 This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23
24 // tr_main.c -- main control flow for each frame
25 #include "tr_local.h"
26 #include "ghoul2/g2_local.h"
27
28 trGlobals_t tr;
29
30 static float s_flipMatrix[16] = {
31 // convert from our coordinate system (looking down X)
32 // to OpenGL's coordinate system (looking down -Z)
33 0, 0, -1, 0,
34 -1, 0, 0, 0,
35 0, 1, 0, 0,
36 0, 0, 0, 1
37 };
38
39 refimport_t ri;
40
41 // entities that will have procedurally generated surfaces will just
42 // point at this for their sorting surface
43 surfaceType_t entitySurface = SF_ENTITY;
44
45 /*
46 =================
47 R_CullLocalBox
48
49 Returns CULL_IN, CULL_CLIP, or CULL_OUT
50 =================
51 */
R_CullLocalBox(const vec3_t bounds[2])52 int R_CullLocalBox (const vec3_t bounds[2]) {
53 int i, j;
54 vec3_t transformed[8];
55 float dists[8];
56 vec3_t v;
57 cplane_t *frust;
58 int anyBack;
59 int front, back;
60
61 if ( r_nocull->integer==1 ) {
62 return CULL_CLIP;
63 }
64
65 // transform into world space
66 for (i = 0 ; i < 8 ; i++) {
67 v[0] = bounds[i&1][0];
68 v[1] = bounds[(i>>1)&1][1];
69 v[2] = bounds[(i>>2)&1][2];
70
71 VectorCopy( tr.ori.origin, transformed[i] );
72 VectorMA( transformed[i], v[0], tr.ori.axis[0], transformed[i] );
73 VectorMA( transformed[i], v[1], tr.ori.axis[1], transformed[i] );
74 VectorMA( transformed[i], v[2], tr.ori.axis[2], transformed[i] );
75 }
76
77 // check against frustum planes
78 anyBack = 0;
79 for (i = 0 ; i < 4 ; i++) {
80 frust = &tr.viewParms.frustum[i];
81
82 front = back = 0;
83 for (j = 0 ; j < 8 ; j++) {
84 dists[j] = DotProduct(transformed[j], frust->normal);
85 if ( dists[j] > frust->dist ) {
86 front = 1;
87 if ( back ) {
88 break; // a point is in front
89 }
90 } else {
91 back = 1;
92 }
93 }
94 if ( !front ) {
95 // all points were behind one of the planes
96 return CULL_OUT;
97 }
98 anyBack |= back;
99 }
100
101 if ( !anyBack ) {
102 return CULL_IN; // completely inside frustum
103 }
104
105 return CULL_CLIP; // partially clipped
106 }
107
108 /*
109 ** R_CullLocalPointAndRadius
110 */
R_CullLocalPointAndRadius(const vec3_t pt,float radius)111 int R_CullLocalPointAndRadius( const vec3_t pt, float radius )
112 {
113 vec3_t transformed;
114
115 R_LocalPointToWorld( pt, transformed );
116
117 return R_CullPointAndRadius( transformed, radius );
118 }
119
120 /*
121 ** R_CullPointAndRadius
122 */
R_CullPointAndRadius(const vec3_t pt,float radius)123 int R_CullPointAndRadius( const vec3_t pt, float radius )
124 {
125 int i;
126 float dist;
127 cplane_t *frust;
128 qboolean mightBeClipped = qfalse;
129
130 if ( r_nocull->integer==1 ) {
131 return CULL_CLIP;
132 }
133
134 // check against frustum planes
135 for (i = 0 ; i < 4 ; i++)
136 {
137 frust = &tr.viewParms.frustum[i];
138
139 dist = DotProduct( pt, frust->normal) - frust->dist;
140 if ( dist < -radius )
141 {
142 return CULL_OUT;
143 }
144 else if ( dist <= radius )
145 {
146 mightBeClipped = qtrue;
147 }
148 }
149
150 if ( mightBeClipped )
151 {
152 return CULL_CLIP;
153 }
154
155 return CULL_IN; // completely inside frustum
156 }
157
158 /*
159 =================
160 R_LocalNormalToWorld
161
162 =================
163 */
R_LocalNormalToWorld(const vec3_t local,vec3_t world)164 void R_LocalNormalToWorld (const vec3_t local, vec3_t world) {
165 world[0] = local[0] * tr.ori.axis[0][0] + local[1] * tr.ori.axis[1][0] + local[2] * tr.ori.axis[2][0];
166 world[1] = local[0] * tr.ori.axis[0][1] + local[1] * tr.ori.axis[1][1] + local[2] * tr.ori.axis[2][1];
167 world[2] = local[0] * tr.ori.axis[0][2] + local[1] * tr.ori.axis[1][2] + local[2] * tr.ori.axis[2][2];
168 }
169
170 /*
171 =================
172 R_LocalPointToWorld
173
174 =================
175 */
R_LocalPointToWorld(const vec3_t local,vec3_t world)176 void R_LocalPointToWorld (const vec3_t local, vec3_t world) {
177 world[0] = local[0] * tr.ori.axis[0][0] + local[1] * tr.ori.axis[1][0] + local[2] * tr.ori.axis[2][0] + tr.ori.origin[0];
178 world[1] = local[0] * tr.ori.axis[0][1] + local[1] * tr.ori.axis[1][1] + local[2] * tr.ori.axis[2][1] + tr.ori.origin[1];
179 world[2] = local[0] * tr.ori.axis[0][2] + local[1] * tr.ori.axis[1][2] + local[2] * tr.ori.axis[2][2] + tr.ori.origin[2];
180 }
181
182 float preTransEntMatrix[16];
183
184 /*
185 =================
186 R_WorldNormalToEntity
187
188 =================
189 */
R_WorldNormalToEntity(const vec3_t worldvec,vec3_t entvec)190 void R_WorldNormalToEntity (const vec3_t worldvec, vec3_t entvec)
191 {
192 entvec[0] = -worldvec[0] * preTransEntMatrix[0] - worldvec[1] * preTransEntMatrix[4] + worldvec[2] * preTransEntMatrix[8];
193 entvec[1] = -worldvec[0] * preTransEntMatrix[1] - worldvec[1] * preTransEntMatrix[5] + worldvec[2] * preTransEntMatrix[9];
194 entvec[2] = -worldvec[0] * preTransEntMatrix[2] - worldvec[1] * preTransEntMatrix[6] + worldvec[2] * preTransEntMatrix[10];
195 }
196
197 /*
198 =================
199 R_WorldPointToEntity
200
201 =================
202 */
203 /*void R_WorldPointToEntity (vec3_t worldvec, vec3_t entvec)
204 {
205 entvec[0] = worldvec[0] * preTransEntMatrix[0] + worldvec[1] * preTransEntMatrix[4] + worldvec[2] * preTransEntMatrix[8]+preTransEntMatrix[12];
206 entvec[1] = worldvec[0] * preTransEntMatrix[1] + worldvec[1] * preTransEntMatrix[5] + worldvec[2] * preTransEntMatrix[9]+preTransEntMatrix[13];
207 entvec[2] = worldvec[0] * preTransEntMatrix[2] + worldvec[1] * preTransEntMatrix[6] + worldvec[2] * preTransEntMatrix[10]+preTransEntMatrix[14];
208 }
209 */
210
211 /*
212 =================
213 R_WorldToLocal
214
215 =================
216 */
R_WorldToLocal(vec3_t world,vec3_t local)217 void R_WorldToLocal (vec3_t world, vec3_t local) {
218 local[0] = DotProduct(world, tr.ori.axis[0]);
219 local[1] = DotProduct(world, tr.ori.axis[1]);
220 local[2] = DotProduct(world, tr.ori.axis[2]);
221 }
222
223 /*
224 ==========================
225 R_TransformModelToClip
226
227 ==========================
228 */
R_TransformModelToClip(const vec3_t src,const float * modelMatrix,const float * projectionMatrix,vec4_t eye,vec4_t dst)229 void R_TransformModelToClip( const vec3_t src, const float *modelMatrix, const float *projectionMatrix,
230 vec4_t eye, vec4_t dst ) {
231 int i;
232
233 for ( i = 0 ; i < 4 ; i++ ) {
234 eye[i] =
235 src[0] * modelMatrix[ i + 0 * 4 ] +
236 src[1] * modelMatrix[ i + 1 * 4 ] +
237 src[2] * modelMatrix[ i + 2 * 4 ] +
238 1 * modelMatrix[ i + 3 * 4 ];
239 }
240
241 for ( i = 0 ; i < 4 ; i++ ) {
242 dst[i] =
243 eye[0] * projectionMatrix[ i + 0 * 4 ] +
244 eye[1] * projectionMatrix[ i + 1 * 4 ] +
245 eye[2] * projectionMatrix[ i + 2 * 4 ] +
246 eye[3] * projectionMatrix[ i + 3 * 4 ];
247 }
248 }
249
250 /*
251 ==========================
252 R_TransformClipToWindow
253
254 ==========================
255 */
R_TransformClipToWindow(const vec4_t clip,const viewParms_t * view,vec4_t normalized,vec4_t window)256 void R_TransformClipToWindow( const vec4_t clip, const viewParms_t *view, vec4_t normalized, vec4_t window ) {
257 normalized[0] = clip[0] / clip[3];
258 normalized[1] = clip[1] / clip[3];
259 normalized[2] = ( clip[2] + clip[3] ) / ( 2 * clip[3] );
260
261 window[0] = 0.5f * ( 1.0f + normalized[0] ) * view->viewportWidth;
262 window[1] = 0.5f * ( 1.0f + normalized[1] ) * view->viewportHeight;
263 window[2] = normalized[2];
264
265 window[0] = (int) ( window[0] + 0.5 );
266 window[1] = (int) ( window[1] + 0.5 );
267 }
268
269
270 /*
271 ==========================
272 myGlMultMatrix
273
274 ==========================
275 */
myGlMultMatrix(const float * a,const float * b,float * out)276 void myGlMultMatrix( const float *a, const float *b, float *out ) {
277 int i, j;
278
279 for ( i = 0 ; i < 4 ; i++ ) {
280 for ( j = 0 ; j < 4 ; j++ ) {
281 out[ i * 4 + j ] =
282 a [ i * 4 + 0 ] * b [ 0 * 4 + j ]
283 + a [ i * 4 + 1 ] * b [ 1 * 4 + j ]
284 + a [ i * 4 + 2 ] * b [ 2 * 4 + j ]
285 + a [ i * 4 + 3 ] * b [ 3 * 4 + j ];
286 }
287 }
288 }
289
290 /*
291 =================
292 R_RotateForEntity
293
294 Generates an orientation for an entity and viewParms
295 Does NOT produce any GL calls
296 Called by both the front end and the back end
297 =================
298 */
R_RotateForEntity(const trRefEntity_t * ent,const viewParms_t * viewParms,orientationr_t * ori)299 void R_RotateForEntity( const trRefEntity_t *ent, const viewParms_t *viewParms,
300 orientationr_t *ori ) {
301 // float glMatrix[16];
302 vec3_t delta;
303 float axisLength;
304
305 if ( ent->e.reType != RT_MODEL ) {
306 *ori = viewParms->world;
307 return;
308 }
309
310 VectorCopy( ent->e.origin, ori->origin );
311
312 VectorCopy( ent->e.axis[0], ori->axis[0] );
313 VectorCopy( ent->e.axis[1], ori->axis[1] );
314 VectorCopy( ent->e.axis[2], ori->axis[2] );
315
316 preTransEntMatrix[0] = ori->axis[0][0];
317 preTransEntMatrix[4] = ori->axis[1][0];
318 preTransEntMatrix[8] = ori->axis[2][0];
319 preTransEntMatrix[12] = ori->origin[0];
320
321 preTransEntMatrix[1] = ori->axis[0][1];
322 preTransEntMatrix[5] = ori->axis[1][1];
323 preTransEntMatrix[9] = ori->axis[2][1];
324 preTransEntMatrix[13] = ori->origin[1];
325
326 preTransEntMatrix[2] = ori->axis[0][2];
327 preTransEntMatrix[6] = ori->axis[1][2];
328 preTransEntMatrix[10] = ori->axis[2][2];
329 preTransEntMatrix[14] = ori->origin[2];
330
331 preTransEntMatrix[3] = 0;
332 preTransEntMatrix[7] = 0;
333 preTransEntMatrix[11] = 0;
334 preTransEntMatrix[15] = 1;
335
336 myGlMultMatrix( preTransEntMatrix, viewParms->world.modelMatrix, ori->modelMatrix );
337
338 // calculate the viewer origin in the model's space
339 // needed for fog, specular, and environment mapping
340 VectorSubtract( viewParms->ori.origin, ori->origin, delta );
341
342 // compensate for scale in the axes if necessary
343 if ( ent->e.nonNormalizedAxes ) {
344 axisLength = VectorLength( ent->e.axis[0] );
345 if ( !axisLength ) {
346 axisLength = 0;
347 } else {
348 axisLength = 1.0f / axisLength;
349 }
350 } else {
351 axisLength = 1.0f;
352 }
353
354 ori->viewOrigin[0] = DotProduct( delta, ori->axis[0] ) * axisLength;
355 ori->viewOrigin[1] = DotProduct( delta, ori->axis[1] ) * axisLength;
356 ori->viewOrigin[2] = DotProduct( delta, ori->axis[2] ) * axisLength;
357 }
358
359 /*
360 =================
361 R_RotateForViewer
362
363 Sets up the modelview matrix for a given viewParm
364 =================
365 */
R_RotateForViewer(void)366 void R_RotateForViewer (void)
367 {
368 float viewerMatrix[16];
369 vec3_t origin;
370
371 memset (&tr.ori, 0, sizeof(tr.ori));
372 tr.ori.axis[0][0] = 1;
373 tr.ori.axis[1][1] = 1;
374 tr.ori.axis[2][2] = 1;
375 VectorCopy (tr.viewParms.ori.origin, tr.ori.viewOrigin);
376
377 // transform by the camera placement
378 VectorCopy( tr.viewParms.ori.origin, origin );
379
380 viewerMatrix[0] = tr.viewParms.ori.axis[0][0];
381 viewerMatrix[4] = tr.viewParms.ori.axis[0][1];
382 viewerMatrix[8] = tr.viewParms.ori.axis[0][2];
383 viewerMatrix[12] = -origin[0] * viewerMatrix[0] + -origin[1] * viewerMatrix[4] + -origin[2] * viewerMatrix[8];
384
385 viewerMatrix[1] = tr.viewParms.ori.axis[1][0];
386 viewerMatrix[5] = tr.viewParms.ori.axis[1][1];
387 viewerMatrix[9] = tr.viewParms.ori.axis[1][2];
388 viewerMatrix[13] = -origin[0] * viewerMatrix[1] + -origin[1] * viewerMatrix[5] + -origin[2] * viewerMatrix[9];
389
390 viewerMatrix[2] = tr.viewParms.ori.axis[2][0];
391 viewerMatrix[6] = tr.viewParms.ori.axis[2][1];
392 viewerMatrix[10] = tr.viewParms.ori.axis[2][2];
393 viewerMatrix[14] = -origin[0] * viewerMatrix[2] + -origin[1] * viewerMatrix[6] + -origin[2] * viewerMatrix[10];
394
395 viewerMatrix[3] = 0;
396 viewerMatrix[7] = 0;
397 viewerMatrix[11] = 0;
398 viewerMatrix[15] = 1;
399
400 // convert from our coordinate system (looking down X)
401 // to OpenGL's coordinate system (looking down -Z)
402 myGlMultMatrix( viewerMatrix, s_flipMatrix, tr.ori.modelMatrix );
403
404 tr.viewParms.world = tr.ori;
405
406 }
407
408 /*
409 ** SetFarClip
410 */
SetFarClip(void)411 static void SetFarClip( void )
412 {
413 float farthestCornerDistance = 0;
414 int i;
415
416 // if not rendering the world (icons, menus, etc)
417 // set a 2k far clip plane
418 if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
419 if (tr.refdef.rdflags & RDF_AUTOMAP)
420 { //override the zfar then
421 tr.viewParms.zFar = 32768.0f;
422 }
423 else
424 {
425 tr.viewParms.zFar = 2048.0f;
426 }
427 return;
428 }
429
430 //
431 // set far clipping planes dynamically
432 //
433 for ( i = 0; i < 8; i++ )
434 {
435 vec3_t v;
436 float distance;
437
438 if ( i & 1 )
439 {
440 v[0] = tr.viewParms.visBounds[0][0];
441 }
442 else
443 {
444 v[0] = tr.viewParms.visBounds[1][0];
445 }
446
447 if ( i & 2 )
448 {
449 v[1] = tr.viewParms.visBounds[0][1];
450 }
451 else
452 {
453 v[1] = tr.viewParms.visBounds[1][1];
454 }
455
456 if ( i & 4 )
457 {
458 v[2] = tr.viewParms.visBounds[0][2];
459 }
460 else
461 {
462 v[2] = tr.viewParms.visBounds[1][2];
463 }
464
465 distance = DistanceSquared(tr.viewParms.ori.origin, v);
466
467 if ( distance > farthestCornerDistance )
468 {
469 farthestCornerDistance = distance;
470 }
471 }
472 // Bring in the zFar to the distanceCull distance
473 // The sky renders at zFar so need to move it out a little
474 // ...and make sure there is a minimum zfar to prevent problems
475 tr.viewParms.zFar = Com_Clamp(2048.0f, tr.distanceCull * (1.732), sqrtf( farthestCornerDistance ));
476
477 /*
478 if (r_shadows->integer == 2)
479 { //volume caps need an "infinite" far clipping plane. So I'm using this semi-arbitrary massive number.
480 tr.viewParms.zFar = 524288.0f;
481 }
482 */
483 }
484
485
486 /*
487 ===============
488 R_SetupProjection
489 ===============
490 */
R_SetupProjection(void)491 void R_SetupProjection( void ) {
492 float xmin, xmax, ymin, ymax;
493 float width, height, depth;
494 float zNear, zFar;
495
496 // dynamically compute far clip plane distance
497 SetFarClip();
498
499 //
500 // set up projection matrix
501 //
502 zNear = r_znear->value;
503 zFar = tr.viewParms.zFar;
504
505 ymax = zNear * tan( tr.refdef.fov_y * M_PI / 360.0f );
506 ymin = -ymax;
507
508 xmax = zNear * tan( tr.refdef.fov_x * M_PI / 360.0f );
509 xmin = -xmax;
510
511 width = xmax - xmin;
512 height = ymax - ymin;
513 depth = zFar - zNear;
514
515 tr.viewParms.projectionMatrix[0] = 2 * zNear / width;
516 tr.viewParms.projectionMatrix[4] = 0;
517 tr.viewParms.projectionMatrix[8] = ( xmax + xmin ) / width; // normally 0
518 tr.viewParms.projectionMatrix[12] = 0;
519
520 tr.viewParms.projectionMatrix[1] = 0;
521 tr.viewParms.projectionMatrix[5] = 2 * zNear / height;
522 tr.viewParms.projectionMatrix[9] = ( ymax + ymin ) / height; // normally 0
523 tr.viewParms.projectionMatrix[13] = 0;
524
525 tr.viewParms.projectionMatrix[2] = 0;
526 tr.viewParms.projectionMatrix[6] = 0;
527 tr.viewParms.projectionMatrix[10] = -( zFar + zNear ) / depth;
528 tr.viewParms.projectionMatrix[14] = -2 * zFar * zNear / depth;
529
530 tr.viewParms.projectionMatrix[3] = 0;
531 tr.viewParms.projectionMatrix[7] = 0;
532 tr.viewParms.projectionMatrix[11] = -1;
533 tr.viewParms.projectionMatrix[15] = 0;
534 }
535
536 /*
537 =================
538 R_SetupFrustum
539
540 Setup that culling frustum planes for the current view
541 =================
542 */
R_SetupFrustum(void)543 void R_SetupFrustum (void) {
544 int i;
545 float xs, xc;
546 float ang;
547
548 ang = tr.viewParms.fovX / 180 * M_PI * 0.5f;
549 xs = sin( ang );
550 xc = cos( ang );
551
552 VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[0].normal );
553 VectorMA( tr.viewParms.frustum[0].normal, xc, tr.viewParms.ori.axis[1], tr.viewParms.frustum[0].normal );
554
555 VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[1].normal );
556 VectorMA( tr.viewParms.frustum[1].normal, -xc, tr.viewParms.ori.axis[1], tr.viewParms.frustum[1].normal );
557
558 ang = tr.viewParms.fovY / 180 * M_PI * 0.5f;
559 xs = sin( ang );
560 xc = cos( ang );
561
562 VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[2].normal );
563 VectorMA( tr.viewParms.frustum[2].normal, xc, tr.viewParms.ori.axis[2], tr.viewParms.frustum[2].normal );
564
565 VectorScale( tr.viewParms.ori.axis[0], xs, tr.viewParms.frustum[3].normal );
566 VectorMA( tr.viewParms.frustum[3].normal, -xc, tr.viewParms.ori.axis[2], tr.viewParms.frustum[3].normal );
567
568 for (i=0 ; i<4 ; i++) {
569 tr.viewParms.frustum[i].type = PLANE_NON_AXIAL;
570 tr.viewParms.frustum[i].dist = DotProduct (tr.viewParms.ori.origin, tr.viewParms.frustum[i].normal);
571 SetPlaneSignbits( &tr.viewParms.frustum[i] );
572 }
573 }
574
575
576 /*
577 =================
578 R_MirrorPoint
579 =================
580 */
R_MirrorPoint(vec3_t in,orientation_t * surface,orientation_t * camera,vec3_t out)581 void R_MirrorPoint (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
582 int i;
583 vec3_t local;
584 vec3_t transformed;
585 float d;
586
587 VectorSubtract( in, surface->origin, local );
588
589 VectorClear( transformed );
590 for ( i = 0 ; i < 3 ; i++ ) {
591 d = DotProduct(local, surface->axis[i]);
592 VectorMA( transformed, d, camera->axis[i], transformed );
593 }
594
595 VectorAdd( transformed, camera->origin, out );
596 }
597
R_MirrorVector(vec3_t in,orientation_t * surface,orientation_t * camera,vec3_t out)598 void R_MirrorVector (vec3_t in, orientation_t *surface, orientation_t *camera, vec3_t out) {
599 int i;
600 float d;
601
602 VectorClear( out );
603 for ( i = 0 ; i < 3 ; i++ ) {
604 d = DotProduct(in, surface->axis[i]);
605 VectorMA( out, d, camera->axis[i], out );
606 }
607 }
608
609
610 /*
611 =============
612 R_PlaneForSurface
613 =============
614 */
R_PlaneForSurface(surfaceType_t * surfType,cplane_t * plane)615 void R_PlaneForSurface (surfaceType_t *surfType, cplane_t *plane) {
616 srfTriangles_t *tri;
617 srfPoly_t *poly;
618 drawVert_t *v1, *v2, *v3;
619 vec4_t plane4;
620
621 if (!surfType) {
622 memset (plane, 0, sizeof(*plane));
623 plane->normal[0] = 1;
624 return;
625 }
626 switch (*surfType) {
627 case SF_FACE:
628 *plane = ((srfSurfaceFace_t *)surfType)->plane;
629 return;
630 case SF_TRIANGLES:
631 tri = (srfTriangles_t *)surfType;
632 v1 = tri->verts + tri->indexes[0];
633 v2 = tri->verts + tri->indexes[1];
634 v3 = tri->verts + tri->indexes[2];
635 PlaneFromPoints( plane4, v1->xyz, v2->xyz, v3->xyz );
636 VectorCopy( plane4, plane->normal );
637 plane->dist = plane4[3];
638 return;
639 case SF_POLY:
640 poly = (srfPoly_t *)surfType;
641 PlaneFromPoints( plane4, poly->verts[0].xyz, poly->verts[1].xyz, poly->verts[2].xyz );
642 VectorCopy( plane4, plane->normal );
643 plane->dist = plane4[3];
644 return;
645 default:
646 memset (plane, 0, sizeof(*plane));
647 plane->normal[0] = 1;
648 return;
649 }
650 }
651
652 /*
653 =================
654 R_GetPortalOrientation
655
656 entityNum is the entity that the portal surface is a part of, which may
657 be moving and rotating.
658
659 Returns qtrue if it should be mirrored
660 =================
661 */
R_GetPortalOrientations(drawSurf_t * drawSurf,int entityNum,orientation_t * surface,orientation_t * camera,vec3_t pvsOrigin,qboolean * mirror)662 qboolean R_GetPortalOrientations( drawSurf_t *drawSurf, int entityNum,
663 orientation_t *surface, orientation_t *camera,
664 vec3_t pvsOrigin, qboolean *mirror ) {
665 int i;
666 cplane_t originalPlane, plane;
667 trRefEntity_t *e;
668 float d;
669 vec3_t transformed;
670
671 // create plane axis for the portal we are seeing
672 R_PlaneForSurface( drawSurf->surface, &originalPlane );
673
674 // rotate the plane if necessary
675 if ( entityNum != REFENTITYNUM_WORLD ) {
676 tr.currentEntityNum = entityNum;
677 tr.currentEntity = &tr.refdef.entities[entityNum];
678
679 // get the orientation of the entity
680 R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.ori );
681
682 // rotate the plane, but keep the non-rotated version for matching
683 // against the portalSurface entities
684 R_LocalNormalToWorld( originalPlane.normal, plane.normal );
685 plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.ori.origin );
686
687 // translate the original plane
688 originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.ori.origin );
689 } else {
690 plane = originalPlane;
691 }
692
693 VectorCopy( plane.normal, surface->axis[0] );
694 PerpendicularVector( surface->axis[1], surface->axis[0] );
695 CrossProduct( surface->axis[0], surface->axis[1], surface->axis[2] );
696
697 // locate the portal entity closest to this plane.
698 // origin will be the origin of the portal, origin2 will be
699 // the origin of the camera
700 for ( i = 0 ; i < tr.refdef.num_entities ; i++ ) {
701 e = &tr.refdef.entities[i];
702 if ( e->e.reType != RT_PORTALSURFACE ) {
703 continue;
704 }
705
706 d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
707 if ( d > 64 || d < -64) {
708 continue;
709 }
710
711 // get the pvsOrigin from the entity
712 VectorCopy( e->e.oldorigin, pvsOrigin );
713
714 // if the entity is just a mirror, don't use as a camera point
715 if ( e->e.oldorigin[0] == e->e.origin[0] &&
716 e->e.oldorigin[1] == e->e.origin[1] &&
717 e->e.oldorigin[2] == e->e.origin[2] ) {
718 VectorScale( plane.normal, plane.dist, surface->origin );
719 VectorCopy( surface->origin, camera->origin );
720 VectorSubtract( vec3_origin, surface->axis[0], camera->axis[0] );
721 VectorCopy( surface->axis[1], camera->axis[1] );
722 VectorCopy( surface->axis[2], camera->axis[2] );
723
724 *mirror = qtrue;
725 return qtrue;
726 }
727
728 // project the origin onto the surface plane to get
729 // an origin point we can rotate around
730 d = DotProduct( e->e.origin, plane.normal ) - plane.dist;
731 VectorMA( e->e.origin, -d, surface->axis[0], surface->origin );
732
733 // now get the camera origin and orientation
734 VectorCopy( e->e.oldorigin, camera->origin );
735 AxisCopy( e->e.axis, camera->axis );
736 VectorSubtract( vec3_origin, camera->axis[0], camera->axis[0] );
737 VectorSubtract( vec3_origin, camera->axis[1], camera->axis[1] );
738
739 // optionally rotate
740 if ( e->e.oldframe ) {
741 // if a speed is specified
742 if ( e->e.frame ) {
743 // continuous rotate
744 d = (tr.refdef.time/1000.0f) * e->e.frame;
745 VectorCopy( camera->axis[1], transformed );
746 RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
747 CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
748 } else {
749 // bobbing rotate, with skinNum being the rotation offset
750 d = sin( tr.refdef.time * 0.003f );
751 d = e->e.skinNum + d * 4;
752 VectorCopy( camera->axis[1], transformed );
753 RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
754 CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
755 }
756 }
757 else if ( e->e.skinNum ) {
758 d = e->e.skinNum;
759 VectorCopy( camera->axis[1], transformed );
760 RotatePointAroundVector( camera->axis[1], camera->axis[0], transformed, d );
761 CrossProduct( camera->axis[0], camera->axis[1], camera->axis[2] );
762 }
763 *mirror = qfalse;
764 return qtrue;
765 }
766
767 // if we didn't locate a portal entity, don't render anything.
768 // We don't want to just treat it as a mirror, because without a
769 // portal entity the server won't have communicated a proper entity set
770 // in the snapshot
771
772 // unfortunately, with local movement prediction it is easily possible
773 // to see a surface before the server has communicated the matching
774 // portal surface entity, so we don't want to print anything here...
775
776 //ri.Printf( PRINT_ALL, "Portal surface without a portal entity\n" );
777
778 return qfalse;
779 }
780
IsMirror(const drawSurf_t * drawSurf,int entityNum)781 static qboolean IsMirror( const drawSurf_t *drawSurf, int entityNum )
782 {
783 int i;
784 cplane_t originalPlane, plane;
785 trRefEntity_t *e;
786 float d;
787
788 // create plane axis for the portal we are seeing
789 R_PlaneForSurface( drawSurf->surface, &originalPlane );
790
791 // rotate the plane if necessary
792 if ( entityNum != REFENTITYNUM_WORLD )
793 {
794 tr.currentEntityNum = entityNum;
795 tr.currentEntity = &tr.refdef.entities[entityNum];
796
797 // get the orientation of the entity
798 R_RotateForEntity( tr.currentEntity, &tr.viewParms, &tr.ori );
799
800 // rotate the plane, but keep the non-rotated version for matching
801 // against the portalSurface entities
802 R_LocalNormalToWorld( originalPlane.normal, plane.normal );
803 plane.dist = originalPlane.dist + DotProduct( plane.normal, tr.ori.origin );
804
805 // translate the original plane
806 originalPlane.dist = originalPlane.dist + DotProduct( originalPlane.normal, tr.ori.origin );
807 }
808 else
809 {
810 plane = originalPlane;
811 }
812
813 // locate the portal entity closest to this plane.
814 // origin will be the origin of the portal, origin2 will be
815 // the origin of the camera
816 for ( i = 0 ; i < tr.refdef.num_entities ; i++ )
817 {
818 e = &tr.refdef.entities[i];
819 if ( e->e.reType != RT_PORTALSURFACE ) {
820 continue;
821 }
822
823 d = DotProduct( e->e.origin, originalPlane.normal ) - originalPlane.dist;
824 if ( d > 64 || d < -64) {
825 continue;
826 }
827
828 // if the entity is just a mirror, don't use as a camera point
829 if ( e->e.oldorigin[0] == e->e.origin[0] &&
830 e->e.oldorigin[1] == e->e.origin[1] &&
831 e->e.oldorigin[2] == e->e.origin[2] )
832 {
833 return qtrue;
834 }
835
836 return qfalse;
837 }
838 return qfalse;
839 }
840
841 /*
842 ** SurfIsOffscreen
843 **
844 ** Determines if a surface is completely offscreen.
845 */
SurfIsOffscreen(const drawSurf_t * drawSurf,vec4_t clipDest[128])846 static qboolean SurfIsOffscreen( const drawSurf_t *drawSurf, vec4_t clipDest[128] ) {
847 float shortest = 100000000;
848 int entityNum;
849 int numTriangles;
850 shader_t *shader;
851 int fogNum;
852 int dlighted;
853 vec4_t clip, eye;
854 int i;
855 unsigned int pointOr = 0;
856 unsigned int pointAnd = (unsigned int)~0;
857
858 R_RotateForViewer();
859
860 R_DecomposeSort( drawSurf->sort, &entityNum, &shader, &fogNum, &dlighted );
861 RB_BeginSurface( shader, fogNum );
862 rb_surfaceTable[ *drawSurf->surface ]( drawSurf->surface );
863 assert( tess.numVertexes < 128 );
864 for ( i = 0; i < tess.numVertexes; i++ )
865 {
866 int j;
867 unsigned int pointFlags = 0;
868
869 R_TransformModelToClip( tess.xyz[i], tr.ori.modelMatrix, tr.viewParms.projectionMatrix, eye, clip );
870
871 for ( j = 0; j < 3; j++ )
872 {
873 if ( clip[j] >= clip[3] )
874 {
875 pointFlags |= (1 << (j*2));
876 }
877 else if ( clip[j] <= -clip[3] )
878 {
879 pointFlags |= ( 1 << (j*2+1));
880 }
881 }
882 pointAnd &= pointFlags;
883 pointOr |= pointFlags;
884 }
885
886 // trivially reject
887 if ( pointAnd )
888 {
889 return qtrue;
890 }
891
892 // determine if this surface is backfaced and also determine the distance
893 // to the nearest vertex so we can cull based on portal range. Culling
894 // based on vertex distance isn't 100% correct (we should be checking for
895 // range to the surface), but it's good enough for the types of portals
896 // we have in the game right now.
897 numTriangles = tess.numIndexes / 3;
898
899 for ( i = 0; i < tess.numIndexes; i += 3 )
900 {
901 vec3_t normal;
902 float dot;
903 float len;
904
905 VectorSubtract( tess.xyz[tess.indexes[i]], tr.viewParms.ori.origin, normal );
906
907 len = VectorLengthSquared( normal ); // lose the sqrt
908 if ( len < shortest )
909 {
910 shortest = len;
911 }
912
913 if ( ( dot = DotProduct( normal, tess.normal[tess.indexes[i]] ) ) >= 0 )
914 {
915 numTriangles--;
916 }
917 }
918 if ( !numTriangles )
919 {
920 return qtrue;
921 }
922
923 // mirrors can early out at this point, since we don't do a fade over distance
924 // with them (although we could)
925 if ( IsMirror( drawSurf, entityNum ) )
926 {
927 return qfalse;
928 }
929
930 if ( shortest > (tess.shader->portalRange*tess.shader->portalRange) )
931 {
932 return qtrue;
933 }
934
935 return qfalse;
936 }
937
938 /*
939 ========================
940 R_MirrorViewBySurface
941
942 Returns qtrue if another view has been rendered
943 ========================
944 */
R_MirrorViewBySurface(drawSurf_t * drawSurf,int entityNum)945 qboolean R_MirrorViewBySurface (drawSurf_t *drawSurf, int entityNum) {
946 vec4_t clipDest[128];
947 viewParms_t newParms;
948 viewParms_t oldParms;
949 orientation_t surface, camera;
950
951 // don't recursively mirror
952 if (tr.viewParms.isPortal) {
953 ri.Printf( PRINT_DEVELOPER, S_COLOR_RED "WARNING: recursive mirror/portal found\n" );
954 return qfalse;
955 }
956
957 if ( r_noportals->integer || (r_fastsky->integer == 1) ) {
958 return qfalse;
959 }
960
961 // trivially reject portal/mirror
962 if ( SurfIsOffscreen( drawSurf, clipDest ) ) {
963 return qfalse;
964 }
965
966 // save old viewParms so we can return to it after the mirror view
967 oldParms = tr.viewParms;
968
969 newParms = tr.viewParms;
970 newParms.isPortal = qtrue;
971 if ( !R_GetPortalOrientations( drawSurf, entityNum, &surface, &camera,
972 newParms.pvsOrigin, &newParms.isMirror ) ) {
973 return qfalse; // bad portal, no portalentity
974 }
975
976 R_MirrorPoint (oldParms.ori.origin, &surface, &camera, newParms.ori.origin );
977
978 VectorSubtract( vec3_origin, camera.axis[0], newParms.portalPlane.normal );
979 newParms.portalPlane.dist = DotProduct( camera.origin, newParms.portalPlane.normal );
980
981 R_MirrorVector (oldParms.ori.axis[0], &surface, &camera, newParms.ori.axis[0]);
982 R_MirrorVector (oldParms.ori.axis[1], &surface, &camera, newParms.ori.axis[1]);
983 R_MirrorVector (oldParms.ori.axis[2], &surface, &camera, newParms.ori.axis[2]);
984
985 // OPTIMIZE: restrict the viewport on the mirrored view
986
987 // render the mirror view
988 R_RenderView (&newParms);
989
990 tr.viewParms = oldParms;
991
992 return qtrue;
993 }
994
995 /*
996 =================
997 R_SpriteFogNum
998
999 See if a sprite is inside a fog volume
1000 =================
1001 */
R_SpriteFogNum(trRefEntity_t * ent)1002 int R_SpriteFogNum( trRefEntity_t *ent ) {
1003 int i, j;
1004 fog_t *fog;
1005
1006 if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
1007 return 0;
1008 }
1009
1010 for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
1011 fog = &tr.world->fogs[i];
1012 for ( j = 0 ; j < 3 ; j++ ) {
1013 if ( ent->e.origin[j] - ent->e.radius >= fog->bounds[1][j] ) {
1014 break;
1015 }
1016 if ( ent->e.origin[j] + ent->e.radius <= fog->bounds[0][j] ) {
1017 break;
1018 }
1019 }
1020 if ( j == 3 ) {
1021 return i;
1022 }
1023 }
1024
1025 return 0;
1026 }
1027
1028 /*
1029 ==========================================================================================
1030
1031 DRAWSURF SORTING
1032
1033 ==========================================================================================
1034 */
1035
1036 /*
1037 ===============
1038 R_Radix
1039 ===============
1040 */
R_Radix(int byte,int size,drawSurf_t * source,drawSurf_t * dest)1041 static QINLINE void R_Radix( int byte, int size, drawSurf_t *source, drawSurf_t *dest )
1042 {
1043 int count[ 256 ] = { 0 };
1044 int index[ 256 ];
1045 int i;
1046 unsigned char *sortKey = NULL;
1047 unsigned char *end = NULL;
1048
1049 sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
1050 end = sortKey + ( size * sizeof( drawSurf_t ) );
1051 for( ; sortKey < end; sortKey += sizeof( drawSurf_t ) )
1052 ++count[ *sortKey ];
1053
1054 index[ 0 ] = 0;
1055
1056 for( i = 1; i < 256; ++i )
1057 index[ i ] = index[ i - 1 ] + count[ i - 1 ];
1058
1059 sortKey = ( (unsigned char *)&source[ 0 ].sort ) + byte;
1060 for( i = 0; i < size; ++i, sortKey += sizeof( drawSurf_t ) )
1061 dest[ index[ *sortKey ]++ ] = source[ i ];
1062 }
1063
1064 /*
1065 ===============
1066 R_RadixSort
1067
1068 Radix sort with 4 byte size buckets
1069 ===============
1070 */
R_RadixSort(drawSurf_t * source,int size)1071 static void R_RadixSort( drawSurf_t *source, int size )
1072 {
1073 static drawSurf_t scratch[ MAX_DRAWSURFS ];
1074 #ifdef Q3_LITTLE_ENDIAN
1075 R_Radix( 0, size, source, scratch );
1076 R_Radix( 1, size, scratch, source );
1077 R_Radix( 2, size, source, scratch );
1078 R_Radix( 3, size, scratch, source );
1079 #else
1080 R_Radix( 3, size, source, scratch );
1081 R_Radix( 2, size, scratch, source );
1082 R_Radix( 1, size, source, scratch );
1083 R_Radix( 0, size, scratch, source );
1084 #endif //Q3_LITTLE_ENDIAN
1085 }
1086
1087 //==========================================================================================
1088
1089 /*
1090 =================
1091 R_AddDrawSurf
1092 =================
1093 */
R_AddDrawSurf(surfaceType_t * surface,shader_t * shader,int fogIndex,int dlightMap)1094 void R_AddDrawSurf( surfaceType_t *surface, shader_t *shader,
1095 int fogIndex, int dlightMap ) {
1096 int index;
1097
1098 if (tr.refdef.rdflags & RDF_NOFOG)
1099 {
1100 fogIndex = 0;
1101 }
1102
1103 if ( (shader->surfaceFlags & SURF_FORCESIGHT) && !(tr.refdef.rdflags & RDF_ForceSightOn) )
1104 { //if shader is only seen with ForceSight and we don't have ForceSight on, then don't draw
1105 return;
1106 }
1107
1108 // instead of checking for overflow, we just mask the index
1109 // so it wraps around
1110 index = tr.refdef.numDrawSurfs & DRAWSURF_MASK;
1111 // the sort data is packed into a single 32 bit value so it can be
1112 // compared quickly during the qsorting process
1113 tr.refdef.drawSurfs[index].sort = (shader->sortedIndex << QSORT_SHADERNUM_SHIFT)
1114 | tr.shiftedEntityNum | ( fogIndex << QSORT_FOGNUM_SHIFT ) | (int)dlightMap;
1115 tr.refdef.drawSurfs[index].surface = surface;
1116 tr.refdef.numDrawSurfs++;
1117 }
1118
1119 /*
1120 =================
1121 R_DecomposeSort
1122 =================
1123 */
R_DecomposeSort(unsigned sort,int * entityNum,shader_t ** shader,int * fogNum,int * dlightMap)1124 void R_DecomposeSort( unsigned sort, int *entityNum, shader_t **shader,
1125 int *fogNum, int *dlightMap ) {
1126 *fogNum = ( sort >> QSORT_FOGNUM_SHIFT ) & 31;
1127 *shader = tr.sortedShaders[ ( sort >> QSORT_SHADERNUM_SHIFT ) & (MAX_SHADERS-1) ];
1128 *entityNum = ( sort >> QSORT_REFENTITYNUM_SHIFT ) & REFENTITYNUM_MASK;
1129 *dlightMap = sort & 3;
1130 }
1131
1132 /*
1133 =================
1134 R_SortDrawSurfs
1135 =================
1136 */
R_SortDrawSurfs(drawSurf_t * drawSurfs,int numDrawSurfs)1137 void R_SortDrawSurfs( drawSurf_t *drawSurfs, int numDrawSurfs ) {
1138 shader_t *shader;
1139 int fogNum;
1140 int entityNum;
1141 int dlighted;
1142 int i;
1143
1144 // it is possible for some views to not have any surfaces
1145 if ( numDrawSurfs < 1 ) {
1146 // we still need to add it for hyperspace cases
1147 R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
1148 return;
1149 }
1150
1151 // if we overflowed MAX_DRAWSURFS, the drawsurfs
1152 // wrapped around in the buffer and we will be missing
1153 // the first surfaces, not the last ones
1154 if ( numDrawSurfs > MAX_DRAWSURFS ) {
1155 numDrawSurfs = MAX_DRAWSURFS;
1156 }
1157
1158 // sort the drawsurfs by sort type, then orientation, then shader
1159 R_RadixSort( drawSurfs, numDrawSurfs );
1160
1161 // check for any pass through drawing, which
1162 // may cause another view to be rendered first
1163 for ( i = 0 ; i < numDrawSurfs ; i++ ) {
1164 R_DecomposeSort( (drawSurfs+i)->sort, &entityNum, &shader, &fogNum, &dlighted );
1165
1166 if ( shader->sort > SS_PORTAL ) {
1167 break;
1168 }
1169
1170 // no shader should ever have this sort type
1171 if ( shader->sort == SS_BAD ) {
1172 Com_Error (ERR_DROP, "Shader '%s'with sort == SS_BAD", shader->name );
1173 }
1174
1175 // if the mirror was completely clipped away, we may need to check another surface
1176 if ( R_MirrorViewBySurface( (drawSurfs+i), entityNum) ) {
1177 // this is a debug option to see exactly what is being mirrored
1178 if ( r_portalOnly->integer ) {
1179 return;
1180 }
1181 break; // only one mirror view at a time
1182 }
1183 }
1184
1185 R_AddDrawSurfCmd( drawSurfs, numDrawSurfs );
1186 }
1187
1188 /*
1189 =============
1190 R_AddEntitySurfaces
1191 =============
1192 */
R_AddEntitySurfaces(void)1193 void R_AddEntitySurfaces (void) {
1194 trRefEntity_t *ent;
1195 shader_t *shader;
1196
1197 if ( !r_drawentities->integer ) {
1198 return;
1199 }
1200
1201 for ( tr.currentEntityNum = 0;
1202 tr.currentEntityNum < tr.refdef.num_entities;
1203 tr.currentEntityNum++ ) {
1204 ent = tr.currentEntity = &tr.refdef.entities[tr.currentEntityNum];
1205
1206 assert(ent->e.renderfx >= 0);
1207
1208 ent->needDlights = qfalse;
1209
1210 // preshift the value we are going to OR into the drawsurf sort
1211 tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
1212
1213 //
1214 // the weapon model must be handled special --
1215 // we don't want the hacked weapon position showing in
1216 // mirrors, because the true body position will already be drawn
1217 //
1218 if ( (ent->e.renderfx & RF_FIRST_PERSON) && tr.viewParms.isPortal) {
1219 continue;
1220 }
1221
1222 // simple generated models, like sprites and beams, are not culled
1223 switch ( ent->e.reType ) {
1224 case RT_PORTALSURFACE:
1225 break; // don't draw anything
1226 case RT_SPRITE:
1227 case RT_BEAM:
1228 case RT_ORIENTED_QUAD:
1229 case RT_ELECTRICITY:
1230 case RT_LINE:
1231 case RT_ORIENTEDLINE:
1232 case RT_CYLINDER:
1233 case RT_SABER_GLOW:
1234 // self blood sprites, talk balloons, etc should not be drawn in the primary
1235 // view. We can't just do this check for all entities, because md3
1236 // entities may still want to cast shadows from them
1237 if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal) {
1238 continue;
1239 }
1240 shader = R_GetShaderByHandle( ent->e.customShader );
1241 R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), 0 );
1242 break;
1243
1244 case RT_MODEL:
1245 // we must set up parts of tr.ori for model culling
1246 R_RotateForEntity( ent, &tr.viewParms, &tr.ori );
1247
1248 tr.currentModel = R_GetModelByHandle( ent->e.hModel );
1249 if (!tr.currentModel) {
1250 R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, 0 );
1251 } else {
1252 switch ( tr.currentModel->type ) {
1253 case MOD_MESH:
1254 R_AddMD3Surfaces( ent );
1255 break;
1256 case MOD_BRUSH:
1257 R_AddBrushModelSurfaces( ent );
1258 break;
1259 /*
1260 Ghoul2 Insert Start
1261 */
1262 case MOD_MDXM:
1263 //g2r
1264 if (ent->e.ghoul2)
1265 {
1266 R_AddGhoulSurfaces( ent);
1267 }
1268 break;
1269 case MOD_BAD: // null model axis
1270 if ( (ent->e.renderfx & RF_THIRD_PERSON) && !tr.viewParms.isPortal)
1271 {
1272 if (!(ent->e.renderfx & RF_SHADOW_ONLY))
1273 {
1274 break;
1275 }
1276 }
1277
1278 if (ent->e.ghoul2 && G2API_HaveWeGhoul2Models(*((CGhoul2Info_v *)ent->e.ghoul2)))
1279 {
1280 R_AddGhoulSurfaces( ent);
1281 break;
1282 }
1283
1284 R_AddDrawSurf( &entitySurface, tr.defaultShader, 0, false );
1285 break;
1286 /*
1287 Ghoul2 Insert End
1288 */
1289 default:
1290 Com_Error( ERR_DROP, "R_AddEntitySurfaces: Bad modeltype" );
1291 break;
1292 }
1293 }
1294 break;
1295
1296 case RT_ENT_CHAIN:
1297 shader = R_GetShaderByHandle( ent->e.customShader );
1298 R_AddDrawSurf( &entitySurface, shader, R_SpriteFogNum( ent ), false );
1299 break;
1300
1301 default:
1302 Com_Error( ERR_DROP, "R_AddEntitySurfaces: Bad reType" );
1303 }
1304 }
1305
1306 }
1307
1308
1309 /*
1310 ====================
1311 R_GenerateDrawSurfs
1312 ====================
1313 */
R_GenerateDrawSurfs(void)1314 void R_GenerateDrawSurfs( void ) {
1315 R_AddWorldSurfaces ();
1316
1317 R_AddPolygonSurfaces();
1318
1319 // set the projection matrix with the minimum zfar
1320 // now that we have the world bounded
1321 // this needs to be done before entities are
1322 // added, because they use the projection
1323 // matrix for lod calculation
1324 R_SetupProjection ();
1325
1326 R_AddEntitySurfaces ();
1327 }
1328
1329 /*
1330 ================
1331 R_DebugPolygon
1332 ================
1333 */
R_DebugPolygon(int color,int numPoints,float * points)1334 void R_DebugPolygon( int color, int numPoints, float *points ) {
1335 int i;
1336
1337 GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
1338
1339 // draw solid shade
1340
1341 qglColor3f( color&1, (color>>1)&1, (color>>2)&1 );
1342 qglBegin( GL_POLYGON );
1343 for ( i = 0 ; i < numPoints ; i++ ) {
1344 qglVertex3fv( points + i * 3 );
1345 }
1346 qglEnd();
1347
1348 // draw wireframe outline
1349 GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE );
1350 qglDepthRange( 0, 0 );
1351 qglColor3f( 1, 1, 1 );
1352 qglBegin( GL_POLYGON );
1353 for ( i = 0 ; i < numPoints ; i++ ) {
1354 qglVertex3fv( points + i * 3 );
1355 }
1356 qglEnd();
1357 qglDepthRange( 0, 1 );
1358 }
1359
1360 /*
1361 ====================
1362 R_DebugGraphics
1363
1364 Visualization aid for movement clipping debugging
1365 ====================
1366 */
R_DebugGraphics(void)1367 void R_DebugGraphics( void ) {
1368 if ( !r_debugSurface->integer ) {
1369 return;
1370 }
1371
1372 // the render thread can't make callbacks to the main thread
1373 R_IssuePendingRenderCommands();
1374
1375 GL_Bind( tr.whiteImage);
1376 GL_Cull( CT_FRONT_SIDED );
1377 ri.CM_DrawDebugSurface( R_DebugPolygon );
1378 }
1379
1380
1381 /*
1382 ================
1383 R_RenderView
1384
1385 A view may be either the actual camera view,
1386 or a mirror / remote location
1387 ================
1388 */
R_RenderView(viewParms_t * parms)1389 void R_RenderView (viewParms_t *parms) {
1390 int firstDrawSurf;
1391
1392 if ( parms->viewportWidth <= 0 || parms->viewportHeight <= 0 ) {
1393 return;
1394 }
1395
1396 tr.viewCount++;
1397
1398 tr.viewParms = *parms;
1399 tr.viewParms.frameSceneNum = tr.frameSceneNum;
1400 tr.viewParms.frameCount = tr.frameCount;
1401
1402 firstDrawSurf = tr.refdef.numDrawSurfs;
1403
1404 tr.viewCount++;
1405
1406 // set viewParms.world
1407 R_RotateForViewer ();
1408
1409 R_SetupFrustum ();
1410
1411 R_GenerateDrawSurfs();
1412
1413 R_SortDrawSurfs( tr.refdef.drawSurfs + firstDrawSurf, tr.refdef.numDrawSurfs - firstDrawSurf );
1414
1415 // draw main system development information (surface outlines, etc)
1416 R_DebugGraphics();
1417 }
1418