]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/qdata_heretic2/common/bspfile.c
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / tools / quake2 / qdata_heretic2 / common / bspfile.c
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 */\r
21 \r
22 \r
23 #include "cmdlib.h"\r
24 #include "inout.h"\r
25 #include "mathlib.h"\r
26 #include "bspfile.h"\r
27 #include "scriplib.h"\r
28 \r
29 void GetLeafNums (void);\r
30 \r
31 //=============================================================================\r
32 \r
33 int                     nummodels;\r
34 dmodel_t        dmodels[MAX_MAP_MODELS];\r
35 \r
36 int                     visdatasize;\r
37 byte            dvisdata[MAX_MAP_VISIBILITY];\r
38 dvis_t          *dvis = (dvis_t *)dvisdata;\r
39 \r
40 int                     lightdatasize;\r
41 byte            dlightdata[MAX_MAP_LIGHTING];\r
42 \r
43 int                     entdatasize;\r
44 char            dentdata[MAX_MAP_ENTSTRING];\r
45 \r
46 int                     numleafs;\r
47 dleaf_t         dleafs[MAX_MAP_LEAFS];\r
48 \r
49 int                     numplanes;\r
50 dplane_t        dplanes[MAX_MAP_PLANES];\r
51 \r
52 int                     numvertexes;\r
53 dvertex_t       dvertexes[MAX_MAP_VERTS];\r
54 \r
55 int                     numnodes;\r
56 dnode_t         dnodes[MAX_MAP_NODES];\r
57 \r
58 int                     numtexinfo;\r
59 texinfo_t       texinfo[MAX_MAP_TEXINFO];\r
60 \r
61 int                     numfaces;\r
62 dface_t         dfaces[MAX_MAP_FACES];\r
63 \r
64 int                     numedges;\r
65 dedge_t         dedges[MAX_MAP_EDGES];\r
66 \r
67 int                     numleaffaces;\r
68 unsigned short          dleaffaces[MAX_MAP_LEAFFACES];\r
69 \r
70 int                     numleafbrushes;\r
71 unsigned short          dleafbrushes[MAX_MAP_LEAFBRUSHES];\r
72 \r
73 int                     numsurfedges;\r
74 int                     dsurfedges[MAX_MAP_SURFEDGES];\r
75 \r
76 int                     numbrushes;\r
77 dbrush_t        dbrushes[MAX_MAP_BRUSHES];\r
78 \r
79 int                     numbrushsides;\r
80 dbrushside_t    dbrushsides[MAX_MAP_BRUSHSIDES];\r
81 \r
82 int                     numareas;\r
83 darea_t         dareas[MAX_MAP_AREAS];\r
84 \r
85 int                     numareaportals;\r
86 dareaportal_t   dareaportals[MAX_MAP_AREAPORTALS];\r
87 \r
88 byte            dpop[256];\r
89 \r
90 /*\r
91 ===============\r
92 CompressVis\r
93 \r
94 ===============\r
95 */\r
96 int CompressVis (byte *vis, byte *dest)\r
97 {\r
98         int             j;\r
99         int             rep;\r
100         int             visrow;\r
101         byte    *dest_p;\r
102         \r
103         dest_p = dest;\r
104 //      visrow = (r_numvisleafs + 7)>>3;\r
105         visrow = (dvis->numclusters + 7)>>3;\r
106         \r
107         for (j=0 ; j<visrow ; j++)\r
108         {\r
109                 *dest_p++ = vis[j];\r
110                 if (vis[j])\r
111                         continue;\r
112 \r
113                 rep = 1;\r
114                 for ( j++; j<visrow ; j++)\r
115                         if (vis[j] || rep == 255)\r
116                                 break;\r
117                         else\r
118                                 rep++;\r
119                 *dest_p++ = rep;\r
120                 j--;\r
121         }\r
122         \r
123         return dest_p - dest;\r
124 }\r
125 \r
126 \r
127 /*\r
128 ===================\r
129 DecompressVis\r
130 ===================\r
131 */\r
132 void DecompressVis (byte *in, byte *decompressed)\r
133 {\r
134         int             c;\r
135         byte    *out;\r
136         int             row;\r
137 \r
138 //      row = (r_numvisleafs+7)>>3;     \r
139         row = (dvis->numclusters+7)>>3; \r
140         out = decompressed;\r
141 \r
142         do\r
143         {\r
144                 if (*in)\r
145                 {\r
146                         *out++ = *in++;\r
147                         continue;\r
148                 }\r
149         \r
150                 c = in[1];\r
151                 if (!c)\r
152                         Error ("DecompressVis: 0 repeat");\r
153                 in += 2;\r
154                 while (c)\r
155                 {\r
156                         *out++ = 0;\r
157                         c--;\r
158                 }\r
159         } while (out - decompressed < row);\r
160 }\r
161 \r
162 //=============================================================================\r
163 \r
164 /*\r
165 =============\r
166 SwapBSPFile\r
167 \r
168 Byte swaps all data in a bsp file.\r
169 =============\r
170 */\r
171 void SwapBSPFile (qboolean todisk)\r
172 {\r
173         int                             i, j;\r
174         dmodel_t                *d;\r
175 \r
176         \r
177 // models       \r
178         for (i=0 ; i<nummodels ; i++)\r
179         {\r
180                 d = &dmodels[i];\r
181 \r
182                 d->firstface = LittleLong (d->firstface);\r
183                 d->numfaces = LittleLong (d->numfaces);\r
184                 d->headnode = LittleLong (d->headnode);\r
185                 \r
186                 for (j=0 ; j<3 ; j++)\r
187                 {\r
188                         d->mins[j] = LittleFloat(d->mins[j]);\r
189                         d->maxs[j] = LittleFloat(d->maxs[j]);\r
190                         d->origin[j] = LittleFloat(d->origin[j]);\r
191                 }\r
192         }\r
193 \r
194 //\r
195 // vertexes\r
196 //\r
197         for (i=0 ; i<numvertexes ; i++)\r
198         {\r
199                 for (j=0 ; j<3 ; j++)\r
200                         dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]);\r
201         }\r
202                 \r
203 //\r
204 // planes\r
205 //      \r
206         for (i=0 ; i<numplanes ; i++)\r
207         {\r
208                 for (j=0 ; j<3 ; j++)\r
209                         dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]);\r
210                 dplanes[i].dist = LittleFloat (dplanes[i].dist);\r
211                 dplanes[i].type = LittleLong (dplanes[i].type);\r
212         }\r
213         \r
214 //\r
215 // texinfos\r
216 //      \r
217         for (i=0 ; i<numtexinfo ; i++)\r
218         {\r
219                 for (j=0 ; j<8 ; j++)\r
220                         texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]);\r
221                 texinfo[i].flags = LittleLong (texinfo[i].flags);\r
222                 texinfo[i].value = LittleLong (texinfo[i].value);\r
223                 texinfo[i].nexttexinfo = LittleLong (texinfo[i].nexttexinfo);\r
224         }\r
225         \r
226 //\r
227 // faces\r
228 //\r
229         for (i=0 ; i<numfaces ; i++)\r
230         {\r
231                 dfaces[i].texinfo = LittleShort (dfaces[i].texinfo);\r
232                 dfaces[i].planenum = LittleShort (dfaces[i].planenum);\r
233                 dfaces[i].side = LittleShort (dfaces[i].side);\r
234                 dfaces[i].lighting.c = LittleLong (dfaces[i].lighting.c);\r
235                 dfaces[i].lightofs = LittleLong (dfaces[i].lightofs);\r
236                 dfaces[i].firstedge = LittleLong (dfaces[i].firstedge);\r
237                 dfaces[i].numedges = LittleShort (dfaces[i].numedges);\r
238         }\r
239 \r
240 //\r
241 // nodes\r
242 //\r
243         for (i=0 ; i<numnodes ; i++)\r
244         {\r
245                 dnodes[i].planenum = LittleLong (dnodes[i].planenum);\r
246                 for (j=0 ; j<3 ; j++)\r
247                 {\r
248                         dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]);\r
249                         dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]);\r
250                 }\r
251                 dnodes[i].children[0] = LittleLong (dnodes[i].children[0]);\r
252                 dnodes[i].children[1] = LittleLong (dnodes[i].children[1]);\r
253                 dnodes[i].firstface = LittleShort (dnodes[i].firstface);\r
254                 dnodes[i].numfaces = LittleShort (dnodes[i].numfaces);\r
255         }\r
256 \r
257 //\r
258 // leafs\r
259 //\r
260         for (i=0 ; i<numleafs ; i++)\r
261         {\r
262                 dleafs[i].contents = LittleLong (dleafs[i].contents);\r
263                 dleafs[i].cluster = LittleShort (dleafs[i].cluster);\r
264                 dleafs[i].area = LittleShort (dleafs[i].area);\r
265                 for (j=0 ; j<3 ; j++)\r
266                 {\r
267                         dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]);\r
268                         dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]);\r
269                 }\r
270 \r
271                 dleafs[i].firstleafface = LittleShort (dleafs[i].firstleafface);\r
272                 dleafs[i].numleaffaces = LittleShort (dleafs[i].numleaffaces);\r
273                 dleafs[i].firstleafbrush = LittleShort (dleafs[i].firstleafbrush);\r
274                 dleafs[i].numleafbrushes = LittleShort (dleafs[i].numleafbrushes);\r
275         }\r
276 \r
277 //\r
278 // leaffaces\r
279 //\r
280         for (i=0 ; i<numleaffaces ; i++)\r
281                 dleaffaces[i] = LittleShort (dleaffaces[i]);\r
282 \r
283 //\r
284 // leafbrushes\r
285 //\r
286         for (i=0 ; i<numleafbrushes ; i++)\r
287                 dleafbrushes[i] = LittleShort (dleafbrushes[i]);\r
288 \r
289 //\r
290 // surfedges\r
291 //\r
292         for (i=0 ; i<numsurfedges ; i++)\r
293                 dsurfedges[i] = LittleLong (dsurfedges[i]);\r
294 \r
295 //\r
296 // edges\r
297 //\r
298         for (i=0 ; i<numedges ; i++)\r
299         {\r
300                 dedges[i].v[0] = LittleShort (dedges[i].v[0]);\r
301                 dedges[i].v[1] = LittleShort (dedges[i].v[1]);\r
302         }\r
303 \r
304 //\r
305 // brushes\r
306 //\r
307         for (i=0 ; i<numbrushes ; i++)\r
308         {\r
309                 dbrushes[i].firstside = LittleLong (dbrushes[i].firstside);\r
310                 dbrushes[i].numsides = LittleLong (dbrushes[i].numsides);\r
311                 dbrushes[i].contents = LittleLong (dbrushes[i].contents);\r
312         }\r
313 \r
314 //\r
315 // areas\r
316 //\r
317         for (i=0 ; i<numareas ; i++)\r
318         {\r
319                 dareas[i].numareaportals = LittleLong (dareas[i].numareaportals);\r
320                 dareas[i].firstareaportal = LittleLong (dareas[i].firstareaportal);\r
321         }\r
322 \r
323 //\r
324 // areasportals\r
325 //\r
326         for (i=0 ; i<numareaportals ; i++)\r
327         {\r
328                 dareaportals[i].portalnum = LittleLong (dareaportals[i].portalnum);\r
329                 dareaportals[i].otherarea = LittleLong (dareaportals[i].otherarea);\r
330         }\r
331 \r
332 //\r
333 // brushsides\r
334 //\r
335         for (i=0 ; i<numbrushsides ; i++)\r
336         {\r
337                 dbrushsides[i].planenum = LittleShort (dbrushsides[i].planenum);\r
338                 dbrushsides[i].texinfo = LittleShort (dbrushsides[i].texinfo);\r
339         }\r
340 \r
341 //\r
342 // visibility\r
343 //\r
344         if (todisk)\r
345                 j = dvis->numclusters;\r
346         else\r
347                 j = LittleLong(dvis->numclusters);\r
348         dvis->numclusters = LittleLong (dvis->numclusters);\r
349         for (i=0 ; i<j ; i++)\r
350         {\r
351                 dvis->bitofs[i][0] = LittleLong (dvis->bitofs[i][0]);\r
352                 dvis->bitofs[i][1] = LittleLong (dvis->bitofs[i][1]);\r
353         }\r
354 }\r
355 \r
356 \r
357 dheader_t       *header;\r
358 \r
359 int CopyLump (int lump, void *dest, int size)\r
360 {\r
361         int             length, ofs;\r
362 \r
363         length = header->lumps[lump].filelen;\r
364         ofs = header->lumps[lump].fileofs;\r
365         \r
366         if (length % size)\r
367                 Error ("LoadBSPFile: odd lump size");\r
368         \r
369         memcpy (dest, (byte *)header + ofs, length);\r
370 \r
371         return length / size;\r
372 }\r
373 \r
374 /*\r
375 =============\r
376 LoadBSPFile\r
377 =============\r
378 */\r
379 void    LoadBSPFile (char *filename)\r
380 {\r
381         int                     i;\r
382         \r
383 //\r
384 // load the file header\r
385 //\r
386         LoadFile (filename, (void **)&header);\r
387 \r
388 // swap the header\r
389         for (i=0 ; i< sizeof(dheader_t)/4 ; i++)\r
390                 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);\r
391 \r
392         if (header->ident != IDBSPHEADER)\r
393                 Error ("%s is not a IBSP file", filename);\r
394         if (header->version != BSPVERSION)\r
395                 Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);\r
396 \r
397         nummodels = CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t));\r
398         numvertexes = CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t));\r
399         numplanes = CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t));\r
400         numleafs = CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t));\r
401         numnodes = CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t));\r
402         numtexinfo = CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t));\r
403         numfaces = CopyLump (LUMP_FACES, dfaces, sizeof(dface_t));\r
404         numleaffaces = CopyLump (LUMP_LEAFFACES, dleaffaces, sizeof(dleaffaces[0]));\r
405         numleafbrushes = CopyLump (LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0]));\r
406         numsurfedges = CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0]));\r
407         numedges = CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t));\r
408         numbrushes = CopyLump (LUMP_BRUSHES, dbrushes, sizeof(dbrush_t));\r
409         numbrushsides = CopyLump (LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t));\r
410         numareas = CopyLump (LUMP_AREAS, dareas, sizeof(darea_t));\r
411         numareaportals = CopyLump (LUMP_AREAPORTALS, dareaportals, sizeof(dareaportal_t));\r
412 \r
413         visdatasize = CopyLump (LUMP_VISIBILITY, dvisdata, 1);\r
414         lightdatasize = CopyLump (LUMP_LIGHTING, dlightdata, 1);\r
415         entdatasize = CopyLump (LUMP_ENTITIES, dentdata, 1);\r
416 \r
417         CopyLump (LUMP_POP, dpop, 1);\r
418 \r
419         free (header);          // everything has been copied out\r
420                 \r
421 //\r
422 // swap everything\r
423 //      \r
424         SwapBSPFile (false);\r
425 }\r
426 \r
427 \r
428 /*\r
429 =============\r
430 LoadBSPFileTexinfo\r
431 \r
432 Only loads the texinfo lump, so qdata can scan for textures\r
433 =============\r
434 */\r
435 void    LoadBSPFileTexinfo (char *filename)\r
436 {\r
437         int                     i;\r
438         FILE            *f;\r
439         int             length, ofs;\r
440 \r
441         header = malloc(sizeof(dheader_t));\r
442 \r
443         f = fopen (filename, "rb");\r
444         fread (header, sizeof(dheader_t), 1, f);\r
445 \r
446 // swap the header\r
447         for (i=0 ; i< sizeof(dheader_t)/4 ; i++)\r
448                 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);\r
449 \r
450         if (header->ident != IDBSPHEADER)\r
451                 Error ("%s is not a IBSP file", filename);\r
452         if (header->version != BSPVERSION)\r
453                 Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);\r
454 \r
455 \r
456         length = header->lumps[LUMP_TEXINFO].filelen;\r
457         ofs = header->lumps[LUMP_TEXINFO].fileofs;\r
458 \r
459         fseek (f, ofs, SEEK_SET);\r
460         fread (texinfo, length, 1, f);\r
461         fclose (f);\r
462 \r
463         numtexinfo = length / sizeof(texinfo_t);\r
464 \r
465         free (header);          // everything has been copied out\r
466                 \r
467         SwapBSPFile (false);\r
468 }\r
469 \r
470 \r
471 //============================================================================\r
472 \r
473 FILE            *wadfile;\r
474 dheader_t       outheader;\r
475 \r
476 void AddLump (int lumpnum, void *data, int len)\r
477 {\r
478         lump_t *lump;\r
479 \r
480         lump = &header->lumps[lumpnum];\r
481         \r
482         lump->fileofs = LittleLong( ftell(wadfile) );\r
483         lump->filelen = LittleLong(len);\r
484         SafeWrite (wadfile, data, (len+3)&~3);\r
485 }\r
486 \r
487 /*\r
488 =============\r
489 WriteBSPFile\r
490 \r
491 Swaps the bsp file in place, so it should not be referenced again\r
492 =============\r
493 */\r
494 void    WriteBSPFile (char *filename)\r
495 {               \r
496         header = &outheader;\r
497         memset (header, 0, sizeof(dheader_t));\r
498         \r
499         SwapBSPFile (true);\r
500 \r
501         header->ident = LittleLong (IDBSPHEADER);\r
502         header->version = LittleLong (BSPVERSION);\r
503         \r
504         wadfile = SafeOpenWrite (filename);\r
505         SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later\r
506 \r
507         AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t));\r
508         AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t));\r
509         AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t));\r
510         AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t));\r
511         AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t));\r
512         AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t));\r
513         AddLump (LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t));\r
514         AddLump (LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t));\r
515         AddLump (LUMP_LEAFFACES, dleaffaces, numleaffaces*sizeof(dleaffaces[0]));\r
516         AddLump (LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0]));\r
517         AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0]));\r
518         AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t));\r
519         AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t));\r
520         AddLump (LUMP_AREAS, dareas, numareas*sizeof(darea_t));\r
521         AddLump (LUMP_AREAPORTALS, dareaportals, numareaportals*sizeof(dareaportal_t));\r
522 \r
523         AddLump (LUMP_LIGHTING, dlightdata, lightdatasize);\r
524         AddLump (LUMP_VISIBILITY, dvisdata, visdatasize);\r
525         AddLump (LUMP_ENTITIES, dentdata, entdatasize);\r
526         AddLump (LUMP_POP, dpop, sizeof(dpop));\r
527         \r
528         fseek (wadfile, 0, SEEK_SET);\r
529         SafeWrite (wadfile, header, sizeof(dheader_t));\r
530         fclose (wadfile);       \r
531 }\r
532 \r
533 //============================================================================\r
534 \r
535 /*\r
536 =============\r
537 PrintBSPFileSizes\r
538 \r
539 Dumps info about current file\r
540 =============\r
541 */\r
542 void PrintBSPFileSizes (void)\r
543 {\r
544         if (!num_entities)\r
545                 ParseEntities ();\r
546 \r
547         printf ("%5i models       %7i\n"\r
548                 ,nummodels, (int)(nummodels*sizeof(dmodel_t)));\r
549         printf ("%5i brushes      %7i\n"\r
550                 ,numbrushes, (int)(numbrushes*sizeof(dbrush_t)));\r
551         printf ("%5i brushsides   %7i\n"\r
552                 ,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t)));\r
553         printf ("%5i planes       %7i\n"\r
554                 ,numplanes, (int)(numplanes*sizeof(dplane_t)));\r
555         printf ("%5i texinfo      %7i\n"\r
556                 ,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t)));\r
557         printf ("%5i entdata      %7i\n", num_entities, entdatasize);\r
558 \r
559         printf ("\n");\r
560 \r
561         printf ("%5i vertexes     %7i\n"\r
562                 ,numvertexes, (int)(numvertexes*sizeof(dvertex_t)));\r
563         printf ("%5i nodes        %7i\n"\r
564                 ,numnodes, (int)(numnodes*sizeof(dnode_t)));\r
565         printf ("%5i faces        %7i\n"\r
566                 ,numfaces, (int)(numfaces*sizeof(dface_t)));\r
567         printf ("%5i leafs        %7i\n"\r
568                 ,numleafs, (int)(numleafs*sizeof(dleaf_t)));\r
569         printf ("%5i leaffaces    %7i\n"\r
570                 ,numleaffaces, (int)(numleaffaces*sizeof(dleaffaces[0])));\r
571         printf ("%5i leafbrushes  %7i\n"\r
572                 ,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0])));\r
573         printf ("%5i surfedges    %7i\n"\r
574                 ,numsurfedges, (int)(numsurfedges*sizeof(dsurfedges[0])));\r
575         printf ("%5i edges        %7i\n"\r
576                 ,numedges, (int)(numedges*sizeof(dedge_t)));\r
577         printf ("      lightdata    %7i\n", lightdatasize);\r
578         printf ("      visdata      %7i\n", visdatasize);\r
579 }\r
580 \r
581 \r
582 //============================================\r
583 \r
584 int                     num_entities;\r
585 entity_t        entities[MAX_MAP_ENTITIES];\r
586 \r
587 void StripTrailing (char *e)\r
588 {\r
589         char    *s;\r
590 \r
591         s = e + strlen(e)-1;\r
592         while (s >= e && *s <= 32)\r
593         {\r
594                 *s = 0;\r
595                 s--;\r
596         }\r
597 }\r
598 \r
599 /*\r
600 =================\r
601 ParseEpair\r
602 =================\r
603 */\r
604 epair_t *ParseEpair (void)\r
605 {\r
606         epair_t *e;\r
607 \r
608         e = malloc (sizeof(epair_t));\r
609         memset (e, 0, sizeof(epair_t));\r
610         \r
611         if (strlen(token) >= MAX_KEY-1)\r
612                 Error ("ParseEpar: token too long");\r
613         e->key = copystring(token);\r
614         GetScriptToken (false);\r
615         if (strlen(token) >= MAX_VALUE-1)\r
616                 Error ("ParseEpar: token too long");\r
617         e->value = copystring(token);\r
618 \r
619         // strip trailing spaces\r
620         StripTrailing (e->key);\r
621         StripTrailing (e->value);\r
622 \r
623         return e;\r
624 }\r
625 \r
626 \r
627 /*\r
628 ================\r
629 ParseEntity\r
630 ================\r
631 */\r
632 qboolean        ParseEntity (void)\r
633 {\r
634         epair_t         *e;\r
635         entity_t        *mapent;\r
636 \r
637         if (!GetScriptToken (true))\r
638                 return false;\r
639 \r
640         if (strcmp (token, "{") )\r
641                 Error ("ParseEntity: { not found");\r
642         \r
643         if (num_entities == MAX_MAP_ENTITIES)\r
644                 Error ("num_entities == MAX_MAP_ENTITIES");\r
645 \r
646         mapent = &entities[num_entities];\r
647         num_entities++;\r
648 \r
649         do\r
650         {\r
651                 if (!GetScriptToken (true))\r
652                         Error ("ParseEntity: EOF without closing brace");\r
653                 if (!strcmp (token, "}") )\r
654                         break;\r
655                 e = ParseEpair ();\r
656                 e->next = mapent->epairs;\r
657                 mapent->epairs = e;\r
658         } while (1);\r
659         \r
660         return true;\r
661 }\r
662 \r
663 /*\r
664 ================\r
665 ParseEntities\r
666 \r
667 Parses the dentdata string into entities\r
668 ================\r
669 */\r
670 void ParseEntities (void)\r
671 {\r
672         num_entities = 0;\r
673         ParseFromMemory (dentdata, entdatasize);\r
674 \r
675         while (ParseEntity ())\r
676         {\r
677         }       \r
678 }\r
679 \r
680 \r
681 /*\r
682 ================\r
683 UnparseEntities\r
684 \r
685 Generates the dentdata string from all the entities\r
686 ================\r
687 */\r
688 void UnparseEntities (void)\r
689 {\r
690         char    *buf, *end;\r
691         epair_t *ep;\r
692         char    line[2048];\r
693         int             i;\r
694         char    key[1024], value[1024];\r
695 \r
696         buf = dentdata;\r
697         end = buf;\r
698         *end = 0;\r
699         \r
700         for (i=0 ; i<num_entities ; i++)\r
701         {\r
702                 ep = entities[i].epairs;\r
703                 if (!ep)\r
704                         continue;       // ent got removed\r
705                 \r
706                 strcat (end,"{\n");\r
707                 end += 2;\r
708                                 \r
709                 for (ep = entities[i].epairs ; ep ; ep=ep->next)\r
710                 {\r
711                         strcpy (key, ep->key);\r
712                         StripTrailing (key);\r
713                         strcpy (value, ep->value);\r
714                         StripTrailing (value);\r
715                                 \r
716                         sprintf (line, "\"%s\" \"%s\"\n", key, value);\r
717                         strcat (end, line);\r
718                         end += strlen(line);\r
719                 }\r
720                 strcat (end,"}\n");\r
721                 end += 2;\r
722 \r
723                 if (end > buf + MAX_MAP_ENTSTRING)\r
724                         Error ("Entity text too long");\r
725         }\r
726         entdatasize = end - buf + 1;\r
727 }\r
728 \r
729 void PrintEntity (entity_t *ent)\r
730 {\r
731         epair_t *ep;\r
732         \r
733         printf ("------- entity %p -------\n", ent);\r
734         for (ep=ent->epairs ; ep ; ep=ep->next)\r
735         {\r
736                 printf ("%s = %s\n", ep->key, ep->value);\r
737         }\r
738 \r
739 }\r
740 \r
741 void    SetKeyValue (entity_t *ent, char *key, char *value)\r
742 {\r
743         epair_t *ep;\r
744         \r
745         for (ep=ent->epairs ; ep ; ep=ep->next)\r
746                 if (!strcmp (ep->key, key) )\r
747                 {\r
748                         free (ep->value);\r
749                         ep->value = copystring(value);\r
750                         return;\r
751                 }\r
752         ep = malloc (sizeof(*ep));\r
753         if (!ep)\r
754                 Error("SetKeyValue MALLOC failed!  Could not allocate %s bytes.", sizeof(*ep));\r
755         ep->next = ent->epairs;\r
756         ent->epairs = ep;\r
757         ep->key = copystring(key);\r
758         ep->value = copystring(value);\r
759 }\r
760 \r
761 char    *ValueForKey (entity_t *ent, char *key)\r
762 {\r
763         epair_t *ep;\r
764         \r
765         for (ep=ent->epairs ; ep ; ep=ep->next)\r
766                 if (!strcmp (ep->key, key) )\r
767                         return ep->value;\r
768         return "";\r
769 }\r
770 \r
771 vec_t   FloatForKey (entity_t *ent, char *key)\r
772 {\r
773         char    *k;\r
774         \r
775         k = ValueForKey (ent, key);\r
776         return atof(k);\r
777 }\r
778 \r
779 void    GetVectorForKey (entity_t *ent, char *key, vec3_t vec)\r
780 {\r
781         char    *k;\r
782         double  v1, v2, v3;\r
783 \r
784         k = ValueForKey (ent, key);\r
785 // scanf into doubles, then assign, so it is vec_t size independent\r
786         v1 = v2 = v3 = 0;\r
787         sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);\r
788         vec[0] = v1;\r
789         vec[1] = v2;\r
790         vec[2] = v3;\r
791 }\r
792 \r
793 \r