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 = MAX_MAP_DRAW_VERTS / 37;
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 if(numBSPDrawVertsBuffer > MAX_MAP_DRAW_VERTS)
78 numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS;
80 bspDrawVerts = realloc(bspDrawVerts, sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer);
83 Error( "realloc() failed (IncDrawVerts)");
86 memset(bspDrawVerts + (numBSPDrawVerts - 1), 0, sizeof(bspDrawVert_t));
89 void SetDrawVerts(int n)
95 numBSPDrawVertsBuffer = numBSPDrawVerts;
97 bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");
99 memset(bspDrawVerts, 0, n * sizeof(bspDrawVert_t));
102 int numBSPDrawSurfacesBuffer = 0;
103 void SetDrawSurfacesBuffer()
105 if(bspDrawSurfaces != 0)
106 free(bspDrawSurfaces);
108 numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
110 bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");
112 memset(bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof(bspDrawVert_t));
115 void SetDrawSurfaces(int n)
117 if(bspDrawSurfaces != 0)
118 free(bspDrawSurfaces);
120 numBSPDrawSurfaces = n;
121 numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
123 bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");
125 memset(bspDrawSurfaces, 0, n * sizeof(bspDrawVert_t));
128 void BSPFilesCleanup()
130 if(bspDrawVerts != 0)
132 if(bspDrawSurfaces != 0)
133 free(bspDrawSurfaces);
134 if(bspLightBytes != 0)
136 if(bspGridPoints != 0)
147 if all values are 32 bits, this can be used to swap everything
150 void SwapBlock( int *block, int size )
161 for( i = 0; i < size; i++ )
162 block[ i ] = LittleLong( block[ i ] );
169 byte swaps all data in the abstract bsp
172 void SwapBSPFile( void )
178 SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) );
180 /* shaders (don't swap the name) */
181 for( i = 0; i < numBSPShaders ; i++ )
183 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
184 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
188 SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
191 SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
194 SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
197 SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
200 SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
203 SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
206 SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
209 ((int*) &bspVisBytes)[ 0 ] = LittleLong( ((int*) &bspVisBytes)[ 0 ] );
210 ((int*) &bspVisBytes)[ 1 ] = LittleLong( ((int*) &bspVisBytes)[ 1 ] );
212 /* drawverts (don't swap colors) */
213 for( i = 0; i < numBSPDrawVerts; i++ )
215 bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
216 bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
217 bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
218 bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
219 bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
220 bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
221 bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
222 bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
223 for( j = 0; j < MAX_LIGHTMAPS; j++ )
225 bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
226 bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
231 SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
234 /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
235 SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
238 for( i = 0; i < numBSPFogs; i++ )
240 bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
241 bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
249 gets the number of elements in a bsp lump
252 int GetLumpElements( bspHeader_t *header, int lump, int size )
254 /* check for odd size */
255 if( header->lumps[ lump ].length % size )
259 Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
263 Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
266 /* return element count */
267 return header->lumps[ lump ].length / size;
274 returns a pointer to the specified lump
277 void *GetLump( bspHeader_t *header, int lump )
279 return (void*)( (byte*) header + header->lumps[ lump ].offset);
286 copies a bsp file lump into a destination buffer
289 int CopyLump( bspHeader_t *header, int lump, void *dest, int size )
294 /* get lump length and offset */
295 length = header->lumps[ lump ].length;
296 offset = header->lumps[ lump ].offset;
298 /* handle erroneous cases */
305 Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
309 Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
312 /* copy block of memory and return */
313 memcpy( dest, (byte*) header + offset, length );
314 return length / size;
321 adds a lump to an outgoing bsp file
324 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length )
329 /* add lump to bsp file header */
330 lump = &header->lumps[ lumpNum ];
331 lump->offset = LittleLong( ftell( file ) );
332 lump->length = LittleLong( length );
334 /* write lump to file */
335 SafeWrite( file, data, (length + 3) & ~3 );
342 loads a bsp file into memory
345 void LoadBSPFile( const char *filename )
348 if( game == NULL || game->load == NULL )
349 Error( "LoadBSPFile: unsupported BSP file format" );
351 /* load it, then byte swap the in-memory version */
352 game->load( filename );
363 void WriteBSPFile( const char *filename )
365 char tempname[ 1024 ];
370 if( game == NULL || game->write == NULL )
371 Error( "WriteBSPFile: unsupported BSP file format" );
373 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
375 sprintf( tempname, "%s.%08X", filename, (int) tm );
377 /* byteswap, write the bsp, then swap back so it can be manipulated further */
379 game->write( tempname );
382 /* replace existing bsp file */
384 rename( tempname, filename );
391 dumps info about current file
394 void PrintBSPFileSizes( void )
396 /* parse entities first */
397 if( numEntities <= 0 )
400 /* note that this is abstracted */
401 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
403 /* print various and sundry bits */
404 Sys_Printf( "%9d models %9d\n",
405 numBSPModels, (int) (numBSPModels * sizeof( bspModel_t )) );
406 Sys_Printf( "%9d shaders %9d\n",
407 numBSPShaders, (int) (numBSPShaders * sizeof( bspShader_t )) );
408 Sys_Printf( "%9d brushes %9d\n",
409 numBSPBrushes, (int) (numBSPBrushes * sizeof( bspBrush_t )) );
410 Sys_Printf( "%9d brushsides %9d *\n",
411 numBSPBrushSides, (int) (numBSPBrushSides * sizeof( bspBrushSide_t )) );
412 Sys_Printf( "%9d fogs %9d\n",
413 numBSPFogs, (int) (numBSPFogs * sizeof( bspFog_t ) ) );
414 Sys_Printf( "%9d planes %9d\n",
415 numBSPPlanes, (int) (numBSPPlanes * sizeof( bspPlane_t )) );
416 Sys_Printf( "%9d entdata %9d\n",
417 numEntities, bspEntDataSize );
420 Sys_Printf( "%9d nodes %9d\n",
421 numBSPNodes, (int) (numBSPNodes * sizeof( bspNode_t)) );
422 Sys_Printf( "%9d leafs %9d\n",
423 numBSPLeafs, (int) (numBSPLeafs * sizeof( bspLeaf_t )) );
424 Sys_Printf( "%9d leafsurfaces %9d\n",
425 numBSPLeafSurfaces, (int) (numBSPLeafSurfaces * sizeof( *bspLeafSurfaces )) );
426 Sys_Printf( "%9d leafbrushes %9d\n",
427 numBSPLeafBrushes, (int) (numBSPLeafBrushes * sizeof( *bspLeafBrushes )) );
430 Sys_Printf( "%9d drawsurfaces %9d *\n",
431 numBSPDrawSurfaces, (int) (numBSPDrawSurfaces * sizeof( *bspDrawSurfaces )) );
432 Sys_Printf( "%9d drawverts %9d *\n",
433 numBSPDrawVerts, (int) (numBSPDrawVerts * sizeof( *bspDrawVerts )) );
434 Sys_Printf( "%9d drawindexes %9d\n",
435 numBSPDrawIndexes, (int) (numBSPDrawIndexes * sizeof( *bspDrawIndexes )) );
438 Sys_Printf( "%9d lightmaps %9d\n",
439 numBSPLightBytes / (game->lightmapSize * game->lightmapSize * 3), numBSPLightBytes );
440 Sys_Printf( "%9d lightgrid %9d *\n",
441 numBSPGridPoints, (int) (numBSPGridPoints * sizeof( *bspGridPoints )) );
442 Sys_Printf( " visibility %9d\n",
448 /* -------------------------------------------------------------------------------
452 ------------------------------------------------------------------------------- */
457 strips low byte chars off the end of a string
460 void StripTrailing( char *e )
465 s = e + strlen( e ) - 1;
466 while( s >= e && *s <= 32 )
477 parses a single quoted "key" "value" pair into an epair struct
480 epair_t *ParseEPair( void )
485 /* allocate and clear new epair */
486 e = safe_malloc( sizeof( epair_t ) );
487 memset( e, 0, sizeof( epair_t ) );
490 if( strlen( token ) >= (MAX_KEY - 1) )
491 Error( "ParseEPair: token too long" );
493 e->key = copystring( token );
497 if( strlen( token ) >= MAX_VALUE - 1 )
498 Error( "ParseEpar: token too long" );
499 e->value = copystring( token );
501 /* strip trailing spaces that sometimes get accidentally added in the editor */
502 StripTrailing( e->key );
503 StripTrailing( e->value );
513 parses an entity's epairs
516 qboolean ParseEntity( void )
522 if( !GetToken( qtrue ) )
524 if( strcmp( token, "{" ) )
525 Error( "ParseEntity: { not found" );
526 if( numEntities == MAX_MAP_ENTITIES )
527 Error( "numEntities == MAX_MAP_ENTITIES" );
529 /* create new entity */
530 mapEnt = &entities[ numEntities ];
536 if( !GetToken( qtrue ) )
537 Error( "ParseEntity: EOF without closing brace" );
538 if( !EPAIR_STRCMP( token, "}" ) )
541 e->next = mapEnt->epairs;
545 /* return to sender */
553 parses the bsp entity data string into entities
556 void ParseEntities( void )
559 ParseFromMemory( bspEntData, bspEntDataSize );
560 while( ParseEntity() );
562 /* ydnar: set number of bsp entities in case a map is loaded on top */
563 numBSPEntities = numEntities;
570 generates the dentdata string from all the entities.
571 this allows the utilities to add or remove key/value
572 pairs to the data created by the map editor
575 void UnparseEntities( void )
581 char key[ 1024 ], value[ 1024 ];
590 /* run through entity list */
591 for( i = 0; i < numBSPEntities && i < numEntities; i++ )
594 ep = entities[ i ].epairs;
596 continue; /* ent got removed */
598 /* ydnar: certain entities get stripped from bsp file */
599 value2 = ValueForKey( &entities[ i ], "classname" );
600 if( !Q_stricmp( value2, "misc_model" ) ||
601 !Q_stricmp( value2, "_decal" ) ||
602 !Q_stricmp( value2, "_skybox" ) )
605 /* add beginning brace */
606 strcat( end, "{\n" );
609 /* walk epair list */
610 for( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
613 strcpy( key, ep->key );
614 StripTrailing( key );
615 strcpy( value, ep->value );
616 StripTrailing( value );
619 sprintf( line, "\"%s\" \"%s\"\n", key, value );
621 end += strlen( line );
624 /* add trailing brace */
628 /* check for overflow */
629 if( end > buf + MAX_MAP_ENTSTRING )
630 Error( "Entity text too long" );
634 bspEntDataSize = end - buf + 1;
641 prints an entity's epairs to the console
644 void PrintEntity( const entity_t *ent )
649 Sys_Printf( "------- entity %p -------\n", ent );
650 for( ep = ent->epairs; ep != NULL; ep = ep->next )
651 Sys_Printf( "%s = %s\n", ep->key, ep->value );
659 sets an epair in an entity
662 void SetKeyValue( entity_t *ent, const char *key, const char *value )
667 /* check for existing epair */
668 for( ep = ent->epairs; ep != NULL; ep = ep->next )
670 if( !EPAIR_STRCMP( ep->key, key ) )
673 ep->value = copystring( value );
678 /* create new epair */
679 ep = safe_malloc( sizeof( *ep ) );
680 ep->next = ent->epairs;
682 ep->key = copystring( key );
683 ep->value = copystring( value );
690 gets the value for an entity key
693 const char *ValueForKey( const entity_t *ent, const char *key )
702 /* walk epair list */
703 for( ep = ent->epairs; ep != NULL; ep = ep->next )
705 if( !EPAIR_STRCMP( ep->key, key ) )
709 /* if no match, return empty string */
717 gets the integer point value for an entity key
720 int IntForKey( const entity_t *ent, const char *key )
725 k = ValueForKey( ent, key );
733 gets the floating point value for an entity key
736 vec_t FloatForKey( const entity_t *ent, const char *key )
741 k = ValueForKey( ent, key );
749 gets a 3-element vector value for an entity key
752 void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec )
759 k = ValueForKey( ent, key );
761 /* scanf into doubles, then assign, so it is vec_t size independent */
763 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
773 finds an entity target
776 entity_t *FindTargetEntity( const char *target )
782 /* walk entity list */
783 for( i = 0; i < numEntities; i++ )
785 n = ValueForKey( &entities[ i ], "targetname" );
786 if ( !strcmp( n, target ) )
787 return &entities[ i ];
797 GetEntityShadowFlags() - ydnar
798 gets an entity's shadow flags
799 note: does not set them to defaults if the keys are not found!
802 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows )
807 /* get cast shadows */
808 if( castShadows != NULL )
810 value = ValueForKey( ent, "_castShadows" );
811 if( value[ 0 ] == '\0' )
812 value = ValueForKey( ent, "_cs" );
813 if( value[ 0 ] == '\0' )
814 value = ValueForKey( ent2, "_castShadows" );
815 if( value[ 0 ] == '\0' )
816 value = ValueForKey( ent2, "_cs" );
817 if( value[ 0 ] != '\0' )
818 *castShadows = atoi( value );
822 if( recvShadows != NULL )
824 value = ValueForKey( ent, "_receiveShadows" );
825 if( value[ 0 ] == '\0' )
826 value = ValueForKey( ent, "_rs" );
827 if( value[ 0 ] == '\0' )
828 value = ValueForKey( ent2, "_receiveShadows" );
829 if( value[ 0 ] == '\0' )
830 value = ValueForKey( ent2, "_rs" );
831 if( value[ 0 ] != '\0' )
832 *recvShadows = atoi( value );