1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 #include "cm_local.h"
23 
24 
25 /*
26 ==================
27 CM_PointLeafnum_r
28 
29 ==================
30 */
CM_PointLeafnum_r(const vec3_t p,int num)31 int CM_PointLeafnum_r( const vec3_t p, int num ) {
32 	float		d;
33 	cNode_t		*node;
34 	cplane_t	*plane;
35 
36 	while (num >= 0)
37 	{
38 		node = cm.nodes + num;
39 		plane = node->plane;
40 
41 		if (plane->type < 3)
42 			d = p[plane->type] - plane->dist;
43 		else
44 			d = DotProduct (plane->normal, p) - plane->dist;
45 		if (d < 0)
46 			num = node->children[1];
47 		else
48 			num = node->children[0];
49 	}
50 
51 	c_pointcontents++;		// optimize counter
52 
53 	return -1 - num;
54 }
55 
CM_PointLeafnum(const vec3_t p)56 int CM_PointLeafnum( const vec3_t p ) {
57 	if ( !cm.numNodes ) {	// map not loaded
58 		return 0;
59 	}
60 	return CM_PointLeafnum_r (p, 0);
61 }
62 
63 
64 /*
65 ======================================================================
66 
67 LEAF LISTING
68 
69 ======================================================================
70 */
71 
72 
CM_StoreLeafs(leafList_t * ll,int nodenum)73 void CM_StoreLeafs( leafList_t *ll, int nodenum ) {
74 	int		leafNum;
75 
76 	leafNum = -1 - nodenum;
77 
78 	// store the lastLeaf even if the list is overflowed
79 	if ( cm.leafs[ leafNum ].cluster != -1 ) {
80 		ll->lastLeaf = leafNum;
81 	}
82 
83 	if ( ll->count >= ll->maxcount) {
84 		ll->overflowed = qtrue;
85 		return;
86 	}
87 	ll->list[ ll->count++ ] = leafNum;
88 }
89 
CM_StoreBrushes(leafList_t * ll,int nodenum)90 void CM_StoreBrushes( leafList_t *ll, int nodenum ) {
91 	int			i, k;
92 	int			leafnum;
93 	int			brushnum;
94 	cLeaf_t		*leaf;
95 	cbrush_t	*b;
96 
97 	leafnum = -1 - nodenum;
98 
99 	leaf = &cm.leafs[leafnum];
100 
101 	for ( k = 0 ; k < leaf->numLeafBrushes ; k++ ) {
102 		brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
103 		b = &cm.brushes[brushnum];
104 		if ( b->checkcount == cm.checkcount ) {
105 			continue;	// already checked this brush in another leaf
106 		}
107 		b->checkcount = cm.checkcount;
108 		for ( i = 0 ; i < 3 ; i++ ) {
109 			if ( b->bounds[0][i] >= ll->bounds[1][i] || b->bounds[1][i] <= ll->bounds[0][i] ) {
110 				break;
111 			}
112 		}
113 		if ( i != 3 ) {
114 			continue;
115 		}
116 		if ( ll->count >= ll->maxcount) {
117 			ll->overflowed = qtrue;
118 			return;
119 		}
120 		((cbrush_t **)ll->list)[ ll->count++ ] = b;
121 	}
122 #if 0
123 	// store patches?
124 	for ( k = 0 ; k < leaf->numLeafSurfaces ; k++ ) {
125 		patch = cm.surfaces[ cm.leafsurfaces[ leaf->firstleafsurface + k ] ];
126 		if ( !patch ) {
127 			continue;
128 		}
129 	}
130 #endif
131 }
132 
133 /*
134 =============
135 CM_BoxLeafnums
136 
137 Fills in a list of all the leafs touched
138 =============
139 */
CM_BoxLeafnums_r(leafList_t * ll,int nodenum)140 void CM_BoxLeafnums_r( leafList_t *ll, int nodenum ) {
141 	cplane_t	*plane;
142 	cNode_t		*node;
143 	int			s;
144 
145 	while (1) {
146 		if (nodenum < 0) {
147 			ll->storeLeafs( ll, nodenum );
148 			return;
149 		}
150 
151 		node = &cm.nodes[nodenum];
152 		plane = node->plane;
153 		s = BoxOnPlaneSide( ll->bounds[0], ll->bounds[1], plane );
154 		if (s == 1) {
155 			nodenum = node->children[0];
156 		} else if (s == 2) {
157 			nodenum = node->children[1];
158 		} else {
159 			// go down both
160 			CM_BoxLeafnums_r( ll, node->children[0] );
161 			nodenum = node->children[1];
162 		}
163 
164 	}
165 }
166 
167 /*
168 ==================
169 CM_BoxLeafnums
170 ==================
171 */
CM_BoxLeafnums(const vec3_t mins,const vec3_t maxs,int * list,int listsize,int * lastLeaf)172 int	CM_BoxLeafnums( const vec3_t mins, const vec3_t maxs, int *list, int listsize, int *lastLeaf) {
173 	leafList_t	ll;
174 
175 	cm.checkcount++;
176 
177 	VectorCopy( mins, ll.bounds[0] );
178 	VectorCopy( maxs, ll.bounds[1] );
179 	ll.count = 0;
180 	ll.maxcount = listsize;
181 	ll.list = list;
182 	ll.storeLeafs = CM_StoreLeafs;
183 	ll.lastLeaf = 0;
184 	ll.overflowed = qfalse;
185 
186 	CM_BoxLeafnums_r( &ll, 0 );
187 
188 	*lastLeaf = ll.lastLeaf;
189 	return ll.count;
190 }
191 
192 /*
193 ==================
194 CM_BoxBrushes
195 ==================
196 */
CM_BoxBrushes(const vec3_t mins,const vec3_t maxs,cbrush_t ** list,int listsize)197 int CM_BoxBrushes( const vec3_t mins, const vec3_t maxs, cbrush_t **list, int listsize ) {
198 	leafList_t	ll;
199 
200 	cm.checkcount++;
201 
202 	VectorCopy( mins, ll.bounds[0] );
203 	VectorCopy( maxs, ll.bounds[1] );
204 	ll.count = 0;
205 	ll.maxcount = listsize;
206 	ll.list = (void *)list;
207 	ll.storeLeafs = CM_StoreBrushes;
208 	ll.lastLeaf = 0;
209 	ll.overflowed = qfalse;
210 
211 	CM_BoxLeafnums_r( &ll, 0 );
212 
213 	return ll.count;
214 }
215 
216 
217 //====================================================================
218 
219 
220 /*
221 ==================
222 CM_PointContents
223 
224 ==================
225 */
CM_PointContents(const vec3_t p,clipHandle_t model)226 int CM_PointContents( const vec3_t p, clipHandle_t model ) {
227 	int			leafnum;
228 	int			i, k;
229 	int			brushnum;
230 	cLeaf_t		*leaf;
231 	cbrush_t	*b;
232 	int			contents;
233 	float		d;
234 	cmodel_t	*clipm;
235 
236 	if (!cm.numNodes) {	// map not loaded
237 		return 0;
238 	}
239 
240 	if ( model ) {
241 		clipm = CM_ClipHandleToModel( model );
242 		leaf = &clipm->leaf;
243 	} else {
244 		leafnum = CM_PointLeafnum_r (p, 0);
245 		leaf = &cm.leafs[leafnum];
246 	}
247 
248 	contents = 0;
249 	for (k=0 ; k<leaf->numLeafBrushes ; k++) {
250 		brushnum = cm.leafbrushes[leaf->firstLeafBrush+k];
251 		b = &cm.brushes[brushnum];
252 
253 		if ( !CM_BoundsIntersectPoint( b->bounds[0], b->bounds[1], p ) ) {
254 			continue;
255 		}
256 
257 		// see if the point is in the brush
258 		for ( i = 0 ; i < b->numsides ; i++ ) {
259 			d = DotProduct( p, b->sides[i].plane->normal );
260 // FIXME test for Cash
261 //			if ( d >= b->sides[i].plane->dist ) {
262 			if ( d > b->sides[i].plane->dist ) {
263 				break;
264 			}
265 		}
266 
267 		if ( i == b->numsides ) {
268 			contents |= b->contents;
269 		}
270 	}
271 
272 	return contents;
273 }
274 
275 /*
276 ==================
277 CM_TransformedPointContents
278 
279 Handles offseting and rotation of the end points for moving and
280 rotating entities
281 ==================
282 */
CM_TransformedPointContents(const vec3_t p,clipHandle_t model,const vec3_t origin,const vec3_t angles)283 int	CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles) {
284 	vec3_t		p_l;
285 	vec3_t		temp;
286 	vec3_t		forward, right, up;
287 
288 	// subtract origin offset
289 	VectorSubtract (p, origin, p_l);
290 
291 	// rotate start and end into the models frame of reference
292 	if ( model != BOX_MODEL_HANDLE &&
293 	(angles[0] || angles[1] || angles[2]) )
294 	{
295 		AngleVectors (angles, forward, right, up);
296 
297 		VectorCopy (p_l, temp);
298 		p_l[0] = DotProduct (temp, forward);
299 		p_l[1] = -DotProduct (temp, right);
300 		p_l[2] = DotProduct (temp, up);
301 	}
302 
303 	return CM_PointContents( p_l, model );
304 }
305 
306 
307 
308 /*
309 ===============================================================================
310 
311 PVS
312 
313 ===============================================================================
314 */
315 
CM_ClusterPVS(int cluster)316 byte	*CM_ClusterPVS (int cluster) {
317 	if (cluster < 0 || cluster >= cm.numClusters || !cm.vised ) {
318 		return cm.visibility;
319 	}
320 
321 	return cm.visibility + cluster * cm.clusterBytes;
322 }
323 
324 
325 
326 /*
327 ===============================================================================
328 
329 AREAPORTALS
330 
331 ===============================================================================
332 */
333 
CM_FloodArea_r(int areaNum,int floodnum)334 void CM_FloodArea_r( int areaNum, int floodnum) {
335 	int		i;
336 	cArea_t *area;
337 	int		*con;
338 
339 	area = &cm.areas[ areaNum ];
340 
341 	if ( area->floodvalid == cm.floodvalid ) {
342 		if (area->floodnum == floodnum)
343 			return;
344 		Com_Error (ERR_DROP, "FloodArea_r: reflooded");
345 	}
346 
347 	area->floodnum = floodnum;
348 	area->floodvalid = cm.floodvalid;
349 	con = cm.areaPortals + areaNum * cm.numAreas;
350 	for ( i=0 ; i < cm.numAreas  ; i++ ) {
351 		if ( con[i] > 0 ) {
352 			CM_FloodArea_r( i, floodnum );
353 		}
354 	}
355 }
356 
357 /*
358 ====================
359 CM_FloodAreaConnections
360 
361 ====================
362 */
CM_FloodAreaConnections(void)363 void	CM_FloodAreaConnections( void ) {
364 	int		i;
365 	cArea_t	*area;
366 	int		floodnum;
367 
368 	// all current floods are now invalid
369 	cm.floodvalid++;
370 	floodnum = 0;
371 
372 	for (i = 0 ; i < cm.numAreas ; i++) {
373 		area = &cm.areas[i];
374 		if (area->floodvalid == cm.floodvalid) {
375 			continue;		// already flooded into
376 		}
377 		floodnum++;
378 		CM_FloodArea_r (i, floodnum);
379 	}
380 
381 }
382 
383 /*
384 ====================
385 CM_AdjustAreaPortalState
386 
387 ====================
388 */
CM_AdjustAreaPortalState(int area1,int area2,qboolean open)389 void	CM_AdjustAreaPortalState( int area1, int area2, qboolean open ) {
390 	if ( area1 < 0 || area2 < 0 ) {
391 		return;
392 	}
393 
394 	if ( area1 >= cm.numAreas || area2 >= cm.numAreas ) {
395 		Com_Error (ERR_DROP, "CM_ChangeAreaPortalState: bad area number");
396 	}
397 
398 	if ( open ) {
399 		cm.areaPortals[ area1 * cm.numAreas + area2 ]++;
400 		cm.areaPortals[ area2 * cm.numAreas + area1 ]++;
401 	} else {
402 		cm.areaPortals[ area1 * cm.numAreas + area2 ]--;
403 		cm.areaPortals[ area2 * cm.numAreas + area1 ]--;
404 		if ( cm.areaPortals[ area2 * cm.numAreas + area1 ] < 0 ) {
405 			Com_Error (ERR_DROP, "CM_AdjustAreaPortalState: negative reference count");
406 		}
407 	}
408 
409 	CM_FloodAreaConnections ();
410 }
411 
412 /*
413 ====================
414 CM_AreasConnected
415 
416 ====================
417 */
CM_AreasConnected(int area1,int area2)418 qboolean	CM_AreasConnected( int area1, int area2 ) {
419 #ifndef BSPC
420 	if ( cm_noAreas->integer ) {
421 		return qtrue;
422 	}
423 #endif
424 
425 	if ( area1 < 0 || area2 < 0 ) {
426 		return qfalse;
427 	}
428 
429 	if (area1 >= cm.numAreas || area2 >= cm.numAreas) {
430 		Com_Error (ERR_DROP, "area >= cm.numAreas");
431 	}
432 
433 	if (cm.areas[area1].floodnum == cm.areas[area2].floodnum) {
434 		return qtrue;
435 	}
436 	return qfalse;
437 }
438 
439 
440 /*
441 =================
442 CM_WriteAreaBits
443 
444 Writes a bit vector of all the areas
445 that are in the same flood as the area parameter
446 Returns the number of bytes needed to hold all the bits.
447 
448 The bits are OR'd in, so you can CM_WriteAreaBits from multiple
449 viewpoints and get the union of all visible areas.
450 
451 This is used to cull non-visible entities from snapshots
452 =================
453 */
CM_WriteAreaBits(byte * buffer,int area)454 int CM_WriteAreaBits (byte *buffer, int area)
455 {
456 	int		i;
457 	int		floodnum;
458 	int		bytes;
459 
460 	bytes = (cm.numAreas+7)>>3;
461 
462 #ifndef BSPC
463 	if (cm_noAreas->integer || area == -1)
464 #else
465 	if ( area == -1)
466 #endif
467 	{	// for debugging, send everything
468 		Com_Memset (buffer, 255, bytes);
469 	}
470 	else
471 	{
472 		floodnum = cm.areas[area].floodnum;
473 		for (i=0 ; i<cm.numAreas ; i++)
474 		{
475 			if (cm.areas[i].floodnum == floodnum || area == -1)
476 				buffer[i>>3] |= 1<<(i&7);
477 		}
478 	}
479 
480 	return bytes;
481 }
482 
483 /*
484 ====================
485 CM_BoundsIntersect
486 ====================
487 */
CM_BoundsIntersect(const vec3_t mins,const vec3_t maxs,const vec3_t mins2,const vec3_t maxs2)488 qboolean CM_BoundsIntersect( const vec3_t mins, const vec3_t maxs, const vec3_t mins2, const vec3_t maxs2 )
489 {
490 	if (maxs[0] < mins2[0] - SURFACE_CLIP_EPSILON ||
491 		maxs[1] < mins2[1] - SURFACE_CLIP_EPSILON ||
492 		maxs[2] < mins2[2] - SURFACE_CLIP_EPSILON ||
493 		mins[0] > maxs2[0] + SURFACE_CLIP_EPSILON ||
494 		mins[1] > maxs2[1] + SURFACE_CLIP_EPSILON ||
495 		mins[2] > maxs2[2] + SURFACE_CLIP_EPSILON)
496 	{
497 		return qfalse;
498 	}
499 
500 	return qtrue;
501 }
502 
503 /*
504 ====================
505 CM_BoundsIntersectPoint
506 ====================
507 */
CM_BoundsIntersectPoint(const vec3_t mins,const vec3_t maxs,const vec3_t point)508 qboolean CM_BoundsIntersectPoint( const vec3_t mins, const vec3_t maxs, const vec3_t point )
509 {
510 	if (maxs[0] < point[0] - SURFACE_CLIP_EPSILON ||
511 		maxs[1] < point[1] - SURFACE_CLIP_EPSILON ||
512 		maxs[2] < point[2] - SURFACE_CLIP_EPSILON ||
513 		mins[0] > point[0] + SURFACE_CLIP_EPSILON ||
514 		mins[1] > point[1] + SURFACE_CLIP_EPSILON ||
515 		mins[2] > point[2] + SURFACE_CLIP_EPSILON)
516 	{
517 		return qfalse;
518 	}
519 
520 	return qtrue;
521 }
522