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 MP Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "tr_local.h"
30
31
32
33 /*
34 ================
35 R_CullSurface
36
37 Tries to cull surfaces before they are lighted or
38 added to the sorting list.
39 ================
40 */
R_CullSurface(msurface_t * surf)41 static qboolean R_CullSurface( msurface_t *surf ) {
42 if ( r_nocull->integer || surf->cullinfo.type == CULLINFO_NONE) {
43 return qfalse;
44 }
45
46 if ( r_nocurves->integer && *surf->data == SF_GRID ) {
47 return qtrue;
48 }
49
50 if (surf->cullinfo.type & CULLINFO_PLANE)
51 {
52 // Only true for SF_FACE, so treat like its own function
53 float d;
54 cullType_t ct;
55
56 if ( !r_facePlaneCull->integer ) {
57 return qfalse;
58 }
59
60 ct = surf->shader->cullType;
61
62 if (ct == CT_TWO_SIDED)
63 {
64 return qfalse;
65 }
66
67 // don't cull for depth shadow
68 /*
69 if ( tr.viewParms.flags & VPF_DEPTHSHADOW )
70 {
71 return qfalse;
72 }
73 */
74
75 // shadowmaps draw back surfaces
76 if ( tr.viewParms.flags & (VPF_SHADOWMAP | VPF_DEPTHSHADOW) )
77 {
78 if (ct == CT_FRONT_SIDED)
79 {
80 ct = CT_BACK_SIDED;
81 }
82 else
83 {
84 ct = CT_FRONT_SIDED;
85 }
86 }
87
88 // do proper cull for orthographic projection
89 if (tr.viewParms.flags & VPF_ORTHOGRAPHIC) {
90 d = DotProduct(tr.viewParms.or.axis[0], surf->cullinfo.plane.normal);
91 if ( ct == CT_FRONT_SIDED ) {
92 if (d > 0)
93 return qtrue;
94 } else {
95 if (d < 0)
96 return qtrue;
97 }
98 return qfalse;
99 }
100
101 d = DotProduct (tr.or.viewOrigin, surf->cullinfo.plane.normal);
102
103 // don't cull exactly on the plane, because there are levels of rounding
104 // through the BSP, ICD, and hardware that may cause pixel gaps if an
105 // epsilon isn't allowed here
106 if ( ct == CT_FRONT_SIDED ) {
107 if ( d < surf->cullinfo.plane.dist - 8 ) {
108 return qtrue;
109 }
110 } else {
111 if ( d > surf->cullinfo.plane.dist + 8 ) {
112 return qtrue;
113 }
114 }
115
116 return qfalse;
117 }
118
119 if (surf->cullinfo.type & CULLINFO_SPHERE)
120 {
121 int sphereCull;
122
123 if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) {
124 sphereCull = R_CullLocalPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius );
125 } else {
126 sphereCull = R_CullPointAndRadius( surf->cullinfo.localOrigin, surf->cullinfo.radius );
127 }
128
129 if ( sphereCull == CULL_OUT )
130 {
131 return qtrue;
132 }
133 }
134
135 if (surf->cullinfo.type & CULLINFO_BOX)
136 {
137 int boxCull;
138
139 if ( tr.currentEntityNum != REFENTITYNUM_WORLD ) {
140 boxCull = R_CullLocalBox( surf->cullinfo.bounds );
141 } else {
142 boxCull = R_CullBox( surf->cullinfo.bounds );
143 }
144
145 if ( boxCull == CULL_OUT )
146 {
147 return qtrue;
148 }
149 }
150
151 return qfalse;
152 }
153
154 /*
155 ====================
156 R_DlightSurface
157
158 The given surface is going to be drawn, and it touches a leaf
159 that is touched by one or more dlights, so try to throw out
160 more dlights if possible.
161 ====================
162 */
R_DlightSurface(msurface_t * surf,int dlightBits)163 static int R_DlightSurface( msurface_t *surf, int dlightBits ) {
164 float d;
165 int i;
166 dlight_t *dl;
167
168 if ( surf->cullinfo.type & CULLINFO_PLANE )
169 {
170 for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
171 if ( ! ( dlightBits & ( 1 << i ) ) ) {
172 continue;
173 }
174 dl = &tr.refdef.dlights[i];
175 d = DotProduct( dl->origin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist;
176 if ( d < -dl->radius || d > dl->radius ) {
177 // dlight doesn't reach the plane
178 dlightBits &= ~( 1 << i );
179 }
180 }
181 }
182
183 if ( surf->cullinfo.type & CULLINFO_BOX )
184 {
185 for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
186 if ( ! ( dlightBits & ( 1 << i ) ) ) {
187 continue;
188 }
189 dl = &tr.refdef.dlights[i];
190 if ( dl->origin[0] - dl->radius > surf->cullinfo.bounds[1][0]
191 || dl->origin[0] + dl->radius < surf->cullinfo.bounds[0][0]
192 || dl->origin[1] - dl->radius > surf->cullinfo.bounds[1][1]
193 || dl->origin[1] + dl->radius < surf->cullinfo.bounds[0][1]
194 || dl->origin[2] - dl->radius > surf->cullinfo.bounds[1][2]
195 || dl->origin[2] + dl->radius < surf->cullinfo.bounds[0][2] ) {
196 // dlight doesn't reach the bounds
197 dlightBits &= ~( 1 << i );
198 }
199 }
200 }
201
202 if ( surf->cullinfo.type & CULLINFO_SPHERE )
203 {
204 for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
205 if ( ! ( dlightBits & ( 1 << i ) ) ) {
206 continue;
207 }
208 dl = &tr.refdef.dlights[i];
209 if (!SpheresIntersect(dl->origin, dl->radius, surf->cullinfo.localOrigin, surf->cullinfo.radius))
210 {
211 // dlight doesn't reach the bounds
212 dlightBits &= ~( 1 << i );
213 }
214 }
215 }
216
217 switch(*surf->data)
218 {
219 case SF_FACE:
220 case SF_GRID:
221 case SF_TRIANGLES:
222 ((srfBspSurface_t *)surf->data)->dlightBits = dlightBits;
223 break;
224
225 default:
226 dlightBits = 0;
227 break;
228 }
229
230 if ( dlightBits ) {
231 tr.pc.c_dlightSurfaces++;
232 } else {
233 tr.pc.c_dlightSurfacesCulled++;
234 }
235
236 return dlightBits;
237 }
238
239 /*
240 ====================
241 R_PshadowSurface
242
243 Just like R_DlightSurface, cull any we can
244 ====================
245 */
R_PshadowSurface(msurface_t * surf,int pshadowBits)246 static int R_PshadowSurface( msurface_t *surf, int pshadowBits ) {
247 float d;
248 int i;
249 pshadow_t *ps;
250
251 if ( surf->cullinfo.type & CULLINFO_PLANE )
252 {
253 for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
254 if ( ! ( pshadowBits & ( 1 << i ) ) ) {
255 continue;
256 }
257 ps = &tr.refdef.pshadows[i];
258 d = DotProduct( ps->lightOrigin, surf->cullinfo.plane.normal ) - surf->cullinfo.plane.dist;
259 if ( d < -ps->lightRadius || d > ps->lightRadius ) {
260 // pshadow doesn't reach the plane
261 pshadowBits &= ~( 1 << i );
262 }
263 }
264 }
265
266 if ( surf->cullinfo.type & CULLINFO_BOX )
267 {
268 for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
269 if ( ! ( pshadowBits & ( 1 << i ) ) ) {
270 continue;
271 }
272 ps = &tr.refdef.pshadows[i];
273 if ( ps->lightOrigin[0] - ps->lightRadius > surf->cullinfo.bounds[1][0]
274 || ps->lightOrigin[0] + ps->lightRadius < surf->cullinfo.bounds[0][0]
275 || ps->lightOrigin[1] - ps->lightRadius > surf->cullinfo.bounds[1][1]
276 || ps->lightOrigin[1] + ps->lightRadius < surf->cullinfo.bounds[0][1]
277 || ps->lightOrigin[2] - ps->lightRadius > surf->cullinfo.bounds[1][2]
278 || ps->lightOrigin[2] + ps->lightRadius < surf->cullinfo.bounds[0][2]
279 || BoxOnPlaneSide(surf->cullinfo.bounds[0], surf->cullinfo.bounds[1], &ps->cullPlane) == 2 ) {
280 // pshadow doesn't reach the bounds
281 pshadowBits &= ~( 1 << i );
282 }
283 }
284 }
285
286 if ( surf->cullinfo.type & CULLINFO_SPHERE )
287 {
288 for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
289 if ( ! ( pshadowBits & ( 1 << i ) ) ) {
290 continue;
291 }
292 ps = &tr.refdef.pshadows[i];
293 if (!SpheresIntersect(ps->viewOrigin, ps->viewRadius, surf->cullinfo.localOrigin, surf->cullinfo.radius)
294 || DotProduct( surf->cullinfo.localOrigin, ps->cullPlane.normal ) - ps->cullPlane.dist < -surf->cullinfo.radius)
295 {
296 // pshadow doesn't reach the bounds
297 pshadowBits &= ~( 1 << i );
298 }
299 }
300 }
301
302 switch(*surf->data)
303 {
304 case SF_FACE:
305 case SF_GRID:
306 case SF_TRIANGLES:
307 ((srfBspSurface_t *)surf->data)->pshadowBits = pshadowBits;
308 break;
309
310 default:
311 pshadowBits = 0;
312 break;
313 }
314
315 if ( pshadowBits ) {
316 //tr.pc.c_dlightSurfaces++;
317 }
318
319 return pshadowBits;
320 }
321
322 /*
323 ======================
324 R_AddWorldSurface
325 ======================
326 */
R_AddWorldSurface(msurface_t * surf,int dlightBits,int pshadowBits)327 static void R_AddWorldSurface( msurface_t *surf, int dlightBits, int pshadowBits ) {
328 // FIXME: bmodel fog?
329
330 // try to cull before dlighting or adding
331 if ( R_CullSurface( surf ) ) {
332 return;
333 }
334
335 // check for dlighting
336 /*if ( dlightBits ) */{
337 dlightBits = R_DlightSurface( surf, dlightBits );
338 dlightBits = ( dlightBits != 0 );
339 }
340
341 // check for pshadows
342 /*if ( pshadowBits ) */{
343 pshadowBits = R_PshadowSurface( surf, pshadowBits);
344 pshadowBits = ( pshadowBits != 0 );
345 }
346
347 // GR - not tessellated
348 R_AddDrawSurf( surf->data, surf->shader, surf->fogIndex, dlightBits, pshadowBits, surf->cubemapIndex, ATI_TESS_NONE );
349 }
350
351 /*
352 =============================================================
353
354 BRUSH MODELS
355
356 =============================================================
357 */
358
359 //----(SA) added
360
361 /*
362 =================
363 R_BmodelFogNum
364
365 See if a sprite is inside a fog volume
366 Return positive with /any part/ of the brush falling within a fog volume
367 =================
368 */
R_BmodelFogNum(trRefEntity_t * re,bmodel_t * bmodel)369 int R_BmodelFogNum( trRefEntity_t *re, bmodel_t *bmodel ) {
370 int i, j;
371 fog_t *fog;
372
373 for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
374 fog = &tr.world->fogs[i];
375 for ( j = 0 ; j < 3 ; j++ ) {
376 if ( re->e.origin[j] + bmodel->bounds[0][j] > fog->bounds[1][j] ) {
377 break;
378 }
379 if ( re->e.origin[j] + bmodel->bounds[0][j] < fog->bounds[0][j] ) {
380 break;
381 }
382 }
383 if ( j == 3 ) {
384 return i;
385 }
386 for ( j = 0 ; j < 3 ; j++ ) {
387 if ( re->e.origin[j] + bmodel->bounds[1][j] > fog->bounds[1][j] ) {
388 break;
389 }
390 if ( bmodel->bounds[1][j] < fog->bounds[0][j] ) {
391 break;
392 }
393 }
394 if ( j == 3 ) {
395 return i;
396 }
397 }
398
399 return 0;
400 }
401
402 //----(SA) done
403
404
405 /*
406 =================
407 R_AddBrushModelSurfaces
408 =================
409
410 void R_AddBrushModelSurfaces( trRefEntity_t *ent ) {
411 bmodel_t *bmodel;
412 int clip;
413 model_t *pModel;
414 int i;
415 int fognum;
416
417 pModel = R_GetModelByHandle( ent->e.hModel );
418
419 bmodel = pModel->bmodel;
420
421 clip = R_CullLocalBox( bmodel->bounds );
422 if ( clip == CULL_OUT ) {
423 return;
424 }
425
426 R_SetupEntityLighting( &tr.refdef, ent );
427 R_DlightBmodel( bmodel );
428
429 //----(SA) modified
430 // determine if in fog
431 fognum = R_BmodelFogNum( ent, bmodel );
432
433 for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
434 ( bmodel->firstSurface + i )->fogIndex = fognum;
435 // Arnout: custom shader support for brushmodels
436 if ( ent->e.customShader ) {
437 R_AddWorldSurface( bmodel->firstSurface + i, R_GetShaderByHandle( ent->e.customShader ), tr.currentEntity->needDlights );
438 } else {
439 R_AddWorldSurface( bmodel->firstSurface + i, ( ( msurface_t * )( bmodel->firstSurface + i ) )->shader, tr.currentEntity->needDlights );
440 }
441 }
442 //----(SA) end
443 }
444 */
445
446 /*
447 =================
448 R_AddBrushModelSurfaces
449 =================
450 */
R_AddBrushModelSurfaces(trRefEntity_t * ent)451 void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
452 bmodel_t *bmodel;
453 int clip;
454 model_t *pModel;
455 int i;
456 int fognum;
457
458 pModel = R_GetModelByHandle( ent->e.hModel );
459
460 bmodel = pModel->bmodel;
461
462 clip = R_CullLocalBox( bmodel->bounds );
463 if ( clip == CULL_OUT ) {
464 return;
465 }
466
467 R_SetupEntityLighting( &tr.refdef, ent );
468 R_DlightBmodel( bmodel );
469
470 //----(SA) modified
471 // determine if in fog
472 fognum = R_BmodelFogNum( ent, bmodel );
473
474 for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
475 int surf = bmodel->firstSurface + i;
476
477 if (tr.world->surfacesViewCount[surf] != tr.viewCount)
478 {
479 tr.world->surfacesViewCount[surf] = tr.viewCount;
480 tr.world->surfaces[surf].fogIndex = fognum;
481 R_AddWorldSurface( tr.world->surfaces + surf, tr.currentEntity->needDlights, 0 );
482 }
483 }
484 //----(SA) end
485 }
486
487 /*
488 =============================================================
489
490 WORLD MODEL
491
492 =============================================================
493 */
494
495
496 /*
497 ================
498 R_RecursiveWorldNode
499 ================
500 */
R_RecursiveWorldNode(mnode_t * node,uint32_t planeBits,uint32_t dlightBits,uint32_t pshadowBits)501 static void R_RecursiveWorldNode( mnode_t *node, uint32_t planeBits, uint32_t dlightBits, uint32_t pshadowBits ) {
502
503 do {
504 uint32_t newDlights[2];
505 uint32_t newPShadows[2];
506
507 // if the node wasn't marked as potentially visible, exit
508 // pvs is skipped for depth shadows
509 if (!(tr.viewParms.flags & VPF_DEPTHSHADOW) && node->visCounts[tr.visIndex] != tr.visCounts[tr.visIndex]) {
510 return;
511 }
512
513 // if the bounding volume is outside the frustum, nothing
514 // inside can be visible OPTIMIZE: don't do this all the way to leafs?
515
516 if ( !r_nocull->integer ) {
517 int r;
518
519 if ( planeBits & 1 ) {
520 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
521 if (r == 2) {
522 return; // culled
523 }
524 if ( r == 1 ) {
525 planeBits &= ~1; // all descendants will also be in front
526 }
527 }
528
529 if ( planeBits & 2 ) {
530 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
531 if (r == 2) {
532 return; // culled
533 }
534 if ( r == 1 ) {
535 planeBits &= ~2; // all descendants will also be in front
536 }
537 }
538
539 if ( planeBits & 4 ) {
540 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
541 if (r == 2) {
542 return; // culled
543 }
544 if ( r == 1 ) {
545 planeBits &= ~4; // all descendants will also be in front
546 }
547 }
548
549 if ( planeBits & 8 ) {
550 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
551 if (r == 2) {
552 return; // culled
553 }
554 if ( r == 1 ) {
555 planeBits &= ~8; // all descendants will also be in front
556 }
557 }
558
559 if ( planeBits & 16 ) {
560 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[4]);
561 if (r == 2) {
562 return; // culled
563 }
564 if ( r == 1 ) {
565 planeBits &= ~16; // all descendants will also be in front
566 }
567 }
568 }
569
570 if ( node->contents != -1 ) {
571 break;
572 }
573
574 // node is just a decision point, so go down both sides
575 // since we don't care about sort orders, just go positive to negative
576
577 // determine which dlights are needed
578 newDlights[0] = 0;
579 newDlights[1] = 0;
580 if ( dlightBits ) {
581 int i;
582
583 for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
584 dlight_t *dl;
585 float dist;
586
587 if ( dlightBits & ( 1 << i ) ) {
588 dl = &tr.refdef.dlights[i];
589 dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;
590
591 if ( dist > -dl->radius ) {
592 newDlights[0] |= ( 1 << i );
593 }
594 if ( dist < dl->radius ) {
595 newDlights[1] |= ( 1 << i );
596 }
597 }
598 }
599 }
600
601 newPShadows[0] = 0;
602 newPShadows[1] = 0;
603 if ( pshadowBits ) {
604 int i;
605
606 for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
607 pshadow_t *shadow;
608 float dist;
609
610 if ( pshadowBits & ( 1 << i ) ) {
611 shadow = &tr.refdef.pshadows[i];
612 dist = DotProduct( shadow->lightOrigin, node->plane->normal ) - node->plane->dist;
613
614 if ( dist > -shadow->lightRadius ) {
615 newPShadows[0] |= ( 1 << i );
616 }
617 if ( dist < shadow->lightRadius ) {
618 newPShadows[1] |= ( 1 << i );
619 }
620 }
621 }
622 }
623
624 // recurse down the children, front side first
625 R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0], newPShadows[0] );
626
627 // tail recurse
628 node = node->children[1];
629 dlightBits = newDlights[1];
630 pshadowBits = newPShadows[1];
631 } while ( 1 );
632
633 {
634 // leaf node, so add mark surfaces
635 int c;
636 int surf, *view;
637
638 // RF, hack, dlight elimination above is unreliable
639 dlightBits = 0xffffffff;
640
641 tr.pc.c_leafs++;
642
643 // add to z buffer bounds
644 if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {
645 tr.viewParms.visBounds[0][0] = node->mins[0];
646 }
647 if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {
648 tr.viewParms.visBounds[0][1] = node->mins[1];
649 }
650 if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {
651 tr.viewParms.visBounds[0][2] = node->mins[2];
652 }
653
654 if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {
655 tr.viewParms.visBounds[1][0] = node->maxs[0];
656 }
657 if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {
658 tr.viewParms.visBounds[1][1] = node->maxs[1];
659 }
660 if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {
661 tr.viewParms.visBounds[1][2] = node->maxs[2];
662 }
663
664 // add surfaces
665 view = tr.world->marksurfaces + node->firstmarksurface;
666
667 c = node->nummarksurfaces;
668 while (c--) {
669 // just mark it as visible, so we don't jump out of the cache derefencing the surface
670 surf = *view;
671 if (tr.world->surfacesViewCount[surf] != tr.viewCount)
672 {
673 tr.world->surfacesViewCount[surf] = tr.viewCount;
674 tr.world->surfacesDlightBits[surf] = dlightBits;
675 tr.world->surfacesPshadowBits[surf] = pshadowBits;
676 }
677 else
678 {
679 tr.world->surfacesDlightBits[surf] |= dlightBits;
680 tr.world->surfacesPshadowBits[surf] |= pshadowBits;
681 }
682 view++;
683 }
684 }
685
686 }
687
688
689 /*
690 ===============
691 R_PointInLeaf
692 ===============
693 */
R_PointInLeaf(vec3_t p)694 static mnode_t *R_PointInLeaf( vec3_t p ) {
695 mnode_t *node;
696 float d;
697 cplane_t *plane;
698
699 if ( !tr.world ) {
700 ri.Error( ERR_DROP, "R_PointInLeaf: bad model" );
701 }
702
703 node = tr.world->nodes;
704 while ( 1 ) {
705 if ( node->contents != -1 ) {
706 break;
707 }
708 plane = node->plane;
709 d = DotProduct( p,plane->normal ) - plane->dist;
710 if ( d > 0 ) {
711 node = node->children[0];
712 } else {
713 node = node->children[1];
714 }
715 }
716
717 return node;
718 }
719
720 /*
721 ==============
722 R_ClusterPVS
723 ==============
724 */
R_ClusterPVS(int cluster)725 static const byte *R_ClusterPVS( int cluster ) {
726 if ( !tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) {
727 return NULL;
728 }
729
730 return tr.world->vis + cluster * tr.world->clusterBytes;
731 }
732
733
734
735 /*
736 ===============
737 R_MarkLeaves
738
739 Mark the leaves and nodes that are in the PVS for the current
740 cluster
741 ===============
742 */
R_MarkLeaves(void)743 static void R_MarkLeaves( void ) {
744 const byte *vis;
745 mnode_t *leaf, *parent;
746 int i;
747 int cluster;
748
749 // lockpvs lets designers walk around to determine the
750 // extent of the current pvs
751 if ( r_lockpvs->integer ) {
752 return;
753 }
754
755 // current viewcluster
756 leaf = R_PointInLeaf( tr.viewParms.pvsOrigin );
757 cluster = leaf->cluster;
758
759 // if the cluster is the same and the area visibility matrix
760 // hasn't changed, we don't need to mark everything again
761
762 for(i = 0; i < MAX_VISCOUNTS; i++)
763 {
764 // if the areamask or r_showcluster was modified, invalidate all visclusters
765 // this caused doors to open into undrawn areas
766 if (tr.refdef.areamaskModified || r_showcluster->modified)
767 {
768 tr.visClusters[i] = -2;
769 }
770 else if(tr.visClusters[i] == cluster)
771 {
772 if(tr.visClusters[i] != tr.visClusters[tr.visIndex] && r_showcluster->integer)
773 {
774 ri.Printf(PRINT_ALL, "found cluster:%i area:%i index:%i\n", cluster, leaf->area, i);
775 }
776 tr.visIndex = i;
777 return;
778 }
779 }
780
781 tr.visIndex = (tr.visIndex + 1) % MAX_VISCOUNTS;
782 tr.visCounts[tr.visIndex]++;
783 tr.visClusters[tr.visIndex] = cluster;
784
785 if ( r_showcluster->modified || r_showcluster->integer ) {
786 r_showcluster->modified = qfalse;
787 if ( r_showcluster->integer ) {
788 ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area );
789 }
790 }
791
792 vis = R_ClusterPVS(tr.visClusters[tr.visIndex]);
793
794 for ( i = 0,leaf = tr.world->nodes ; i < tr.world->numnodes ; i++, leaf++ ) {
795 cluster = leaf->cluster;
796 if ( cluster < 0 || cluster >= tr.world->numClusters ) {
797 continue;
798 }
799
800 // check general pvs
801 if ( vis && !(vis[cluster>>3] & (1<<(cluster&7))) ) {
802 continue;
803 }
804
805 // check for door connection
806 if ( ( tr.refdef.areamask[leaf->area >> 3] & ( 1 << ( leaf->area & 7 ) ) ) ) {
807 continue; // not visible
808 }
809
810 parent = leaf;
811 do {
812 if(parent->visCounts[tr.visIndex] == tr.visCounts[tr.visIndex])
813 break;
814 parent->visCounts[tr.visIndex] = tr.visCounts[tr.visIndex];
815 parent = parent->parent;
816 } while ( parent );
817 }
818 }
819
820
821 /*
822 =============
823 R_AddWorldSurfaces
824 =============
825 */
R_AddWorldSurfaces(void)826 void R_AddWorldSurfaces( void ) {
827 uint32_t planeBits, dlightBits, pshadowBits;
828
829 if ( !r_drawworld->integer ) {
830 return;
831 }
832
833 if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
834 return;
835 }
836
837 tr.currentEntityNum = REFENTITYNUM_WORLD;
838 tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
839
840 // determine which leaves are in the PVS / areamask
841 if (!(tr.viewParms.flags & VPF_DEPTHSHADOW))
842 R_MarkLeaves ();
843
844 // clear out the visible min/max
845 ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
846
847 // perform frustum culling and flag all the potentially visible surfaces
848 if ( tr.refdef.num_dlights > MAX_DLIGHTS ) {
849 tr.refdef.num_dlights = MAX_DLIGHTS ;
850 }
851
852 if ( tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS ) {
853 tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS;
854 }
855
856 planeBits = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 31 : 15;
857
858 if ( tr.viewParms.flags & VPF_DEPTHSHADOW )
859 {
860 dlightBits = 0;
861 pshadowBits = 0;
862 }
863 else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) )
864 {
865 dlightBits = ( 1ULL << tr.refdef.num_dlights ) - 1;
866 pshadowBits = ( 1ULL << tr.refdef.num_pshadows ) - 1;
867 }
868 else
869 {
870 dlightBits = ( 1ULL << tr.refdef.num_dlights ) - 1;
871 pshadowBits = 0;
872 }
873
874 R_RecursiveWorldNode( tr.world->nodes, planeBits, dlightBits, pshadowBits);
875
876 // now add all the potentially visible surfaces
877 // also mask invisible dlights for next frame
878 {
879 int i;
880
881 tr.refdef.dlightMask = 0;
882
883 for (i = 0; i < tr.world->numWorldSurfaces; i++)
884 {
885 if (tr.world->surfacesViewCount[i] != tr.viewCount)
886 continue;
887
888 R_AddWorldSurface( tr.world->surfaces + i, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] );
889 tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i];
890 }
891
892 tr.refdef.dlightMask = ~tr.refdef.dlightMask;
893 }
894 }
895