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 // cm_common.c
22 // Wraps functionality between the two formats, leaving the other systems
23 // perfectly ignorant to the actual format loaded
24 //
25 
26 #include "cm_common.h"
27 
28 enum {
29 	BSP_TYPE_Q2,
30 	BSP_TYPE_Q3,
31 };
32 
33 static int				cm_bspType;
34 
35 static char				cm_mapName[MAX_QPATH];
36 static uint32			cm_mapChecksum;
37 
38 int						cm_numCModels;
39 cBspModel_t				cm_mapCModels[MAX_CM_CMODELS];
40 
41 int						cm_numTraces;
42 int						cm_numBrushTraces;
43 int						cm_numPointContents;
44 
45 cVar_t					*flushmap;
46 cVar_t					*cm_noAreas;
47 cVar_t					*cm_noCurves;
48 cVar_t					*cm_showTrace;
49 
50 /*
51 =============================================================================
52 
53 	BSP LOADING
54 
55 =============================================================================
56 */
57 
58 /*
59 ==================
60 CM_PrepMap
61 ==================
62 */
CM_PrepMap(void)63 static void CM_PrepMap (void)
64 {
65 	if (cm_bspType == BSP_TYPE_Q3)
66 		CM_Q3BSP_PrepMap ();
67 	else
68 		CM_Q2BSP_PrepMap ();
69 }
70 
71 
72 /*
73 ==================
74 CM_LoadMap
75 
76 Loads in the map and all submodels
77 ==================
78 */
79 typedef struct bspFormat_s {
80 	byte			type;
81 	const char		*headerStr;
82 	byte			headerLen;
83 	byte			version;
84 	cBspModel_t		*(*loader) (uint32 *buffer);
85 } bspFormat_t;
86 
87 static bspFormat_t bspFormats[] = {
88 	{ BSP_TYPE_Q2,	Q2BSP_HEADER,		4,	Q2BSP_VERSION,			CM_Q2BSP_LoadMap },	// Quake2 BSP models
89 	{ BSP_TYPE_Q3,	Q3BSP_HEADER,		4,	Q3BSP_VERSION,			CM_Q3BSP_LoadMap },	// Quake3 BSP models
90 
91 	{ 0,			NULL,				0,	0,						NULL }
92 };
93 
94 static int numBSPFormats = (sizeof (bspFormats) / sizeof (bspFormats[0])) - 1;
CM_LoadMap(char * name,qBool clientLoad,uint32 * checksum)95 cBspModel_t *CM_LoadMap (char *name, qBool clientLoad, uint32 *checksum)
96 {
97 	cBspModel_t	*model;
98 	uint32		*buffer;
99 	int			fileLen, i;
100 	bspFormat_t	*descr;
101 	char		fixedName[MAX_QPATH];
102 
103 	flushmap		= Cvar_Register ("flushmap",		"0",		0);
104 	cm_noAreas		= Cvar_Register ("cm_noAreas",		"0",		CVAR_CHEAT);
105 	cm_noCurves		= Cvar_Register ("cm_noCurves",		"0",		CVAR_CHEAT);
106 	cm_showTrace	= Cvar_Register ("cm_showTrace",	"0",		0);
107 
108 	Com_NormalizePath (fixedName, sizeof (fixedName), name);
109 	if (fixedName[0])	// Demos will pass a NULL name, don't need to append an extension to that...
110 		Com_DefaultExtension (fixedName, ".bsp", sizeof (fixedName));
111 	if (!strcmp (cm_mapName, fixedName) && (clientLoad || !flushmap->intVal)) {
112 		*checksum = cm_mapChecksum;
113 		if (!clientLoad)
114 			CM_PrepMap ();
115 
116 		return &cm_mapCModels[0];		// still have the right version
117 	}
118 
119 	// Free old stuff
120 	CM_UnloadMap ();
121 	if (!fixedName[0]) {
122 		*checksum = cm_mapChecksum;
123 		return &cm_mapCModels[0];		// cinematic servers won't have anything at all
124 	}
125 
126 	// Load the file
127 	fileLen = FS_LoadFile (fixedName, (void **)&buffer, NULL);
128 	if (!buffer || fileLen <= 0)
129 		Com_Error (ERR_DROP, "CM_LoadMap: Couldn't %s %s", fixedName, (fileLen == -1) ? "find" : "load");
130 
131 	// Calculate checksum
132 	cm_mapChecksum = LittleLong (Com_BlockChecksum (buffer, fileLen));
133 	*checksum = cm_mapChecksum;
134 
135 	// Load the model
136 	descr = bspFormats;
137 	for (i=0 ; i<numBSPFormats ; i++, descr++) {
138 		if (strncmp ((const char *)buffer, descr->headerStr, descr->headerLen))
139 			continue;
140 		if (((int *)buffer)[1] != descr->version)
141 			continue;
142 		break;
143 	}
144 	if (i == numBSPFormats)
145 		Com_Error (ERR_DROP, "CM_LoadMap: unknown fileId for %s", fixedName);
146 
147 	model = descr->loader (buffer);
148 	if (!model) {
149 		FS_FreeFile (buffer);
150 		return NULL;
151 	}
152 
153 	cm_bspType = descr->type;
154 	Q_strncpyz (cm_mapName, fixedName, sizeof (cm_mapName));
155 
156 	// Free the buffer
157 	FS_FreeFile (buffer);
158 
159 	// Check integrity and return
160 	Mem_CheckPoolIntegrity (com_cmodelSysPool);
161 	return model;
162 }
163 
164 
165 /*
166 ==================
167 CM_UnloadMap
168 ==================
169 */
CM_UnloadMap(void)170 void CM_UnloadMap (void)
171 {
172 	Mem_FreePool (com_cmodelSysPool);
173 
174 	if (cm_bspType == BSP_TYPE_Q3)
175 		CM_Q3BSP_UnloadMap ();
176 	else
177 		CM_Q2BSP_UnloadMap ();
178 
179 	cm_mapName[0] = 0;
180 	cm_mapChecksum = 0;
181 
182 	cm_numCModels = 0;
183 
184 	cm_numTraces = 0;
185 	cm_numBrushTraces = 0;
186 	cm_numPointContents = 0;
187 }
188 
189 
190 /*
191 ==================
192 CM_InlineModel
193 ==================
194 */
CM_InlineModel(char * name)195 cBspModel_t *CM_InlineModel (char *name)
196 {
197 	int		num;
198 
199 	if (!name || name[0] != '*')
200 		Com_Error (ERR_DROP, "CM_InlineModel: bad name '%s'", name);
201 	num = atoi (name+1);
202 	if (num < 1 || num >= cm_numCModels)
203 		Com_Error (ERR_DROP, "CM_InlineModel: bad number %i (%i)", num, cm_numCModels);
204 
205 	return &cm_mapCModels[num];
206 }
207 
208 
209 /*
210 ==================
211 CM_InlineModelBounds
212 ==================
213 */
CM_InlineModelBounds(cBspModel_t * model,vec3_t mins,vec3_t maxs)214 void CM_InlineModelBounds (cBspModel_t *model, vec3_t mins, vec3_t maxs)
215 {
216 	if (model) {
217 		Vec3Copy (model->mins, mins);
218 		Vec3Copy (model->maxs, maxs);
219 	}
220 }
221 
222 
223 /*
224 ==================
225 CM_InlineModelBounds
226 ==================
227 */
CM_InlineModelHeadNode(cBspModel_t * model)228 int CM_InlineModelHeadNode (cBspModel_t *model)
229 {
230 	if (model)
231 		return model->headNode;
232 
233 	return 0;
234 }
235 
236 /*
237 =============================================================================
238 
239 	BSP INFORMATION
240 
241 =============================================================================
242 */
243 
244 /*
245 ==================
246 CM_EntityString
247 ==================
248 */
CM_EntityString(void)249 char *CM_EntityString (void)
250 {
251 	if (cm_bspType == BSP_TYPE_Q3)
252 		return CM_Q3BSP_EntityString ();
253 	return CM_Q2BSP_EntityString ();
254 }
255 
256 
257 /*
258 ==================
259 CM_SurfRName
260 ==================
261 */
CM_SurfRName(int texNum)262 char *CM_SurfRName (int texNum)
263 {
264 	if (cm_bspType == BSP_TYPE_Q3)
265 		return CM_Q3BSP_SurfRName (texNum);
266 	return CM_Q2BSP_SurfRName (texNum);
267 }
268 
269 
270 /*
271 ==================
272 CM_NumClusters
273 ==================
274 */
CM_NumClusters(void)275 int CM_NumClusters (void)
276 {
277 	if (cm_bspType == BSP_TYPE_Q3)
278 		return CM_Q3BSP_NumClusters ();
279 	return CM_Q2BSP_NumClusters ();
280 }
281 
282 
283 /*
284 ==================
285 CM_NumInlineModels
286 ==================
287 */
CM_NumInlineModels(void)288 int CM_NumInlineModels (void)
289 {
290 	return cm_numCModels;
291 }
292 
293 
294 /*
295 ==================
296 CM_NumTexInfo
297 ==================
298 */
CM_NumTexInfo(void)299 int CM_NumTexInfo (void)
300 {
301 	if (cm_bspType == BSP_TYPE_Q3)
302 		return CM_Q3BSP_NumTexInfo ();
303 	return CM_Q2BSP_NumTexInfo ();
304 }
305 
306 /*
307 =============================================================================
308 
309 	TRACING
310 
311 =============================================================================
312 */
313 
CM_LeafArea(int leafNum)314 int CM_LeafArea (int leafNum)
315 {
316 	if (cm_bspType == BSP_TYPE_Q3)
317 		return CM_Q3BSP_LeafArea (leafNum);
318 	return CM_Q2BSP_LeafArea (leafNum);
319 }
320 
CM_LeafCluster(int leafNum)321 int CM_LeafCluster (int leafNum)
322 {
323 	if (cm_bspType == BSP_TYPE_Q3)
324 		return CM_Q3BSP_LeafCluster (leafNum);
325 	return CM_Q2BSP_LeafCluster (leafNum);
326 }
327 
CM_LeafContents(int leafNum)328 int CM_LeafContents (int leafNum)
329 {
330 	if (cm_bspType == BSP_TYPE_Q3)
331 		return CM_Q3BSP_LeafContents (leafNum);
332 	return CM_Q2BSP_LeafContents (leafNum);
333 }
334 
335 // ==========================================================================
336 
CM_HeadnodeForBox(vec3_t mins,vec3_t maxs)337 int	CM_HeadnodeForBox (vec3_t mins, vec3_t maxs)
338 {
339 	if (cm_bspType == BSP_TYPE_Q3)
340 		return CM_Q3BSP_HeadnodeForBox (mins, maxs);
341 	return CM_Q2BSP_HeadnodeForBox (mins, maxs);
342 }
343 
CM_PointLeafnum(vec3_t p)344 int CM_PointLeafnum (vec3_t p)
345 {
346 	if (cm_bspType == BSP_TYPE_Q3)
347 		return CM_Q3BSP_PointLeafnum (p);
348 	return CM_Q2BSP_PointLeafnum (p);
349 }
350 
CM_BoxLeafnums(vec3_t mins,vec3_t maxs,int * list,int listSize,int * topNode)351 int	CM_BoxLeafnums (vec3_t mins, vec3_t maxs, int *list, int listSize, int *topNode)
352 {
353 	if (cm_bspType == BSP_TYPE_Q3)
354 		return CM_Q3BSP_BoxLeafnums (mins, maxs, list, listSize, topNode);
355 	return CM_Q2BSP_BoxLeafnums (mins, maxs, list, listSize, topNode);
356 }
357 
CM_PointContents(vec3_t p,int headNode)358 int CM_PointContents (vec3_t p, int headNode)
359 {
360 	if (cm_bspType == BSP_TYPE_Q3)
361 		return CM_Q3BSP_PointContents (p, headNode);
362 	return CM_Q2BSP_PointContents (p, headNode);
363 }
364 
CM_TransformedPointContents(vec3_t p,int headNode,vec3_t origin,vec3_t angles)365 int	CM_TransformedPointContents (vec3_t p, int headNode, vec3_t origin, vec3_t angles)
366 {
367 	if (cm_bspType == BSP_TYPE_Q3)
368 		return CM_Q3BSP_TransformedPointContents (p, headNode, origin, angles);
369 	return CM_Q2BSP_TransformedPointContents (p, headNode, origin, angles);
370 }
371 
372 /*
373 =============================================================================
374 
375 	BOX TRACING
376 
377 =============================================================================
378 */
379 
CM_Trace(vec3_t start,vec3_t end,float size,int contentMask)380 trace_t CM_Trace (vec3_t start, vec3_t end, float size, int contentMask)
381 {
382 	if (cm_bspType == BSP_TYPE_Q3)
383 		return CM_Q3BSP_Trace (start, end, size, contentMask);
384 	return CM_Q2BSP_Trace (start, end, size, contentMask);
385 }
386 
CM_BoxTrace(vec3_t start,vec3_t end,vec3_t mins,vec3_t maxs,int headNode,int brushMask)387 trace_t CM_BoxTrace (vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int headNode, int brushMask)
388 {
389 	if (cm_bspType == BSP_TYPE_Q3)
390 		return CM_Q3BSP_BoxTrace (start, end, mins, maxs, headNode, brushMask);
391 	return CM_Q2BSP_BoxTrace (start, end, mins, maxs, headNode, brushMask);
392 }
393 
CM_TransformedBoxTrace(trace_t * out,vec3_t start,vec3_t end,vec3_t mins,vec3_t maxs,int headNode,int brushMask,vec3_t origin,vec3_t angles)394 void CM_TransformedBoxTrace (trace_t *out, vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int headNode, int brushMask, vec3_t origin, vec3_t angles)
395 {
396 	if (!out)
397 		return;
398 
399 	if (cm_bspType == BSP_TYPE_Q3) {
400 		CM_Q3BSP_TransformedBoxTrace (out, start, end, mins, maxs, headNode, brushMask, origin, angles);
401 		return;
402 	}
403 	CM_Q2BSP_TransformedBoxTrace (out, start, end, mins, maxs, headNode, brushMask, origin, angles);
404 }
405 
406 /*
407 =============================================================================
408 
409 	PVS / PHS
410 
411 =============================================================================
412 */
413 
CM_ClusterPVS(int cluster)414 byte *CM_ClusterPVS (int cluster)
415 {
416 	if (cm_bspType == BSP_TYPE_Q3)
417 		return CM_Q3BSP_ClusterPVS (cluster);
418 	return CM_Q2BSP_ClusterPVS (cluster);
419 }
420 
CM_ClusterPHS(int cluster)421 byte *CM_ClusterPHS (int cluster)
422 {
423 	if (cm_bspType == BSP_TYPE_Q3)
424 		return CM_Q3BSP_ClusterPHS (cluster);
425 	return CM_Q2BSP_ClusterPHS (cluster);
426 }
427 
428 /*
429 =============================================================================
430 
431 	AREAPORTALS
432 
433 =============================================================================
434 */
435 
CM_SetAreaPortalState(int portalNum,int area,int otherArea,qBool open)436 void CM_SetAreaPortalState (int portalNum, int area, int otherArea, qBool open)
437 {
438 	if (cm_bspType == BSP_TYPE_Q3) {
439 		if (area && otherArea) // Must be touching two areas
440 			CM_Q3BSP_SetAreaPortalState (portalNum, area, otherArea, open);
441 		return;
442 	}
443 	CM_Q2BSP_SetAreaPortalState (portalNum, open);
444 }
445 
CM_AreasConnected(int area1,int area2)446 qBool CM_AreasConnected (int area1, int area2)
447 {
448 	if (cm_bspType == BSP_TYPE_Q3)
449 		return CM_Q3BSP_AreasConnected (area1, area2);
450 	return CM_Q2BSP_AreasConnected (area1, area2);
451 }
452 
CM_WriteAreaBits(byte * buffer,int area)453 int CM_WriteAreaBits (byte *buffer, int area)
454 {
455 	if (cm_bspType == BSP_TYPE_Q3)
456 		return CM_Q3BSP_WriteAreaBits (buffer, area);
457 	return CM_Q2BSP_WriteAreaBits (buffer, area);
458 }
459 
CM_WritePortalState(fileHandle_t fileNum)460 void CM_WritePortalState (fileHandle_t fileNum)
461 {
462 	if (cm_bspType == BSP_TYPE_Q3) {
463 		CM_Q3BSP_WritePortalState (fileNum);
464 		return;
465 	}
466 	CM_Q2BSP_WritePortalState (fileNum);
467 }
468 
CM_ReadPortalState(fileHandle_t fileNum)469 void CM_ReadPortalState (fileHandle_t fileNum)
470 {
471 	if (cm_bspType == BSP_TYPE_Q3) {
472 		CM_Q3BSP_ReadPortalState (fileNum);
473 		return;
474 	}
475 	CM_Q2BSP_ReadPortalState (fileNum);
476 }
477 
CM_HeadnodeVisible(int nodeNum,byte * visBits)478 qBool CM_HeadnodeVisible (int nodeNum, byte *visBits)
479 {
480 	if (cm_bspType == BSP_TYPE_Q3)
481 		return CM_Q3BSP_HeadnodeVisible (nodeNum, visBits);
482 	return CM_Q2BSP_HeadnodeVisible (nodeNum, visBits);
483 }
484 
485 /*
486 =============================================================================
487 
488 	MISCELLANEOUS
489 
490 =============================================================================
491 */
492 
493 /*
494 ==================
495 CM_PrintStats
496 ==================
497 */
CM_PrintStats(void)498 void CM_PrintStats (void)
499 {
500 	static int	highTrace = 0;
501 	static int	highBTrace = 0;
502 	static int	highPC = 0;
503 
504 	if (cm_showTrace && cm_showTrace->intVal)
505 		Com_Printf (0, "%4i/%4i tr %4i/%4i brtr %4i/%4i pt\n",
506 			cm_numTraces, highTrace,
507 			cm_numBrushTraces, highBTrace,
508 			cm_numPointContents, highPC);
509 
510 	if (cm_numTraces > highTrace)
511 		highTrace = cm_numTraces;
512 	if (cm_numBrushTraces > highBTrace)
513 		highBTrace = cm_numBrushTraces;
514 	if (cm_numPointContents > highPC)
515 		highPC = cm_numPointContents;
516 
517 	// Reset
518 	cm_numTraces = 0;
519 	cm_numBrushTraces = 0;
520 	cm_numPointContents = 0;
521 }
522