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;
64 if ( bspDrawVerts == 0 ) {
65 numBSPDrawVertsBuffer = 1024;
67 bspDrawVerts = safe_malloc_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
70 else if ( numBSPDrawVerts > numBSPDrawVertsBuffer ) {
71 numBSPDrawVertsBuffer *= 3; // multiply by 1.5
72 numBSPDrawVertsBuffer /= 2;
74 bspDrawVerts = realloc( bspDrawVerts, sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer );
76 if ( !bspDrawVerts ) {
77 Error( "realloc() failed (IncDrawVerts)" );
81 memset( bspDrawVerts + ( numBSPDrawVerts - 1 ), 0, sizeof( bspDrawVert_t ) );
84 void SetDrawVerts( int n ){
85 if ( bspDrawVerts != 0 ) {
90 numBSPDrawVertsBuffer = numBSPDrawVerts;
92 bspDrawVerts = safe_malloc_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
94 memset( bspDrawVerts, 0, n * sizeof( bspDrawVert_t ) );
97 int numBSPDrawSurfacesBuffer = 0;
98 void SetDrawSurfacesBuffer(){
99 if ( bspDrawSurfaces != 0 ) {
100 free( bspDrawSurfaces );
103 numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
105 bspDrawSurfaces = safe_malloc_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
107 memset( bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof( bspDrawSurface_t ) );
110 void SetDrawSurfaces( int n ){
111 if ( bspDrawSurfaces != 0 ) {
112 free( bspDrawSurfaces );
115 numBSPDrawSurfaces = n;
116 numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
118 bspDrawSurfaces = safe_malloc_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
120 memset( bspDrawSurfaces, 0, n * sizeof( bspDrawSurface_t ) );
123 void BSPFilesCleanup(){
124 if ( bspDrawVerts != 0 ) {
125 free( bspDrawVerts );
127 if ( bspDrawSurfaces != 0 ) {
128 free( bspDrawSurfaces );
130 if ( bspLightBytes != 0 ) {
131 free( bspLightBytes );
133 if ( bspGridPoints != 0 ) {
134 free( bspGridPoints );
145 if all values are 32 bits, this can be used to swap everything
148 void SwapBlock( int *block, int size ){
153 if ( block == NULL ) {
159 for ( i = 0; i < size; i++ )
160 block[ i ] = LittleLong( block[ i ] );
167 byte swaps all data in the abstract bsp
170 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 ){
268 /* check for odd size */
269 if ( header->lumps[ lump ].length % size ) {
271 Sys_FPrintf( SYS_WRN, "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
275 Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
279 /* return element count */
280 return header->lumps[ lump ].length / size;
287 returns a pointer to the specified lump
290 void *GetLump( bspHeader_t *header, int lump ){
291 return (void*)( (byte*) header + header->lumps[ lump ].offset );
298 copies a bsp file lump into a destination buffer
301 int CopyLump( bspHeader_t *header, int lump, void *dest, int size ){
305 /* get lump length and offset */
306 length = header->lumps[ lump ].length;
307 offset = header->lumps[ lump ].offset;
309 /* handle erroneous cases */
313 if ( length % size ) {
315 Sys_FPrintf( SYS_WRN, "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
319 Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
323 /* copy block of memory and return */
324 memcpy( dest, (byte*) header + offset, length );
325 return length / size;
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 );
338 adds a lump to an outgoing bsp file
341 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
344 /* add lump to bsp file header */
345 lump = &header->lumps[ lumpNum ];
346 lump->offset = LittleLong( ftell( file ) );
347 lump->length = LittleLong( length );
349 /* write lump to file */
350 SafeWrite( file, data, length );
352 /* write padding zeros */
353 char *zeros[3] = { 0, 0, 0 };
354 SafeWrite( file, zeros, ( ( length + 3 ) & ~3 ) - length );
361 loads a bsp file into memory
364 void LoadBSPFile( const char *filename ){
366 if ( game == NULL || game->load == NULL ) {
367 Error( "LoadBSPFile: unsupported BSP file format" );
370 /* load it, then byte swap the in-memory version */
371 game->load( filename );
382 void WriteBSPFile( const char *filename ){
383 char tempname[ 1024 ];
388 if ( game == NULL || game->write == NULL ) {
389 Error( "WriteBSPFile: unsupported BSP file format" );
392 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
394 sprintf( tempname, "%s.%08X", filename, (int) tm );
396 /* byteswap, write the bsp, then swap back so it can be manipulated further */
398 game->write( tempname );
401 /* replace existing bsp file */
403 rename( tempname, filename );
410 dumps info about current file
413 void PrintBSPFileSizes( void ){
414 /* parse entities first */
415 if ( numEntities <= 0 ) {
419 /* note that this is abstracted */
420 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
422 /* print various and sundry bits */
423 Sys_Printf( "%9d models %9d\n",
424 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
425 Sys_Printf( "%9d shaders %9d\n",
426 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
427 Sys_Printf( "%9d brushes %9d\n",
428 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
429 Sys_Printf( "%9d brushsides %9d *\n",
430 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
431 Sys_Printf( "%9d fogs %9d\n",
432 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
433 Sys_Printf( "%9d planes %9d\n",
434 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
435 Sys_Printf( "%9d entdata %9d\n",
436 numEntities, bspEntDataSize );
439 Sys_Printf( "%9d nodes %9d\n",
440 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
441 Sys_Printf( "%9d leafs %9d\n",
442 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
443 Sys_Printf( "%9d leafsurfaces %9d\n",
444 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
445 Sys_Printf( "%9d leafbrushes %9d\n",
446 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
449 Sys_Printf( "%9d drawsurfaces %9d *\n",
450 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
451 Sys_Printf( "%9d drawverts %9d *\n",
452 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
453 Sys_Printf( "%9d drawindexes %9d\n",
454 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
457 Sys_Printf( "%9d lightmaps %9d\n",
458 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
459 Sys_Printf( "%9d lightgrid %9d *\n",
460 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
461 Sys_Printf( " visibility %9d\n",
467 /* -------------------------------------------------------------------------------
471 ------------------------------------------------------------------------------- */
476 strips low byte chars off the end of a string
479 void StripTrailing( char *e ){
483 s = e + strlen( e ) - 1;
484 while ( s >= e && *s <= 32 )
495 parses a single quoted "key" "value" pair into an epair struct
498 epair_t *ParseEPair( void ){
502 /* allocate and clear new epair */
503 e = safe_malloc( sizeof( epair_t ) );
504 memset( e, 0, sizeof( epair_t ) );
507 if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
508 Error( "ParseEPair: token too long" );
511 e->key = copystring( token );
515 if ( strlen( token ) >= MAX_VALUE - 1 ) {
516 Error( "ParseEpar: token too long" );
518 e->value = copystring( token );
520 /* strip trailing spaces that sometimes get accidentally added in the editor */
521 StripTrailing( e->key );
522 StripTrailing( e->value );
532 parses an entity's epairs
535 qboolean ParseEntity( void ){
540 if ( !GetToken( qtrue ) ) {
543 if ( strcmp( token, "{" ) ) {
544 Error( "ParseEntity: { not found" );
546 AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
548 /* create new entity */
549 mapEnt = &entities[ numEntities ];
551 memset( mapEnt, 0, sizeof( *mapEnt ) );
556 if ( !GetToken( qtrue ) ) {
557 Error( "ParseEntity: EOF without closing brace" );
559 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 ){
580 ParseFromMemory( bspEntData, bspEntDataSize );
581 while ( ParseEntity() ) ;
583 /* ydnar: set number of bsp entities in case a map is loaded on top */
584 numBSPEntities = numEntities;
590 * must be called before UnparseEntities
592 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 ) {
602 inpos = previousCommandLine;
603 while ( outpos != sentinel && *inpos )
604 *outpos++ = *inpos++;
605 if ( outpos != sentinel ) {
608 if ( outpos != sentinel ) {
613 for ( i = beginArgs; i < endArgs; ++i )
615 if ( outpos != sentinel && i != beginArgs ) {
619 while ( outpos != sentinel && *inpos )
620 if ( *inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ' ) {
621 *outpos++ = *inpos++;
626 SetKeyValue( &entities[0], "_q3map2_cmdline", newCommandLine );
627 SetKeyValue( &entities[0], "_q3map2_version", Q3MAP_VERSION );
634 generates the dentdata string from all the entities.
635 this allows the utilities to add or remove key/value
636 pairs to the data created by the map editor
639 void UnparseEntities( void ){
644 char key[ 1024 ], value[ 1024 ];
649 AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
655 /* run through entity list */
656 for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
660 AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
666 ep = entities[ i ].epairs;
668 continue; /* ent got removed */
671 /* ydnar: certain entities get stripped from bsp file */
672 value2 = ValueForKey( &entities[ i ], "classname" );
673 if ( !Q_stricmp( value2, "misc_model" ) ||
674 !Q_stricmp( value2, "_decal" ) ||
675 !Q_stricmp( value2, "_skybox" ) ) {
679 /* add beginning brace */
680 strcat( end, "{\n" );
683 /* walk epair list */
684 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
687 strcpy( key, ep->key );
688 StripTrailing( key );
689 strcpy( value, ep->value );
690 StripTrailing( value );
693 sprintf( line, "\"%s\" \"%s\"\n", key, value );
695 end += strlen( line );
698 /* add trailing brace */
702 /* check for overflow */
703 if ( end > buf + allocatedBSPEntData ) {
704 Error( "Entity text too long" );
709 bspEntDataSize = end - buf + 1;
716 prints an entity's epairs to the console
719 void PrintEntity( const entity_t *ent ){
723 Sys_Printf( "------- entity %p -------\n", ent );
724 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
725 Sys_Printf( "%s = %s\n", ep->key, ep->value );
733 sets an epair in an entity
736 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
740 /* check for existing epair */
741 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
743 if ( !EPAIR_STRCMP( ep->key, key ) ) {
745 ep->value = copystring( value );
750 /* create new epair */
751 ep = safe_malloc( sizeof( *ep ) );
752 ep->next = ent->epairs;
754 ep->key = copystring( key );
755 ep->value = copystring( value );
762 returns true if entity has this key
765 qboolean KeyExists( const entity_t *ent, const char *key ){
768 /* walk epair list */
769 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
771 if ( !EPAIR_STRCMP( ep->key, key ) ) {
784 gets the value for an entity key
787 const char *ValueForKey( const entity_t *ent, const char *key ){
796 /* walk epair list */
797 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
799 if ( !EPAIR_STRCMP( ep->key, key ) ) {
804 /* if no match, return empty string */
812 gets the integer point value for an entity key
815 int IntForKey( const entity_t *ent, const char *key ){
819 k = ValueForKey( ent, key );
827 gets the floating point value for an entity key
830 vec_t FloatForKey( const entity_t *ent, const char *key ){
834 k = ValueForKey( ent, key );
842 gets a 3-element vector value for an entity key
845 qboolean GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
851 k = ValueForKey( ent, key );
853 /* scanf into doubles, then assign, so it is vec_t size independent */
855 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
860 /* true if the key is found, false otherwise */
868 finds an entity target
871 entity_t *FindTargetEntity( const char *target ){
876 /* walk entity list */
877 for ( i = 0; i < numEntities; i++ )
879 n = ValueForKey( &entities[ i ], "targetname" );
880 if ( !strcmp( n, target ) ) {
881 return &entities[ i ];
892 GetEntityShadowFlags() - ydnar
893 gets an entity's shadow flags
894 note: does not set them to defaults if the keys are not found!
897 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
900 /* get cast shadows */
901 if ( castShadows != NULL ) {
902 value = ValueForKey( ent, "_castShadows" );
903 if ( value[ 0 ] == '\0' ) {
904 value = ValueForKey( ent, "_cs" );
906 if ( value[ 0 ] == '\0' ) {
907 value = ValueForKey( ent2, "_castShadows" );
909 if ( value[ 0 ] == '\0' ) {
910 value = ValueForKey( ent2, "_cs" );
912 if ( value[ 0 ] != '\0' ) {
913 *castShadows = atoi( value );
918 if ( recvShadows != NULL ) {
919 value = ValueForKey( ent, "_receiveShadows" );
920 if ( value[ 0 ] == '\0' ) {
921 value = ValueForKey( ent, "_rs" );
923 if ( value[ 0 ] == '\0' ) {
924 value = ValueForKey( ent2, "_receiveShadows" );
926 if ( value[ 0 ] == '\0' ) {
927 value = ValueForKey( ent2, "_rs" );
929 if ( value[ 0 ] != '\0' ) {
930 *recvShadows = atoi( value );
934 /* vortex: game-specific default eneity keys */
935 value = ValueForKey( ent, "classname" );
936 if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
937 /* vortex: deluxe quake default shadow flags */
938 if ( !Q_stricmp( value, "func_wall" ) ) {
939 if ( recvShadows != NULL ) {
942 if ( castShadows != NULL ) {