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