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_malloc0_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
95 int numBSPDrawSurfacesBuffer = 0;
96 void SetDrawSurfacesBuffer(){
97 if ( bspDrawSurfaces != 0 ) {
98 free( bspDrawSurfaces );
101 numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
103 bspDrawSurfaces = safe_malloc0_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
106 void SetDrawSurfaces( int n ){
107 if ( bspDrawSurfaces != 0 ) {
108 free( bspDrawSurfaces );
111 numBSPDrawSurfaces = n;
112 numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
114 bspDrawSurfaces = safe_malloc0_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
117 void BSPFilesCleanup(){
118 if ( bspDrawVerts != 0 ) {
119 free( bspDrawVerts );
121 if ( bspDrawSurfaces != 0 ) {
122 free( bspDrawSurfaces );
124 if ( bspLightBytes != 0 ) {
125 free( bspLightBytes );
127 if ( bspGridPoints != 0 ) {
128 free( bspGridPoints );
139 if all values are 32 bits, this can be used to swap everything
142 void SwapBlock( int *block, int size ){
147 if ( block == NULL ) {
153 for ( i = 0; i < size; i++ )
154 block[ i ] = LittleLong( block[ i ] );
161 byte swaps all data in the abstract bsp
164 void SwapBSPFile( void ){
169 SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) );
171 /* shaders (don't swap the name) */
172 for ( i = 0; i < numBSPShaders ; i++ )
174 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
175 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
179 SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
182 SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
185 SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
188 SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
191 SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
194 SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
197 SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
200 ( (int*) &bspVisBytes )[ 0 ] = LittleLong( ( (int*) &bspVisBytes )[ 0 ] );
201 ( (int*) &bspVisBytes )[ 1 ] = LittleLong( ( (int*) &bspVisBytes )[ 1 ] );
203 /* drawverts (don't swap colors) */
204 for ( i = 0; i < numBSPDrawVerts; i++ )
206 bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
207 bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
208 bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
209 bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
210 bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
211 bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
212 bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
213 bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
214 for ( j = 0; j < MAX_LIGHTMAPS; j++ )
216 bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
217 bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
222 SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
225 /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
226 SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
229 for ( i = 0; i < numBSPFogs; i++ )
231 bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
232 bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
236 for ( i = 0; i < numBSPAds; i++ )
238 bspAds[ i ].cellId = LittleLong( bspAds[ i ].cellId );
239 bspAds[ i ].normal[ 0 ] = LittleFloat( bspAds[ i ].normal[ 0 ] );
240 bspAds[ i ].normal[ 1 ] = LittleFloat( bspAds[ i ].normal[ 1 ] );
241 bspAds[ i ].normal[ 2 ] = LittleFloat( bspAds[ i ].normal[ 2 ] );
243 for ( j = 0; j < 4; j++ )
245 bspAds[ i ].rect[j][ 0 ] = LittleFloat( bspAds[ i ].rect[j][ 0 ] );
246 bspAds[ i ].rect[j][ 1 ] = LittleFloat( bspAds[ i ].rect[j][ 1 ] );
247 bspAds[ i ].rect[j][ 2 ] = LittleFloat( bspAds[ i ].rect[j][ 2 ] );
250 //bspAds[ i ].model[ MAX_QPATH ];
258 gets the number of elements in a bsp lump
261 int GetLumpElements( bspHeader_t *header, int lump, int size ){
262 /* check for odd size */
263 if ( header->lumps[ lump ].length % size ) {
265 Sys_FPrintf( SYS_WRN, "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
269 Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
273 /* return element count */
274 return header->lumps[ lump ].length / size;
281 returns a pointer to the specified lump
284 void *GetLump( bspHeader_t *header, int lump ){
285 return (void*)( (byte*) header + header->lumps[ lump ].offset );
292 copies a bsp file lump into a destination buffer
295 int CopyLump( bspHeader_t *header, int lump, void *dest, int size ){
299 /* get lump length and offset */
300 length = header->lumps[ lump ].length;
301 offset = header->lumps[ lump ].offset;
303 /* handle erroneous cases */
307 if ( length % size ) {
309 Sys_FPrintf( SYS_WRN, "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
313 Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
317 /* copy block of memory and return */
318 memcpy( dest, (byte*) header + offset, length );
319 return length / size;
322 int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable ){
323 /* get lump length and offset */
324 *allocationVariable = header->lumps[ lump ].length / size;
325 *dest = realloc( *dest, size * *allocationVariable );
326 return CopyLump( header, lump, *dest, size );
332 adds a lump to an outgoing bsp file
335 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
338 /* add lump to bsp file header */
339 lump = &header->lumps[ lumpNum ];
340 lump->offset = LittleLong( ftell( file ) );
341 lump->length = LittleLong( length );
343 /* write lump to file */
344 SafeWrite( file, data, length );
346 /* write padding zeros */
347 SafeWrite( file, (const byte[3]){ 0, 0, 0 }, ( ( length + 3 ) & ~3 ) - length );
354 loads a bsp file into memory
357 void LoadBSPFile( const char *filename ){
359 if ( game == NULL || game->load == NULL ) {
360 Error( "LoadBSPFile: unsupported BSP file format" );
363 /* load it, then byte swap the in-memory version */
364 game->load( filename );
375 void WriteBSPFile( const char *filename ){
376 char tempname[ 1024 ];
381 if ( game == NULL || game->write == NULL ) {
382 Error( "WriteBSPFile: unsupported BSP file format" );
385 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
387 sprintf( tempname, "%s.%08X", filename, (int) tm );
389 /* byteswap, write the bsp, then swap back so it can be manipulated further */
391 game->write( tempname );
394 /* replace existing bsp file */
396 rename( tempname, filename );
403 dumps info about current file
406 void PrintBSPFileSizes( void ){
407 /* parse entities first */
408 if ( numEntities <= 0 ) {
412 /* note that this is abstracted */
413 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
415 /* print various and sundry bits */
416 Sys_Printf( "%9d models %9d\n",
417 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
418 Sys_Printf( "%9d shaders %9d\n",
419 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
420 Sys_Printf( "%9d brushes %9d\n",
421 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
422 Sys_Printf( "%9d brushsides %9d *\n",
423 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
424 Sys_Printf( "%9d fogs %9d\n",
425 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
426 Sys_Printf( "%9d planes %9d\n",
427 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
428 Sys_Printf( "%9d entdata %9d\n",
429 numEntities, bspEntDataSize );
432 Sys_Printf( "%9d nodes %9d\n",
433 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
434 Sys_Printf( "%9d leafs %9d\n",
435 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
436 Sys_Printf( "%9d leafsurfaces %9d\n",
437 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
438 Sys_Printf( "%9d leafbrushes %9d\n",
439 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
442 Sys_Printf( "%9d drawsurfaces %9d *\n",
443 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
444 Sys_Printf( "%9d drawverts %9d *\n",
445 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
446 Sys_Printf( "%9d drawindexes %9d\n",
447 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
450 Sys_Printf( "%9d lightmaps %9d\n",
451 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
452 Sys_Printf( "%9d lightgrid %9d *\n",
453 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
454 Sys_Printf( " visibility %9d\n",
460 /* -------------------------------------------------------------------------------
464 ------------------------------------------------------------------------------- */
469 strips low byte chars off the end of a string
472 void StripTrailing( char *e ){
476 s = e + strlen( e ) - 1;
477 while ( s >= e && *s <= 32 )
488 parses a single quoted "key" "value" pair into an epair struct
491 epair_t *ParseEPair( void ){
495 /* allocate and clear new epair */
496 e = safe_malloc0( sizeof( epair_t ) );
499 if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
500 Error( "ParseEPair: token too long" );
503 e->key = copystring( token );
507 if ( strlen( token ) >= MAX_VALUE - 1 ) {
508 Error( "ParseEpar: token too long" );
510 e->value = copystring( token );
512 /* strip trailing spaces that sometimes get accidentally added in the editor */
513 StripTrailing( e->key );
514 StripTrailing( e->value );
524 parses an entity's epairs
527 qboolean ParseEntity( void ){
532 if ( !GetToken( qtrue ) ) {
535 if ( strcmp( token, "{" ) ) {
536 Error( "ParseEntity: { not found" );
538 AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
540 /* create new entity */
541 mapEnt = &entities[ numEntities ];
543 memset( mapEnt, 0, sizeof( *mapEnt ) );
548 if ( !GetToken( qtrue ) ) {
549 Error( "ParseEntity: EOF without closing brace" );
551 if ( !EPAIR_STRCMP( token, "}" ) ) {
555 e->next = mapEnt->epairs;
559 /* return to sender */
567 parses the bsp entity data string into entities
570 void ParseEntities( void ){
572 ParseFromMemory( bspEntData, bspEntDataSize );
573 while ( ParseEntity() ) ;
575 /* ydnar: set number of bsp entities in case a map is loaded on top */
576 numBSPEntities = numEntities;
582 * must be called before UnparseEntities
584 void InjectCommandLine( char **argv, int beginArgs, int endArgs ){
585 const char *previousCommandLine;
586 char newCommandLine[1024];
588 char *outpos = newCommandLine;
589 char *sentinel = newCommandLine + sizeof( newCommandLine ) - 1;
592 previousCommandLine = ValueForKey( &entities[0], "_q3map2_cmdline" );
593 if ( previousCommandLine && *previousCommandLine ) {
594 inpos = previousCommandLine;
595 while ( outpos != sentinel && *inpos )
596 *outpos++ = *inpos++;
597 if ( outpos != sentinel ) {
600 if ( outpos != sentinel ) {
605 for ( i = beginArgs; i < endArgs; ++i )
607 if ( argv[i] == NULL ) {
610 if ( outpos != sentinel && i != beginArgs ) {
614 while ( outpos != sentinel && *inpos )
615 if ( *inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ' ) {
616 *outpos++ = *inpos++;
621 SetKeyValue( &entities[0], "_q3map2_cmdline", newCommandLine );
622 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 ){
639 char key[ 1024 ], value[ 1024 ];
644 AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
650 /* run through entity list */
651 for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
655 AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
661 ep = entities[ i ].epairs;
663 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" ) ) {
674 /* add beginning brace */
675 strcat( end, "{\n" );
678 /* walk epair list */
679 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
682 strcpy( key, ep->key );
683 StripTrailing( key );
684 strcpy( value, ep->value );
685 StripTrailing( value );
688 sprintf( line, "\"%s\" \"%s\"\n", key, value );
690 end += strlen( line );
693 /* add trailing brace */
697 /* check for overflow */
698 if ( end > buf + allocatedBSPEntData ) {
699 Error( "Entity text too long" );
704 bspEntDataSize = end - buf + 1;
711 prints an entity's epairs to the console
714 void PrintEntity( const entity_t *ent ){
718 Sys_Printf( "------- entity %p -------\n", ent );
719 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
720 Sys_Printf( "%s = %s\n", ep->key, ep->value );
728 sets an epair in an entity
731 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 ) ) {
740 ep->value = copystring( value );
745 /* create new epair */
746 ep = safe_malloc( sizeof( *ep ) );
747 ep->next = ent->epairs;
749 ep->key = copystring( key );
750 ep->value = copystring( value );
757 returns true if entity has this key
760 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 ) ) {
779 gets the value for an entity key
782 const char *ValueForKey( const entity_t *ent, const char *key ){
791 /* walk epair list */
792 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
794 if ( !EPAIR_STRCMP( ep->key, key ) ) {
799 /* if no match, return empty string */
807 gets the integer point value for an entity key
810 int IntForKey( const entity_t *ent, const char *key ){
814 k = ValueForKey( ent, key );
822 gets the floating point value for an entity key
825 vec_t FloatForKey( const entity_t *ent, const char *key ){
829 k = ValueForKey( ent, key );
837 gets a 3-element vector value for an entity key
840 qboolean GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
846 k = ValueForKey( ent, key );
848 /* scanf into doubles, then assign, so it is vec_t size independent */
850 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
855 /* true if the key is found, false otherwise */
863 finds an entity target
866 entity_t *FindTargetEntity( const char *target ){
871 /* walk entity list */
872 for ( i = 0; i < numEntities; i++ )
874 n = ValueForKey( &entities[ i ], "targetname" );
875 if ( !strcmp( n, target ) ) {
876 return &entities[ i ];
887 GetEntityShadowFlags() - ydnar
888 gets an entity's shadow flags
889 note: does not set them to defaults if the keys are not found!
892 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
895 /* get cast shadows */
896 if ( castShadows != NULL ) {
897 value = ValueForKey( ent, "_castShadows" );
898 if ( value[ 0 ] == '\0' ) {
899 value = ValueForKey( ent, "_cs" );
901 if ( value[ 0 ] == '\0' ) {
902 value = ValueForKey( ent2, "_castShadows" );
904 if ( value[ 0 ] == '\0' ) {
905 value = ValueForKey( ent2, "_cs" );
907 if ( value[ 0 ] != '\0' ) {
908 *castShadows = atoi( value );
913 if ( recvShadows != NULL ) {
914 value = ValueForKey( ent, "_receiveShadows" );
915 if ( value[ 0 ] == '\0' ) {
916 value = ValueForKey( ent, "_rs" );
918 if ( value[ 0 ] == '\0' ) {
919 value = ValueForKey( ent2, "_receiveShadows" );
921 if ( value[ 0 ] == '\0' ) {
922 value = ValueForKey( ent2, "_rs" );
924 if ( value[ 0 ] != '\0' ) {
925 *recvShadows = atoi( value );
929 /* vortex: game-specific default eneity keys */
930 value = ValueForKey( ent, "classname" );
931 if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
932 /* vortex: deluxe quake default shadow flags */
933 if ( !Q_stricmp( value, "func_wall" ) ) {
934 if ( recvShadows != NULL ) {
937 if ( castShadows != NULL ) {