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