]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/common/bspfile.c
edc3cd6580806996f416d8cb1e636a15e8c9bc22
[xonotic/netradiant.git] / tools / quake3 / 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 "mathlib.h"\r
25 #include "inout.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     bsp_version = Q3_BSP_VERSION;\r
34 \r
35 int                     nummodels;\r
36 dmodel_t        dmodels[MAX_MAP_MODELS];\r
37 \r
38 int                     numShaders;\r
39 dshader_t       dshaders[MAX_MAP_SHADERS];\r
40 \r
41 int                     entdatasize;\r
42 char            dentdata[MAX_MAP_ENTSTRING];\r
43 \r
44 int                     numleafs;\r
45 dleaf_t         dleafs[MAX_MAP_LEAFS];\r
46 \r
47 int                     numplanes;\r
48 dplane_t        dplanes[MAX_MAP_PLANES];\r
49 \r
50 int                     numnodes;\r
51 dnode_t         dnodes[MAX_MAP_NODES];\r
52 \r
53 int                     numleafsurfaces;\r
54 int                     dleafsurfaces[MAX_MAP_LEAFFACES];\r
55 \r
56 int                     numleafbrushes;\r
57 int                     dleafbrushes[MAX_MAP_LEAFBRUSHES];\r
58 \r
59 int                     numbrushes;\r
60 dbrush_t        dbrushes[MAX_MAP_BRUSHES];\r
61 \r
62 int                     numbrushsides;\r
63 dbrushside_t    dbrushsides[MAX_MAP_BRUSHSIDES];\r
64 \r
65 int                     numLightBytes;\r
66 byte            *lightBytes;\r
67 \r
68 int                     numGridPoints;\r
69 byte            *gridData;\r
70 \r
71 int                     numVisBytes;\r
72 byte            visBytes[MAX_MAP_VISIBILITY];\r
73 \r
74 int                     numDrawVerts = 0;\r
75 int         numDrawVertsBuffer = 0;\r
76 drawVert_t      *drawVerts = NULL;\r
77 \r
78 int                     numDrawIndexes;\r
79 int                     drawIndexes[MAX_MAP_DRAW_INDEXES];\r
80 \r
81 int                     numDrawSurfaces;\r
82 int         numDrawSurfacesBuffer = 0;\r
83 dsurface_t      *drawSurfaces = NULL;\r
84 \r
85 int                     numFogs;\r
86 dfog_t          dfogs[MAX_MAP_FOGS];\r
87 \r
88 void SetLightBytes(int n)\r
89 {\r
90         if(lightBytes != 0)\r
91                 free(lightBytes);\r
92 \r
93         numLightBytes = n;\r
94 \r
95         if(n == 0)\r
96                 return;\r
97 \r
98         lightBytes = safe_malloc_info(numLightBytes, "SetLightBytes");\r
99 \r
100         memset(lightBytes, 0, numLightBytes);\r
101 }\r
102 \r
103 void SetGridPoints(int n)\r
104 {\r
105         if(gridData != 0)\r
106                 free(gridData);\r
107 \r
108         numGridPoints = n;\r
109 \r
110         if(n == 0)\r
111                 return;\r
112 \r
113   gridData = safe_malloc_info(numGridPoints * 8, "SetGridPoints");\r
114 \r
115         memset(gridData, 0, numGridPoints * 8);\r
116 }\r
117 \r
118 void IncDrawVerts()\r
119 {\r
120         numDrawVerts++;\r
121 \r
122         if(drawVerts == 0)\r
123         {\r
124                 numDrawVertsBuffer = MAX_MAP_DRAW_VERTS / 37;\r
125                 \r
126                 drawVerts = safe_malloc_info(sizeof(drawVert_t) * numDrawVertsBuffer, "IncDrawVerts");\r
127 \r
128         }\r
129         else if(numDrawVerts > numDrawVertsBuffer)\r
130         {\r
131                 numDrawVertsBuffer *= 3; // multiply by 1.5\r
132                 numDrawVertsBuffer /= 2;\r
133 \r
134                 if(numDrawVertsBuffer > MAX_MAP_DRAW_VERTS)\r
135                         numDrawVertsBuffer = MAX_MAP_DRAW_VERTS;\r
136 \r
137                 drawVerts = realloc(drawVerts, sizeof(drawVert_t) * numDrawVertsBuffer);\r
138 \r
139                 if(!drawVerts)\r
140                         Error( "realloc() failed (IncDrawVerts)");\r
141         }\r
142 \r
143         memset(drawVerts + (numDrawVerts - 1), 0, sizeof(drawVert_t));\r
144 }\r
145 \r
146 void SetDrawVerts(int n)\r
147 {\r
148         if(drawVerts != 0)\r
149                 free(drawVerts);\r
150 \r
151         numDrawVerts = n;\r
152         numDrawVertsBuffer = numDrawVerts;\r
153 \r
154         drawVerts = safe_malloc_info(sizeof(drawVert_t) * numDrawVertsBuffer, "IncDrawVerts");\r
155 \r
156         memset(drawVerts, 0, n * sizeof(drawVert_t));\r
157 }\r
158 \r
159 void SetDrawSurfacesBuffer()\r
160 {\r
161         if(drawSurfaces != 0)\r
162                 free(drawSurfaces);\r
163 \r
164         numDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;\r
165 \r
166         drawSurfaces = safe_malloc_info(sizeof(dsurface_t) * numDrawSurfacesBuffer, "IncDrawSurfaces");\r
167 \r
168         memset(drawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof(drawVert_t));\r
169 }\r
170 \r
171 void SetDrawSurfaces(int n)\r
172 {\r
173         if(drawSurfaces != 0)\r
174                 free(drawSurfaces);\r
175 \r
176         numDrawSurfaces = n;\r
177         numDrawSurfacesBuffer = numDrawSurfaces;\r
178 \r
179         drawSurfaces = safe_malloc_info(sizeof(dsurface_t) * numDrawSurfacesBuffer, "IncDrawSurfaces");\r
180 \r
181         memset(drawSurfaces, 0, n * sizeof(drawVert_t));\r
182 }\r
183 \r
184 void BspFilesCleanup()\r
185 {\r
186         if(drawVerts != 0)\r
187                 free(drawVerts);\r
188         if(drawSurfaces != 0)\r
189                 free(drawSurfaces);\r
190         if(lightBytes != 0)\r
191                 free(lightBytes);\r
192         if(gridData != 0)\r
193                 free(gridData);\r
194 }\r
195 \r
196 //=============================================================================\r
197 \r
198 /*\r
199 =============\r
200 SwapBlock\r
201 \r
202 If all values are 32 bits, this can be used to swap everything\r
203 =============\r
204 */\r
205 void SwapBlock( int *block, int sizeOfBlock ) {\r
206         int             i;\r
207 \r
208         sizeOfBlock >>= 2;\r
209         for ( i = 0 ; i < sizeOfBlock ; i++ ) {\r
210                 block[i] = LittleLong( block[i] );\r
211         }\r
212 }\r
213 \r
214 /*\r
215 =============\r
216 SwapBSPFile\r
217 \r
218 Byte swaps all data in a bsp file.\r
219 =============\r
220 */\r
221 void SwapBSPFile( void ) {\r
222         int                             i;\r
223         \r
224         // models       \r
225         SwapBlock( (int *)dmodels, nummodels * sizeof( dmodels[0] ) );\r
226 \r
227         // shaders (don't swap the name)\r
228         for ( i = 0 ; i < numShaders ; i++ ) {\r
229                 dshaders[i].contentFlags = LittleLong( dshaders[i].contentFlags );\r
230                 dshaders[i].surfaceFlags = LittleLong( dshaders[i].surfaceFlags );\r
231         }\r
232 \r
233         // planes\r
234         SwapBlock( (int *)dplanes, numplanes * sizeof( dplanes[0] ) );\r
235         \r
236         // nodes\r
237         SwapBlock( (int *)dnodes, numnodes * sizeof( dnodes[0] ) );\r
238 \r
239         // leafs\r
240         SwapBlock( (int *)dleafs, numleafs * sizeof( dleafs[0] ) );\r
241 \r
242         // leaffaces\r
243         SwapBlock( (int *)dleafsurfaces, numleafsurfaces * sizeof( dleafsurfaces[0] ) );\r
244 \r
245         // leafbrushes\r
246         SwapBlock( (int *)dleafbrushes, numleafbrushes * sizeof( dleafbrushes[0] ) );\r
247 \r
248         // brushes\r
249         SwapBlock( (int *)dbrushes, numbrushes * sizeof( dbrushes[0] ) );\r
250 \r
251         // brushsides\r
252         SwapBlock( (int *)dbrushsides, numbrushsides * sizeof( dbrushsides[0] ) );\r
253 \r
254         // vis\r
255         ((int *)&visBytes)[0] = LittleLong( ((int *)&visBytes)[0] );\r
256         ((int *)&visBytes)[1] = LittleLong( ((int *)&visBytes)[1] );\r
257 \r
258         // drawverts (don't swap colors )\r
259         for ( i = 0 ; i < numDrawVerts ; i++ ) {\r
260                 drawVerts[i].lightmap[0] = LittleFloat( drawVerts[i].lightmap[0] );\r
261                 drawVerts[i].lightmap[1] = LittleFloat( drawVerts[i].lightmap[1] );\r
262                 drawVerts[i].st[0] = LittleFloat( drawVerts[i].st[0] );\r
263                 drawVerts[i].st[1] = LittleFloat( drawVerts[i].st[1] );\r
264                 drawVerts[i].xyz[0] = LittleFloat( drawVerts[i].xyz[0] );\r
265                 drawVerts[i].xyz[1] = LittleFloat( drawVerts[i].xyz[1] );\r
266                 drawVerts[i].xyz[2] = LittleFloat( drawVerts[i].xyz[2] );\r
267                 drawVerts[i].normal[0] = LittleFloat( drawVerts[i].normal[0] );\r
268                 drawVerts[i].normal[1] = LittleFloat( drawVerts[i].normal[1] );\r
269                 drawVerts[i].normal[2] = LittleFloat( drawVerts[i].normal[2] );\r
270         }\r
271 \r
272         // drawindexes\r
273         SwapBlock( (int *)drawIndexes, numDrawIndexes * sizeof( drawIndexes[0] ) );\r
274 \r
275         // drawsurfs\r
276         SwapBlock( (int *)drawSurfaces, numDrawSurfaces * sizeof( drawSurfaces[0] ) );\r
277 \r
278         // fogs\r
279         for ( i = 0 ; i < numFogs ; i++ ) {\r
280                 dfogs[i].brushNum = LittleLong( dfogs[i].brushNum );\r
281                 dfogs[i].visibleSide = LittleLong( dfogs[i].visibleSide );\r
282         }\r
283 }\r
284 \r
285 \r
286 \r
287 /*\r
288 =============\r
289 GetLumpElements\r
290 =============\r
291 */\r
292 int GetLumpElements( dheader_t  *header, int lump, int size ) {\r
293         int             length, ofs;\r
294 \r
295         length = header->lumps[lump].filelen;\r
296         ofs = header->lumps[lump].fileofs;\r
297         \r
298         if ( length % size ) {\r
299                 Error ("LoadBSPFile: odd lump size");\r
300         }\r
301 \r
302         return length / size;\r
303 }\r
304 \r
305 /*\r
306 =============\r
307 CopyLump\r
308 =============\r
309 */\r
310 int CopyLump( dheader_t *header, int lump, void *dest, int size ) {\r
311         int             length, ofs;\r
312 \r
313         length = header->lumps[lump].filelen;\r
314         ofs = header->lumps[lump].fileofs;\r
315         \r
316         if(length == 0)\r
317                 return 0;\r
318         \r
319         if ( length % size ) {\r
320                 Error ("LoadBSPFile: odd lump size");\r
321         }\r
322 \r
323         memcpy( dest, (byte *)header + ofs, length );\r
324 \r
325         return length / size;\r
326 }\r
327 \r
328 /*\r
329 =============\r
330 LoadBSPFile\r
331 =============\r
332 */\r
333 void    LoadBSPFile( const char *filename ) {\r
334         dheader_t       *header;\r
335 \r
336         // load the file header\r
337         LoadFile (filename, (void **)&header);\r
338 \r
339         // swap the header\r
340         SwapBlock( (int *)header, sizeof(*header) );\r
341 \r
342         if ( header->ident != BSP_IDENT ) {\r
343                 Error( "%s is not a IBSP file", filename );\r
344         }\r
345         if ( header->version != bsp_version ) {\r
346                 Error( "%s is version %i, not %i", filename, header->version, bsp_version );\r
347         }\r
348 \r
349         numShaders = CopyLump( header, LUMP_SHADERS, dshaders, sizeof(dshader_t) );\r
350         nummodels = CopyLump( header, LUMP_MODELS, dmodels, sizeof(dmodel_t) );\r
351         numplanes = CopyLump( header, LUMP_PLANES, dplanes, sizeof(dplane_t) );\r
352         numleafs = CopyLump( header, LUMP_LEAFS, dleafs, sizeof(dleaf_t) );\r
353         numnodes = CopyLump( header, LUMP_NODES, dnodes, sizeof(dnode_t) );\r
354         numleafsurfaces = CopyLump( header, LUMP_LEAFSURFACES, dleafsurfaces, sizeof(dleafsurfaces[0]) );\r
355         numleafbrushes = CopyLump( header, LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0]) );\r
356         numbrushes = CopyLump( header, LUMP_BRUSHES, dbrushes, sizeof(dbrush_t) );\r
357         numbrushsides = CopyLump( header, LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t) );\r
358         numDrawVerts = GetLumpElements( header, LUMP_DRAWVERTS, sizeof(drawVert_t) );\r
359                 SetDrawVerts(numDrawVerts);\r
360                 CopyLump( header, LUMP_DRAWVERTS, drawVerts, sizeof(drawVert_t) );\r
361         numDrawSurfaces = GetLumpElements( header, LUMP_SURFACES, sizeof(dsurface_t) );\r
362                 SetDrawSurfaces(numDrawSurfaces);\r
363                 numDrawSurfaces = CopyLump( header, LUMP_SURFACES, drawSurfaces, sizeof(dsurface_t) );\r
364         numFogs = CopyLump( header, LUMP_FOGS, dfogs, sizeof(dfog_t) );\r
365         numDrawIndexes = CopyLump( header, LUMP_DRAWINDEXES, drawIndexes, sizeof(drawIndexes[0]) );\r
366 \r
367         numVisBytes = CopyLump( header, LUMP_VISIBILITY, visBytes, 1 );\r
368         numLightBytes = GetLumpElements( header, LUMP_LIGHTMAPS, 1 );\r
369                 SetLightBytes(numLightBytes);\r
370                 CopyLump( header, LUMP_LIGHTMAPS, lightBytes, 1 );\r
371         entdatasize = CopyLump( header, LUMP_ENTITIES, dentdata, 1);\r
372 \r
373         numGridPoints = GetLumpElements( header, LUMP_LIGHTGRID, 8 );\r
374                 SetGridPoints(numGridPoints);\r
375                 CopyLump( header, LUMP_LIGHTGRID, gridData, 8 );\r
376 \r
377 \r
378         free( header );         // everything has been copied out\r
379                 \r
380         // swap everything\r
381         SwapBSPFile();\r
382 }\r
383 \r
384 \r
385 //============================================================================\r
386 \r
387 /*\r
388 =============\r
389 AddLump\r
390 =============\r
391 */\r
392 void AddLump( FILE *bspfile, dheader_t *header, int lumpnum, const void *data, int len ) {\r
393         lump_t *lump;\r
394 \r
395         lump = &header->lumps[lumpnum];\r
396         \r
397         lump->fileofs = LittleLong( ftell(bspfile) );\r
398         lump->filelen = LittleLong( len );\r
399         SafeWrite( bspfile, data, (len+3)&~3 );\r
400 }\r
401 \r
402 /*\r
403 =============\r
404 WriteBSPFile\r
405 \r
406 Swaps the bsp file in place, so it should not be referenced again\r
407 =============\r
408 */\r
409 void    WriteBSPFile( const char *filename ) {          \r
410         dheader_t       outheader, *header;\r
411         FILE            *bspfile;\r
412 \r
413         header = &outheader;\r
414         memset( header, 0, sizeof(dheader_t) );\r
415         \r
416         SwapBSPFile();\r
417 \r
418         header->ident = LittleLong( BSP_IDENT );\r
419         header->version = LittleLong( bsp_version );\r
420         \r
421         bspfile = SafeOpenWrite( filename );\r
422         SafeWrite( bspfile, header, sizeof(dheader_t) );        // overwritten later\r
423 \r
424         AddLump( bspfile, header, LUMP_SHADERS, dshaders, numShaders*sizeof(dshader_t) );\r
425         AddLump( bspfile, header, LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t) );\r
426         AddLump( bspfile, header, LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t) );\r
427         AddLump( bspfile, header, LUMP_NODES, dnodes, numnodes*sizeof(dnode_t) );\r
428         AddLump( bspfile, header, LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t) );\r
429         AddLump( bspfile, header, LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t) );\r
430         AddLump( bspfile, header, LUMP_LEAFSURFACES, dleafsurfaces, numleafsurfaces*sizeof(dleafsurfaces[0]) );\r
431         AddLump( bspfile, header, LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0]) );\r
432         AddLump( bspfile, header, LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t) );\r
433         AddLump( bspfile, header, LUMP_DRAWVERTS, drawVerts, numDrawVerts*sizeof(drawVert_t) );\r
434         AddLump( bspfile, header, LUMP_SURFACES, drawSurfaces, numDrawSurfaces*sizeof(dsurface_t) );\r
435         AddLump( bspfile, header, LUMP_VISIBILITY, visBytes, numVisBytes );\r
436         AddLump( bspfile, header, LUMP_LIGHTMAPS, lightBytes, numLightBytes );\r
437         AddLump( bspfile, header, LUMP_LIGHTGRID, gridData, 8 * numGridPoints );\r
438         AddLump( bspfile, header, LUMP_ENTITIES, dentdata, entdatasize );\r
439         AddLump( bspfile, header, LUMP_FOGS, dfogs, numFogs * sizeof(dfog_t) );\r
440         AddLump( bspfile, header, LUMP_DRAWINDEXES, drawIndexes, numDrawIndexes * sizeof(drawIndexes[0]) );\r
441         \r
442         fseek (bspfile, 0, SEEK_SET);\r
443         SafeWrite (bspfile, header, sizeof(dheader_t));\r
444         fclose (bspfile);       \r
445 }\r
446 \r
447 //============================================================================\r
448 \r
449 /*\r
450 =============\r
451 PrintBSPFileSizes\r
452 \r
453 Dumps info about current file\r
454 =============\r
455 */\r
456 void PrintBSPFileSizes( void ) {\r
457         if ( !num_entities ) {\r
458                 ParseEntities();\r
459         }\r
460 \r
461         Sys_Printf ("%6i models       %7i\n"\r
462                 ,nummodels, (int)(nummodels*sizeof(dmodel_t)));\r
463         Sys_Printf ("%6i shaders      %7i\n"\r
464                 ,numShaders, (int)(numShaders*sizeof(dshader_t)));\r
465         Sys_Printf ("%6i brushes      %7i\n"\r
466                 ,numbrushes, (int)(numbrushes*sizeof(dbrush_t)));\r
467         Sys_Printf ("%6i brushsides   %7i\n"\r
468                 ,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t)));\r
469         Sys_Printf ("%6i fogs         %7i\n"\r
470                 ,numFogs, (int)(numFogs*sizeof(dfog_t)));\r
471         Sys_Printf ("%6i planes       %7i\n"\r
472                 ,numplanes, (int)(numplanes*sizeof(dplane_t)));\r
473         Sys_Printf ("%6i entdata      %7i\n", num_entities, entdatasize);\r
474 \r
475         Sys_Printf ("\n");\r
476 \r
477         Sys_Printf ("%6i nodes        %7i\n"\r
478                 ,numnodes, (int)(numnodes*sizeof(dnode_t)));\r
479         Sys_Printf ("%6i leafs        %7i\n"\r
480                 ,numleafs, (int)(numleafs*sizeof(dleaf_t)));\r
481         Sys_Printf ("%6i leafsurfaces %7i\n"\r
482                 ,numleafsurfaces, (int)(numleafsurfaces*sizeof(dleafsurfaces[0])));\r
483         Sys_Printf ("%6i leafbrushes  %7i\n"\r
484                 ,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0])));\r
485         Sys_Printf ("%6i drawverts    %7i\n"\r
486                 ,numDrawVerts, (int)(numDrawVerts*sizeof(drawVerts[0])));\r
487         Sys_Printf ("%6i drawindexes  %7i\n"\r
488                 ,numDrawIndexes, (int)(numDrawIndexes*sizeof(drawIndexes[0])));\r
489         Sys_Printf ("%6i drawsurfaces %7i\n"\r
490                 ,numDrawSurfaces, (int)(numDrawSurfaces*sizeof(drawSurfaces[0])));\r
491 \r
492         Sys_Printf ("%6i lightmaps    %7i\n"\r
493                 ,numLightBytes / (LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT*3), numLightBytes );\r
494         Sys_Printf ("       visibility   %7i\n"\r
495                 , numVisBytes );\r
496 }\r
497 \r
498 \r
499 //============================================\r
500 \r
501 int                     num_entities;\r
502 entity_t        entities[MAX_MAP_ENTITIES];\r
503 \r
504 void StripTrailing( char *e ) {\r
505         char    *s;\r
506 \r
507         s = e + strlen(e)-1;\r
508         while (s >= e && *s <= 32)\r
509         {\r
510                 *s = 0;\r
511                 s--;\r
512         }\r
513 }\r
514 \r
515 /*\r
516 =================\r
517 ParseEpair\r
518 =================\r
519 */\r
520 epair_t *ParseEpair( void ) {\r
521         epair_t *e;\r
522 \r
523         e = safe_malloc( sizeof(epair_t) );\r
524         memset( e, 0, sizeof(epair_t) );\r
525         \r
526         if ( strlen(token) >= MAX_KEY-1 ) {\r
527                 Error ("ParseEpar: token too long");\r
528         }\r
529         e->key = copystring( token );\r
530         GetToken( qfalse );\r
531         if ( strlen(token) >= MAX_VALUE-1 ) {\r
532                 Error ("ParseEpar: token too long");\r
533         }\r
534         e->value = copystring( token );\r
535 \r
536         // strip trailing spaces that sometimes get accidentally\r
537         // added in the editor\r
538         StripTrailing( e->key );\r
539         StripTrailing( e->value );\r
540 \r
541         return e;\r
542 }\r
543 \r
544 \r
545 /*\r
546 ================\r
547 ParseEntity\r
548 ================\r
549 */\r
550 qboolean        ParseEntity( void ) {\r
551         epair_t         *e;\r
552         entity_t        *mapent;\r
553 \r
554         if ( !GetToken (qtrue) ) {\r
555                 return qfalse;\r
556         }\r
557 \r
558         if ( strcmp (token, "{") ) {\r
559                 Error ("ParseEntity: { not found");\r
560         }\r
561         if ( num_entities == MAX_MAP_ENTITIES ) {\r
562                 Error ("num_entities == MAX_MAP_ENTITIES");\r
563         }\r
564         mapent = &entities[num_entities];\r
565         num_entities++;\r
566 \r
567         do {\r
568                 if ( !GetToken (qtrue) ) {\r
569                         Error ("ParseEntity: EOF without closing brace");\r
570                 }\r
571                 if ( !strcmp (token, "}") ) {\r
572                         break;\r
573                 }\r
574                 e = ParseEpair ();\r
575                 e->next = mapent->epairs;\r
576                 mapent->epairs = e;\r
577         } while (1);\r
578         \r
579         return qtrue;\r
580 }\r
581 \r
582 /*\r
583 ================\r
584 ParseEntities\r
585 \r
586 Parses the dentdata string into entities\r
587 ================\r
588 */\r
589 void ParseEntities( void ) {\r
590         num_entities = 0;\r
591         ParseFromMemory( dentdata, entdatasize );\r
592 \r
593         while ( ParseEntity () ) {\r
594         }       \r
595 }\r
596 \r
597 \r
598 /*\r
599 ================\r
600 UnparseEntities\r
601 \r
602 Generates the dentdata string from all the entities\r
603 This allows the utilities to add or remove key/value pairs\r
604 to the data created by the map editor.\r
605 ================\r
606 */\r
607 void UnparseEntities( void ) {\r
608         char    *buf, *end;\r
609         epair_t *ep;\r
610         char    line[2048];\r
611         int             i;\r
612         char    key[1024], value[1024];\r
613 \r
614         buf = dentdata;\r
615         end = buf;\r
616         *end = 0;\r
617         \r
618         for (i=0 ; i<num_entities ; i++) {\r
619                 ep = entities[i].epairs;\r
620                 if ( !ep ) {\r
621                         continue;       // ent got removed\r
622                 }\r
623                 \r
624                 strcat (end,"{\n");\r
625                 end += 2;\r
626                                 \r
627                 for ( ep = entities[i].epairs ; ep ; ep=ep->next ) {\r
628                         strcpy (key, ep->key);\r
629                         StripTrailing (key);\r
630                         strcpy (value, ep->value);\r
631                         StripTrailing (value);\r
632                                 \r
633                         sprintf (line, "\"%s\" \"%s\"\n", key, value);\r
634                         strcat (end, line);\r
635                         end += strlen(line);\r
636                 }\r
637                 strcat (end,"}\n");\r
638                 end += 2;\r
639 \r
640                 if (end > buf + MAX_MAP_ENTSTRING) {\r
641                         Error ("Entity text too long");\r
642                 }\r
643         }\r
644         entdatasize = end - buf + 1;\r
645 }\r
646 \r
647 void PrintEntity( const entity_t *ent ) {\r
648         epair_t *ep;\r
649         \r
650         Sys_Printf ("------- entity %p -------\n", ent);\r
651         for (ep=ent->epairs ; ep ; ep=ep->next) {\r
652                 Sys_Printf( "%s = %s\n", ep->key, ep->value );\r
653         }\r
654 \r
655 }\r
656 \r
657 void    SetKeyValue( entity_t *ent, const char *key, const char *value ) {\r
658         epair_t *ep;\r
659         \r
660         for ( ep=ent->epairs ; ep ; ep=ep->next ) {\r
661                 if ( !strcmp (ep->key, key) ) {\r
662                         free (ep->value);\r
663                         ep->value = copystring(value);\r
664                         return;\r
665                 }\r
666         }\r
667         ep = safe_malloc (sizeof(*ep));\r
668         ep->next = ent->epairs;\r
669         ent->epairs = ep;\r
670         ep->key = copystring(key);\r
671         ep->value = copystring(value);\r
672 }\r
673 \r
674 const char      *ValueForKey( const entity_t *ent, const char *key ) {\r
675         epair_t *ep;\r
676         \r
677         for (ep=ent->epairs ; ep ; ep=ep->next) {\r
678                 if (!strcmp (ep->key, key) ) {\r
679                         return ep->value;\r
680                 }\r
681         }\r
682         return "";\r
683 }\r
684 \r
685 vec_t   FloatForKey( const entity_t *ent, const char *key ) {\r
686         const char      *k;\r
687         \r
688         k = ValueForKey( ent, key );\r
689         return atof(k);\r
690 }\r
691 \r
692 void    GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ) {\r
693         const char      *k;\r
694         double  v1, v2, v3;\r
695 \r
696         k = ValueForKey (ent, key);\r
697 \r
698         // scanf into doubles, then assign, so it is vec_t size independent\r
699         v1 = v2 = v3 = 0;\r
700         sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);\r
701         vec[0] = v1;\r
702         vec[1] = v2;\r
703         vec[2] = v3;\r
704 }\r
705 \r
706 \r