1 /*
2 ===========================================================================
3
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (RTCW MP Source Code).
8
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #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,shader_t * shader,int dlightBits,int pshadowBits)327 static void R_AddWorldSurface( msurface_t *surf, shader_t *shader, 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 R_AddDrawSurf( surf->data, shader, surf->fogIndex, dlightBits, pshadowBits, surf->cubemapIndex );
348 }
349
350 /*
351 =============================================================
352
353 BRUSH MODELS
354
355 =============================================================
356 */
357
358 //----(SA) added
359
360 /*
361 =================
362 R_BmodelFogNum
363
364 See if a sprite is inside a fog volume
365 Return positive with /any part/ of the brush falling within a fog volume
366 =================
367 */
R_BmodelFogNum(trRefEntity_t * re,bmodel_t * bmodel)368 int R_BmodelFogNum( trRefEntity_t *re, bmodel_t *bmodel ) {
369 int i, j;
370 fog_t *fog;
371
372 for ( i = 1 ; i < tr.world->numfogs ; i++ ) {
373 fog = &tr.world->fogs[i];
374 for ( j = 0 ; j < 3 ; j++ ) {
375 if ( re->e.origin[j] + bmodel->bounds[0][j] > fog->bounds[1][j] ) {
376 break;
377 }
378 if ( re->e.origin[j] + bmodel->bounds[0][j] < fog->bounds[0][j] ) {
379 break;
380 }
381 }
382 if ( j == 3 ) {
383 return i;
384 }
385 for ( j = 0 ; j < 3 ; j++ ) {
386 if ( re->e.origin[j] + bmodel->bounds[1][j] > fog->bounds[1][j] ) {
387 break;
388 }
389 if ( bmodel->bounds[1][j] < fog->bounds[0][j] ) {
390 break;
391 }
392 }
393 if ( j == 3 ) {
394 return i;
395 }
396 }
397
398 return 0;
399 }
400
401 //----(SA) done
402
403
404 /*
405 =================
406 R_AddBrushModelSurfaces
407 =================
408 */
R_AddBrushModelSurfaces(trRefEntity_t * ent)409 void R_AddBrushModelSurfaces ( trRefEntity_t *ent ) {
410 bmodel_t *bmodel;
411 int clip;
412 model_t *pModel;
413 int i;
414 int fognum;
415
416 pModel = R_GetModelByHandle( ent->e.hModel );
417
418 bmodel = pModel->bmodel;
419
420 clip = R_CullLocalBox( bmodel->bounds );
421 if ( clip == CULL_OUT ) {
422 return;
423 }
424
425 R_SetupEntityLighting( &tr.refdef, ent );
426 R_DlightBmodel( bmodel );
427
428 //----(SA) modified
429 // determine if in fog
430 fognum = R_BmodelFogNum( ent, bmodel );
431
432 for ( i = 0 ; i < bmodel->numSurfaces ; i++ ) {
433 int surf = bmodel->firstSurface + i;
434
435 if (tr.world->surfacesViewCount[surf] != tr.viewCount)
436 {
437 tr.world->surfacesViewCount[surf] = tr.viewCount;
438 tr.world->surfaces[surf].fogIndex = fognum;
439
440 // Arnout: custom shader support for brushmodels
441 if ( ent->e.customShader ) {
442 R_AddWorldSurface( tr.world->surfaces + surf, R_GetShaderByHandle( ent->e.customShader ), tr.currentEntity->needDlights, 0 );
443 } else {
444 R_AddWorldSurface( tr.world->surfaces + surf, ( ( msurface_t * )( tr.world->surfaces + surf ) )->shader, tr.currentEntity->needDlights, 0 );
445 }
446 }
447 }
448 //----(SA) end
449 }
450
451 /*
452 =============================================================
453
454 WORLD MODEL
455
456 =============================================================
457 */
458
459
460 /*
461 ================
462 R_RecursiveWorldNode
463 ================
464 */
R_RecursiveWorldNode(mnode_t * node,uint32_t planeBits,uint32_t dlightBits,uint32_t pshadowBits)465 static void R_RecursiveWorldNode( mnode_t *node, uint32_t planeBits, uint32_t dlightBits, uint32_t pshadowBits ) {
466
467 do {
468 uint32_t newDlights[2];
469 uint32_t newPShadows[2];
470
471 // if the node wasn't marked as potentially visible, exit
472 // pvs is skipped for depth shadows
473 if (!(tr.viewParms.flags & VPF_DEPTHSHADOW) && node->visCounts[tr.visIndex] != tr.visCounts[tr.visIndex]) {
474 return;
475 }
476
477 // if the bounding volume is outside the frustum, nothing
478 // inside can be visible OPTIMIZE: don't do this all the way to leafs?
479
480 if ( !r_nocull->integer ) {
481 int r;
482
483 if ( planeBits & 1 ) {
484 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[0]);
485 if (r == 2) {
486 return; // culled
487 }
488 if ( r == 1 ) {
489 planeBits &= ~1; // all descendants will also be in front
490 }
491 }
492
493 if ( planeBits & 2 ) {
494 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[1]);
495 if (r == 2) {
496 return; // culled
497 }
498 if ( r == 1 ) {
499 planeBits &= ~2; // all descendants will also be in front
500 }
501 }
502
503 if ( planeBits & 4 ) {
504 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[2]);
505 if (r == 2) {
506 return; // culled
507 }
508 if ( r == 1 ) {
509 planeBits &= ~4; // all descendants will also be in front
510 }
511 }
512
513 if ( planeBits & 8 ) {
514 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[3]);
515 if (r == 2) {
516 return; // culled
517 }
518 if ( r == 1 ) {
519 planeBits &= ~8; // all descendants will also be in front
520 }
521 }
522
523 if ( planeBits & 16 ) {
524 r = BoxOnPlaneSide(node->mins, node->maxs, &tr.viewParms.frustum[4]);
525 if (r == 2) {
526 return; // culled
527 }
528 if ( r == 1 ) {
529 planeBits &= ~16; // all descendants will also be in front
530 }
531 }
532 }
533
534 if ( node->contents != -1 ) {
535 break;
536 }
537
538 // node is just a decision point, so go down both sides
539 // since we don't care about sort orders, just go positive to negative
540
541 // determine which dlights are needed
542 newDlights[0] = 0;
543 newDlights[1] = 0;
544 if ( dlightBits ) {
545 int i;
546
547 for ( i = 0 ; i < tr.refdef.num_dlights ; i++ ) {
548 dlight_t *dl;
549 float dist;
550
551 if ( dlightBits & ( 1 << i ) ) {
552 dl = &tr.refdef.dlights[i];
553 dist = DotProduct( dl->origin, node->plane->normal ) - node->plane->dist;
554
555 if ( dist > -dl->radius ) {
556 newDlights[0] |= ( 1 << i );
557 }
558 if ( dist < dl->radius ) {
559 newDlights[1] |= ( 1 << i );
560 }
561 }
562 }
563 }
564
565 newPShadows[0] = 0;
566 newPShadows[1] = 0;
567 if ( pshadowBits ) {
568 int i;
569
570 for ( i = 0 ; i < tr.refdef.num_pshadows ; i++ ) {
571 pshadow_t *shadow;
572 float dist;
573
574 if ( pshadowBits & ( 1 << i ) ) {
575 shadow = &tr.refdef.pshadows[i];
576 dist = DotProduct( shadow->lightOrigin, node->plane->normal ) - node->plane->dist;
577
578 if ( dist > -shadow->lightRadius ) {
579 newPShadows[0] |= ( 1 << i );
580 }
581 if ( dist < shadow->lightRadius ) {
582 newPShadows[1] |= ( 1 << i );
583 }
584 }
585 }
586 }
587
588 // recurse down the children, front side first
589 R_RecursiveWorldNode (node->children[0], planeBits, newDlights[0], newPShadows[0] );
590
591 // tail recurse
592 node = node->children[1];
593 dlightBits = newDlights[1];
594 pshadowBits = newPShadows[1];
595 } while ( 1 );
596
597 {
598 // leaf node, so add mark surfaces
599 int c;
600 int surf, *view;
601
602 // RF, hack, dlight elimination above is unreliable
603 dlightBits = 0xffffffff;
604
605 tr.pc.c_leafs++;
606
607 // add to z buffer bounds
608 if ( node->mins[0] < tr.viewParms.visBounds[0][0] ) {
609 tr.viewParms.visBounds[0][0] = node->mins[0];
610 }
611 if ( node->mins[1] < tr.viewParms.visBounds[0][1] ) {
612 tr.viewParms.visBounds[0][1] = node->mins[1];
613 }
614 if ( node->mins[2] < tr.viewParms.visBounds[0][2] ) {
615 tr.viewParms.visBounds[0][2] = node->mins[2];
616 }
617
618 if ( node->maxs[0] > tr.viewParms.visBounds[1][0] ) {
619 tr.viewParms.visBounds[1][0] = node->maxs[0];
620 }
621 if ( node->maxs[1] > tr.viewParms.visBounds[1][1] ) {
622 tr.viewParms.visBounds[1][1] = node->maxs[1];
623 }
624 if ( node->maxs[2] > tr.viewParms.visBounds[1][2] ) {
625 tr.viewParms.visBounds[1][2] = node->maxs[2];
626 }
627
628 // add surfaces
629 view = tr.world->marksurfaces + node->firstmarksurface;
630
631 c = node->nummarksurfaces;
632 while (c--) {
633 // just mark it as visible, so we don't jump out of the cache derefencing the surface
634 surf = *view;
635 if (tr.world->surfacesViewCount[surf] != tr.viewCount)
636 {
637 tr.world->surfacesViewCount[surf] = tr.viewCount;
638 tr.world->surfacesDlightBits[surf] = dlightBits;
639 tr.world->surfacesPshadowBits[surf] = pshadowBits;
640 }
641 else
642 {
643 tr.world->surfacesDlightBits[surf] |= dlightBits;
644 tr.world->surfacesPshadowBits[surf] |= pshadowBits;
645 }
646 view++;
647 }
648 }
649
650 }
651
652
653 /*
654 ===============
655 R_PointInLeaf
656 ===============
657 */
R_PointInLeaf(vec3_t p)658 static mnode_t *R_PointInLeaf( vec3_t p ) {
659 mnode_t *node;
660 float d;
661 cplane_t *plane;
662
663 if ( !tr.world ) {
664 ri.Error( ERR_DROP, "R_PointInLeaf: bad model" );
665 }
666
667 node = tr.world->nodes;
668 while ( 1 ) {
669 if ( node->contents != -1 ) {
670 break;
671 }
672 plane = node->plane;
673 d = DotProduct( p,plane->normal ) - plane->dist;
674 if ( d > 0 ) {
675 node = node->children[0];
676 } else {
677 node = node->children[1];
678 }
679 }
680
681 return node;
682 }
683
684 /*
685 ==============
686 R_ClusterPVS
687 ==============
688 */
R_ClusterPVS(int cluster)689 static const byte *R_ClusterPVS( int cluster ) {
690 if ( !tr.world->vis || cluster < 0 || cluster >= tr.world->numClusters ) {
691 return NULL;
692 }
693
694 return tr.world->vis + cluster * tr.world->clusterBytes;
695 }
696
697
698
699 /*
700 ===============
701 R_MarkLeaves
702
703 Mark the leaves and nodes that are in the PVS for the current
704 cluster
705 ===============
706 */
R_MarkLeaves(void)707 static void R_MarkLeaves( void ) {
708 const byte *vis;
709 mnode_t *leaf, *parent;
710 int i;
711 int cluster;
712
713 // lockpvs lets designers walk around to determine the
714 // extent of the current pvs
715 if ( r_lockpvs->integer ) {
716 return;
717 }
718
719 // current viewcluster
720 leaf = R_PointInLeaf( tr.viewParms.pvsOrigin );
721 cluster = leaf->cluster;
722
723 // if the cluster is the same and the area visibility matrix
724 // hasn't changed, we don't need to mark everything again
725
726 for(i = 0; i < MAX_VISCOUNTS; i++)
727 {
728 // if the areamask or r_showcluster was modified, invalidate all visclusters
729 // this caused doors to open into undrawn areas
730 if (tr.refdef.areamaskModified || r_showcluster->modified)
731 {
732 tr.visClusters[i] = -2;
733 }
734 else if(tr.visClusters[i] == cluster)
735 {
736 if(tr.visClusters[i] != tr.visClusters[tr.visIndex] && r_showcluster->integer)
737 {
738 ri.Printf(PRINT_ALL, "found cluster:%i area:%i index:%i\n", cluster, leaf->area, i);
739 }
740 tr.visIndex = i;
741 return;
742 }
743 }
744
745 tr.visIndex = (tr.visIndex + 1) % MAX_VISCOUNTS;
746 tr.visCounts[tr.visIndex]++;
747 tr.visClusters[tr.visIndex] = cluster;
748
749 if ( r_showcluster->modified || r_showcluster->integer ) {
750 r_showcluster->modified = qfalse;
751 if ( r_showcluster->integer ) {
752 ri.Printf( PRINT_ALL, "cluster:%i area:%i\n", cluster, leaf->area );
753 }
754 }
755
756 vis = R_ClusterPVS(tr.visClusters[tr.visIndex]);
757
758 for ( i = 0,leaf = tr.world->nodes ; i < tr.world->numnodes ; i++, leaf++ ) {
759 cluster = leaf->cluster;
760 if ( cluster < 0 || cluster >= tr.world->numClusters ) {
761 continue;
762 }
763
764 // check general pvs
765 if ( vis && !(vis[cluster>>3] & (1<<(cluster&7))) ) {
766 continue;
767 }
768
769 // check for door connection
770 if ( ( tr.refdef.areamask[leaf->area >> 3] & ( 1 << ( leaf->area & 7 ) ) ) ) {
771 continue; // not visible
772 }
773
774 parent = leaf;
775 do {
776 if(parent->visCounts[tr.visIndex] == tr.visCounts[tr.visIndex])
777 break;
778 parent->visCounts[tr.visIndex] = tr.visCounts[tr.visIndex];
779 parent = parent->parent;
780 } while ( parent );
781 }
782 }
783
784
785 /*
786 =============
787 R_AddWorldSurfaces
788 =============
789 */
R_AddWorldSurfaces(void)790 void R_AddWorldSurfaces( void ) {
791 uint32_t planeBits, dlightBits, pshadowBits;
792
793 if ( !r_drawworld->integer ) {
794 return;
795 }
796
797 if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) {
798 return;
799 }
800
801 tr.currentEntityNum = REFENTITYNUM_WORLD;
802 tr.shiftedEntityNum = tr.currentEntityNum << QSORT_REFENTITYNUM_SHIFT;
803
804 // determine which leaves are in the PVS / areamask
805 if (!(tr.viewParms.flags & VPF_DEPTHSHADOW))
806 R_MarkLeaves ();
807
808 // clear out the visible min/max
809 ClearBounds( tr.viewParms.visBounds[0], tr.viewParms.visBounds[1] );
810
811 // perform frustum culling and flag all the potentially visible surfaces
812 if ( tr.refdef.num_dlights > MAX_DLIGHTS ) {
813 tr.refdef.num_dlights = MAX_DLIGHTS ;
814 }
815
816 if ( tr.refdef.num_pshadows > MAX_DRAWN_PSHADOWS ) {
817 tr.refdef.num_pshadows = MAX_DRAWN_PSHADOWS;
818 }
819
820 planeBits = (tr.viewParms.flags & VPF_FARPLANEFRUSTUM) ? 31 : 15;
821
822 if ( tr.viewParms.flags & VPF_DEPTHSHADOW )
823 {
824 dlightBits = 0;
825 pshadowBits = 0;
826 }
827 else if ( !(tr.viewParms.flags & VPF_SHADOWMAP) )
828 {
829 dlightBits = ( 1ULL << tr.refdef.num_dlights ) - 1;
830 pshadowBits = ( 1ULL << tr.refdef.num_pshadows ) - 1;
831 }
832 else
833 {
834 dlightBits = ( 1ULL << tr.refdef.num_dlights ) - 1;
835 pshadowBits = 0;
836 }
837
838 R_RecursiveWorldNode( tr.world->nodes, planeBits, dlightBits, pshadowBits);
839
840 // now add all the potentially visible surfaces
841 // also mask invisible dlights for next frame
842 {
843 int i;
844 msurface_t *surf;
845
846 tr.refdef.dlightMask = 0;
847
848 for (i = 0; i < tr.world->numWorldSurfaces; i++)
849 {
850 if (tr.world->surfacesViewCount[i] != tr.viewCount)
851 continue;
852
853 surf = (msurface_t*)tr.world->surfaces + i;
854
855 R_AddWorldSurface( surf, surf->shader, tr.world->surfacesDlightBits[i], tr.world->surfacesPshadowBits[i] );
856 tr.refdef.dlightMask |= tr.world->surfacesDlightBits[i];
857 }
858
859 tr.refdef.dlightMask = ~tr.refdef.dlightMask;
860 }
861 }
862