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 ( outpos != sentinel && i != beginArgs ) {
611 while ( outpos != sentinel && *inpos )
612 if ( *inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ' ) {
613 *outpos++ = *inpos++;
618 SetKeyValue( &entities[0], "_q3map2_cmdline", newCommandLine );
619 SetKeyValue( &entities[0], "_q3map2_version", Q3MAP_VERSION );
626 generates the dentdata string from all the entities.
627 this allows the utilities to add or remove key/value
628 pairs to the data created by the map editor
631 void UnparseEntities( void ){
636 char key[ 1024 ], value[ 1024 ];
641 AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
647 /* run through entity list */
648 for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
652 AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
658 ep = entities[ i ].epairs;
660 continue; /* ent got removed */
663 /* ydnar: certain entities get stripped from bsp file */
664 value2 = ValueForKey( &entities[ i ], "classname" );
665 if ( !Q_stricmp( value2, "misc_model" ) ||
666 !Q_stricmp( value2, "_decal" ) ||
667 !Q_stricmp( value2, "_skybox" ) ) {
671 /* add beginning brace */
672 strcat( end, "{\n" );
675 /* walk epair list */
676 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
679 strcpy( key, ep->key );
680 StripTrailing( key );
681 strcpy( value, ep->value );
682 StripTrailing( value );
685 sprintf( line, "\"%s\" \"%s\"\n", key, value );
687 end += strlen( line );
690 /* add trailing brace */
694 /* check for overflow */
695 if ( end > buf + allocatedBSPEntData ) {
696 Error( "Entity text too long" );
701 bspEntDataSize = end - buf + 1;
708 prints an entity's epairs to the console
711 void PrintEntity( const entity_t *ent ){
715 Sys_Printf( "------- entity %p -------\n", ent );
716 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
717 Sys_Printf( "%s = %s\n", ep->key, ep->value );
725 sets an epair in an entity
728 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
732 /* check for existing epair */
733 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
735 if ( !EPAIR_STRCMP( ep->key, key ) ) {
737 ep->value = copystring( value );
742 /* create new epair */
743 ep = safe_malloc( sizeof( *ep ) );
744 ep->next = ent->epairs;
746 ep->key = copystring( key );
747 ep->value = copystring( value );
754 returns true if entity has this key
757 qboolean KeyExists( const entity_t *ent, const char *key ){
760 /* walk epair list */
761 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
763 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 ) ) {
796 /* if no match, return empty string */
804 gets the integer point value for an entity key
807 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 ){
826 k = ValueForKey( ent, key );
834 gets a 3-element vector value for an entity key
837 qboolean GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
843 k = ValueForKey( ent, key );
845 /* scanf into doubles, then assign, so it is vec_t size independent */
847 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
852 /* true if the key is found, false otherwise */
860 finds an entity target
863 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 ];
884 GetEntityShadowFlags() - ydnar
885 gets an entity's shadow flags
886 note: does not set them to defaults if the keys are not found!
889 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
892 /* get cast shadows */
893 if ( castShadows != NULL ) {
894 value = ValueForKey( ent, "_castShadows" );
895 if ( value[ 0 ] == '\0' ) {
896 value = ValueForKey( ent, "_cs" );
898 if ( value[ 0 ] == '\0' ) {
899 value = ValueForKey( ent2, "_castShadows" );
901 if ( value[ 0 ] == '\0' ) {
902 value = ValueForKey( ent2, "_cs" );
904 if ( value[ 0 ] != '\0' ) {
905 *castShadows = atoi( value );
910 if ( recvShadows != NULL ) {
911 value = ValueForKey( ent, "_receiveShadows" );
912 if ( value[ 0 ] == '\0' ) {
913 value = ValueForKey( ent, "_rs" );
915 if ( value[ 0 ] == '\0' ) {
916 value = ValueForKey( ent2, "_receiveShadows" );
918 if ( value[ 0 ] == '\0' ) {
919 value = ValueForKey( ent2, "_rs" );
921 if ( value[ 0 ] != '\0' ) {
922 *recvShadows = atoi( value );
926 /* vortex: game-specific default eneity keys */
927 value = ValueForKey( ent, "classname" );
928 if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
929 /* vortex: deluxe quake default shadow flags */
930 if ( !Q_stricmp( value, "func_wall" ) ) {
931 if ( recvShadows != NULL ) {
934 if ( castShadows != NULL ) {