]> icculus.org git repositories - divverent/netradiant.git/blob - tools/quake3/q3map2/bspfile_abstract.c
fix a warning; NULL out the unused faces of misc_models (apparently this changes...
[divverent/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 {
63         numBSPDrawVerts++;
64
65         if(bspDrawVerts == 0)
66         {
67                 numBSPDrawVertsBuffer = 1024;
68                 
69                 bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");
70
71         }
72         else if(numBSPDrawVerts > numBSPDrawVertsBuffer)
73         {
74                 numBSPDrawVertsBuffer *= 3; // multiply by 1.5
75                 numBSPDrawVertsBuffer /= 2;
76
77                 bspDrawVerts = realloc(bspDrawVerts, sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer);
78
79                 if(!bspDrawVerts)
80                         Error( "realloc() failed (IncDrawVerts)");
81         }
82
83         memset(bspDrawVerts + (numBSPDrawVerts - 1), 0, sizeof(bspDrawVert_t));
84 }
85
86 void SetDrawVerts(int n)
87 {
88         if(bspDrawVerts != 0)
89                 free(bspDrawVerts);
90
91         numBSPDrawVerts = n;
92         numBSPDrawVertsBuffer = numBSPDrawVerts;
93
94         bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");
95
96         memset(bspDrawVerts, 0, n * sizeof(bspDrawVert_t));
97 }
98
99 int numBSPDrawSurfacesBuffer = 0;
100 void SetDrawSurfacesBuffer()
101 {
102         if(bspDrawSurfaces != 0)
103                 free(bspDrawSurfaces);
104
105         numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
106
107         bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");
108
109         memset(bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof(bspDrawVert_t));
110 }
111
112 void SetDrawSurfaces(int n)
113 {
114         if(bspDrawSurfaces != 0)
115                 free(bspDrawSurfaces);
116
117         numBSPDrawSurfaces = n;
118         numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
119
120         bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");
121
122         memset(bspDrawSurfaces, 0, n * sizeof(bspDrawVert_t));
123 }
124
125 void BSPFilesCleanup()
126 {
127         if(bspDrawVerts != 0)
128                 free(bspDrawVerts);
129         if(bspDrawSurfaces != 0)
130                 free(bspDrawSurfaces);
131         if(bspLightBytes != 0)
132                 free(bspLightBytes);
133         if(bspGridPoints != 0)
134                 free(bspGridPoints);
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 {
149         int             i;
150         
151         
152         /* dummy check */
153         if( block == NULL )
154                 return;
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 {
171         int             i, j;
172         
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                 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
262 /*
263 GetLumpElements()
264 gets the number of elements in a bsp lump
265 */
266
267 int GetLumpElements( bspHeader_t *header, int lump, int size )
268 {
269         /* check for odd size */
270         if( header->lumps[ lump ].length % size )
271         {
272                 if( force )
273                 {
274                         Sys_Printf( "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         /* return element count */
282         return header->lumps[ lump ].length / size;
283 }
284
285
286
287 /*
288 GetLump()
289 returns a pointer to the specified lump
290 */
291
292 void *GetLump( bspHeader_t *header, int lump )
293 {
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 {
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         if( length % size )
317         {
318                 if( force )
319                 {
320                         Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
321                         return 0;
322                 }
323                 else
324                         Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
325         }
326         
327         /* copy block of memory and return */
328         memcpy( dest, (byte*) header + offset, length );
329         return length / size;
330 }
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 {
341         bspLump_t       *lump;
342         
343         
344         /* add lump to bsp file header */
345         lump = &header->lumps[ lumpNum ];
346         lump->offset = LittleLong( ftell( file ) );
347         lump->length = LittleLong( length );
348         
349         /* write lump to file */
350         SafeWrite( file, data, (length + 3) & ~3 );
351 }
352
353
354
355 /*
356 LoadBSPFile()
357 loads a bsp file into memory
358 */
359
360 void LoadBSPFile( const char *filename )
361 {
362         /* dummy check */
363         if( game == NULL || game->load == NULL )
364                 Error( "LoadBSPFile: unsupported BSP file format" );
365         
366         /* load it, then byte swap the in-memory version */
367         game->load( filename );
368         SwapBSPFile();
369 }
370
371
372
373 /*
374 WriteBSPFile()
375 writes a bsp file
376 */
377
378 void WriteBSPFile( const char *filename )
379 {
380         char    tempname[ 1024 ];
381         time_t  tm;
382         
383         
384         /* dummy check */
385         if( game == NULL || game->write == NULL )
386                 Error( "WriteBSPFile: unsupported BSP file format" );
387         
388         /* make fake temp name so existing bsp file isn't damaged in case write process fails */
389         time( &tm );
390         sprintf( tempname, "%s.%08X", filename, (int) tm );
391         
392         /* byteswap, write the bsp, then swap back so it can be manipulated further */
393         SwapBSPFile();
394         game->write( tempname );
395         SwapBSPFile();
396         
397         /* replace existing bsp file */
398         remove( filename );
399         rename( tempname, filename );
400 }
401
402
403
404 /*
405 PrintBSPFileSizes()
406 dumps info about current file
407 */
408
409 void PrintBSPFileSizes( void )
410 {
411         /* parse entities first */
412         if( numEntities <= 0 )
413                 ParseEntities();
414         
415         /* note that this is abstracted */
416         Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
417         
418         /* print various and sundry bits */
419         Sys_Printf( "%9d models        %9d\n",
420                 numBSPModels, (int) (numBSPModels * sizeof( bspModel_t )) );
421         Sys_Printf( "%9d shaders       %9d\n",
422                 numBSPShaders, (int) (numBSPShaders * sizeof( bspShader_t )) );
423         Sys_Printf( "%9d brushes       %9d\n",
424                 numBSPBrushes, (int) (numBSPBrushes * sizeof( bspBrush_t )) );
425         Sys_Printf( "%9d brushsides    %9d *\n",
426                 numBSPBrushSides, (int) (numBSPBrushSides * sizeof( bspBrushSide_t )) );
427         Sys_Printf( "%9d fogs          %9d\n",
428                 numBSPFogs, (int) (numBSPFogs * sizeof( bspFog_t ) ) );
429         Sys_Printf( "%9d planes        %9d\n",
430                 numBSPPlanes, (int) (numBSPPlanes * sizeof( bspPlane_t )) );
431         Sys_Printf( "%9d entdata       %9d\n",
432                 numEntities, bspEntDataSize );
433         Sys_Printf( "\n");
434         
435         Sys_Printf( "%9d nodes         %9d\n",
436                 numBSPNodes, (int) (numBSPNodes * sizeof( bspNode_t)) );
437         Sys_Printf( "%9d leafs         %9d\n",
438                 numBSPLeafs, (int) (numBSPLeafs * sizeof( bspLeaf_t )) );
439         Sys_Printf( "%9d leafsurfaces  %9d\n",
440                 numBSPLeafSurfaces, (int) (numBSPLeafSurfaces * sizeof( *bspLeafSurfaces )) );
441         Sys_Printf( "%9d leafbrushes   %9d\n",
442                 numBSPLeafBrushes, (int) (numBSPLeafBrushes * sizeof( *bspLeafBrushes )) );
443         Sys_Printf( "\n");
444         
445         Sys_Printf( "%9d drawsurfaces  %9d *\n",
446                 numBSPDrawSurfaces, (int) (numBSPDrawSurfaces * sizeof( *bspDrawSurfaces )) );
447         Sys_Printf( "%9d drawverts     %9d *\n",
448                 numBSPDrawVerts, (int) (numBSPDrawVerts * sizeof( *bspDrawVerts )) );
449         Sys_Printf( "%9d drawindexes   %9d\n",
450                 numBSPDrawIndexes, (int) (numBSPDrawIndexes * sizeof( *bspDrawIndexes )) );
451         Sys_Printf( "\n");
452         
453         Sys_Printf( "%9d lightmaps     %9d\n",
454                 numBSPLightBytes / (game->lightmapSize * game->lightmapSize * 3), numBSPLightBytes );
455         Sys_Printf( "%9d lightgrid     %9d *\n",
456                 numBSPGridPoints, (int) (numBSPGridPoints * sizeof( *bspGridPoints )) );
457         Sys_Printf( "          visibility    %9d\n",
458                 numBSPVisBytes );
459 }
460
461
462
463 /* -------------------------------------------------------------------------------
464
465 entity data handling
466
467 ------------------------------------------------------------------------------- */
468
469
470 /*
471 StripTrailing()
472 strips low byte chars off the end of a string
473 */
474
475 void StripTrailing( char *e )
476 {
477         char    *s;
478         
479         
480         s = e + strlen( e ) - 1;
481         while( s >= e && *s <= 32 )
482         {
483                 *s = 0;
484                 s--;
485         }
486 }
487
488
489
490 /*
491 ParseEpair()
492 parses a single quoted "key" "value" pair into an epair struct
493 */
494
495 epair_t *ParseEPair( void )
496 {
497         epair_t         *e;
498         
499         
500         /* allocate and clear new epair */
501         e = safe_malloc( sizeof( epair_t ) );
502         memset( e, 0, sizeof( epair_t ) );
503         
504         /* handle key */
505         if( strlen( token ) >= (MAX_KEY - 1) )
506                 Error( "ParseEPair: token too long" );
507         
508         e->key = copystring( token );
509         GetToken( qfalse );
510         
511         /* handle value */
512         if( strlen( token ) >= MAX_VALUE - 1 )
513                 Error( "ParseEpar: token too long" );
514         e->value = copystring( token );
515         
516         /* strip trailing spaces that sometimes get accidentally added in the editor */
517         StripTrailing( e->key );
518         StripTrailing( e->value );
519         
520         /* return it */
521         return e;
522 }
523
524
525
526 /*
527 ParseEntity()
528 parses an entity's epairs
529 */
530
531 qboolean ParseEntity( void )
532 {
533         epair_t         *e;
534         
535         
536         /* dummy check */
537         if( !GetToken( qtrue ) )
538                 return qfalse;
539         if( strcmp( token, "{" ) )
540                 Error( "ParseEntity: { not found" );
541         if( numEntities == MAX_MAP_ENTITIES )
542                 Error( "numEntities == MAX_MAP_ENTITIES" );
543         
544         /* create new entity */
545         mapEnt = &entities[ numEntities ];
546         numEntities++;
547         
548         /* parse */
549         while( 1 )
550         {
551                 if( !GetToken( qtrue ) )
552                         Error( "ParseEntity: EOF without closing brace" );
553                 if( !EPAIR_STRCMP( token, "}" ) )
554                         break;
555                 e = ParseEPair();
556                 e->next = mapEnt->epairs;
557                 mapEnt->epairs = e;
558         }
559         
560         /* return to sender */
561         return qtrue;
562 }
563
564
565
566 /*
567 ParseEntities()
568 parses the bsp entity data string into entities
569 */
570
571 void ParseEntities( void )
572 {
573         numEntities = 0;
574         ParseFromMemory( bspEntData, bspEntDataSize );
575         while( ParseEntity() );
576         
577         /* ydnar: set number of bsp entities in case a map is loaded on top */
578         numBSPEntities = numEntities;
579 }
580
581
582
583 /*
584 UnparseEntities()
585 generates the dentdata string from all the entities.
586 this allows the utilities to add or remove key/value
587 pairs to the data created by the map editor
588 */
589
590 void UnparseEntities( void )
591 {
592         int                     i;
593         char            *buf, *end;
594         epair_t         *ep;
595         char            line[ 2048 ];
596         char            key[ 1024 ], value[ 1024 ];
597         const char      *value2;
598         
599         
600         /* setup */
601         buf = bspEntData;
602         end = buf;
603         *end = 0;
604         
605         /* run through entity list */
606         for( i = 0; i < numBSPEntities && i < numEntities; i++ )
607         {
608                 /* get epair */
609                 ep = entities[ i ].epairs;
610                 if( ep == NULL )
611                         continue;       /* ent got removed */
612                 
613                 /* ydnar: certain entities get stripped from bsp file */
614                 value2 = ValueForKey( &entities[ i ], "classname" );
615                 if( !Q_stricmp( value2, "misc_model" ) ||
616                         !Q_stricmp( value2, "_decal" ) ||
617                         !Q_stricmp( value2, "_skybox" ) )
618                         continue;
619                 
620                 /* add beginning brace */
621                 strcat( end, "{\n" );
622                 end += 2;
623                 
624                 /* walk epair list */
625                 for( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
626                 {
627                         /* copy and clean */
628                         strcpy( key, ep->key );
629                         StripTrailing( key );
630                         strcpy( value, ep->value );
631                         StripTrailing( value );
632                         
633                         /* add to buffer */
634                         sprintf( line, "\"%s\" \"%s\"\n", key, value );
635                         strcat( end, line );
636                         end += strlen( line );
637                 }
638                 
639                 /* add trailing brace */
640                 strcat( end,"}\n" );
641                 end += 2;
642                 
643                 /* check for overflow */
644                 if( end > buf + MAX_MAP_ENTSTRING )
645                         Error( "Entity text too long" );
646         }
647         
648         /* set size */
649         bspEntDataSize = end - buf + 1;
650 }
651
652
653
654 /*
655 PrintEntity()
656 prints an entity's epairs to the console
657 */
658
659 void PrintEntity( const entity_t *ent )
660 {
661         epair_t *ep;
662         
663
664         Sys_Printf( "------- entity %p -------\n", ent );
665         for( ep = ent->epairs; ep != NULL; ep = ep->next )
666                 Sys_Printf( "%s = %s\n", ep->key, ep->value );
667
668 }
669
670
671
672 /*
673 SetKeyValue()
674 sets an epair in an entity
675 */
676
677 void SetKeyValue( entity_t *ent, const char *key, const char *value )
678 {
679         epair_t *ep;
680         
681         
682         /* check for existing epair */
683         for( ep = ent->epairs; ep != NULL; ep = ep->next )
684         {
685                 if( !EPAIR_STRCMP( ep->key, key ) )
686                 {
687                         free( ep->value );
688                         ep->value = copystring( value );
689                         return;
690                 }
691         }
692         
693         /* create new epair */
694         ep = safe_malloc( sizeof( *ep ) );
695         ep->next = ent->epairs;
696         ent->epairs = ep;
697         ep->key = copystring( key );
698         ep->value = copystring( value );
699 }
700
701
702
703 /*
704 ValueForKey()
705 gets the value for an entity key
706 */
707
708 const char *ValueForKey( const entity_t *ent, const char *key )
709 {
710         epair_t *ep;
711         
712         
713         /* dummy check */
714         if( ent == NULL )
715                 return "";
716         
717         /* walk epair list */
718         for( ep = ent->epairs; ep != NULL; ep = ep->next )
719         {
720                 if( !EPAIR_STRCMP( ep->key, key ) )
721                         return ep->value;
722         }
723         
724         /* if no match, return empty string */
725         return "";
726 }
727
728
729
730 /*
731 IntForKey()
732 gets the integer point value for an entity key
733 */
734
735 int IntForKey( const entity_t *ent, const char *key )
736 {
737         const char      *k;
738         
739         
740         k = ValueForKey( ent, key );
741         return atoi( k );
742 }
743
744
745
746 /*
747 FloatForKey()
748 gets the floating point value for an entity key
749 */
750
751 vec_t FloatForKey( const entity_t *ent, const char *key )
752 {
753         const char      *k;
754         
755         
756         k = ValueForKey( ent, key );
757         return atof( k );
758 }
759
760
761
762 /*
763 GetVectorForKey()
764 gets a 3-element vector value for an entity key
765 */
766
767 void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec )
768 {
769         const char      *k;
770         double          v1, v2, v3;
771         
772
773         /* get value */
774         k = ValueForKey( ent, key );
775         
776         /* scanf into doubles, then assign, so it is vec_t size independent */
777         v1 = v2 = v3 = 0.0;
778         sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
779         vec[ 0 ] = v1;
780         vec[ 1 ] = v2;
781         vec[ 2 ] = v3;
782 }
783
784
785
786 /*
787 FindTargetEntity()
788 finds an entity target
789 */
790
791 entity_t *FindTargetEntity( const char *target )
792 {
793         int                     i;
794         const char      *n;
795
796         
797         /* walk entity list */
798         for( i = 0; i < numEntities; i++ )
799         {
800                 n = ValueForKey( &entities[ i ], "targetname" );
801                 if ( !strcmp( n, target ) )
802                         return &entities[ i ];
803         }
804         
805         /* nada */
806         return NULL;
807 }
808
809
810
811 /*
812 GetEntityShadowFlags() - ydnar
813 gets an entity's shadow flags
814 note: does not set them to defaults if the keys are not found!
815 */
816
817 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows )
818 {
819         const char      *value;
820         
821         
822         /* get cast shadows */
823         if( castShadows != NULL )
824         {
825                 value = ValueForKey( ent, "_castShadows" );
826                 if( value[ 0 ] == '\0' )
827                         value = ValueForKey( ent, "_cs" );
828                 if( value[ 0 ] == '\0' )
829                         value = ValueForKey( ent2, "_castShadows" );
830                 if( value[ 0 ] == '\0' )
831                         value = ValueForKey( ent2, "_cs" );
832                 if( value[ 0 ] != '\0' )
833                         *castShadows = atoi( value );
834         }
835         
836         /* receive */
837         if( recvShadows != NULL )
838         {
839                 value = ValueForKey( ent, "_receiveShadows" );
840                 if( value[ 0 ] == '\0' )
841                         value = ValueForKey( ent, "_rs" );
842                 if( value[ 0 ] == '\0' )
843                         value = ValueForKey( ent2, "_receiveShadows" );
844                 if( value[ 0 ] == '\0' )
845                         value = ValueForKey( ent2, "_rs" );
846                 if( value[ 0 ] != '\0' )
847                         *recvShadows = atoi( value );
848         }
849 }
850