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