]> git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/bspfile_abstract.c
Merge commit '7d7436ec3dd43cbdb04ad41f0a2c92a905f26807' into garux-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                 numBSPDrawVertsBuffer *= 3; // multiply by 1.5
72                 numBSPDrawVertsBuffer /= 2;
73
74                 bspDrawVerts = realloc( bspDrawVerts, sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer );
75
76                 if ( !bspDrawVerts ) {
77                         Error( "realloc() failed (IncDrawVerts)" );
78                 }
79         }
80
81         memset( bspDrawVerts + ( numBSPDrawVerts - 1 ), 0, sizeof( bspDrawVert_t ) );
82 }
83
84 void SetDrawVerts( int n ){
85         if ( bspDrawVerts != 0 ) {
86                 free( bspDrawVerts );
87         }
88
89         numBSPDrawVerts = n;
90         numBSPDrawVertsBuffer = numBSPDrawVerts;
91
92         bspDrawVerts = safe_malloc_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
93
94         memset( bspDrawVerts, 0, n * sizeof( bspDrawVert_t ) );
95 }
96
97 int numBSPDrawSurfacesBuffer = 0;
98 void SetDrawSurfacesBuffer(){
99         if ( bspDrawSurfaces != 0 ) {
100                 free( bspDrawSurfaces );
101         }
102
103         numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
104
105         bspDrawSurfaces = safe_malloc_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
106
107         memset( bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof( bspDrawSurface_t ) );
108 }
109
110 void SetDrawSurfaces( int n ){
111         if ( bspDrawSurfaces != 0 ) {
112                 free( bspDrawSurfaces );
113         }
114
115         numBSPDrawSurfaces = n;
116         numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
117
118         bspDrawSurfaces = safe_malloc_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
119
120         memset( bspDrawSurfaces, 0, n * sizeof( bspDrawSurface_t ) );
121 }
122
123 void BSPFilesCleanup(){
124         if ( bspDrawVerts != 0 ) {
125                 free( bspDrawVerts );
126         }
127         if ( bspDrawSurfaces != 0 ) {
128                 free( bspDrawSurfaces );
129         }
130         if ( bspLightBytes != 0 ) {
131                 free( bspLightBytes );
132         }
133         if ( bspGridPoints != 0 ) {
134                 free( bspGridPoints );
135         }
136 }
137
138
139
140
141
142
143 /*
144    SwapBlock()
145    if all values are 32 bits, this can be used to swap everything
146  */
147
148 void SwapBlock( int *block, int size ){
149         int i;
150
151
152         /* dummy check */
153         if ( block == NULL ) {
154                 return;
155         }
156
157         /* swap */
158         size >>= 2;
159         for ( i = 0; i < size; i++ )
160                 block[ i ] = LittleLong( block[ i ] );
161 }
162
163
164
165 /*
166    SwapBSPFile()
167    byte swaps all data in the abstract bsp
168  */
169
170 void SwapBSPFile( void ){
171         int i, j;
172         shaderInfo_t    *si;
173
174         /* models */
175         SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) );
176
177         /* shaders (don't swap the name) */
178         for ( i = 0; i < numBSPShaders ; i++ )
179         {
180         if ( doingBSP ){
181                 si = ShaderInfoForShader( bspShaders[ i ].shader );
182                 if ( si->remapShader && si->remapShader[ 0 ] ) {
183                         strcpy( bspShaders[ i ].shader, si->remapShader );
184                 }
185         }
186                 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
187                 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
188         }
189
190         /* planes */
191         SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
192
193         /* nodes */
194         SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
195
196         /* leafs */
197         SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
198
199         /* leaffaces */
200         SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
201
202         /* leafbrushes */
203         SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
204
205         // brushes
206         SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
207
208         // brushsides
209         SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
210
211         // vis
212         ( (int*) &bspVisBytes )[ 0 ] = LittleLong( ( (int*) &bspVisBytes )[ 0 ] );
213         ( (int*) &bspVisBytes )[ 1 ] = LittleLong( ( (int*) &bspVisBytes )[ 1 ] );
214
215         /* drawverts (don't swap colors) */
216         for ( i = 0; i < numBSPDrawVerts; i++ )
217         {
218                 bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
219                 bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
220                 bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
221                 bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
222                 bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
223                 bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
224                 bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
225                 bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
226                 for ( j = 0; j < MAX_LIGHTMAPS; j++ )
227                 {
228                         bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
229                         bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
230                 }
231         }
232
233         /* drawindexes */
234         SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
235
236         /* drawsurfs */
237         /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
238         SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
239
240         /* fogs */
241         for ( i = 0; i < numBSPFogs; i++ )
242         {
243                 bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
244                 bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
245         }
246
247         /* advertisements */
248         for ( i = 0; i < numBSPAds; i++ )
249         {
250                 bspAds[ i ].cellId = LittleLong( bspAds[ i ].cellId );
251                 bspAds[ i ].normal[ 0 ] = LittleFloat( bspAds[ i ].normal[ 0 ] );
252                 bspAds[ i ].normal[ 1 ] = LittleFloat( bspAds[ i ].normal[ 1 ] );
253                 bspAds[ i ].normal[ 2 ] = LittleFloat( bspAds[ i ].normal[ 2 ] );
254
255                 for ( j = 0; j < 4; j++ )
256                 {
257                         bspAds[ i ].rect[j][ 0 ] = LittleFloat( bspAds[ i ].rect[j][ 0 ] );
258                         bspAds[ i ].rect[j][ 1 ] = LittleFloat( bspAds[ i ].rect[j][ 1 ] );
259                         bspAds[ i ].rect[j][ 2 ] = LittleFloat( bspAds[ i ].rect[j][ 2 ] );
260                 }
261
262                 //bspAds[ i ].model[ MAX_QPATH ];
263         }
264 }
265
266 /*
267    GetLumpElements()
268    gets the number of elements in a bsp lump
269  */
270
271 int GetLumpElements( bspHeader_t *header, int lump, int size ){
272         /* check for odd size */
273         if ( header->lumps[ lump ].length % size ) {
274                 if ( force ) {
275                         Sys_FPrintf( SYS_WRN, "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
276                         return 0;
277                 }
278                 else{
279                         Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
280                 }
281         }
282
283         /* return element count */
284         return header->lumps[ lump ].length / size;
285 }
286
287
288
289 /*
290    GetLump()
291    returns a pointer to the specified lump
292  */
293
294 void *GetLump( bspHeader_t *header, int lump ){
295         return (void*)( (byte*) header + header->lumps[ lump ].offset );
296 }
297
298
299
300 /*
301    CopyLump()
302    copies a bsp file lump into a destination buffer
303  */
304
305 int CopyLump( bspHeader_t *header, int lump, void *dest, int size ){
306         int length, offset;
307
308
309         /* get lump length and offset */
310         length = header->lumps[ lump ].length;
311         offset = header->lumps[ lump ].offset;
312
313         /* handle erroneous cases */
314         if ( length == 0 ) {
315                 return 0;
316         }
317         if ( length % size ) {
318                 if ( force ) {
319                         Sys_FPrintf( SYS_WRN, "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
320                         return 0;
321                 }
322                 else{
323                         Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
324                 }
325         }
326
327         /* copy block of memory and return */
328         memcpy( dest, (byte*) header + offset, length );
329         return length / size;
330 }
331
332 int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable ){
333         /* get lump length and offset */
334         *allocationVariable = header->lumps[ lump ].length / size;
335         *dest = realloc( *dest, size * *allocationVariable );
336         return CopyLump( header, lump, *dest, size );
337 }
338
339
340 /*
341    AddLump()
342    adds a lump to an outgoing bsp file
343  */
344
345 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
346         bspLump_t   *lump;
347
348
349         /* add lump to bsp file header */
350         lump = &header->lumps[ lumpNum ];
351         lump->offset = LittleLong( ftell( file ) );
352         lump->length = LittleLong( length );
353
354         /* write lump to file */
355         SafeWrite( file, data, ( length + 3 ) & ~3 );
356 }
357
358
359
360 /*
361    LoadBSPFile()
362    loads a bsp file into memory
363  */
364
365 void LoadBSPFile( const char *filename ){
366         /* dummy check */
367         if ( game == NULL || game->load == NULL ) {
368                 Error( "LoadBSPFile: unsupported BSP file format" );
369         }
370
371         /* load it, then byte swap the in-memory version */
372         game->load( filename );
373         SwapBSPFile();
374 }
375
376 /*
377    PartialLoadBSPFile()
378    partially loads a bsp file into memory
379    for autopacker
380  */
381
382 void PartialLoadBSPFile( const char *filename ){
383         /* dummy check */
384         if ( game == NULL || game->load == NULL ) {
385                 Error( "LoadBSPFile: unsupported BSP file format" );
386         }
387
388         /* load it, then byte swap the in-memory version */
389         //game->load( filename );
390         PartialLoadIBSPFile( filename );
391
392         /* PartialSwapBSPFile() */
393         int i, j;
394         shaderInfo_t    *si;
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_malloc( sizeof( epair_t ) );
535         memset( e, 0, sizeof( epair_t ) );
536
537         /* handle key */
538         if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
539                 Error( "ParseEPair: token too long" );
540         }
541
542         e->key = copystring( token );
543         GetToken( qfalse );
544
545         /* handle value */
546         if ( strlen( token ) >= MAX_VALUE - 1 ) {
547                 Error( "ParseEpar: token too long" );
548         }
549         e->value = copystring( token );
550
551         /* strip trailing spaces that sometimes get accidentally added in the editor */
552         StripTrailing( e->key );
553         StripTrailing( e->value );
554
555         /* return it */
556         return e;
557 }
558
559
560
561 /*
562    ParseEntity()
563    parses an entity's epairs
564  */
565
566 qboolean ParseEntity( void ){
567         epair_t     *e;
568
569
570         /* dummy check */
571         if ( !GetToken( qtrue ) ) {
572                 return qfalse;
573         }
574         if ( strcmp( token, "{" ) ) {
575                 Error( "ParseEntity: { not found" );
576         }
577         AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
578
579         /* create new entity */
580         mapEnt = &entities[ numEntities ];
581         numEntities++;
582         memset( mapEnt, 0, sizeof( *mapEnt ) );
583
584         /* parse */
585         while ( 1 )
586         {
587                 if ( !GetToken( qtrue ) ) {
588                         Error( "ParseEntity: EOF without closing brace" );
589                 }
590                 if ( !EPAIR_STRCMP( token, "}" ) ) {
591                         break;
592                 }
593                 e = ParseEPair();
594                 e->next = mapEnt->epairs;
595                 mapEnt->epairs = e;
596         }
597
598         /* return to sender */
599         return qtrue;
600 }
601
602
603
604 /*
605    ParseEntities()
606    parses the bsp entity data string into entities
607  */
608
609 void ParseEntities( void ){
610         numEntities = 0;
611         ParseFromMemory( bspEntData, bspEntDataSize );
612         while ( ParseEntity() ) ;
613
614         /* ydnar: set number of bsp entities in case a map is loaded on top */
615         numBSPEntities = numEntities;
616 }
617
618
619
620 /*
621  * must be called before UnparseEntities
622  */
623 void InjectCommandLine( char **argv, int beginArgs, int endArgs ){
624         const char *previousCommandLine;
625         char newCommandLine[1024];
626         const char *inpos;
627         char *outpos = newCommandLine;
628         char *sentinel = newCommandLine + sizeof( newCommandLine ) - 1;
629         int i;
630
631 if (nocmdline)
632 {
633         return;
634 }
635         previousCommandLine = ValueForKey( &entities[0], "_q3map2_cmdline" );
636         if ( previousCommandLine && *previousCommandLine ) {
637                 inpos = previousCommandLine;
638                 while ( outpos != sentinel && *inpos )
639                         *outpos++ = *inpos++;
640                 if ( outpos != sentinel ) {
641                         *outpos++ = ';';
642                 }
643                 if ( outpos != sentinel ) {
644                         *outpos++ = ' ';
645                 }
646         }
647
648         for ( i = beginArgs; i < endArgs; ++i )
649         {
650                 if ( outpos != sentinel && i != beginArgs ) {
651                         *outpos++ = ' ';
652                 }
653                 inpos = argv[i];
654                 while ( outpos != sentinel && *inpos )
655                         if ( *inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ' ) {
656                                 *outpos++ = *inpos++;
657                         }
658         }
659
660         *outpos = 0;
661         SetKeyValue( &entities[0], "_q3map2_cmdline", newCommandLine );
662         SetKeyValue( &entities[0], "_q3map2_version", Q3MAP_VERSION );
663 }
664
665
666
667 /*
668    UnparseEntities()
669    generates the dentdata string from all the entities.
670    this allows the utilities to add or remove key/value
671    pairs to the data created by the map editor
672  */
673
674 void UnparseEntities( void ){
675         int i;
676         char        *buf, *end;
677         epair_t     *ep;
678         char line[ 2048 ];
679         char key[ 1024 ], value[ 1024 ];
680         const char  *value2;
681
682
683         /* setup */
684         AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
685         buf = bspEntData;
686         end = buf;
687         *end = 0;
688
689
690         /* run through entity list */
691         for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
692         {
693                 {
694                         int sz = end - buf;
695                         AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
696                         buf = bspEntData;
697                         end = buf + sz;
698                 }
699
700                 /* get epair */
701                 ep = entities[ i ].epairs;
702                 if ( ep == NULL ) {
703                         continue;   /* ent got removed */
704
705                 }
706                 /* ydnar: certain entities get stripped from bsp file */
707                 value2 = ValueForKey( &entities[ i ], "classname" );
708                 if ( !Q_stricmp( value2, "misc_model" ) ||
709                          !Q_stricmp( value2, "_decal" ) ||
710                          !Q_stricmp( value2, "_skybox" ) ) {
711                         continue;
712                 }
713
714                 /* add beginning brace */
715                 strcat( end, "{\n" );
716                 end += 2;
717
718                 /* walk epair list */
719                 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
720                 {
721                         /* copy and clean */
722                         strcpy( key, ep->key );
723                         StripTrailing( key );
724                         strcpy( value, ep->value );
725                         StripTrailing( value );
726
727                         /* add to buffer */
728                         sprintf( line, "\"%s\" \"%s\"\n", key, value );
729                         strcat( end, line );
730                         end += strlen( line );
731                 }
732
733                 /* add trailing brace */
734                 strcat( end,"}\n" );
735                 end += 2;
736
737                 /* check for overflow */
738                 if ( end > buf + allocatedBSPEntData ) {
739                         Error( "Entity text too long" );
740                 }
741         }
742
743         /* set size */
744         bspEntDataSize = end - buf + 1;
745 }
746
747
748
749 /*
750    PrintEntity()
751    prints an entity's epairs to the console
752  */
753
754 void PrintEntity( const entity_t *ent ){
755         epair_t *ep;
756
757
758         Sys_Printf( "------- entity %p -------\n", ent );
759         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
760                 Sys_Printf( "%s = %s\n", ep->key, ep->value );
761
762 }
763
764
765
766 /*
767    SetKeyValue()
768    sets an epair in an entity
769  */
770
771 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
772         epair_t *ep;
773
774
775         /* check for existing epair */
776         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
777         {
778                 if ( !EPAIR_STRCMP( ep->key, key ) ) {
779                         free( ep->value );
780                         ep->value = copystring( value );
781                         return;
782                 }
783         }
784
785         /* create new epair */
786         ep = safe_malloc( sizeof( *ep ) );
787         ep->next = ent->epairs;
788         ent->epairs = ep;
789         ep->key = copystring( key );
790         ep->value = copystring( value );
791 }
792
793
794
795 /*
796    KeyExists()
797    returns true if entity has this key
798  */
799
800 qboolean KeyExists( const entity_t *ent, const char *key ){
801         epair_t *ep;
802
803         /* walk epair list */
804         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
805         {
806                 if ( !EPAIR_STRCMP( ep->key, key ) ) {
807                         return qtrue;
808                 }
809         }
810
811         /* no match */
812         return qfalse;
813 }
814
815
816
817 /*
818    ValueForKey()
819    gets the value for an entity key
820  */
821
822 const char *ValueForKey( const entity_t *ent, const char *key ){
823         epair_t *ep;
824
825
826         /* dummy check */
827         if ( ent == NULL ) {
828                 return "";
829         }
830
831         /* walk epair list */
832         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
833         {
834                 if ( !EPAIR_STRCMP( ep->key, key ) ) {
835                         return ep->value;
836                 }
837         }
838
839         /* if no match, return empty string */
840         return "";
841 }
842
843
844
845 /*
846    IntForKey()
847    gets the integer point value for an entity key
848  */
849
850 int IntForKey( const entity_t *ent, const char *key ){
851         const char  *k;
852
853
854         k = ValueForKey( ent, key );
855         return atoi( k );
856 }
857
858
859
860 /*
861    FloatForKey()
862    gets the floating point value for an entity key
863  */
864
865 vec_t FloatForKey( const entity_t *ent, const char *key ){
866         const char  *k;
867
868
869         k = ValueForKey( ent, key );
870         return atof( k );
871 }
872
873
874
875 /*
876    GetVectorForKey()
877    gets a 3-element vector value for an entity key
878  */
879
880 qboolean GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
881         const char  *k;
882         double v1, v2, v3;
883
884
885         /* get value */
886         k = ValueForKey( ent, key );
887
888         /* scanf into doubles, then assign, so it is vec_t size independent */
889         v1 = v2 = v3 = 0.0;
890         sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
891         vec[ 0 ] = v1;
892         vec[ 1 ] = v2;
893         vec[ 2 ] = v3;
894
895         /* true if the key is found, false otherwise */
896         return strlen( k );
897 }
898
899
900
901 /*
902    FindTargetEntity()
903    finds an entity target
904  */
905
906 entity_t *FindTargetEntity( const char *target ){
907         int i;
908         const char  *n;
909
910
911         /* walk entity list */
912         for ( i = 0; i < numEntities; i++ )
913         {
914                 n = ValueForKey( &entities[ i ], "targetname" );
915                 if ( !strcmp( n, target ) ) {
916                         return &entities[ i ];
917                 }
918         }
919
920         /* nada */
921         return NULL;
922 }
923
924
925
926 /*
927    GetEntityShadowFlags() - ydnar
928    gets an entity's shadow flags
929    note: does not set them to defaults if the keys are not found!
930  */
931
932 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
933         const char  *value;
934
935         /* get cast shadows */
936         if ( castShadows != NULL ) {
937                 value = ValueForKey( ent, "_castShadows" );
938                 if ( value[ 0 ] == '\0' ) {
939                         value = ValueForKey( ent, "_cs" );
940                 }
941                 if ( value[ 0 ] == '\0' ) {
942                         value = ValueForKey( ent2, "_castShadows" );
943                 }
944                 if ( value[ 0 ] == '\0' ) {
945                         value = ValueForKey( ent2, "_cs" );
946                 }
947                 if ( value[ 0 ] != '\0' ) {
948                         *castShadows = atoi( value );
949                 }
950         }
951
952         /* receive */
953         if ( recvShadows != NULL ) {
954                 value = ValueForKey( ent, "_receiveShadows" );
955                 if ( value[ 0 ] == '\0' ) {
956                         value = ValueForKey( ent, "_rs" );
957                 }
958                 if ( value[ 0 ] == '\0' ) {
959                         value = ValueForKey( ent2, "_receiveShadows" );
960                 }
961                 if ( value[ 0 ] == '\0' ) {
962                         value = ValueForKey( ent2, "_rs" );
963                 }
964                 if ( value[ 0 ] != '\0' ) {
965                         *recvShadows = atoi( value );
966                 }
967         }
968
969         /* vortex: game-specific default entity keys */
970         value = ValueForKey( ent, "classname" );
971         if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
972                 /* vortex: deluxe quake default shadow flags */
973                 if ( !Q_stricmp( value, "func_wall" ) ) {
974                         if ( recvShadows != NULL ) {
975                                 *recvShadows = 1;
976                         }
977                         if ( castShadows != NULL ) {
978                                 *castShadows = 1;
979                         }
980                 }
981         }
982 }