1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
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.
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.
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
22 ----------------------------------------------------------------------------------
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."
27 ------------------------------------------------------------------------------- */
32 #define BSPFILE_ABSTRACT_C
42 /* -------------------------------------------------------------------------------
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.
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.
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.
54 ------------------------------------------------------------------------------- */
58 /* FIXME: remove the functions below that handle memory management of bsp file chunks */
60 int numBSPDrawVertsBuffer = 0;
67 numBSPDrawVertsBuffer = 1024;
69 bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");
72 else if(numBSPDrawVerts > numBSPDrawVertsBuffer)
74 numBSPDrawVertsBuffer *= 3; // multiply by 1.5
75 numBSPDrawVertsBuffer /= 2;
77 bspDrawVerts = realloc(bspDrawVerts, sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer);
80 Error( "realloc() failed (IncDrawVerts)");
83 memset(bspDrawVerts + (numBSPDrawVerts - 1), 0, sizeof(bspDrawVert_t));
86 void SetDrawVerts(int n)
92 numBSPDrawVertsBuffer = numBSPDrawVerts;
94 bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");
96 memset(bspDrawVerts, 0, n * sizeof(bspDrawVert_t));
99 int numBSPDrawSurfacesBuffer = 0;
100 void SetDrawSurfacesBuffer()
102 if(bspDrawSurfaces != 0)
103 free(bspDrawSurfaces);
105 numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
107 bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");
109 memset(bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof(bspDrawVert_t));
112 void SetDrawSurfaces(int n)
114 if(bspDrawSurfaces != 0)
115 free(bspDrawSurfaces);
117 numBSPDrawSurfaces = n;
118 numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
120 bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");
122 memset(bspDrawSurfaces, 0, n * sizeof(bspDrawVert_t));
125 void BSPFilesCleanup()
127 if(bspDrawVerts != 0)
129 if(bspDrawSurfaces != 0)
130 free(bspDrawSurfaces);
131 if(bspLightBytes != 0)
133 if(bspGridPoints != 0)
144 if all values are 32 bits, this can be used to swap everything
147 void SwapBlock( int *block, int size )
158 for( i = 0; i < size; i++ )
159 block[ i ] = LittleLong( block[ i ] );
166 byte swaps all data in the abstract bsp
169 void SwapBSPFile( void )
175 SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) );
177 /* shaders (don't swap the name) */
178 for( i = 0; i < numBSPShaders ; i++ )
180 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
181 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
185 SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
188 SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
191 SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
194 SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
197 SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
200 SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
203 SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
206 ((int*) &bspVisBytes)[ 0 ] = LittleLong( ((int*) &bspVisBytes)[ 0 ] );
207 ((int*) &bspVisBytes)[ 1 ] = LittleLong( ((int*) &bspVisBytes)[ 1 ] );
209 /* drawverts (don't swap colors) */
210 for( i = 0; i < numBSPDrawVerts; i++ )
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++ )
222 bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
223 bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
228 SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
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 ] ) );
235 for( i = 0; i < numBSPFogs; i++ )
237 bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
238 bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
242 for( i = 0; i < numBSPAds; i++ )
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 ] );
249 for( j = 0; j < 4; j++ )
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 ] );
256 //bspAds[ i ].model[ MAX_QPATH ];
264 gets the number of elements in a bsp lump
267 int GetLumpElements( bspHeader_t *header, int lump, int size )
269 /* check for odd size */
270 if( header->lumps[ lump ].length % size )
274 Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
278 Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
281 /* return element count */
282 return header->lumps[ lump ].length / size;
289 returns a pointer to the specified lump
292 void *GetLump( bspHeader_t *header, int lump )
294 return (void*)( (byte*) header + header->lumps[ lump ].offset);
301 copies a bsp file lump into a destination buffer
304 int CopyLump( bspHeader_t *header, int lump, void *dest, int size )
309 /* get lump length and offset */
310 length = header->lumps[ lump ].length;
311 offset = header->lumps[ lump ].offset;
313 /* handle erroneous cases */
320 Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
324 Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
327 /* copy block of memory and return */
328 memcpy( dest, (byte*) header + offset, length );
329 return length / size;
332 int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable )
334 /* get lump length and offset */
335 *allocationVariable = header->lumps[ lump ].length / size;
336 *dest = realloc(*dest, size * *allocationVariable);
337 return CopyLump(header, lump, *dest, size);
343 adds a lump to an outgoing bsp file
346 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length )
351 /* add lump to bsp file header */
352 lump = &header->lumps[ lumpNum ];
353 lump->offset = LittleLong( ftell( file ) );
354 lump->length = LittleLong( length );
356 /* write lump to file */
357 SafeWrite( file, data, (length + 3) & ~3 );
364 loads a bsp file into memory
367 void LoadBSPFile( const char *filename )
370 if( game == NULL || game->load == NULL )
371 Error( "LoadBSPFile: unsupported BSP file format" );
373 /* load it, then byte swap the in-memory version */
374 game->load( filename );
385 void WriteBSPFile( const char *filename )
387 char tempname[ 1024 ];
392 if( game == NULL || game->write == NULL )
393 Error( "WriteBSPFile: unsupported BSP file format" );
395 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
397 sprintf( tempname, "%s.%08X", filename, (int) tm );
399 /* byteswap, write the bsp, then swap back so it can be manipulated further */
401 game->write( tempname );
404 /* replace existing bsp file */
406 rename( tempname, filename );
413 dumps info about current file
416 void PrintBSPFileSizes( void )
418 /* parse entities first */
419 if( numEntities <= 0 )
422 /* note that this is abstracted */
423 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
425 /* print various and sundry bits */
426 Sys_Printf( "%9d models %9d\n",
427 numBSPModels, (int) (numBSPModels * sizeof( bspModel_t )) );
428 Sys_Printf( "%9d shaders %9d\n",
429 numBSPShaders, (int) (numBSPShaders * sizeof( bspShader_t )) );
430 Sys_Printf( "%9d brushes %9d\n",
431 numBSPBrushes, (int) (numBSPBrushes * sizeof( bspBrush_t )) );
432 Sys_Printf( "%9d brushsides %9d *\n",
433 numBSPBrushSides, (int) (numBSPBrushSides * sizeof( bspBrushSide_t )) );
434 Sys_Printf( "%9d fogs %9d\n",
435 numBSPFogs, (int) (numBSPFogs * sizeof( bspFog_t ) ) );
436 Sys_Printf( "%9d planes %9d\n",
437 numBSPPlanes, (int) (numBSPPlanes * sizeof( bspPlane_t )) );
438 Sys_Printf( "%9d entdata %9d\n",
439 numEntities, bspEntDataSize );
442 Sys_Printf( "%9d nodes %9d\n",
443 numBSPNodes, (int) (numBSPNodes * sizeof( bspNode_t)) );
444 Sys_Printf( "%9d leafs %9d\n",
445 numBSPLeafs, (int) (numBSPLeafs * sizeof( bspLeaf_t )) );
446 Sys_Printf( "%9d leafsurfaces %9d\n",
447 numBSPLeafSurfaces, (int) (numBSPLeafSurfaces * sizeof( *bspLeafSurfaces )) );
448 Sys_Printf( "%9d leafbrushes %9d\n",
449 numBSPLeafBrushes, (int) (numBSPLeafBrushes * sizeof( *bspLeafBrushes )) );
452 Sys_Printf( "%9d drawsurfaces %9d *\n",
453 numBSPDrawSurfaces, (int) (numBSPDrawSurfaces * sizeof( *bspDrawSurfaces )) );
454 Sys_Printf( "%9d drawverts %9d *\n",
455 numBSPDrawVerts, (int) (numBSPDrawVerts * sizeof( *bspDrawVerts )) );
456 Sys_Printf( "%9d drawindexes %9d\n",
457 numBSPDrawIndexes, (int) (numBSPDrawIndexes * sizeof( *bspDrawIndexes )) );
460 Sys_Printf( "%9d lightmaps %9d\n",
461 numBSPLightBytes / (game->lightmapSize * game->lightmapSize * 3), numBSPLightBytes );
462 Sys_Printf( "%9d lightgrid %9d *\n",
463 numBSPGridPoints, (int) (numBSPGridPoints * sizeof( *bspGridPoints )) );
464 Sys_Printf( " visibility %9d\n",
470 /* -------------------------------------------------------------------------------
474 ------------------------------------------------------------------------------- */
479 strips low byte chars off the end of a string
482 void StripTrailing( char *e )
487 s = e + strlen( e ) - 1;
488 while( s >= e && *s <= 32 )
499 parses a single quoted "key" "value" pair into an epair struct
502 epair_t *ParseEPair( void )
507 /* allocate and clear new epair */
508 e = safe_malloc( sizeof( epair_t ) );
509 memset( e, 0, sizeof( epair_t ) );
512 if( strlen( token ) >= (MAX_KEY - 1) )
513 Error( "ParseEPair: token too long" );
515 e->key = copystring( token );
519 if( strlen( token ) >= MAX_VALUE - 1 )
520 Error( "ParseEpar: token too long" );
521 e->value = copystring( token );
523 /* strip trailing spaces that sometimes get accidentally added in the editor */
524 StripTrailing( e->key );
525 StripTrailing( e->value );
535 parses an entity's epairs
538 qboolean ParseEntity( void )
544 if( !GetToken( qtrue ) )
546 if( strcmp( token, "{" ) )
547 Error( "ParseEntity: { not found" );
548 AUTOEXPAND_BY_REALLOC(entities, numEntities, allocatedEntities, 32);
550 /* create new entity */
551 mapEnt = &entities[ numEntities ];
553 memset( mapEnt, 0, sizeof( *mapEnt ) );
558 if( !GetToken( qtrue ) )
559 Error( "ParseEntity: EOF without closing brace" );
560 if( !EPAIR_STRCMP( token, "}" ) )
563 e->next = mapEnt->epairs;
567 /* return to sender */
575 parses the bsp entity data string into entities
578 void ParseEntities( void )
581 ParseFromMemory( bspEntData, bspEntDataSize );
582 while( ParseEntity() );
584 /* ydnar: set number of bsp entities in case a map is loaded on top */
585 numBSPEntities = numEntities;
589 * must be called before UnparseEntities
591 void InjectCommandLine(char **argv, int beginArgs, int endArgs)
593 const char *previousCommandLine;
594 char newCommandLine[1024];
596 char *outpos = newCommandLine;
597 char *sentinel = newCommandLine + sizeof(newCommandLine) - 1;
600 previousCommandLine = ValueForKey(&entities[0], "_q3map2_cmdline");
601 if(previousCommandLine && *previousCommandLine)
603 inpos = previousCommandLine;
604 while(outpos != sentinel && *inpos)
605 *outpos++ = *inpos++;
606 if(outpos != sentinel)
608 if(outpos != sentinel)
612 for(i = beginArgs; i < endArgs; ++i)
614 if(outpos != sentinel && i != beginArgs)
617 while(outpos != sentinel && *inpos)
618 if(*inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ')
619 *outpos++ = *inpos++;
623 SetKeyValue(&entities[0], "_q3map2_cmdline", newCommandLine);
624 SetKeyValue(&entities[0], "_q3map2_version", Q3MAP_VERSION);
629 generates the dentdata string from all the entities.
630 this allows the utilities to add or remove key/value
631 pairs to the data created by the map editor
634 void UnparseEntities( void )
640 char key[ 1024 ], value[ 1024 ];
645 AUTOEXPAND_BY_REALLOC(bspEntData, 0, allocatedBSPEntData, 1024);
651 /* run through entity list */
652 for( i = 0; i < numBSPEntities && i < numEntities; i++ )
656 AUTOEXPAND_BY_REALLOC(bspEntData, sz + 65536, allocatedBSPEntData, 1024);
662 ep = entities[ i ].epairs;
664 continue; /* ent got removed */
666 /* ydnar: certain entities get stripped from bsp file */
667 value2 = ValueForKey( &entities[ i ], "classname" );
668 if( !Q_stricmp( value2, "misc_model" ) ||
669 !Q_stricmp( value2, "_decal" ) ||
670 !Q_stricmp( value2, "_skybox" ) )
673 /* add beginning brace */
674 strcat( end, "{\n" );
677 /* walk epair list */
678 for( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
681 strcpy( key, ep->key );
682 StripTrailing( key );
683 strcpy( value, ep->value );
684 StripTrailing( value );
687 sprintf( line, "\"%s\" \"%s\"\n", key, value );
689 end += strlen( line );
692 /* add trailing brace */
696 /* check for overflow */
697 if( end > buf + allocatedBSPEntData )
698 Error( "Entity text too long" );
702 bspEntDataSize = end - buf + 1;
709 prints an entity's epairs to the console
712 void PrintEntity( const entity_t *ent )
717 Sys_Printf( "------- entity %p -------\n", ent );
718 for( ep = ent->epairs; ep != NULL; ep = ep->next )
719 Sys_Printf( "%s = %s\n", ep->key, ep->value );
727 sets an epair in an entity
730 void SetKeyValue( entity_t *ent, const char *key, const char *value )
735 /* check for existing epair */
736 for( ep = ent->epairs; ep != NULL; ep = ep->next )
738 if( !EPAIR_STRCMP( ep->key, key ) )
741 ep->value = copystring( value );
746 /* create new epair */
747 ep = safe_malloc( sizeof( *ep ) );
748 ep->next = ent->epairs;
750 ep->key = copystring( key );
751 ep->value = copystring( value );
756 returns true if entity has this key
759 qboolean KeyExists( const entity_t *ent, const char *key )
763 /* walk epair list */
764 for( ep = ent->epairs; ep != NULL; ep = ep->next )
766 if( !EPAIR_STRCMP( ep->key, key ) )
776 gets the value for an entity key
779 const char *ValueForKey( const entity_t *ent, const char *key )
788 /* walk epair list */
789 for( ep = ent->epairs; ep != NULL; ep = ep->next )
791 if( !EPAIR_STRCMP( ep->key, key ) )
795 /* if no match, return empty string */
803 gets the integer point value for an entity key
806 int IntForKey( const entity_t *ent, const char *key )
811 k = ValueForKey( ent, key );
819 gets the floating point value for an entity key
822 vec_t FloatForKey( const entity_t *ent, const char *key )
827 k = ValueForKey( ent, key );
835 gets a 3-element vector value for an entity key
838 void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec )
845 k = ValueForKey( ent, key );
847 /* scanf into doubles, then assign, so it is vec_t size independent */
849 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
859 finds an entity target
862 entity_t *FindTargetEntity( const char *target )
868 /* walk entity list */
869 for( i = 0; i < numEntities; i++ )
871 n = ValueForKey( &entities[ i ], "targetname" );
872 if ( !strcmp( n, target ) )
873 return &entities[ i ];
883 GetEntityShadowFlags() - ydnar
884 gets an entity's shadow flags
885 note: does not set them to defaults if the keys are not found!
888 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows )
892 /* get cast shadows */
893 if( castShadows != NULL )
895 value = ValueForKey( ent, "_castShadows" );
896 if( value[ 0 ] == '\0' )
897 value = ValueForKey( ent, "_cs" );
898 if( value[ 0 ] == '\0' )
899 value = ValueForKey( ent2, "_castShadows" );
900 if( value[ 0 ] == '\0' )
901 value = ValueForKey( ent2, "_cs" );
902 if( value[ 0 ] != '\0' )
903 *castShadows = atoi( value );
907 if( recvShadows != NULL )
909 value = ValueForKey( ent, "_receiveShadows" );
910 if( value[ 0 ] == '\0' )
911 value = ValueForKey( ent, "_rs" );
912 if( value[ 0 ] == '\0' )
913 value = ValueForKey( ent2, "_receiveShadows" );
914 if( value[ 0 ] == '\0' )
915 value = ValueForKey( ent2, "_rs" );
916 if( value[ 0 ] != '\0' )
917 *recvShadows = atoi( value );
920 /* vortex: game-specific default eneity keys */
921 value = ValueForKey( ent, "classname" );
922 if (!Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) )
924 /* vortex: deluxe quake default shadow flags */
925 if (!Q_stricmp( value, "func_wall" ) )
927 if( recvShadows != NULL )
929 if( castShadows != NULL )