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