1 #include "cmdlib.h"
2 #include "filelib.h"
3 #include "messages.h"
4 #include "hlassert.h"
5 #include "log.h"
6 #include "mathlib.h"
7 #include "bspfile.h"
8 #include "scriplib.h"
9 #include "blockmem.h"
10 
11 //=============================================================================
12 
13 int             g_max_map_miptex = DEFAULT_MAX_MAP_MIPTEX;
14 int				g_max_map_lightdata = DEFAULT_MAX_MAP_LIGHTDATA;
15 
16 int             g_nummodels;
17 dmodel_t        g_dmodels[MAX_MAP_MODELS];
18 int             g_dmodels_checksum;
19 
20 int             g_visdatasize;
21 byte            g_dvisdata[MAX_MAP_VISIBILITY];
22 int             g_dvisdata_checksum;
23 
24 int             g_lightdatasize;
25 byte*           g_dlightdata;
26 int             g_dlightdata_checksum;
27 
28 int             g_texdatasize;
29 byte*           g_dtexdata;                                  // (dmiptexlump_t)
30 int             g_dtexdata_checksum;
31 
32 int             g_entdatasize;
33 char            g_dentdata[MAX_MAP_ENTSTRING];
34 int             g_dentdata_checksum;
35 
36 int             g_numleafs;
37 dleaf_t         g_dleafs[MAX_MAP_LEAFS];
38 int             g_dleafs_checksum;
39 
40 int             g_numplanes;
41 dplane_t        g_dplanes[MAX_INTERNAL_MAP_PLANES];
42 int             g_dplanes_checksum;
43 
44 int             g_numvertexes;
45 dvertex_t       g_dvertexes[MAX_MAP_VERTS];
46 int             g_dvertexes_checksum;
47 
48 int             g_numnodes;
49 dnode_t         g_dnodes[MAX_MAP_NODES];
50 int             g_dnodes_checksum;
51 
52 int             g_numtexinfo;
53 texinfo_t       g_texinfo[MAX_MAP_TEXINFO];
54 int             g_texinfo_checksum;
55 
56 int             g_numfaces;
57 dface_t         g_dfaces[MAX_MAP_FACES];
58 int             g_dfaces_checksum;
59 
60 int             g_numclipnodes;
61 dclipnode_t     g_dclipnodes[MAX_MAP_CLIPNODES];
62 int             g_dclipnodes_checksum;
63 
64 int             g_numedges;
65 dedge_t         g_dedges[MAX_MAP_EDGES];
66 int             g_dedges_checksum;
67 
68 int             g_nummarksurfaces;
69 unsigned short  g_dmarksurfaces[MAX_MAP_MARKSURFACES];
70 int             g_dmarksurfaces_checksum;
71 
72 int             g_numsurfedges;
73 int             g_dsurfedges[MAX_MAP_SURFEDGES];
74 int             g_dsurfedges_checksum;
75 
76 int             g_numentities;
77 entity_t        g_entities[MAX_MAP_ENTITIES];
78 
79 /*
80  * ===============
81  * FastChecksum
82  * ===============
83  */
84 
FastChecksum(const void * const buffer,int bytes)85 static int      FastChecksum(const void* const buffer, int bytes)
86 {
87     int             checksum = 0;
88     char*           buf = (char*)buffer;
89 
90     while (bytes--)
91     {
92         checksum = rotl(checksum, 4) ^ (*buf);
93         buf++;
94     }
95 
96     return checksum;
97 }
98 
99 /*
100  * ===============
101  * CompressVis
102  * ===============
103  */
CompressVis(const byte * const src,const unsigned int src_length,byte * dest,unsigned int dest_length)104 int             CompressVis(const byte* const src, const unsigned int src_length, byte* dest, unsigned int dest_length)
105 {
106     unsigned int    j;
107     byte*           dest_p = dest;
108     unsigned int    current_length = 0;
109 
110     for (j = 0; j < src_length; j++)
111     {
112         current_length++;
113         hlassume(current_length <= dest_length, assume_COMPRESSVIS_OVERFLOW);
114 
115         *dest_p = src[j];
116         dest_p++;
117 
118         if (src[j])
119         {
120             continue;
121         }
122 
123         unsigned char   rep = 1;
124 
125         for (j++; j < src_length; j++)
126         {
127             if (src[j] || rep == 255)
128             {
129                 break;
130             }
131             else
132             {
133                 rep++;
134             }
135         }
136         current_length++;
137         hlassume(current_length <= dest_length, assume_COMPRESSVIS_OVERFLOW);
138 
139         *dest_p = rep;
140         dest_p++;
141         j--;
142     }
143 
144     return dest_p - dest;
145 }
146 
147 // =====================================================================================
148 //  DecompressVis
149 //
150 // =====================================================================================
DecompressVis(const byte * src,byte * const dest,const unsigned int dest_length)151 void            DecompressVis(const byte* src, byte* const dest, const unsigned int dest_length)
152 {
153     unsigned int    current_length = 0;
154     int             c;
155     byte*           out;
156     int             row;
157 
158     row = (g_numleafs + 7) >> 3;
159     out = dest;
160 
161     do
162     {
163         if (*src)
164         {
165             current_length++;
166             hlassume(current_length <= dest_length, assume_DECOMPRESSVIS_OVERFLOW);
167 
168             *out = *src;
169             out++;
170             src++;
171             continue;
172         }
173 
174         c = src[1];
175         src += 2;
176         while (c)
177         {
178             current_length++;
179             hlassume(current_length <= dest_length, assume_DECOMPRESSVIS_OVERFLOW);
180 
181             *out = 0;
182             out++;
183             c--;
184 
185             if (out - dest >= row)
186             {
187                 return;
188             }
189         }
190     }
191     while (out - dest < row);
192 }
193 
194 //
195 // =====================================================================================
196 //
197 
198 // =====================================================================================
199 //  SwapBSPFile
200 //      byte swaps all data in a bsp file
201 // =====================================================================================
SwapBSPFile(const bool todisk)202 static void     SwapBSPFile(const bool todisk)
203 {
204     int             i, j, c;
205     dmodel_t*       d;
206     dmiptexlump_t*  mtl;
207 
208     // models
209     for (i = 0; i < g_nummodels; i++)
210     {
211         d = &g_dmodels[i];
212 
213         for (j = 0; j < MAX_MAP_HULLS; j++)
214         {
215             d->headnode[j] = LittleLong(d->headnode[j]);
216         }
217 
218         d->visleafs = LittleLong(d->visleafs);
219         d->firstface = LittleLong(d->firstface);
220         d->numfaces = LittleLong(d->numfaces);
221 
222         for (j = 0; j < 3; j++)
223         {
224             d->mins[j] = LittleFloat(d->mins[j]);
225             d->maxs[j] = LittleFloat(d->maxs[j]);
226             d->origin[j] = LittleFloat(d->origin[j]);
227         }
228     }
229 
230     //
231     // vertexes
232     //
233     for (i = 0; i < g_numvertexes; i++)
234     {
235         for (j = 0; j < 3; j++)
236         {
237             g_dvertexes[i].point[j] = LittleFloat(g_dvertexes[i].point[j]);
238         }
239     }
240 
241     //
242     // planes
243     //
244     for (i = 0; i < g_numplanes; i++)
245     {
246         for (j = 0; j < 3; j++)
247         {
248             g_dplanes[i].normal[j] = LittleFloat(g_dplanes[i].normal[j]);
249         }
250         g_dplanes[i].dist = LittleFloat(g_dplanes[i].dist);
251         g_dplanes[i].type = (planetypes)LittleLong(g_dplanes[i].type);
252     }
253 
254     //
255     // texinfos
256     //
257     for (i = 0; i < g_numtexinfo; i++)
258     {
259         for (j = 0; j < 8; j++)
260         {
261             g_texinfo[i].vecs[0][j] = LittleFloat(g_texinfo[i].vecs[0][j]);
262         }
263         g_texinfo[i].miptex = LittleLong(g_texinfo[i].miptex);
264         g_texinfo[i].flags = LittleLong(g_texinfo[i].flags);
265     }
266 
267     //
268     // faces
269     //
270     for (i = 0; i < g_numfaces; i++)
271     {
272         g_dfaces[i].texinfo = LittleShort(g_dfaces[i].texinfo);
273         g_dfaces[i].planenum = LittleShort(g_dfaces[i].planenum);
274         g_dfaces[i].side = LittleShort(g_dfaces[i].side);
275         g_dfaces[i].lightofs = LittleLong(g_dfaces[i].lightofs);
276         g_dfaces[i].firstedge = LittleLong(g_dfaces[i].firstedge);
277         g_dfaces[i].numedges = LittleShort(g_dfaces[i].numedges);
278     }
279 
280     //
281     // nodes
282     //
283     for (i = 0; i < g_numnodes; i++)
284     {
285         g_dnodes[i].planenum = LittleLong(g_dnodes[i].planenum);
286         for (j = 0; j < 3; j++)
287         {
288             g_dnodes[i].mins[j] = LittleShort(g_dnodes[i].mins[j]);
289             g_dnodes[i].maxs[j] = LittleShort(g_dnodes[i].maxs[j]);
290         }
291         g_dnodes[i].children[0] = LittleShort(g_dnodes[i].children[0]);
292         g_dnodes[i].children[1] = LittleShort(g_dnodes[i].children[1]);
293         g_dnodes[i].firstface = LittleShort(g_dnodes[i].firstface);
294         g_dnodes[i].numfaces = LittleShort(g_dnodes[i].numfaces);
295     }
296 
297     //
298     // leafs
299     //
300     for (i = 0; i < g_numleafs; i++)
301     {
302         g_dleafs[i].contents = LittleLong(g_dleafs[i].contents);
303         for (j = 0; j < 3; j++)
304         {
305             g_dleafs[i].mins[j] = LittleShort(g_dleafs[i].mins[j]);
306             g_dleafs[i].maxs[j] = LittleShort(g_dleafs[i].maxs[j]);
307         }
308 
309         g_dleafs[i].firstmarksurface = LittleShort(g_dleafs[i].firstmarksurface);
310         g_dleafs[i].nummarksurfaces = LittleShort(g_dleafs[i].nummarksurfaces);
311         g_dleafs[i].visofs = LittleLong(g_dleafs[i].visofs);
312     }
313 
314     //
315     // clipnodes
316     //
317     for (i = 0; i < g_numclipnodes; i++)
318     {
319         g_dclipnodes[i].planenum = LittleLong(g_dclipnodes[i].planenum);
320         g_dclipnodes[i].children[0] = LittleShort(g_dclipnodes[i].children[0]);
321         g_dclipnodes[i].children[1] = LittleShort(g_dclipnodes[i].children[1]);
322     }
323 
324     //
325     // miptex
326     //
327     if (g_texdatasize)
328     {
329         mtl = (dmiptexlump_t*)g_dtexdata;
330         if (todisk)
331         {
332             c = mtl->nummiptex;
333         }
334         else
335         {
336             c = LittleLong(mtl->nummiptex);
337         }
338         mtl->nummiptex = LittleLong(mtl->nummiptex);
339         for (i = 0; i < c; i++)
340         {
341             mtl->dataofs[i] = LittleLong(mtl->dataofs[i]);
342         }
343     }
344 
345     //
346     // marksurfaces
347     //
348     for (i = 0; i < g_nummarksurfaces; i++)
349     {
350         g_dmarksurfaces[i] = LittleShort(g_dmarksurfaces[i]);
351     }
352 
353     //
354     // surfedges
355     //
356     for (i = 0; i < g_numsurfedges; i++)
357     {
358         g_dsurfedges[i] = LittleLong(g_dsurfedges[i]);
359     }
360 
361     //
362     // edges
363     //
364     for (i = 0; i < g_numedges; i++)
365     {
366         g_dedges[i].v[0] = LittleShort(g_dedges[i].v[0]);
367         g_dedges[i].v[1] = LittleShort(g_dedges[i].v[1]);
368     }
369 }
370 
371 // =====================================================================================
372 //  CopyLump
373 //      balh
374 // =====================================================================================
CopyLump(int lump,void * dest,int size,const dheader_t * const header)375 static int      CopyLump(int lump, void* dest, int size, const dheader_t* const header)
376 {
377     int             length, ofs;
378 
379     length = header->lumps[lump].filelen;
380     ofs = header->lumps[lump].fileofs;
381 
382     if (length % size)
383     {
384         Error("LoadBSPFile: odd lump size");
385     }
386 
387 	//special handling for tex and lightdata to keep things from exploding - KGP
388 	if(lump == LUMP_TEXTURES && dest == (void*)g_dtexdata)
389 	{ hlassume(g_max_map_miptex > length,assume_MAX_MAP_MIPTEX); }
390 	else if(lump == LUMP_LIGHTING && dest == (void*)g_dlightdata)
391 	{ hlassume(g_max_map_lightdata > length,assume_MAX_MAP_LIGHTING); }
392 
393     memcpy(dest, (byte*) header + ofs, length);
394 
395     return length / size;
396 }
397 
398 
399 // =====================================================================================
400 //  LoadBSPFile
401 //      balh
402 // =====================================================================================
LoadBSPFile(const char * const filename)403 void            LoadBSPFile(const char* const filename)
404 {
405     dheader_t* header;
406     LoadFile(filename, (char**)&header);
407     LoadBSPImage(header);
408 }
409 
410 // =====================================================================================
411 //  LoadBSPImage
412 //      balh
413 // =====================================================================================
LoadBSPImage(dheader_t * const header)414 void            LoadBSPImage(dheader_t* const header)
415 {
416     unsigned int     i;
417 
418     // swap the header
419     for (i = 0; i < sizeof(dheader_t) / 4; i++)
420     {
421         ((int*)header)[i] = LittleLong(((int*)header)[i]);
422     }
423 
424     if (header->version != BSPVERSION)
425     {
426         Error("BSP is version %i, not %i", header->version, BSPVERSION);
427     }
428 
429     g_nummodels = CopyLump(LUMP_MODELS, g_dmodels, sizeof(dmodel_t), header);
430     g_numvertexes = CopyLump(LUMP_VERTEXES, g_dvertexes, sizeof(dvertex_t), header);
431     g_numplanes = CopyLump(LUMP_PLANES, g_dplanes, sizeof(dplane_t), header);
432     g_numleafs = CopyLump(LUMP_LEAFS, g_dleafs, sizeof(dleaf_t), header);
433     g_numnodes = CopyLump(LUMP_NODES, g_dnodes, sizeof(dnode_t), header);
434     g_numtexinfo = CopyLump(LUMP_TEXINFO, g_texinfo, sizeof(texinfo_t), header);
435     g_numclipnodes = CopyLump(LUMP_CLIPNODES, g_dclipnodes, sizeof(dclipnode_t), header);
436     g_numfaces = CopyLump(LUMP_FACES, g_dfaces, sizeof(dface_t), header);
437     g_nummarksurfaces = CopyLump(LUMP_MARKSURFACES, g_dmarksurfaces, sizeof(g_dmarksurfaces[0]), header);
438     g_numsurfedges = CopyLump(LUMP_SURFEDGES, g_dsurfedges, sizeof(g_dsurfedges[0]), header);
439     g_numedges = CopyLump(LUMP_EDGES, g_dedges, sizeof(dedge_t), header);
440     g_texdatasize = CopyLump(LUMP_TEXTURES, g_dtexdata, 1, header);
441     g_visdatasize = CopyLump(LUMP_VISIBILITY, g_dvisdata, 1, header);
442     g_lightdatasize = CopyLump(LUMP_LIGHTING, g_dlightdata, 1, header);
443     g_entdatasize = CopyLump(LUMP_ENTITIES, g_dentdata, 1, header);
444 
445     Free(header);                                          // everything has been copied out
446 
447     //
448     // swap everything
449     //
450     SwapBSPFile(false);
451 
452     g_dmodels_checksum = FastChecksum(g_dmodels, g_nummodels * sizeof(g_dmodels[0]));
453     g_dvertexes_checksum = FastChecksum(g_dvertexes, g_numvertexes * sizeof(g_dvertexes[0]));
454     g_dplanes_checksum = FastChecksum(g_dplanes, g_numplanes * sizeof(g_dplanes[0]));
455     g_dleafs_checksum = FastChecksum(g_dleafs, g_numleafs * sizeof(g_dleafs[0]));
456     g_dnodes_checksum = FastChecksum(g_dnodes, g_numnodes * sizeof(g_dnodes[0]));
457     g_texinfo_checksum = FastChecksum(g_texinfo, g_numtexinfo * sizeof(g_texinfo[0]));
458     g_dclipnodes_checksum = FastChecksum(g_dclipnodes, g_numclipnodes * sizeof(g_dclipnodes[0]));
459     g_dfaces_checksum = FastChecksum(g_dfaces, g_numfaces * sizeof(g_dfaces[0]));
460     g_dmarksurfaces_checksum = FastChecksum(g_dmarksurfaces, g_nummarksurfaces * sizeof(g_dmarksurfaces[0]));
461     g_dsurfedges_checksum = FastChecksum(g_dsurfedges, g_numsurfedges * sizeof(g_dsurfedges[0]));
462     g_dedges_checksum = FastChecksum(g_dedges, g_numedges * sizeof(g_dedges[0]));
463     g_dtexdata_checksum = FastChecksum(g_dtexdata, g_numedges * sizeof(g_dtexdata[0]));
464     g_dvisdata_checksum = FastChecksum(g_dvisdata, g_visdatasize * sizeof(g_dvisdata[0]));
465     g_dlightdata_checksum = FastChecksum(g_dlightdata, g_lightdatasize * sizeof(g_dlightdata[0]));
466     g_dentdata_checksum = FastChecksum(g_dentdata, g_entdatasize * sizeof(g_dentdata[0]));
467 }
468 
469 //
470 // =====================================================================================
471 //
472 
473 // =====================================================================================
474 //  AddLump
475 //      balh
476 // =====================================================================================
AddLump(int lumpnum,void * data,int len,dheader_t * header,FILE * bspfile)477 static void     AddLump(int lumpnum, void* data, int len, dheader_t* header, FILE* bspfile)
478 {
479     lump_t* lump =&header->lumps[lumpnum];
480     lump->fileofs = LittleLong(ftell(bspfile));
481     lump->filelen = LittleLong(len);
482     SafeWrite(bspfile, data, (len + 3) & ~3);
483 }
484 
485 // =====================================================================================
486 //  WriteBSPFile
487 //      Swaps the bsp file in place, so it should not be referenced again
488 // =====================================================================================
WriteBSPFile(const char * const filename)489 void            WriteBSPFile(const char* const filename)
490 {
491     dheader_t       outheader;
492     dheader_t*      header;
493     FILE*           bspfile;
494 
495     header = &outheader;
496     memset(header, 0, sizeof(dheader_t));
497 
498     SwapBSPFile(true);
499 
500     header->version = LittleLong(BSPVERSION);
501 
502     bspfile = SafeOpenWrite(filename);
503     SafeWrite(bspfile, header, sizeof(dheader_t));         // overwritten later
504 
505     //      LUMP TYPE       DATA            LENGTH                              HEADER  BSPFILE
506     AddLump(LUMP_PLANES,    g_dplanes,      g_numplanes * sizeof(dplane_t),     header, bspfile);
507     AddLump(LUMP_LEAFS,     g_dleafs,       g_numleafs * sizeof(dleaf_t),       header, bspfile);
508     AddLump(LUMP_VERTEXES,  g_dvertexes,    g_numvertexes * sizeof(dvertex_t),  header, bspfile);
509     AddLump(LUMP_NODES,     g_dnodes,       g_numnodes * sizeof(dnode_t),       header, bspfile);
510     AddLump(LUMP_TEXINFO,   g_texinfo,      g_numtexinfo * sizeof(texinfo_t),   header, bspfile);
511     AddLump(LUMP_FACES,     g_dfaces,       g_numfaces * sizeof(dface_t),       header, bspfile);
512     AddLump(LUMP_CLIPNODES, g_dclipnodes,   g_numclipnodes * sizeof(dclipnode_t), header, bspfile);
513 
514     AddLump(LUMP_MARKSURFACES, g_dmarksurfaces, g_nummarksurfaces * sizeof(g_dmarksurfaces[0]), header, bspfile);
515     AddLump(LUMP_SURFEDGES, g_dsurfedges,   g_numsurfedges * sizeof(g_dsurfedges[0]), header, bspfile);
516     AddLump(LUMP_EDGES,     g_dedges,       g_numedges * sizeof(dedge_t),       header, bspfile);
517     AddLump(LUMP_MODELS,    g_dmodels,      g_nummodels * sizeof(dmodel_t),     header, bspfile);
518 
519     AddLump(LUMP_LIGHTING,  g_dlightdata,   g_lightdatasize,                    header, bspfile);
520     AddLump(LUMP_VISIBILITY,g_dvisdata,     g_visdatasize,                      header, bspfile);
521     AddLump(LUMP_ENTITIES,  g_dentdata,     g_entdatasize,                      header, bspfile);
522     AddLump(LUMP_TEXTURES,  g_dtexdata,     g_texdatasize,                      header, bspfile);
523 
524     fseek(bspfile, 0, SEEK_SET);
525     SafeWrite(bspfile, header, sizeof(dheader_t));
526 
527     fclose(bspfile);
528 }
529 
530 //
531 // =====================================================================================
532 //
533 
534 #define ENTRIES(a)		(sizeof(a)/sizeof(*(a)))
535 #define ENTRYSIZE(a)	(sizeof(*(a)))
536 
537 // =====================================================================================
538 //  ArrayUsage
539 //      blah
540 // =====================================================================================
ArrayUsage(const char * const szItem,const int items,const int maxitems,const int itemsize)541 static int      ArrayUsage(const char* const szItem, const int items, const int maxitems, const int itemsize)
542 {
543     float           percentage = maxitems ? items * 100.0 / maxitems : 0.0;
544 
545     Log("%-12s  %7i/%-7i  %7i/%-7i  (%4.1f%%)\n", szItem, items, maxitems, items * itemsize, maxitems * itemsize, percentage);
546 
547     return items * itemsize;
548 }
549 
550 // =====================================================================================
551 //  GlobUsage
552 //      pritn out global ussage line in chart
553 // =====================================================================================
GlobUsage(const char * const szItem,const int itemstorage,const int maxstorage)554 static int      GlobUsage(const char* const szItem, const int itemstorage, const int maxstorage)
555 {
556     float           percentage = maxstorage ? itemstorage * 100.0 / maxstorage : 0.0;
557 
558     Log("%-12s     [variable]    %7i/%-7i  (%4.1f%%)\n", szItem, itemstorage, maxstorage, percentage);
559 
560     return itemstorage;
561 }
562 
563 // =====================================================================================
564 //  PrintBSPFileSizes
565 //      Dumps info about current file
566 // =====================================================================================
PrintBSPFileSizes()567 void            PrintBSPFileSizes()
568 {
569     int             numtextures = g_texdatasize ? ((dmiptexlump_t*)g_dtexdata)->nummiptex : 0;
570     int             totalmemory = 0;
571 
572     Log("\n");
573     Log("Object names  Objects/Maxobjs  Memory / Maxmem  Fullness\n");
574     Log("------------  ---------------  ---------------  --------\n");
575 
576     totalmemory += ArrayUsage("models", g_nummodels, ENTRIES(g_dmodels), ENTRYSIZE(g_dmodels));
577     totalmemory += ArrayUsage("planes", g_numplanes, MAX_MAP_PLANES, ENTRYSIZE(g_dplanes));
578     totalmemory += ArrayUsage("vertexes", g_numvertexes, ENTRIES(g_dvertexes), ENTRYSIZE(g_dvertexes));
579     totalmemory += ArrayUsage("nodes", g_numnodes, ENTRIES(g_dnodes), ENTRYSIZE(g_dnodes));
580     totalmemory += ArrayUsage("texinfos", g_numtexinfo, ENTRIES(g_texinfo), ENTRYSIZE(g_texinfo));
581     totalmemory += ArrayUsage("faces", g_numfaces, ENTRIES(g_dfaces), ENTRYSIZE(g_dfaces));
582     totalmemory += ArrayUsage("clipnodes", g_numclipnodes, ENTRIES(g_dclipnodes), ENTRYSIZE(g_dclipnodes));
583     totalmemory += ArrayUsage("leaves", g_numleafs, ENTRIES(g_dleafs), ENTRYSIZE(g_dleafs));
584     totalmemory += ArrayUsage("marksurfaces", g_nummarksurfaces, ENTRIES(g_dmarksurfaces), ENTRYSIZE(g_dmarksurfaces));
585     totalmemory += ArrayUsage("surfedges", g_numsurfedges, ENTRIES(g_dsurfedges), ENTRYSIZE(g_dsurfedges));
586     totalmemory += ArrayUsage("edges", g_numedges, ENTRIES(g_dedges), ENTRYSIZE(g_dedges));
587 
588     totalmemory += GlobUsage("texdata", g_texdatasize, g_max_map_miptex);
589     totalmemory += GlobUsage("lightdata", g_lightdatasize, g_max_map_lightdata);
590     totalmemory += GlobUsage("visdata", g_visdatasize, sizeof(g_dvisdata));
591     totalmemory += GlobUsage("entdata", g_entdatasize, sizeof(g_dentdata));
592 
593     Log("%i textures referenced\n", numtextures);
594 
595     Log("=== Total BSP file data space used: %d bytes ===\n", totalmemory);
596 }
597 
598 
599 // =====================================================================================
600 //  ParseEpair
601 //      entity key/value pairs
602 // =====================================================================================
ParseEpair()603 epair_t*        ParseEpair()
604 {
605     epair_t*        e;
606 
607     e = (epair_t*)Alloc(sizeof(epair_t));
608 
609     if (strlen(g_token) >= MAX_KEY - 1)
610         Error("ParseEpair: Key token too long (%i > MAX_KEY)", (int)strlen(g_token));
611 
612     e->key = _strdup(g_token);
613     GetToken(false);
614 
615     if (strlen(g_token) >= ZHLT3_MAX_VALUE - 1)
616         Error("ParseEpar: Value token too long (%i > ZHLT3_MAX_VALUE)", (int)strlen(g_token));
617 
618     e->value = _strdup(g_token);
619 
620     return e;
621 }
622 
623 /*
624  * ================
625  * ParseEntity
626  * ================
627  */
628 
629 #ifdef ZHLT_INFO_COMPILE_PARAMETERS
630 // AJM: each tool should have its own version of GetParamsFromEnt which parseentity calls
631 extern void     GetParamsFromEnt(entity_t* mapent);
632 #endif
633 
ParseEntity()634 bool            ParseEntity()
635 {
636     epair_t*        e;
637     entity_t*       mapent;
638 
639     if (!GetToken(true))
640     {
641         return false;
642     }
643 
644     if (strcmp(g_token, "{"))
645     {
646         Error("ParseEntity: { not found");
647     }
648 
649     if (g_numentities == MAX_MAP_ENTITIES)
650     {
651         Error("g_numentities == MAX_MAP_ENTITIES");
652     }
653 
654     mapent = &g_entities[g_numentities];
655     g_numentities++;
656 
657     while (1)
658     {
659         if (!GetToken(true))
660         {
661             Error("ParseEntity: EOF without closing brace");
662         }
663         if (!strcmp(g_token, "}"))
664         {
665             break;
666         }
667         e = ParseEpair();
668         e->next = mapent->epairs;
669         mapent->epairs = e;
670     }
671 
672 #ifdef ZHLT_INFO_COMPILE_PARAMETERS // AJM
673     if (!strcmp(ValueForKey(mapent, "classname"), "info_compile_parameters"))
674     {
675         Log("Map entity info_compile_parameters detected, using compile settings\n");
676         GetParamsFromEnt(mapent);
677     }
678 #endif
679 
680     return true;
681 }
682 
683 // =====================================================================================
684 //  ParseEntities
685 //      Parses the dentdata string into entities
686 // =====================================================================================
ParseEntities()687 void            ParseEntities()
688 {
689     g_numentities = 0;
690     ParseFromMemory(g_dentdata, g_entdatasize);
691 
692     while (ParseEntity())
693     {
694     }
695 }
696 
697 // =====================================================================================
698 //  UnparseEntities
699 //      Generates the dentdata string from all the entities
700 // =====================================================================================
UnparseEntities()701 void            UnparseEntities()
702 {
703     char*           buf;
704     char*           end;
705     epair_t*        ep;
706     char            line[MAXTOKEN];
707     int             i;
708 
709     buf = g_dentdata;
710     end = buf;
711     *end = 0;
712 
713     for (i = 0; i < g_numentities; i++)
714     {
715         ep = g_entities[i].epairs;
716         if (!ep)
717         {
718             continue;                                      // ent got removed
719         }
720 
721         strcat(end, "{\n");
722         end += 2;
723 
724         for (ep = g_entities[i].epairs; ep; ep = ep->next)
725         {
726             sprintf(line, "\"%s\" \"%s\"\n", ep->key, ep->value);
727             strcat(end, line);
728             end += strlen(line);
729         }
730         strcat(end, "}\n");
731         end += 2;
732 
733         if (end > buf + MAX_MAP_ENTSTRING)
734         {
735             Error("Entity text too long");
736         }
737     }
738     g_entdatasize = end - buf + 1;
739 }
740 
741 // =====================================================================================
742 //  SetKeyValue
743 //      makes a keyvalue
744 // =====================================================================================
SetKeyValue(entity_t * ent,const char * const key,const char * const value)745 void            SetKeyValue(entity_t* ent, const char* const key, const char* const value)
746 {
747     epair_t*        ep;
748 
749     for (ep = ent->epairs; ep; ep = ep->next)
750     {
751         if (!strcmp(ep->key, key))
752         {
753             Free(ep->value);
754             ep->value = strdup(value);
755             return;
756         }
757     }
758     ep = (epair_t*)Alloc(sizeof(*ep));
759     ep->next = ent->epairs;
760     ent->epairs = ep;
761     ep->key = strdup(key);
762     ep->value = strdup(value);
763 }
764 
765 // =====================================================================================
766 //  ValueForKey
767 //      returns the value for a passed entity and key
768 // =====================================================================================
ValueForKey(const entity_t * const ent,const char * const key)769 const char*     ValueForKey(const entity_t* const ent, const char* const key)
770 {
771     epair_t*        ep;
772 
773     for (ep = ent->epairs; ep; ep = ep->next)
774     {
775         if (!strcmp(ep->key, key))
776         {
777             return ep->value;
778         }
779     }
780     return "";
781 }
782 
783 // =====================================================================================
784 //  IntForKey
785 // =====================================================================================
IntForKey(const entity_t * const ent,const char * const key)786 int             IntForKey(const entity_t* const ent, const char* const key)
787 {
788     return atoi(ValueForKey(ent, key));
789 }
790 
791 // =====================================================================================
792 //  FloatForKey
793 // =====================================================================================
FloatForKey(const entity_t * const ent,const char * const key)794 vec_t           FloatForKey(const entity_t* const ent, const char* const key)
795 {
796     return atof(ValueForKey(ent, key));
797 }
798 
799 // =====================================================================================
800 //  GetVectorForKey
801 //      returns value for key in vec[0-2]
802 // =====================================================================================
GetVectorForKey(const entity_t * const ent,const char * const key,vec3_t vec)803 void            GetVectorForKey(const entity_t* const ent, const char* const key, vec3_t vec)
804 {
805     const char*     k;
806     double          v1, v2, v3;
807 
808     k = ValueForKey(ent, key);
809     // scanf into doubles, then assign, so it is vec_t size independent
810     v1 = v2 = v3 = 0;
811     sscanf(k, "%lf %lf %lf", &v1, &v2, &v3);
812     vec[0] = v1;
813     vec[1] = v2;
814     vec[2] = v3;
815 }
816 
817 // =====================================================================================
818 //  FindTargetEntity
819 //
820 // =====================================================================================
FindTargetEntity(const char * const target)821 entity_t *FindTargetEntity(const char* const target)
822 {
823     int             i;
824     const char*     n;
825 
826     for (i = 0; i < g_numentities; i++)
827     {
828         n = ValueForKey(&g_entities[i], "targetname");
829         if (!strcmp(n, target))
830         {
831             return &g_entities[i];
832         }
833     }
834 
835     return NULL;
836 }
837 
838 
dtexdata_init()839 void            dtexdata_init()
840 {
841     g_dtexdata = (byte*)AllocBlock(g_max_map_miptex);
842     hlassume(g_dtexdata != NULL, assume_NoMemory);
843 	g_dlightdata = (byte*)AllocBlock(g_max_map_lightdata);
844 	hlassume(g_dlightdata != NULL, assume_NoMemory);
845 }
846 
dtexdata_free()847 void CDECL      dtexdata_free()
848 {
849     FreeBlock(g_dtexdata);
850     g_dtexdata = NULL;
851 	FreeBlock(g_dlightdata);
852 	g_dlightdata = NULL;
853 }
854 
855 // =====================================================================================
856 //  GetTextureByNumber
857 //      Touchy function, can fail with a page fault if all the data isnt kosher
858 //      (i.e. map was compiled with missing textures)
859 // =====================================================================================
GetTextureByNumber(int texturenumber)860 char*           GetTextureByNumber(int texturenumber)
861 {
862     texinfo_t*      info;
863     miptex_t*       miptex;
864     int             ofs;
865 
866     info = &g_texinfo[texturenumber];
867     ofs = ((dmiptexlump_t*)g_dtexdata)->dataofs[info->miptex];
868     miptex = (miptex_t*)(&g_dtexdata[ofs]);
869 
870     return miptex->name;
871 }
872 
873 // =====================================================================================
874 //  EntityForModel
875 //      returns entity addy for given modelnum
876 // =====================================================================================
EntityForModel(const int modnum)877 entity_t*       EntityForModel(const int modnum)
878 {
879     int             i;
880     const char*     s;
881     char            name[16];
882 
883     sprintf(name, "*%i", modnum);
884     // search the entities for one using modnum
885     for (i = 0; i < g_numentities; i++)
886     {
887         s = ValueForKey(&g_entities[i], "model");
888         if (!strcmp(s, name))
889         {
890             return &g_entities[i];
891         }
892     }
893 
894     return &g_entities[0];
895 }