]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/bspfile_abstract.c
Merge commit '84881a66140ad93d0b6cd4d55efbbb459bd91f48' into master-merge
[xonotic/netradiant.git] / tools / quake3 / q3map2 / bspfile_abstract.c
1 /* -------------------------------------------------------------------------------
2
3    Copyright (C) 1999-2007 id Software, Inc. and contributors.
4    For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6    This file is part of GtkRadiant.
7
8    GtkRadiant is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    GtkRadiant is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with GtkRadiant; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22    ----------------------------------------------------------------------------------
23
24    This code has been altered significantly from its original form, to support
25    several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27    ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define BSPFILE_ABSTRACT_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41
42 /* -------------------------------------------------------------------------------
43
44    this file was copied out of the common directory in order to not break
45    compatibility with the q3map 1.x tree. it was moved out in order to support
46    the raven bsp format (RBSP) used in soldier of fortune 2 and jedi knight 2.
47
48    since each game has its own set of particular features, the data structures
49    below no longer directly correspond to the binary format of a particular game.
50
51    the translation will be done at bsp load/save time to keep any sort of
52    special-case code messiness out of the rest of the program.
53
54    ------------------------------------------------------------------------------- */
55
56
57
58 /* FIXME: remove the functions below that handle memory management of bsp file chunks */
59
60 int numBSPDrawVertsBuffer = 0;
61 void IncDrawVerts(){
62         numBSPDrawVerts++;
63
64         if ( bspDrawVerts == 0 ) {
65                 numBSPDrawVertsBuffer = 1024;
66
67                 bspDrawVerts = safe_malloc_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
68
69         }
70         else if ( numBSPDrawVerts > numBSPDrawVertsBuffer ) {
71                 bspDrawVert_t *newBspDrawVerts;
72
73                 numBSPDrawVertsBuffer *= 3; // multiply by 1.5
74                 numBSPDrawVertsBuffer /= 2;
75
76                 newBspDrawVerts = realloc( bspDrawVerts, sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer );
77
78                 if ( !newBspDrawVerts ) {
79                         free (bspDrawVerts);
80                         Error( "realloc() failed (IncDrawVerts)" );
81                 }
82
83                 bspDrawVerts = newBspDrawVerts;
84         }
85
86         memset( bspDrawVerts + ( numBSPDrawVerts - 1 ), 0, sizeof( bspDrawVert_t ) );
87 }
88
89 void SetDrawVerts( int n ){
90         if ( bspDrawVerts != 0 ) {
91                 free( bspDrawVerts );
92         }
93
94         numBSPDrawVerts = n;
95         numBSPDrawVertsBuffer = numBSPDrawVerts;
96
97         bspDrawVerts = safe_malloc0_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
98 }
99
100 int numBSPDrawSurfacesBuffer = 0;
101 void SetDrawSurfacesBuffer(){
102         if ( bspDrawSurfaces != 0 ) {
103                 free( bspDrawSurfaces );
104         }
105
106         numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
107
108         bspDrawSurfaces = safe_malloc0_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
109 }
110
111 void SetDrawSurfaces( int n ){
112         if ( bspDrawSurfaces != 0 ) {
113                 free( bspDrawSurfaces );
114         }
115
116         numBSPDrawSurfaces = n;
117         numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
118
119         bspDrawSurfaces = safe_malloc0_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
120 }
121
122 void BSPFilesCleanup(){
123         if ( bspDrawVerts != 0 ) {
124                 free( bspDrawVerts );
125         }
126         if ( bspDrawSurfaces != 0 ) {
127                 free( bspDrawSurfaces );
128         }
129         if ( bspLightBytes != 0 ) {
130                 free( bspLightBytes );
131         }
132         if ( bspGridPoints != 0 ) {
133                 free( bspGridPoints );
134         }
135 }
136
137
138
139
140
141
142 /*
143    SwapBlock()
144    if all values are 32 bits, this can be used to swap everything
145  */
146
147 void SwapBlock( int *block, int size ){
148         int i;
149
150
151         /* dummy check */
152         if ( block == NULL ) {
153                 return;
154         }
155
156         /* swap */
157         size >>= 2;
158         for ( i = 0; i < size; i++ )
159                 block[ i ] = LittleLong( block[ i ] );
160 }
161
162
163
164 /*
165    SwapBSPFile()
166    byte swaps all data in the abstract bsp
167  */
168
169 void SwapBSPFile( void ){
170         int i, j;
171         shaderInfo_t    *si;
172
173         /* models */
174         SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) );
175
176         /* shaders (don't swap the name) */
177         for ( i = 0; i < numBSPShaders ; i++ )
178         {
179         if ( doingBSP ){
180                 si = ShaderInfoForShader( bspShaders[ i ].shader );
181                 if ( si->remapShader && si->remapShader[ 0 ] ) {
182                         strcpy( bspShaders[ i ].shader, si->remapShader );
183                 }
184         }
185                 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
186                 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
187         }
188
189         /* planes */
190         SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
191
192         /* nodes */
193         SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
194
195         /* leafs */
196         SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
197
198         /* leaffaces */
199         SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
200
201         /* leafbrushes */
202         SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
203
204         // brushes
205         SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
206
207         // brushsides
208         SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
209
210         // vis
211         ( (int*) &bspVisBytes )[ 0 ] = LittleLong( ( (int*) &bspVisBytes )[ 0 ] );
212         ( (int*) &bspVisBytes )[ 1 ] = LittleLong( ( (int*) &bspVisBytes )[ 1 ] );
213
214         /* drawverts (don't swap colors) */
215         for ( i = 0; i < numBSPDrawVerts; i++ )
216         {
217                 bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
218                 bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
219                 bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
220                 bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
221                 bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
222                 bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
223                 bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
224                 bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
225                 for ( j = 0; j < MAX_LIGHTMAPS; j++ )
226                 {
227                         bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
228                         bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
229                 }
230         }
231
232         /* drawindexes */
233         SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
234
235         /* drawsurfs */
236         /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
237         SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
238
239         /* fogs */
240         for ( i = 0; i < numBSPFogs; i++ )
241         {
242                 bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
243                 bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
244         }
245
246         /* advertisements */
247         for ( i = 0; i < numBSPAds; i++ )
248         {
249                 bspAds[ i ].cellId = LittleLong( bspAds[ i ].cellId );
250                 bspAds[ i ].normal[ 0 ] = LittleFloat( bspAds[ i ].normal[ 0 ] );
251                 bspAds[ i ].normal[ 1 ] = LittleFloat( bspAds[ i ].normal[ 1 ] );
252                 bspAds[ i ].normal[ 2 ] = LittleFloat( bspAds[ i ].normal[ 2 ] );
253
254                 for ( j = 0; j < 4; j++ )
255                 {
256                         bspAds[ i ].rect[j][ 0 ] = LittleFloat( bspAds[ i ].rect[j][ 0 ] );
257                         bspAds[ i ].rect[j][ 1 ] = LittleFloat( bspAds[ i ].rect[j][ 1 ] );
258                         bspAds[ i ].rect[j][ 2 ] = LittleFloat( bspAds[ i ].rect[j][ 2 ] );
259                 }
260
261                 //bspAds[ i ].model[ MAX_QPATH ];
262         }
263 }
264
265 /*
266    GetLumpElements()
267    gets the number of elements in a bsp lump
268  */
269
270 int GetLumpElements( bspHeader_t *header, int lump, int size ){
271         /* check for odd size */
272         if ( header->lumps[ lump ].length % size ) {
273                 if ( force ) {
274                         Sys_FPrintf( SYS_WRN, "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
275                         return 0;
276                 }
277                 else{
278                         Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
279                 }
280         }
281
282         /* return element count */
283         return header->lumps[ lump ].length / size;
284 }
285
286
287
288 /*
289    GetLump()
290    returns a pointer to the specified lump
291  */
292
293 void *GetLump( bspHeader_t *header, int lump ){
294         return (void*)( (byte*) header + header->lumps[ lump ].offset );
295 }
296
297
298
299 /*
300    CopyLump()
301    copies a bsp file lump into a destination buffer
302  */
303
304 int CopyLump( bspHeader_t *header, int lump, void *dest, int size ){
305         int length, offset;
306
307
308         /* get lump length and offset */
309         length = header->lumps[ lump ].length;
310         offset = header->lumps[ lump ].offset;
311
312         /* handle erroneous cases */
313         if ( length == 0 ) {
314                 return 0;
315         }
316         if ( length % size ) {
317                 if ( force ) {
318                         Sys_FPrintf( SYS_WRN, "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
319                         return 0;
320                 }
321                 else{
322                         Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
323                 }
324         }
325
326         /* copy block of memory and return */
327         memcpy( dest, (byte*) header + offset, length );
328         return length / size;
329 }
330
331 int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable ){
332         /* get lump length and offset */
333         *allocationVariable = header->lumps[ lump ].length / size;
334         *dest = realloc( *dest, size * *allocationVariable );
335         return CopyLump( header, lump, *dest, size );
336 }
337
338
339 /*
340    AddLump()
341    adds a lump to an outgoing bsp file
342  */
343
344 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
345         bspLump_t   *lump;
346
347         /* add lump to bsp file header */
348         lump = &header->lumps[ lumpNum ];
349         lump->offset = LittleLong( ftell( file ) );
350         lump->length = LittleLong( length );
351
352         /* write lump to file */
353         SafeWrite( file, data, length );
354
355         /* write padding zeros */
356         SafeWrite( file, (const byte[3]){ 0, 0, 0 }, ( ( length + 3 ) & ~3 ) - length );
357 }
358
359
360
361 /*
362    LoadBSPFile()
363    loads a bsp file into memory
364  */
365
366 void LoadBSPFile( const char *filename ){
367         /* dummy check */
368         if ( game == NULL || game->load == NULL ) {
369                 Error( "LoadBSPFile: unsupported BSP file format" );
370         }
371
372         /* load it, then byte swap the in-memory version */
373         game->load( filename );
374         SwapBSPFile();
375 }
376
377 /*
378    PartialLoadBSPFile()
379    partially loads a bsp file into memory
380    for autopacker
381  */
382
383 void PartialLoadBSPFile( const char *filename ){
384         /* dummy check */
385         if ( game == NULL || game->load == NULL ) {
386                 Error( "LoadBSPFile: unsupported BSP file format" );
387         }
388
389         /* load it, then byte swap the in-memory version */
390         //game->load( filename );
391         PartialLoadIBSPFile( filename );
392
393         /* PartialSwapBSPFile() */
394         int i;
395
396         /* shaders (don't swap the name) */
397         for ( i = 0; i < numBSPShaders ; i++ )
398         {
399                 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
400                 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
401         }
402
403         /* drawsurfs */
404         /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
405         SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
406 }
407
408 /*
409    WriteBSPFile()
410    writes a bsp file
411  */
412
413 void WriteBSPFile( const char *filename ){
414         char tempname[ 1024 ];
415         time_t tm;
416
417
418         /* dummy check */
419         if ( game == NULL || game->write == NULL ) {
420                 Error( "WriteBSPFile: unsupported BSP file format" );
421         }
422
423         /* make fake temp name so existing bsp file isn't damaged in case write process fails */
424         time( &tm );
425         sprintf( tempname, "%s.%08X", filename, (int) tm );
426
427         /* byteswap, write the bsp, then swap back so it can be manipulated further */
428         SwapBSPFile();
429         game->write( tempname );
430         SwapBSPFile();
431
432         /* replace existing bsp file */
433         remove( filename );
434         rename( tempname, filename );
435 }
436
437
438
439 /*
440    PrintBSPFileSizes()
441    dumps info about current file
442  */
443
444 void PrintBSPFileSizes( void ){
445         /* parse entities first */
446         if ( numEntities <= 0 ) {
447                 ParseEntities();
448         }
449
450         /* note that this is abstracted */
451         Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
452
453         /* print various and sundry bits */
454         Sys_Printf( "%9d models        %9d\n",
455                                 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
456         Sys_Printf( "%9d shaders       %9d\n",
457                                 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
458         Sys_Printf( "%9d brushes       %9d\n",
459                                 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
460         Sys_Printf( "%9d brushsides    %9d *\n",
461                                 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
462         Sys_Printf( "%9d fogs          %9d\n",
463                                 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
464         Sys_Printf( "%9d planes        %9d\n",
465                                 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
466         Sys_Printf( "%9d entdata       %9d\n",
467                                 numEntities, bspEntDataSize );
468         Sys_Printf( "\n" );
469
470         Sys_Printf( "%9d nodes         %9d\n",
471                                 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
472         Sys_Printf( "%9d leafs         %9d\n",
473                                 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
474         Sys_Printf( "%9d leafsurfaces  %9d\n",
475                                 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
476         Sys_Printf( "%9d leafbrushes   %9d\n",
477                                 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
478         Sys_Printf( "\n" );
479
480         Sys_Printf( "%9d drawsurfaces  %9d *\n",
481                                 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
482         Sys_Printf( "%9d drawverts     %9d *\n",
483                                 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
484         Sys_Printf( "%9d drawindexes   %9d\n",
485                                 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
486         Sys_Printf( "\n" );
487
488         Sys_Printf( "%9d lightmaps     %9d\n",
489                                 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
490         Sys_Printf( "%9d lightgrid     %9d *\n",
491                                 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
492         Sys_Printf( "          visibility    %9d\n",
493                                 numBSPVisBytes );
494 }
495
496
497
498 /* -------------------------------------------------------------------------------
499
500    entity data handling
501
502    ------------------------------------------------------------------------------- */
503
504
505 /*
506    StripTrailing()
507    strips low byte chars off the end of a string
508  */
509
510 void StripTrailing( char *e ){
511         char    *s;
512
513
514         s = e + strlen( e ) - 1;
515         while ( s >= e && *s <= 32 )
516         {
517                 *s = 0;
518                 s--;
519         }
520 }
521
522
523
524 /*
525    ParseEpair()
526    parses a single quoted "key" "value" pair into an epair struct
527  */
528
529 epair_t *ParseEPair( void ){
530         epair_t     *e;
531
532
533         /* allocate and clear new epair */
534         e = safe_malloc0( sizeof( epair_t ) );
535
536         /* handle key */
537         if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
538                 Error( "ParseEPair: token too long" );
539         }
540
541         e->key = copystring( token );
542         GetToken( qfalse );
543
544         /* handle value */
545         if ( strlen( token ) >= MAX_VALUE - 1 ) {
546                 Error( "ParseEpar: token too long" );
547         }
548         e->value = copystring( token );
549
550         /* strip trailing spaces that sometimes get accidentally added in the editor */
551         StripTrailing( e->key );
552         StripTrailing( e->value );
553
554         /* return it */
555         return e;
556 }
557
558
559
560 /*
561    ParseEntity()
562    parses an entity's epairs
563  */
564
565 qboolean ParseEntity( void ){
566         epair_t     *e;
567
568
569         /* dummy check */
570         if ( !GetToken( qtrue ) ) {
571                 return qfalse;
572         }
573         if ( strcmp( token, "{" ) ) {
574                 Error( "ParseEntity: { not found" );
575         }
576         AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
577
578         /* create new entity */
579         mapEnt = &entities[ numEntities ];
580         numEntities++;
581         memset( mapEnt, 0, sizeof( *mapEnt ) );
582
583         /* parse */
584         while ( 1 )
585         {
586                 if ( !GetToken( qtrue ) ) {
587                         Error( "ParseEntity: EOF without closing brace" );
588                 }
589                 if ( !EPAIR_STRCMP( token, "}" ) ) {
590                         break;
591                 }
592                 e = ParseEPair();
593                 e->next = mapEnt->epairs;
594                 mapEnt->epairs = e;
595         }
596
597         /* return to sender */
598         return qtrue;
599 }
600
601
602
603 /*
604    ParseEntities()
605    parses the bsp entity data string into entities
606  */
607
608 void ParseEntities( void ){
609         numEntities = 0;
610         ParseFromMemory( bspEntData, bspEntDataSize );
611         while ( ParseEntity() ) ;
612
613         /* ydnar: set number of bsp entities in case a map is loaded on top */
614         numBSPEntities = numEntities;
615 }
616
617
618
619 /*
620  * must be called before UnparseEntities
621  */
622 void InjectCommandLine( char **argv, int beginArgs, int endArgs ){
623         const char *previousCommandLine;
624         char newCommandLine[1024];
625         const char *inpos;
626         char *outpos = newCommandLine;
627         char *sentinel = newCommandLine + sizeof( newCommandLine ) - 1;
628         int i;
629
630 if (nocmdline)
631 {
632         return;
633 }
634         previousCommandLine = ValueForKey( &entities[0], "_q3map2_cmdline" );
635         if ( previousCommandLine && *previousCommandLine ) {
636                 inpos = previousCommandLine;
637                 while ( outpos != sentinel && *inpos )
638                         *outpos++ = *inpos++;
639                 if ( outpos != sentinel ) {
640                         *outpos++ = ';';
641                 }
642                 if ( outpos != sentinel ) {
643                         *outpos++ = ' ';
644                 }
645         }
646
647         for ( i = beginArgs; i < endArgs; ++i )
648         {
649                 if ( argv[i] == NULL ) {
650                         continue;
651                 }
652                 if ( outpos != sentinel && i != beginArgs ) {
653                         *outpos++ = ' ';
654                 }
655                 inpos = argv[i];
656                 while ( outpos != sentinel && *inpos )
657                         if ( *inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ' ) {
658                                 *outpos++ = *inpos++;
659                         }
660         }
661
662         *outpos = 0;
663         SetKeyValue( &entities[0], "_q3map2_cmdline", newCommandLine );
664         SetKeyValue( &entities[0], "_q3map2_version", Q3MAP_VERSION );
665 }
666
667
668
669 /*
670    UnparseEntities()
671    generates the dentdata string from all the entities.
672    this allows the utilities to add or remove key/value
673    pairs to the data created by the map editor
674  */
675
676 void UnparseEntities( void ){
677         int i;
678         char        *buf, *end;
679         epair_t     *ep;
680         char line[ 2048 ];
681         char key[ 1024 ], value[ 1024 ];
682         const char  *value2;
683
684
685         /* setup */
686         AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
687         buf = bspEntData;
688         end = buf;
689         *end = 0;
690
691
692         /* run through entity list */
693         for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
694         {
695                 {
696                         int sz = end - buf;
697                         AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
698                         buf = bspEntData;
699                         end = buf + sz;
700                 }
701
702                 /* get epair */
703                 ep = entities[ i ].epairs;
704                 if ( ep == NULL ) {
705                         continue;   /* ent got removed */
706
707                 }
708                 /* ydnar: certain entities get stripped from bsp file */
709                 value2 = ValueForKey( &entities[ i ], "classname" );
710                 if ( !Q_stricmp( value2, "misc_model" ) ||
711                          !Q_stricmp( value2, "_decal" ) ||
712                          !Q_stricmp( value2, "_skybox" ) ) {
713                         continue;
714                 }
715
716                 /* add beginning brace */
717                 strcat( end, "{\n" );
718                 end += 2;
719
720                 /* walk epair list */
721                 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
722                 {
723                         /* copy and clean */
724                         strcpy( key, ep->key );
725                         StripTrailing( key );
726                         strcpy( value, ep->value );
727                         StripTrailing( value );
728
729                         /* add to buffer */
730                         sprintf( line, "\"%s\" \"%s\"\n", key, value );
731                         strcat( end, line );
732                         end += strlen( line );
733                 }
734
735                 /* add trailing brace */
736                 strcat( end,"}\n" );
737                 end += 2;
738
739                 /* check for overflow */
740                 if ( end > buf + allocatedBSPEntData ) {
741                         Error( "Entity text too long" );
742                 }
743         }
744
745         /* set size */
746         bspEntDataSize = end - buf + 1;
747 }
748
749
750
751 /*
752    PrintEntity()
753    prints an entity's epairs to the console
754  */
755
756 void PrintEntity( const entity_t *ent ){
757         epair_t *ep;
758
759
760         Sys_Printf( "------- entity %p -------\n", ent );
761         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
762                 Sys_Printf( "%s = %s\n", ep->key, ep->value );
763
764 }
765
766
767
768 /*
769    SetKeyValue()
770    sets an epair in an entity
771  */
772
773 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
774         epair_t *ep;
775
776
777         /* check for existing epair */
778         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
779         {
780                 if ( !EPAIR_STRCMP( ep->key, key ) ) {
781                         free( ep->value );
782                         ep->value = copystring( value );
783                         return;
784                 }
785         }
786
787         /* create new epair */
788         ep = safe_malloc( sizeof( *ep ) );
789         ep->next = ent->epairs;
790         ent->epairs = ep;
791         ep->key = copystring( key );
792         ep->value = copystring( value );
793 }
794
795
796
797 /*
798    KeyExists()
799    returns true if entity has this key
800  */
801
802 qboolean KeyExists( const entity_t *ent, const char *key ){
803         epair_t *ep;
804
805         /* walk epair list */
806         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
807         {
808                 if ( !EPAIR_STRCMP( ep->key, key ) ) {
809                         return qtrue;
810                 }
811         }
812
813         /* no match */
814         return qfalse;
815 }
816
817
818
819 /*
820    ValueForKey()
821    gets the value for an entity key
822  */
823
824 const char *ValueForKey( const entity_t *ent, const char *key ){
825         epair_t *ep;
826
827
828         /* dummy check */
829         if ( ent == NULL ) {
830                 return "";
831         }
832
833         /* walk epair list */
834         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
835         {
836                 if ( !EPAIR_STRCMP( ep->key, key ) ) {
837                         return ep->value;
838                 }
839         }
840
841         /* if no match, return empty string */
842         return "";
843 }
844
845
846
847 /*
848    IntForKey()
849    gets the integer point value for an entity key
850  */
851
852 int IntForKey( const entity_t *ent, const char *key ){
853         const char  *k;
854
855
856         k = ValueForKey( ent, key );
857         return atoi( k );
858 }
859
860
861
862 /*
863    FloatForKey()
864    gets the floating point value for an entity key
865  */
866
867 vec_t FloatForKey( const entity_t *ent, const char *key ){
868         const char  *k;
869
870
871         k = ValueForKey( ent, key );
872         return atof( k );
873 }
874
875
876
877 /*
878    GetVectorForKey()
879    gets a 3-element vector value for an entity key
880  */
881
882 qboolean GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
883         const char  *k;
884         double v1, v2, v3;
885
886
887         /* get value */
888         k = ValueForKey( ent, key );
889
890         /* scanf into doubles, then assign, so it is vec_t size independent */
891         v1 = v2 = v3 = 0.0;
892         sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
893         vec[ 0 ] = v1;
894         vec[ 1 ] = v2;
895         vec[ 2 ] = v3;
896
897         /* true if the key is found, false otherwise */
898         return strlen( k );
899 }
900
901
902
903 /*
904    FindTargetEntity()
905    finds an entity target
906  */
907
908 entity_t *FindTargetEntity( const char *target ){
909         int i;
910         const char  *n;
911
912
913         /* walk entity list */
914         for ( i = 0; i < numEntities; i++ )
915         {
916                 n = ValueForKey( &entities[ i ], "targetname" );
917                 if ( !strcmp( n, target ) ) {
918                         return &entities[ i ];
919                 }
920         }
921
922         /* nada */
923         return NULL;
924 }
925
926
927
928 /*
929    GetEntityShadowFlags() - ydnar
930    gets an entity's shadow flags
931    note: does not set them to defaults if the keys are not found!
932  */
933
934 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
935         const char  *value;
936
937         /* get cast shadows */
938         if ( castShadows != NULL ) {
939                 value = ValueForKey( ent, "_castShadows" );
940                 if ( value[ 0 ] == '\0' ) {
941                         value = ValueForKey( ent, "_cs" );
942                 }
943                 if ( value[ 0 ] == '\0' ) {
944                         value = ValueForKey( ent2, "_castShadows" );
945                 }
946                 if ( value[ 0 ] == '\0' ) {
947                         value = ValueForKey( ent2, "_cs" );
948                 }
949                 if ( value[ 0 ] != '\0' ) {
950                         *castShadows = atoi( value );
951                 }
952         }
953
954         /* receive */
955         if ( recvShadows != NULL ) {
956                 value = ValueForKey( ent, "_receiveShadows" );
957                 if ( value[ 0 ] == '\0' ) {
958                         value = ValueForKey( ent, "_rs" );
959                 }
960                 if ( value[ 0 ] == '\0' ) {
961                         value = ValueForKey( ent2, "_receiveShadows" );
962                 }
963                 if ( value[ 0 ] == '\0' ) {
964                         value = ValueForKey( ent2, "_rs" );
965                 }
966                 if ( value[ 0 ] != '\0' ) {
967                         *recvShadows = atoi( value );
968                 }
969         }
970
971         /* vortex: game-specific default entity keys */
972         value = ValueForKey( ent, "classname" );
973         if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
974                 /* vortex: deluxe quake default shadow flags */
975                 if ( !Q_stricmp( value, "func_wall" ) ) {
976                         if ( recvShadows != NULL ) {
977                                 *recvShadows = 1;
978                         }
979                         if ( castShadows != NULL ) {
980                                 *castShadows = 1;
981                         }
982                 }
983         }
984 }