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;
336 adds a lump to an outgoing bsp file
339 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 + 3) & ~3 );
357 loads a bsp file into memory
360 void LoadBSPFile( const char *filename )
363 if( game == NULL || game->load == NULL )
364 Error( "LoadBSPFile: unsupported BSP file format" );
366 /* load it, then byte swap the in-memory version */
367 game->load( filename );
378 void WriteBSPFile( const char *filename )
380 char tempname[ 1024 ];
385 if( game == NULL || game->write == NULL )
386 Error( "WriteBSPFile: unsupported BSP file format" );
388 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
390 sprintf( tempname, "%s.%08X", filename, (int) tm );
392 /* byteswap, write the bsp, then swap back so it can be manipulated further */
394 game->write( tempname );
397 /* replace existing bsp file */
399 rename( tempname, filename );
406 dumps info about current file
409 void PrintBSPFileSizes( void )
411 /* parse entities first */
412 if( numEntities <= 0 )
415 /* note that this is abstracted */
416 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
418 /* print various and sundry bits */
419 Sys_Printf( "%9d models %9d\n",
420 numBSPModels, (int) (numBSPModels * sizeof( bspModel_t )) );
421 Sys_Printf( "%9d shaders %9d\n",
422 numBSPShaders, (int) (numBSPShaders * sizeof( bspShader_t )) );
423 Sys_Printf( "%9d brushes %9d\n",
424 numBSPBrushes, (int) (numBSPBrushes * sizeof( bspBrush_t )) );
425 Sys_Printf( "%9d brushsides %9d *\n",
426 numBSPBrushSides, (int) (numBSPBrushSides * sizeof( bspBrushSide_t )) );
427 Sys_Printf( "%9d fogs %9d\n",
428 numBSPFogs, (int) (numBSPFogs * sizeof( bspFog_t ) ) );
429 Sys_Printf( "%9d planes %9d\n",
430 numBSPPlanes, (int) (numBSPPlanes * sizeof( bspPlane_t )) );
431 Sys_Printf( "%9d entdata %9d\n",
432 numEntities, bspEntDataSize );
435 Sys_Printf( "%9d nodes %9d\n",
436 numBSPNodes, (int) (numBSPNodes * sizeof( bspNode_t)) );
437 Sys_Printf( "%9d leafs %9d\n",
438 numBSPLeafs, (int) (numBSPLeafs * sizeof( bspLeaf_t )) );
439 Sys_Printf( "%9d leafsurfaces %9d\n",
440 numBSPLeafSurfaces, (int) (numBSPLeafSurfaces * sizeof( *bspLeafSurfaces )) );
441 Sys_Printf( "%9d leafbrushes %9d\n",
442 numBSPLeafBrushes, (int) (numBSPLeafBrushes * sizeof( *bspLeafBrushes )) );
445 Sys_Printf( "%9d drawsurfaces %9d *\n",
446 numBSPDrawSurfaces, (int) (numBSPDrawSurfaces * sizeof( *bspDrawSurfaces )) );
447 Sys_Printf( "%9d drawverts %9d *\n",
448 numBSPDrawVerts, (int) (numBSPDrawVerts * sizeof( *bspDrawVerts )) );
449 Sys_Printf( "%9d drawindexes %9d\n",
450 numBSPDrawIndexes, (int) (numBSPDrawIndexes * sizeof( *bspDrawIndexes )) );
453 Sys_Printf( "%9d lightmaps %9d\n",
454 numBSPLightBytes / (game->lightmapSize * game->lightmapSize * 3), numBSPLightBytes );
455 Sys_Printf( "%9d lightgrid %9d *\n",
456 numBSPGridPoints, (int) (numBSPGridPoints * sizeof( *bspGridPoints )) );
457 Sys_Printf( " visibility %9d\n",
463 /* -------------------------------------------------------------------------------
467 ------------------------------------------------------------------------------- */
472 strips low byte chars off the end of a string
475 void StripTrailing( char *e )
480 s = e + strlen( e ) - 1;
481 while( s >= e && *s <= 32 )
492 parses a single quoted "key" "value" pair into an epair struct
495 epair_t *ParseEPair( void )
500 /* allocate and clear new epair */
501 e = safe_malloc( sizeof( epair_t ) );
502 memset( e, 0, sizeof( epair_t ) );
505 if( strlen( token ) >= (MAX_KEY - 1) )
506 Error( "ParseEPair: token too long" );
508 e->key = copystring( token );
512 if( strlen( token ) >= MAX_VALUE - 1 )
513 Error( "ParseEpar: token too long" );
514 e->value = copystring( token );
516 /* strip trailing spaces that sometimes get accidentally added in the editor */
517 StripTrailing( e->key );
518 StripTrailing( e->value );
528 parses an entity's epairs
531 qboolean ParseEntity( void )
537 if( !GetToken( qtrue ) )
539 if( strcmp( token, "{" ) )
540 Error( "ParseEntity: { not found" );
541 if( numEntities == MAX_MAP_ENTITIES )
542 Error( "numEntities == MAX_MAP_ENTITIES" );
544 /* create new entity */
545 mapEnt = &entities[ numEntities ];
551 if( !GetToken( qtrue ) )
552 Error( "ParseEntity: EOF without closing brace" );
553 if( !EPAIR_STRCMP( token, "}" ) )
556 e->next = mapEnt->epairs;
560 /* return to sender */
568 parses the bsp entity data string into entities
571 void ParseEntities( void )
574 ParseFromMemory( bspEntData, bspEntDataSize );
575 while( ParseEntity() );
577 /* ydnar: set number of bsp entities in case a map is loaded on top */
578 numBSPEntities = numEntities;
582 * must be called before UnparseEntities
584 void InjectCommandLine(char **argv, int beginArgs, int endArgs)
586 const char *previousCommandLine;
587 char newCommandLine[1024];
589 char *outpos = newCommandLine;
590 char *sentinel = newCommandLine + sizeof(newCommandLine) - 1;
593 previousCommandLine = ValueForKey(&entities[0], "_q3map2_cmdline");
594 if(previousCommandLine && *previousCommandLine)
596 inpos = previousCommandLine;
597 while(outpos != sentinel && *inpos)
598 *outpos++ = *inpos++;
599 if(outpos != sentinel)
601 if(outpos != sentinel)
605 for(i = beginArgs; i < endArgs; ++i)
607 if(outpos != sentinel && i != beginArgs)
610 while(outpos != sentinel && *inpos)
611 if(*inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ')
612 *outpos++ = *inpos++;
616 SetKeyValue(&entities[0], "_q3map2_cmdline", newCommandLine);
617 SetKeyValue(&entities[0], "_q3map2_version", Q3MAP_VERSION);
622 generates the dentdata string from all the entities.
623 this allows the utilities to add or remove key/value
624 pairs to the data created by the map editor
627 void UnparseEntities( void )
633 char key[ 1024 ], value[ 1024 ];
642 /* run through entity list */
643 for( i = 0; i < numBSPEntities && i < numEntities; i++ )
646 ep = entities[ i ].epairs;
648 continue; /* ent got removed */
650 /* ydnar: certain entities get stripped from bsp file */
651 value2 = ValueForKey( &entities[ i ], "classname" );
652 if( !Q_stricmp( value2, "misc_model" ) ||
653 !Q_stricmp( value2, "_decal" ) ||
654 !Q_stricmp( value2, "_skybox" ) )
657 /* add beginning brace */
658 strcat( end, "{\n" );
661 /* walk epair list */
662 for( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
665 strcpy( key, ep->key );
666 StripTrailing( key );
667 strcpy( value, ep->value );
668 StripTrailing( value );
671 sprintf( line, "\"%s\" \"%s\"\n", key, value );
673 end += strlen( line );
676 /* add trailing brace */
680 /* check for overflow */
681 if( end > buf + MAX_MAP_ENTSTRING )
682 Error( "Entity text too long" );
686 bspEntDataSize = end - buf + 1;
693 prints an entity's epairs to the console
696 void PrintEntity( const entity_t *ent )
701 Sys_Printf( "------- entity %p -------\n", ent );
702 for( ep = ent->epairs; ep != NULL; ep = ep->next )
703 Sys_Printf( "%s = %s\n", ep->key, ep->value );
711 sets an epair in an entity
714 void SetKeyValue( entity_t *ent, const char *key, const char *value )
719 /* check for existing epair */
720 for( ep = ent->epairs; ep != NULL; ep = ep->next )
722 if( !EPAIR_STRCMP( ep->key, key ) )
725 ep->value = copystring( value );
730 /* create new epair */
731 ep = safe_malloc( sizeof( *ep ) );
732 ep->next = ent->epairs;
734 ep->key = copystring( key );
735 ep->value = copystring( value );
742 gets the value for an entity key
745 const char *ValueForKey( const entity_t *ent, const char *key )
754 /* walk epair list */
755 for( ep = ent->epairs; ep != NULL; ep = ep->next )
757 if( !EPAIR_STRCMP( ep->key, key ) )
761 /* if no match, return empty string */
769 gets the integer point value for an entity key
772 int IntForKey( const entity_t *ent, const char *key )
777 k = ValueForKey( ent, key );
785 gets the floating point value for an entity key
788 vec_t FloatForKey( const entity_t *ent, const char *key )
793 k = ValueForKey( ent, key );
801 gets a 3-element vector value for an entity key
804 void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec )
811 k = ValueForKey( ent, key );
813 /* scanf into doubles, then assign, so it is vec_t size independent */
815 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
825 finds an entity target
828 entity_t *FindTargetEntity( const char *target )
834 /* walk entity list */
835 for( i = 0; i < numEntities; i++ )
837 n = ValueForKey( &entities[ i ], "targetname" );
838 if ( !strcmp( n, target ) )
839 return &entities[ i ];
849 GetEntityShadowFlags() - ydnar
850 gets an entity's shadow flags
851 note: does not set them to defaults if the keys are not found!
854 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows )
859 /* get cast shadows */
860 if( castShadows != NULL )
862 value = ValueForKey( ent, "_castShadows" );
863 if( value[ 0 ] == '\0' )
864 value = ValueForKey( ent, "_cs" );
865 if( value[ 0 ] == '\0' )
866 value = ValueForKey( ent2, "_castShadows" );
867 if( value[ 0 ] == '\0' )
868 value = ValueForKey( ent2, "_cs" );
869 if( value[ 0 ] != '\0' )
870 *castShadows = atoi( value );
874 if( recvShadows != NULL )
876 value = ValueForKey( ent, "_receiveShadows" );
877 if( value[ 0 ] == '\0' )
878 value = ValueForKey( ent, "_rs" );
879 if( value[ 0 ] == '\0' )
880 value = ValueForKey( ent2, "_receiveShadows" );
881 if( value[ 0 ] == '\0' )
882 value = ValueForKey( ent2, "_rs" );
883 if( value[ 0 ] != '\0' )
884 *recvShadows = atoi( value );