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;
IncDrawVerts()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
SetDrawVerts(int n)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;
SetDrawSurfacesBuffer()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
SetDrawSurfaces(int n)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
BSPFilesCleanup()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
SwapBlock(int * block,int size)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
SwapBSPFile(void)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
GetLumpElements(bspHeader_t * header,int lump,int size)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
GetLump(bspHeader_t * header,int lump)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
CopyLump(bspHeader_t * header,int lump,void * dest,int size)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
AddLump(FILE * file,bspHeader_t * header,int lumpNum,const void * data,int length)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
LoadBSPFile(const char * filename)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
WriteBSPFile(const char * filename)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
PrintBSPFileSizes(void)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
StripTrailing(char * e)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
ParseEPair(void)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
ParseEntity(void)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
ParseEntities(void)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
UnparseEntities(void)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
PrintEntity(const entity_t * ent)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
SetKeyValue(entity_t * ent,const char * key,const char * value)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
ValueForKey(const entity_t * ent,const char * key)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
IntForKey(const entity_t * ent,const char * key)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
FloatForKey(const entity_t * ent,const char * key)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
GetVectorForKey(const entity_t * ent,const char * key,vec3_t vec)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
FindTargetEntity(const char * target)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
GetEntityShadowFlags(const entity_t * ent,const entity_t * ent2,int * castShadows,int * recvShadows)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
836