]> git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/bspfile_abstract.c
Merge commit 'b681f28130ff2e9789253eff1c1d41163e427eaa' 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, j;
395         shaderInfo_t    *si;
396
397         /* shaders (don't swap the name) */
398         for ( i = 0; i < numBSPShaders ; i++ )
399         {
400                 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
401                 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
402         }
403
404         /* drawsurfs */
405         /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
406         SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
407 }
408
409 /*
410    WriteBSPFile()
411    writes a bsp file
412  */
413
414 void WriteBSPFile( const char *filename ){
415         char tempname[ 1024 ];
416         time_t tm;
417
418
419         /* dummy check */
420         if ( game == NULL || game->write == NULL ) {
421                 Error( "WriteBSPFile: unsupported BSP file format" );
422         }
423
424         /* make fake temp name so existing bsp file isn't damaged in case write process fails */
425         time( &tm );
426         sprintf( tempname, "%s.%08X", filename, (int) tm );
427
428         /* byteswap, write the bsp, then swap back so it can be manipulated further */
429         SwapBSPFile();
430         game->write( tempname );
431         SwapBSPFile();
432
433         /* replace existing bsp file */
434         remove( filename );
435         rename( tempname, filename );
436 }
437
438
439
440 /*
441    PrintBSPFileSizes()
442    dumps info about current file
443  */
444
445 void PrintBSPFileSizes( void ){
446         /* parse entities first */
447         if ( numEntities <= 0 ) {
448                 ParseEntities();
449         }
450
451         /* note that this is abstracted */
452         Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
453
454         /* print various and sundry bits */
455         Sys_Printf( "%9d models        %9d\n",
456                                 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
457         Sys_Printf( "%9d shaders       %9d\n",
458                                 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
459         Sys_Printf( "%9d brushes       %9d\n",
460                                 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
461         Sys_Printf( "%9d brushsides    %9d *\n",
462                                 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
463         Sys_Printf( "%9d fogs          %9d\n",
464                                 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
465         Sys_Printf( "%9d planes        %9d\n",
466                                 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
467         Sys_Printf( "%9d entdata       %9d\n",
468                                 numEntities, bspEntDataSize );
469         Sys_Printf( "\n" );
470
471         Sys_Printf( "%9d nodes         %9d\n",
472                                 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
473         Sys_Printf( "%9d leafs         %9d\n",
474                                 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
475         Sys_Printf( "%9d leafsurfaces  %9d\n",
476                                 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
477         Sys_Printf( "%9d leafbrushes   %9d\n",
478                                 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
479         Sys_Printf( "\n" );
480
481         Sys_Printf( "%9d drawsurfaces  %9d *\n",
482                                 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
483         Sys_Printf( "%9d drawverts     %9d *\n",
484                                 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
485         Sys_Printf( "%9d drawindexes   %9d\n",
486                                 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
487         Sys_Printf( "\n" );
488
489         Sys_Printf( "%9d lightmaps     %9d\n",
490                                 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
491         Sys_Printf( "%9d lightgrid     %9d *\n",
492                                 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
493         Sys_Printf( "          visibility    %9d\n",
494                                 numBSPVisBytes );
495 }
496
497
498
499 /* -------------------------------------------------------------------------------
500
501    entity data handling
502
503    ------------------------------------------------------------------------------- */
504
505
506 /*
507    StripTrailing()
508    strips low byte chars off the end of a string
509  */
510
511 void StripTrailing( char *e ){
512         char    *s;
513
514
515         s = e + strlen( e ) - 1;
516         while ( s >= e && *s <= 32 )
517         {
518                 *s = 0;
519                 s--;
520         }
521 }
522
523
524
525 /*
526    ParseEpair()
527    parses a single quoted "key" "value" pair into an epair struct
528  */
529
530 epair_t *ParseEPair( void ){
531         epair_t     *e;
532
533
534         /* allocate and clear new epair */
535         e = safe_malloc0( 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 ( argv[i] == NULL ) {
651                         continue;
652                 }
653                 if ( outpos != sentinel && i != beginArgs ) {
654                         *outpos++ = ' ';
655                 }
656                 inpos = argv[i];
657                 while ( outpos != sentinel && *inpos )
658                         if ( *inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ' ) {
659                                 *outpos++ = *inpos++;
660                         }
661         }
662
663         *outpos = 0;
664         SetKeyValue( &entities[0], "_q3map2_cmdline", newCommandLine );
665         SetKeyValue( &entities[0], "_q3map2_version", Q3MAP_VERSION );
666 }
667
668
669
670 /*
671    UnparseEntities()
672    generates the dentdata string from all the entities.
673    this allows the utilities to add or remove key/value
674    pairs to the data created by the map editor
675  */
676
677 void UnparseEntities( void ){
678         int i;
679         char        *buf, *end;
680         epair_t     *ep;
681         char line[ 2048 ];
682         char key[ 1024 ], value[ 1024 ];
683         const char  *value2;
684
685
686         /* setup */
687         AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
688         buf = bspEntData;
689         end = buf;
690         *end = 0;
691
692
693         /* run through entity list */
694         for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
695         {
696                 {
697                         int sz = end - buf;
698                         AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
699                         buf = bspEntData;
700                         end = buf + sz;
701                 }
702
703                 /* get epair */
704                 ep = entities[ i ].epairs;
705                 if ( ep == NULL ) {
706                         continue;   /* ent got removed */
707
708                 }
709                 /* ydnar: certain entities get stripped from bsp file */
710                 value2 = ValueForKey( &entities[ i ], "classname" );
711                 if ( !Q_stricmp( value2, "misc_model" ) ||
712                          !Q_stricmp( value2, "_decal" ) ||
713                          !Q_stricmp( value2, "_skybox" ) ) {
714                         continue;
715                 }
716
717                 /* add beginning brace */
718                 strcat( end, "{\n" );
719                 end += 2;
720
721                 /* walk epair list */
722                 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
723                 {
724                         /* copy and clean */
725                         strcpy( key, ep->key );
726                         StripTrailing( key );
727                         strcpy( value, ep->value );
728                         StripTrailing( value );
729
730                         /* add to buffer */
731                         sprintf( line, "\"%s\" \"%s\"\n", key, value );
732                         strcat( end, line );
733                         end += strlen( line );
734                 }
735
736                 /* add trailing brace */
737                 strcat( end,"}\n" );
738                 end += 2;
739
740                 /* check for overflow */
741                 if ( end > buf + allocatedBSPEntData ) {
742                         Error( "Entity text too long" );
743                 }
744         }
745
746         /* set size */
747         bspEntDataSize = end - buf + 1;
748 }
749
750
751
752 /*
753    PrintEntity()
754    prints an entity's epairs to the console
755  */
756
757 void PrintEntity( const entity_t *ent ){
758         epair_t *ep;
759
760
761         Sys_Printf( "------- entity %p -------\n", ent );
762         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
763                 Sys_Printf( "%s = %s\n", ep->key, ep->value );
764
765 }
766
767
768
769 /*
770    SetKeyValue()
771    sets an epair in an entity
772  */
773
774 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
775         epair_t *ep;
776
777
778         /* check for existing epair */
779         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
780         {
781                 if ( !EPAIR_STRCMP( ep->key, key ) ) {
782                         free( ep->value );
783                         ep->value = copystring( value );
784                         return;
785                 }
786         }
787
788         /* create new epair */
789         ep = safe_malloc( sizeof( *ep ) );
790         ep->next = ent->epairs;
791         ent->epairs = ep;
792         ep->key = copystring( key );
793         ep->value = copystring( value );
794 }
795
796
797
798 /*
799    KeyExists()
800    returns true if entity has this key
801  */
802
803 qboolean KeyExists( const entity_t *ent, const char *key ){
804         epair_t *ep;
805
806         /* walk epair list */
807         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
808         {
809                 if ( !EPAIR_STRCMP( ep->key, key ) ) {
810                         return qtrue;
811                 }
812         }
813
814         /* no match */
815         return qfalse;
816 }
817
818
819
820 /*
821    ValueForKey()
822    gets the value for an entity key
823  */
824
825 const char *ValueForKey( const entity_t *ent, const char *key ){
826         epair_t *ep;
827
828
829         /* dummy check */
830         if ( ent == NULL ) {
831                 return "";
832         }
833
834         /* walk epair list */
835         for ( ep = ent->epairs; ep != NULL; ep = ep->next )
836         {
837                 if ( !EPAIR_STRCMP( ep->key, key ) ) {
838                         return ep->value;
839                 }
840         }
841
842         /* if no match, return empty string */
843         return "";
844 }
845
846
847
848 /*
849    IntForKey()
850    gets the integer point value for an entity key
851  */
852
853 int IntForKey( const entity_t *ent, const char *key ){
854         const char  *k;
855
856
857         k = ValueForKey( ent, key );
858         return atoi( k );
859 }
860
861
862
863 /*
864    FloatForKey()
865    gets the floating point value for an entity key
866  */
867
868 vec_t FloatForKey( const entity_t *ent, const char *key ){
869         const char  *k;
870
871
872         k = ValueForKey( ent, key );
873         return atof( k );
874 }
875
876
877
878 /*
879    GetVectorForKey()
880    gets a 3-element vector value for an entity key
881  */
882
883 qboolean GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
884         const char  *k;
885         double v1, v2, v3;
886
887
888         /* get value */
889         k = ValueForKey( ent, key );
890
891         /* scanf into doubles, then assign, so it is vec_t size independent */
892         v1 = v2 = v3 = 0.0;
893         sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
894         vec[ 0 ] = v1;
895         vec[ 1 ] = v2;
896         vec[ 2 ] = v3;
897
898         /* true if the key is found, false otherwise */
899         return strlen( k );
900 }
901
902
903
904 /*
905    FindTargetEntity()
906    finds an entity target
907  */
908
909 entity_t *FindTargetEntity( const char *target ){
910         int i;
911         const char  *n;
912
913
914         /* walk entity list */
915         for ( i = 0; i < numEntities; i++ )
916         {
917                 n = ValueForKey( &entities[ i ], "targetname" );
918                 if ( !strcmp( n, target ) ) {
919                         return &entities[ i ];
920                 }
921         }
922
923         /* nada */
924         return NULL;
925 }
926
927
928
929 /*
930    GetEntityShadowFlags() - ydnar
931    gets an entity's shadow flags
932    note: does not set them to defaults if the keys are not found!
933  */
934
935 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
936         const char  *value;
937
938         /* get cast shadows */
939         if ( castShadows != NULL ) {
940                 value = ValueForKey( ent, "_castShadows" );
941                 if ( value[ 0 ] == '\0' ) {
942                         value = ValueForKey( ent, "_cs" );
943                 }
944                 if ( value[ 0 ] == '\0' ) {
945                         value = ValueForKey( ent2, "_castShadows" );
946                 }
947                 if ( value[ 0 ] == '\0' ) {
948                         value = ValueForKey( ent2, "_cs" );
949                 }
950                 if ( value[ 0 ] != '\0' ) {
951                         *castShadows = atoi( value );
952                 }
953         }
954
955         /* receive */
956         if ( recvShadows != NULL ) {
957                 value = ValueForKey( ent, "_receiveShadows" );
958                 if ( value[ 0 ] == '\0' ) {
959                         value = ValueForKey( ent, "_rs" );
960                 }
961                 if ( value[ 0 ] == '\0' ) {
962                         value = ValueForKey( ent2, "_receiveShadows" );
963                 }
964                 if ( value[ 0 ] == '\0' ) {
965                         value = ValueForKey( ent2, "_rs" );
966                 }
967                 if ( value[ 0 ] != '\0' ) {
968                         *recvShadows = atoi( value );
969                 }
970         }
971
972         /* vortex: game-specific default entity keys */
973         value = ValueForKey( ent, "classname" );
974         if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
975                 /* vortex: deluxe quake default shadow flags */
976                 if ( !Q_stricmp( value, "func_wall" ) ) {
977                         if ( recvShadows != NULL ) {
978                                 *recvShadows = 1;
979                         }
980                         if ( castShadows != NULL ) {
981                                 *castShadows = 1;
982                         }
983                 }
984         }
985 }