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