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( bspDrawVert_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( bspDrawVert_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++ )
181 si = ShaderInfoForShader( bspShaders[ i ].shader );
182 if ( si->remapShader && si->remapShader[ 0 ] ) {
183 strcpy( bspShaders[ i ].shader, si->remapShader );
186 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
187 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
191 SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
194 SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
197 SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
200 SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
203 SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
206 SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
209 SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
212 ( (int*) &bspVisBytes )[ 0 ] = LittleLong( ( (int*) &bspVisBytes )[ 0 ] );
213 ( (int*) &bspVisBytes )[ 1 ] = LittleLong( ( (int*) &bspVisBytes )[ 1 ] );
215 /* drawverts (don't swap colors) */
216 for ( i = 0; i < numBSPDrawVerts; i++ )
218 bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
219 bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
220 bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
221 bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
222 bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
223 bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
224 bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
225 bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
226 for ( j = 0; j < MAX_LIGHTMAPS; j++ )
228 bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
229 bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
234 SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
237 /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
238 SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
241 for ( i = 0; i < numBSPFogs; i++ )
243 bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
244 bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
248 for ( i = 0; i < numBSPAds; i++ )
250 bspAds[ i ].cellId = LittleLong( bspAds[ i ].cellId );
251 bspAds[ i ].normal[ 0 ] = LittleFloat( bspAds[ i ].normal[ 0 ] );
252 bspAds[ i ].normal[ 1 ] = LittleFloat( bspAds[ i ].normal[ 1 ] );
253 bspAds[ i ].normal[ 2 ] = LittleFloat( bspAds[ i ].normal[ 2 ] );
255 for ( j = 0; j < 4; j++ )
257 bspAds[ i ].rect[j][ 0 ] = LittleFloat( bspAds[ i ].rect[j][ 0 ] );
258 bspAds[ i ].rect[j][ 1 ] = LittleFloat( bspAds[ i ].rect[j][ 1 ] );
259 bspAds[ i ].rect[j][ 2 ] = LittleFloat( bspAds[ i ].rect[j][ 2 ] );
262 //bspAds[ i ].model[ MAX_QPATH ];
270 gets the number of elements in a bsp lump
273 int GetLumpElements( bspHeader_t *header, int lump, int size ){
274 /* check for odd size */
275 if ( header->lumps[ lump ].length % size ) {
277 Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
281 Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
285 /* return element count */
286 return header->lumps[ lump ].length / size;
293 returns a pointer to the specified lump
296 void *GetLump( bspHeader_t *header, int lump ){
297 return (void*)( (byte*) header + header->lumps[ lump ].offset );
304 copies a bsp file lump into a destination buffer
307 int CopyLump( bspHeader_t *header, int lump, void *dest, int size ){
311 /* get lump length and offset */
312 length = header->lumps[ lump ].length;
313 offset = header->lumps[ lump ].offset;
315 /* handle erroneous cases */
319 if ( length % size ) {
321 Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
325 Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
329 /* copy block of memory and return */
330 memcpy( dest, (byte*) header + offset, length );
331 return length / size;
334 int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable ){
335 /* get lump length and offset */
336 *allocationVariable = header->lumps[ lump ].length / size;
337 *dest = realloc( *dest, size * *allocationVariable );
338 return CopyLump( header, lump, *dest, size );
344 adds a lump to an outgoing bsp file
347 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
351 /* add lump to bsp file header */
352 lump = &header->lumps[ lumpNum ];
353 lump->offset = LittleLong( ftell( file ) );
354 lump->length = LittleLong( length );
356 /* write lump to file */
357 SafeWrite( file, data, ( length + 3 ) & ~3 );
364 loads a bsp file into memory
367 void LoadBSPFile( const char *filename ){
369 if ( game == NULL || game->load == NULL ) {
370 Error( "LoadBSPFile: unsupported BSP file format" );
373 /* load it, then byte swap the in-memory version */
374 game->load( filename );
385 void WriteBSPFile( const char *filename ){
386 char tempname[ 1024 ];
391 if ( game == NULL || game->write == NULL ) {
392 Error( "WriteBSPFile: unsupported BSP file format" );
395 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
397 sprintf( tempname, "%s.%08X", filename, (int) tm );
399 /* byteswap, write the bsp, then swap back so it can be manipulated further */
401 game->write( tempname );
404 /* replace existing bsp file */
406 rename( tempname, filename );
413 dumps info about current file
416 void PrintBSPFileSizes( void ){
417 /* parse entities first */
418 if ( numEntities <= 0 ) {
422 /* note that this is abstracted */
423 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
425 /* print various and sundry bits */
426 Sys_Printf( "%9d models %9d\n",
427 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
428 Sys_Printf( "%9d shaders %9d\n",
429 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
430 Sys_Printf( "%9d brushes %9d\n",
431 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
432 Sys_Printf( "%9d brushsides %9d *\n",
433 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
434 Sys_Printf( "%9d fogs %9d\n",
435 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
436 Sys_Printf( "%9d planes %9d\n",
437 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
438 Sys_Printf( "%9d entdata %9d\n",
439 numEntities, bspEntDataSize );
442 Sys_Printf( "%9d nodes %9d\n",
443 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
444 Sys_Printf( "%9d leafs %9d\n",
445 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
446 Sys_Printf( "%9d leafsurfaces %9d\n",
447 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
448 Sys_Printf( "%9d leafbrushes %9d\n",
449 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
452 Sys_Printf( "%9d drawsurfaces %9d *\n",
453 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
454 Sys_Printf( "%9d drawverts %9d *\n",
455 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
456 Sys_Printf( "%9d drawindexes %9d\n",
457 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
460 Sys_Printf( "%9d lightmaps %9d\n",
461 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
462 Sys_Printf( "%9d lightgrid %9d *\n",
463 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
464 Sys_Printf( " visibility %9d\n",
470 /* -------------------------------------------------------------------------------
474 ------------------------------------------------------------------------------- */
479 strips low byte chars off the end of a string
482 void StripTrailing( char *e ){
486 s = e + strlen( e ) - 1;
487 while ( s >= e && *s <= 32 )
498 parses a single quoted "key" "value" pair into an epair struct
501 epair_t *ParseEPair( void ){
505 /* allocate and clear new epair */
506 e = safe_malloc( sizeof( epair_t ) );
507 memset( e, 0, sizeof( epair_t ) );
510 if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
511 Error( "ParseEPair: token too long" );
514 e->key = copystring( token );
518 if ( strlen( token ) >= MAX_VALUE - 1 ) {
519 Error( "ParseEpar: token too long" );
521 e->value = copystring( token );
523 /* strip trailing spaces that sometimes get accidentally added in the editor */
524 StripTrailing( e->key );
525 StripTrailing( e->value );
535 parses an entity's epairs
538 qboolean ParseEntity( void ){
543 if ( !GetToken( qtrue ) ) {
546 if ( strcmp( token, "{" ) ) {
547 Error( "ParseEntity: { not found" );
549 AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
551 /* create new entity */
552 mapEnt = &entities[ numEntities ];
554 memset( mapEnt, 0, sizeof( *mapEnt ) );
559 if ( !GetToken( qtrue ) ) {
560 Error( "ParseEntity: EOF without closing brace" );
562 if ( !EPAIR_STRCMP( token, "}" ) ) {
566 e->next = mapEnt->epairs;
570 /* return to sender */
578 parses the bsp entity data string into entities
581 void ParseEntities( void ){
583 ParseFromMemory( bspEntData, bspEntDataSize );
584 while ( ParseEntity() ) ;
586 /* ydnar: set number of bsp entities in case a map is loaded on top */
587 numBSPEntities = numEntities;
591 * must be called before UnparseEntities
593 void InjectCommandLine( char **argv, int beginArgs, int endArgs ){
594 const char *previousCommandLine;
595 char newCommandLine[1024];
597 char *outpos = newCommandLine;
598 char *sentinel = newCommandLine + sizeof( newCommandLine ) - 1;
605 previousCommandLine = ValueForKey( &entities[0], "_q3map2_cmdline" );
606 if ( previousCommandLine && *previousCommandLine ) {
607 inpos = previousCommandLine;
608 while ( outpos != sentinel && *inpos )
609 *outpos++ = *inpos++;
610 if ( outpos != sentinel ) {
613 if ( outpos != sentinel ) {
618 for ( i = beginArgs; i < endArgs; ++i )
620 if ( outpos != sentinel && i != beginArgs ) {
624 while ( outpos != sentinel && *inpos )
625 if ( *inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ' ) {
626 *outpos++ = *inpos++;
631 SetKeyValue( &entities[0], "_q3map2_cmdline", newCommandLine );
632 SetKeyValue( &entities[0], "_q3map2_version", Q3MAP_VERSION );
637 generates the dentdata string from all the entities.
638 this allows the utilities to add or remove key/value
639 pairs to the data created by the map editor
642 void UnparseEntities( void ){
647 char key[ 1024 ], value[ 1024 ];
652 AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
658 /* run through entity list */
659 for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
663 AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
669 ep = entities[ i ].epairs;
671 continue; /* ent got removed */
674 /* ydnar: certain entities get stripped from bsp file */
675 value2 = ValueForKey( &entities[ i ], "classname" );
676 if ( !Q_stricmp( value2, "misc_model" ) ||
677 !Q_stricmp( value2, "_decal" ) ||
678 !Q_stricmp( value2, "_skybox" ) ) {
682 /* add beginning brace */
683 strcat( end, "{\n" );
686 /* walk epair list */
687 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
690 strcpy( key, ep->key );
691 StripTrailing( key );
692 strcpy( value, ep->value );
693 StripTrailing( value );
696 sprintf( line, "\"%s\" \"%s\"\n", key, value );
698 end += strlen( line );
701 /* add trailing brace */
705 /* check for overflow */
706 if ( end > buf + allocatedBSPEntData ) {
707 Error( "Entity text too long" );
712 bspEntDataSize = end - buf + 1;
719 prints an entity's epairs to the console
722 void PrintEntity( const entity_t *ent ){
726 Sys_Printf( "------- entity %p -------\n", ent );
727 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
728 Sys_Printf( "%s = %s\n", ep->key, ep->value );
736 sets an epair in an entity
739 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
743 /* check for existing epair */
744 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
746 if ( !EPAIR_STRCMP( ep->key, key ) ) {
748 ep->value = copystring( value );
753 /* create new epair */
754 ep = safe_malloc( sizeof( *ep ) );
755 ep->next = ent->epairs;
757 ep->key = copystring( key );
758 ep->value = copystring( value );
763 returns true if entity has this key
766 qboolean KeyExists( const entity_t *ent, const char *key ){
769 /* walk epair list */
770 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
772 if ( !EPAIR_STRCMP( ep->key, key ) ) {
783 gets the value for an entity key
786 const char *ValueForKey( const entity_t *ent, const char *key ){
795 /* walk epair list */
796 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
798 if ( !EPAIR_STRCMP( ep->key, key ) ) {
803 /* if no match, return empty string */
811 gets the integer point value for an entity key
814 int IntForKey( const entity_t *ent, const char *key ){
818 k = ValueForKey( ent, key );
826 gets the floating point value for an entity key
829 vec_t FloatForKey( const entity_t *ent, const char *key ){
833 k = ValueForKey( ent, key );
841 gets a 3-element vector value for an entity key
844 void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
850 k = ValueForKey( ent, key );
852 /* scanf into doubles, then assign, so it is vec_t size independent */
854 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
864 finds an entity target
867 entity_t *FindTargetEntity( const char *target ){
872 /* walk entity list */
873 for ( i = 0; i < numEntities; i++ )
875 n = ValueForKey( &entities[ i ], "targetname" );
876 if ( !strcmp( n, target ) ) {
877 return &entities[ i ];
888 GetEntityShadowFlags() - ydnar
889 gets an entity's shadow flags
890 note: does not set them to defaults if the keys are not found!
893 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
896 /* get cast shadows */
897 if ( castShadows != NULL ) {
898 value = ValueForKey( ent, "_castShadows" );
899 if ( value[ 0 ] == '\0' ) {
900 value = ValueForKey( ent, "_cs" );
902 if ( value[ 0 ] == '\0' ) {
903 value = ValueForKey( ent2, "_castShadows" );
905 if ( value[ 0 ] == '\0' ) {
906 value = ValueForKey( ent2, "_cs" );
908 if ( value[ 0 ] != '\0' ) {
909 *castShadows = atoi( value );
914 if ( recvShadows != NULL ) {
915 value = ValueForKey( ent, "_receiveShadows" );
916 if ( value[ 0 ] == '\0' ) {
917 value = ValueForKey( ent, "_rs" );
919 if ( value[ 0 ] == '\0' ) {
920 value = ValueForKey( ent2, "_receiveShadows" );
922 if ( value[ 0 ] == '\0' ) {
923 value = ValueForKey( ent2, "_rs" );
925 if ( value[ 0 ] != '\0' ) {
926 *recvShadows = atoi( value );
930 /* vortex: game-specific default eneity keys */
931 value = ValueForKey( ent, "classname" );
932 if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
933 /* vortex: deluxe quake default shadow flags */
934 if ( !Q_stricmp( value, "func_wall" ) ) {
935 if ( recvShadows != NULL ) {
938 if ( castShadows != NULL ) {