1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19 
20 //
21 // rf_cull.c
22 //
23 
24 #include "rf_local.h"
25 
26 /*
27 =============================================================================
28 
29 	FRUSTUM CULLING
30 
31 =============================================================================
32 */
33 
34 /*
35 ===============
36 R_SetupFrustum
37 ===============
38 */
R_SetupFrustum(void)39 void R_SetupFrustum (void)
40 {
41 	int		i;
42 
43 	// Calculate the view frustum
44 	Vec3Copy (ri.def.viewAxis[0], ri.scn.viewFrustum[0].normal);
45 	RotatePointAroundVector (ri.scn.viewFrustum[1].normal, ri.def.viewAxis[2], ri.def.viewAxis[0], -(90-ri.def.fovX / 2));
46 	RotatePointAroundVector (ri.scn.viewFrustum[2].normal, ri.def.viewAxis[2], ri.def.viewAxis[0], 90-ri.def.fovX / 2);
47 	RotatePointAroundVector (ri.scn.viewFrustum[3].normal, ri.def.rightVec, ri.def.viewAxis[0], 90-ri.def.fovY / 2);
48 	RotatePointAroundVector (ri.scn.viewFrustum[4].normal, ri.def.rightVec, ri.def.viewAxis[0], -(90 - ri.def.fovY / 2));
49 
50 	for (i=0 ; i<5 ; i++) {
51 		ri.scn.viewFrustum[i].type = PLANE_NON_AXIAL;
52 		ri.scn.viewFrustum[i].dist = DotProduct (ri.def.viewOrigin, ri.scn.viewFrustum[i].normal);
53 		ri.scn.viewFrustum[i].signBits = SignbitsForPlane (&ri.scn.viewFrustum[i]);
54 	}
55 
56 	ri.scn.viewFrustum[0].dist += r_zNear->floatVal;
57 }
58 
59 
60 /*
61 =================
62 R_CullBox
63 
64 Returns qTrue if the box is completely outside the frustum
65 =================
66 */
R_CullBox(vec3_t mins,vec3_t maxs,int clipFlags)67 qBool R_CullBox (vec3_t mins, vec3_t maxs, int clipFlags)
68 {
69 	int			i;
70 	cBspPlane_t	*p;
71 
72 	if (r_noCull->intVal)
73 		return qFalse;
74 
75 	for (i=0, p=ri.scn.viewFrustum ; i<5 ; p++, i++) {
76 		if (!(clipFlags & (1<<i)))
77 			continue;
78 
79 		switch (p->signBits) {
80 		case 0:
81 			if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) {
82 				ri.pc.cullBounds[CULL_PASS]++;
83 				return qTrue;
84 			}
85 			break;
86 
87 		case 1:
88 			if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist) {
89 				ri.pc.cullBounds[CULL_PASS]++;
90 				return qTrue;
91 			}
92 			break;
93 
94 		case 2:
95 			if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) {
96 				ri.pc.cullBounds[CULL_PASS]++;
97 				return qTrue;
98 			}
99 			break;
100 
101 		case 3:
102 			if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist) {
103 				ri.pc.cullBounds[CULL_PASS]++;
104 				return qTrue;
105 			}
106 			break;
107 
108 		case 4:
109 			if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) {
110 				ri.pc.cullBounds[CULL_PASS]++;
111 				return qTrue;
112 			}
113 			break;
114 
115 		case 5:
116 			if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist) {
117 				ri.pc.cullBounds[CULL_PASS]++;
118 				return qTrue;
119 			}
120 			break;
121 
122 		case 6:
123 			if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) {
124 				ri.pc.cullBounds[CULL_PASS]++;
125 				return qTrue;
126 			}
127 			break;
128 
129 		case 7:
130 			if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist) {
131 				ri.pc.cullBounds[CULL_PASS]++;
132 				return qTrue;
133 			}
134 			break;
135 
136 		default:
137 			assert (0);
138 			return qFalse;
139 		}
140 	}
141 
142 	ri.pc.cullBounds[CULL_FAIL]++;
143 	return qFalse;
144 }
145 
146 
147 /*
148 =================
149 R_CullSphere
150 
151 Returns qTrue if the sphere is completely outside the frustum
152 =================
153 */
R_CullSphere(const vec3_t origin,const float radius,int clipFlags)154 qBool R_CullSphere (const vec3_t origin, const float radius, int clipFlags)
155 {
156 	int			i;
157 	cBspPlane_t	*p;
158 
159 	if (r_noCull->intVal)
160 		return qFalse;
161 
162 	for (i=0, p=ri.scn.viewFrustum ; i<5 ; p++, i++) {
163 		if (!(clipFlags & (1<<i)))
164 			continue;
165 
166 		if (DotProduct(origin, p->normal)-p->dist <= -radius) {
167 			ri.pc.cullRadius[CULL_PASS]++;
168 			return qTrue;
169 		}
170 	}
171 
172 	ri.pc.cullRadius[CULL_FAIL]++;
173 	return qFalse;
174 }
175 
176 /*
177 =============================================================================
178 
179 	MAP VISIBILITY CULLING
180 
181 =============================================================================
182 */
183 
184 /*
185 ===============
186 R_CullNode
187 
188 Returns qTrue if this node hasn't been touched this frame
189 ===============
190 */
R_CullNode(mBspNode_t * node)191 qBool R_CullNode (mBspNode_t *node)
192 {
193 	if (r_noCull->intVal)
194 		return qFalse;
195 
196 	if (!node || node->c.visFrame == ri.scn.visFrameCount) {
197 		ri.pc.cullVis[CULL_FAIL]++;
198 		return qFalse;
199 	}
200 
201 	ri.pc.cullVis[CULL_PASS]++;
202 	return qTrue;
203 }
204 
205 
206 /*
207 ===============
208 R_CullSurface
209 
210 Returns qTrue if this surface hasn't been touched this frame
211 ===============
212 */
R_CullSurface(mBspSurface_t * surf)213 qBool R_CullSurface (mBspSurface_t *surf)
214 {
215 	if (r_noCull->intVal)
216 		return qFalse;
217 
218 	if (!surf || surf->visFrame == ri.frameCount) {
219 		ri.pc.cullSurf[CULL_FAIL]++;
220 		return qFalse;
221 	}
222 
223 	ri.pc.cullSurf[CULL_PASS]++;
224 	return qTrue;
225 }
226