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;
IncDrawVerts()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
SetDrawVerts(int n)84 void SetDrawVerts( int n ){
85 if ( bspDrawVerts != 0 ) {
86 free( bspDrawVerts );
87 }
88
89 numBSPDrawVerts = n;
90 numBSPDrawVertsBuffer = numBSPDrawVerts;
91
92 bspDrawVerts = safe_malloc_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
93
94 memset( bspDrawVerts, 0, n * sizeof( bspDrawVert_t ) );
95 }
96
97 int numBSPDrawSurfacesBuffer = 0;
SetDrawSurfacesBuffer()98 void SetDrawSurfacesBuffer(){
99 if ( bspDrawSurfaces != 0 ) {
100 free( bspDrawSurfaces );
101 }
102
103 numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
104
105 bspDrawSurfaces = safe_malloc_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
106
107 memset( bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof( bspDrawVert_t ) );
108 }
109
SetDrawSurfaces(int n)110 void SetDrawSurfaces( int n ){
111 if ( bspDrawSurfaces != 0 ) {
112 free( bspDrawSurfaces );
113 }
114
115 numBSPDrawSurfaces = n;
116 numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
117
118 bspDrawSurfaces = safe_malloc_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
119
120 memset( bspDrawSurfaces, 0, n * sizeof( bspDrawVert_t ) );
121 }
122
BSPFilesCleanup()123 void BSPFilesCleanup(){
124 if ( bspDrawVerts != 0 ) {
125 free( bspDrawVerts );
126 }
127 if ( bspDrawSurfaces != 0 ) {
128 free( bspDrawSurfaces );
129 }
130 if ( bspLightBytes != 0 ) {
131 free( bspLightBytes );
132 }
133 if ( bspGridPoints != 0 ) {
134 free( bspGridPoints );
135 }
136 }
137
138
139
140
141
142
143 /*
144 SwapBlock()
145 if all values are 32 bits, this can be used to swap everything
146 */
147
SwapBlock(int * block,int size)148 void SwapBlock( int *block, int size ){
149 int i;
150
151
152 /* dummy check */
153 if ( block == NULL ) {
154 return;
155 }
156
157 /* swap */
158 size >>= 2;
159 for ( i = 0; i < size; i++ )
160 block[ i ] = LittleLong( block[ i ] );
161 }
162
163
164
165 /*
166 SwapBSPFile()
167 byte swaps all data in the abstract bsp
168 */
169
SwapBSPFile(void)170 void SwapBSPFile( void ){
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
GetLumpElements(bspHeader_t * header,int lump,int size)267 int GetLumpElements( bspHeader_t *header, int lump, int size ){
268 /* check for odd size */
269 if ( header->lumps[ lump ].length % size ) {
270 if ( force ) {
271 Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
272 return 0;
273 }
274 else{
275 Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
276 }
277 }
278
279 /* return element count */
280 return header->lumps[ lump ].length / size;
281 }
282
283
284
285 /*
286 GetLump()
287 returns a pointer to the specified lump
288 */
289
GetLump(bspHeader_t * header,int lump)290 void *GetLump( bspHeader_t *header, int lump ){
291 return (void*)( (byte*) header + header->lumps[ lump ].offset );
292 }
293
294
295
296 /*
297 CopyLump()
298 copies a bsp file lump into a destination buffer
299 */
300
CopyLump(bspHeader_t * header,int lump,void * dest,int size)301 int CopyLump( bspHeader_t *header, int lump, void *dest, int size ){
302 int length, offset;
303
304
305 /* get lump length and offset */
306 length = header->lumps[ lump ].length;
307 offset = header->lumps[ lump ].offset;
308
309 /* handle erroneous cases */
310 if ( length == 0 ) {
311 return 0;
312 }
313 if ( length % size ) {
314 if ( force ) {
315 Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
316 return 0;
317 }
318 else{
319 Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
320 }
321 }
322
323 /* copy block of memory and return */
324 memcpy( dest, (byte*) header + offset, length );
325 return length / size;
326 }
327
CopyLump_Allocate(bspHeader_t * header,int lump,void ** dest,int size,int * allocationVariable)328 int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable ){
329 /* get lump length and offset */
330 *allocationVariable = header->lumps[ lump ].length / size;
331 *dest = realloc( *dest, size * *allocationVariable );
332 return CopyLump( header, lump, *dest, size );
333 }
334
335
336 /*
337 AddLump()
338 adds a lump to an outgoing bsp file
339 */
340
AddLump(FILE * file,bspHeader_t * header,int lumpNum,const void * data,int length)341 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
342 bspLump_t *lump;
343
344
345 /* add lump to bsp file header */
346 lump = &header->lumps[ lumpNum ];
347 lump->offset = LittleLong( ftell( file ) );
348 lump->length = LittleLong( length );
349
350 /* write lump to file */
351 SafeWrite( file, data, ( length + 3 ) & ~3 );
352 }
353
354
355
356 /*
357 LoadBSPFile()
358 loads a bsp file into memory
359 */
360
LoadBSPFile(const char * filename)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
374 /*
375 WriteBSPFile()
376 writes a bsp file
377 */
378
WriteBSPFile(const char * filename)379 void WriteBSPFile( const char *filename ){
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
389 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
390 time( &tm );
391 sprintf( tempname, "%s.%08X", filename, (int) tm );
392
393 /* byteswap, write the bsp, then swap back so it can be manipulated further */
394 SwapBSPFile();
395 game->write( tempname );
396 SwapBSPFile();
397
398 /* replace existing bsp file */
399 remove( filename );
400 rename( tempname, filename );
401 }
402
403
404
405 /*
406 PrintBSPFileSizes()
407 dumps info about current file
408 */
409
PrintBSPFileSizes(void)410 void PrintBSPFileSizes( void ){
411 /* parse entities first */
412 if ( numEntities <= 0 ) {
413 ParseEntities();
414 }
415
416 /* note that this is abstracted */
417 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
418
419 /* print various and sundry bits */
420 Sys_Printf( "%9d models %9d\n",
421 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
422 Sys_Printf( "%9d shaders %9d\n",
423 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
424 Sys_Printf( "%9d brushes %9d\n",
425 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
426 Sys_Printf( "%9d brushsides %9d *\n",
427 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
428 Sys_Printf( "%9d fogs %9d\n",
429 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
430 Sys_Printf( "%9d planes %9d\n",
431 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
432 Sys_Printf( "%9d entdata %9d\n",
433 numEntities, bspEntDataSize );
434 Sys_Printf( "\n" );
435
436 Sys_Printf( "%9d nodes %9d\n",
437 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
438 Sys_Printf( "%9d leafs %9d\n",
439 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
440 Sys_Printf( "%9d leafsurfaces %9d\n",
441 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
442 Sys_Printf( "%9d leafbrushes %9d\n",
443 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
444 Sys_Printf( "\n" );
445
446 Sys_Printf( "%9d drawsurfaces %9d *\n",
447 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
448 Sys_Printf( "%9d drawverts %9d *\n",
449 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
450 Sys_Printf( "%9d drawindexes %9d\n",
451 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
452 Sys_Printf( "\n" );
453
454 Sys_Printf( "%9d lightmaps %9d\n",
455 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
456 Sys_Printf( "%9d lightgrid %9d *\n",
457 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
458 Sys_Printf( " visibility %9d\n",
459 numBSPVisBytes );
460 }
461
462
463
464 /* -------------------------------------------------------------------------------
465
466 entity data handling
467
468 ------------------------------------------------------------------------------- */
469
470
471 /*
472 StripTrailing()
473 strips low byte chars off the end of a string
474 */
475
StripTrailing(char * e)476 void StripTrailing( char *e ){
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
ParseEPair(void)495 epair_t *ParseEPair( void ){
496 epair_t *e;
497
498
499 /* allocate and clear new epair */
500 e = safe_malloc( sizeof( epair_t ) );
501 memset( e, 0, sizeof( epair_t ) );
502
503 /* handle key */
504 if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
505 Error( "ParseEPair: token too long" );
506 }
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 }
515 e->value = copystring( token );
516
517 /* strip trailing spaces that sometimes get accidentally added in the editor */
518 StripTrailing( e->key );
519 StripTrailing( e->value );
520
521 /* return it */
522 return e;
523 }
524
525
526
527 /*
528 ParseEntity()
529 parses an entity's epairs
530 */
531
ParseEntity(void)532 qboolean ParseEntity( void ){
533 epair_t *e;
534
535
536 /* dummy check */
537 if ( !GetToken( qtrue ) ) {
538 return qfalse;
539 }
540 if ( strcmp( token, "{" ) ) {
541 Error( "ParseEntity: { not found" );
542 }
543 AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
544
545 /* create new entity */
546 mapEnt = &entities[ numEntities ];
547 numEntities++;
548 memset( mapEnt, 0, sizeof( *mapEnt ) );
549
550 /* parse */
551 while ( 1 )
552 {
553 if ( !GetToken( qtrue ) ) {
554 Error( "ParseEntity: EOF without closing brace" );
555 }
556 if ( !EPAIR_STRCMP( token, "}" ) ) {
557 break;
558 }
559 e = ParseEPair();
560 e->next = mapEnt->epairs;
561 mapEnt->epairs = e;
562 }
563
564 /* return to sender */
565 return qtrue;
566 }
567
568
569
570 /*
571 ParseEntities()
572 parses the bsp entity data string into entities
573 */
574
ParseEntities(void)575 void ParseEntities( void ){
576 numEntities = 0;
577 ParseFromMemory( bspEntData, bspEntDataSize );
578 while ( ParseEntity() ) ;
579
580 /* ydnar: set number of bsp entities in case a map is loaded on top */
581 numBSPEntities = numEntities;
582 }
583
584 /*
585 * must be called before UnparseEntities
586 */
InjectCommandLine(char ** argv,int beginArgs,int endArgs)587 void InjectCommandLine( char **argv, int beginArgs, int endArgs ){
588 const char *previousCommandLine;
589 char newCommandLine[1024];
590 const char *inpos;
591 char *outpos = newCommandLine;
592 char *sentinel = newCommandLine + sizeof( newCommandLine ) - 1;
593 int i;
594
595 previousCommandLine = ValueForKey( &entities[0], "_q3map2_cmdline" );
596 if ( previousCommandLine && *previousCommandLine ) {
597 inpos = previousCommandLine;
598 while ( outpos != sentinel && *inpos )
599 *outpos++ = *inpos++;
600 if ( outpos != sentinel ) {
601 *outpos++ = ';';
602 }
603 if ( outpos != sentinel ) {
604 *outpos++ = ' ';
605 }
606 }
607
608 for ( i = beginArgs; i < endArgs; ++i )
609 {
610 if ( outpos != sentinel && i != beginArgs ) {
611 *outpos++ = ' ';
612 }
613 inpos = argv[i];
614 while ( outpos != sentinel && *inpos )
615 if ( *inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ' ) {
616 *outpos++ = *inpos++;
617 }
618 }
619
620 *outpos = 0;
621 SetKeyValue( &entities[0], "_q3map2_cmdline", newCommandLine );
622 SetKeyValue( &entities[0], "_q3map2_version", Q3MAP_VERSION );
623 }
624
625 /*
626 UnparseEntities()
627 generates the dentdata string from all the entities.
628 this allows the utilities to add or remove key/value
629 pairs to the data created by the map editor
630 */
631
UnparseEntities(void)632 void UnparseEntities( void ){
633 int i;
634 char *buf, *end;
635 epair_t *ep;
636 char line[ 2048 ];
637 char key[ 1024 ], value[ 1024 ];
638 const char *value2;
639
640
641 /* setup */
642 AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
643 buf = bspEntData;
644 end = buf;
645 *end = 0;
646
647
648 /* run through entity list */
649 for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
650 {
651 {
652 int sz = end - buf;
653 AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
654 buf = bspEntData;
655 end = buf + sz;
656 }
657
658 /* get epair */
659 ep = entities[ i ].epairs;
660 if ( ep == NULL ) {
661 continue; /* ent got removed */
662
663 }
664 /* ydnar: certain entities get stripped from bsp file */
665 value2 = ValueForKey( &entities[ i ], "classname" );
666 if ( !Q_stricmp( value2, "misc_model" ) ||
667 !Q_stricmp( value2, "_decal" ) ||
668 !Q_stricmp( value2, "_skybox" ) ) {
669 continue;
670 }
671
672 /* add beginning brace */
673 strcat( end, "{\n" );
674 end += 2;
675
676 /* walk epair list */
677 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
678 {
679 /* copy and clean */
680 strcpy( key, ep->key );
681 StripTrailing( key );
682 strcpy( value, ep->value );
683 StripTrailing( value );
684
685 /* add to buffer */
686 sprintf( line, "\"%s\" \"%s\"\n", key, value );
687 strcat( end, line );
688 end += strlen( line );
689 }
690
691 /* add trailing brace */
692 strcat( end,"}\n" );
693 end += 2;
694
695 /* check for overflow */
696 if ( end > buf + allocatedBSPEntData ) {
697 Error( "Entity text too long" );
698 }
699 }
700
701 /* set size */
702 bspEntDataSize = end - buf + 1;
703 }
704
705
706
707 /*
708 PrintEntity()
709 prints an entity's epairs to the console
710 */
711
PrintEntity(const entity_t * ent)712 void PrintEntity( const entity_t *ent ){
713 epair_t *ep;
714
715
716 Sys_Printf( "------- entity %p -------\n", ent );
717 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
718 Sys_Printf( "%s = %s\n", ep->key, ep->value );
719
720 }
721
722
723
724 /*
725 SetKeyValue()
726 sets an epair in an entity
727 */
728
SetKeyValue(entity_t * ent,const char * key,const char * value)729 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
730 epair_t *ep;
731
732
733 /* check for existing epair */
734 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
735 {
736 if ( !EPAIR_STRCMP( ep->key, key ) ) {
737 free( ep->value );
738 ep->value = copystring( value );
739 return;
740 }
741 }
742
743 /* create new epair */
744 ep = safe_malloc( sizeof( *ep ) );
745 ep->next = ent->epairs;
746 ent->epairs = ep;
747 ep->key = copystring( key );
748 ep->value = copystring( value );
749 }
750
751 /*
752 KeyExists()
753 returns true if entity has this key
754 */
755
KeyExists(const entity_t * ent,const char * key)756 qboolean KeyExists( const entity_t *ent, const char *key ){
757 epair_t *ep;
758
759 /* walk epair list */
760 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
761 {
762 if ( !EPAIR_STRCMP( ep->key, key ) ) {
763 return qtrue;
764 }
765 }
766
767 /* no match */
768 return qfalse;
769 }
770
771 /*
772 ValueForKey()
773 gets the value for an entity key
774 */
775
ValueForKey(const entity_t * ent,const char * key)776 const char *ValueForKey( const entity_t *ent, const char *key ){
777 epair_t *ep;
778
779
780 /* dummy check */
781 if ( ent == NULL ) {
782 return "";
783 }
784
785 /* walk epair list */
786 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
787 {
788 if ( !EPAIR_STRCMP( ep->key, key ) ) {
789 return ep->value;
790 }
791 }
792
793 /* if no match, return empty string */
794 return "";
795 }
796
797
798
799 /*
800 IntForKey()
801 gets the integer point value for an entity key
802 */
803
IntForKey(const entity_t * ent,const char * key)804 int IntForKey( const entity_t *ent, const char *key ){
805 const char *k;
806
807
808 k = ValueForKey( ent, key );
809 return atoi( k );
810 }
811
812
813
814 /*
815 FloatForKey()
816 gets the floating point value for an entity key
817 */
818
FloatForKey(const entity_t * ent,const char * key)819 vec_t FloatForKey( const entity_t *ent, const char *key ){
820 const char *k;
821
822
823 k = ValueForKey( ent, key );
824 return atof( k );
825 }
826
827
828
829 /*
830 GetVectorForKey()
831 gets a 3-element vector value for an entity key
832 */
833
GetVectorForKey(const entity_t * ent,const char * key,vec3_t vec)834 void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
835 const char *k;
836 double v1, v2, v3;
837
838
839 /* get value */
840 k = ValueForKey( ent, key );
841
842 /* scanf into doubles, then assign, so it is vec_t size independent */
843 v1 = v2 = v3 = 0.0;
844 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
845 vec[ 0 ] = v1;
846 vec[ 1 ] = v2;
847 vec[ 2 ] = v3;
848 }
849
850
851
852 /*
853 FindTargetEntity()
854 finds an entity target
855 */
856
FindTargetEntity(const char * target)857 entity_t *FindTargetEntity( const char *target ){
858 int i;
859 const char *n;
860
861
862 /* walk entity list */
863 for ( i = 0; i < numEntities; i++ )
864 {
865 n = ValueForKey( &entities[ i ], "targetname" );
866 if ( !strcmp( n, target ) ) {
867 return &entities[ i ];
868 }
869 }
870
871 /* nada */
872 return NULL;
873 }
874
875
876
877 /*
878 GetEntityShadowFlags() - ydnar
879 gets an entity's shadow flags
880 note: does not set them to defaults if the keys are not found!
881 */
882
GetEntityShadowFlags(const entity_t * ent,const entity_t * ent2,int * castShadows,int * recvShadows)883 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
884 const char *value;
885
886 /* get cast shadows */
887 if ( castShadows != NULL ) {
888 value = ValueForKey( ent, "_castShadows" );
889 if ( value[ 0 ] == '\0' ) {
890 value = ValueForKey( ent, "_cs" );
891 }
892 if ( value[ 0 ] == '\0' ) {
893 value = ValueForKey( ent2, "_castShadows" );
894 }
895 if ( value[ 0 ] == '\0' ) {
896 value = ValueForKey( ent2, "_cs" );
897 }
898 if ( value[ 0 ] != '\0' ) {
899 *castShadows = atoi( value );
900 }
901 }
902
903 /* receive */
904 if ( recvShadows != NULL ) {
905 value = ValueForKey( ent, "_receiveShadows" );
906 if ( value[ 0 ] == '\0' ) {
907 value = ValueForKey( ent, "_rs" );
908 }
909 if ( value[ 0 ] == '\0' ) {
910 value = ValueForKey( ent2, "_receiveShadows" );
911 }
912 if ( value[ 0 ] == '\0' ) {
913 value = ValueForKey( ent2, "_rs" );
914 }
915 if ( value[ 0 ] != '\0' ) {
916 *recvShadows = atoi( value );
917 }
918 }
919
920 /* vortex: game-specific default eneity keys */
921 value = ValueForKey( ent, "classname" );
922 if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
923 /* vortex: deluxe quake default shadow flags */
924 if ( !Q_stricmp( value, "func_wall" ) ) {
925 if ( recvShadows != NULL ) {
926 *recvShadows = 1;
927 }
928 if ( castShadows != NULL ) {
929 *castShadows = 1;
930 }
931 }
932 }
933 }
934