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