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