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( bspDrawSurface_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( bspDrawSurface_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++ )
180 si = ShaderInfoForShader( bspShaders[ i ].shader );
181 if ( si->remapShader && si->remapShader[ 0 ] ) {
182 strcpy( bspShaders[ i ].shader, si->remapShader );
185 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
186 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
190 SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
193 SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
196 SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
199 SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
202 SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
205 SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
208 SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
211 ( (int*) &bspVisBytes )[ 0 ] = LittleLong( ( (int*) &bspVisBytes )[ 0 ] );
212 ( (int*) &bspVisBytes )[ 1 ] = LittleLong( ( (int*) &bspVisBytes )[ 1 ] );
214 /* drawverts (don't swap colors) */
215 for ( i = 0; i < numBSPDrawVerts; i++ )
217 bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
218 bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
219 bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
220 bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
221 bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
222 bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
223 bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
224 bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
225 for ( j = 0; j < MAX_LIGHTMAPS; j++ )
227 bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
228 bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
233 SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
236 /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
237 SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
240 for ( i = 0; i < numBSPFogs; i++ )
242 bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
243 bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
247 for ( i = 0; i < numBSPAds; i++ )
249 bspAds[ i ].cellId = LittleLong( bspAds[ i ].cellId );
250 bspAds[ i ].normal[ 0 ] = LittleFloat( bspAds[ i ].normal[ 0 ] );
251 bspAds[ i ].normal[ 1 ] = LittleFloat( bspAds[ i ].normal[ 1 ] );
252 bspAds[ i ].normal[ 2 ] = LittleFloat( bspAds[ i ].normal[ 2 ] );
254 for ( j = 0; j < 4; j++ )
256 bspAds[ i ].rect[j][ 0 ] = LittleFloat( bspAds[ i ].rect[j][ 0 ] );
257 bspAds[ i ].rect[j][ 1 ] = LittleFloat( bspAds[ i ].rect[j][ 1 ] );
258 bspAds[ i ].rect[j][ 2 ] = LittleFloat( bspAds[ i ].rect[j][ 2 ] );
261 //bspAds[ i ].model[ MAX_QPATH ];
269 gets the number of elements in a bsp lump
272 int GetLumpElements( bspHeader_t *header, int lump, int size ){
273 /* check for odd size */
274 if ( header->lumps[ lump ].length % size ) {
276 Sys_FPrintf( SYS_WRN, "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
280 Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
284 /* return element count */
285 return header->lumps[ lump ].length / size;
292 returns a pointer to the specified lump
295 void *GetLump( bspHeader_t *header, int lump ){
296 return (void*)( (byte*) header + header->lumps[ lump ].offset );
303 copies a bsp file lump into a destination buffer
306 int CopyLump( bspHeader_t *header, int lump, void *dest, int size ){
310 /* get lump length and offset */
311 length = header->lumps[ lump ].length;
312 offset = header->lumps[ lump ].offset;
314 /* handle erroneous cases */
318 if ( length % size ) {
320 Sys_FPrintf( SYS_WRN, "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
324 Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
328 /* copy block of memory and return */
329 memcpy( dest, (byte*) header + offset, length );
330 return length / size;
333 int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable ){
334 /* get lump length and offset */
335 *allocationVariable = header->lumps[ lump ].length / size;
336 *dest = realloc( *dest, size * *allocationVariable );
337 return CopyLump( header, lump, *dest, size );
343 adds a lump to an outgoing bsp file
346 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
350 /* add lump to bsp file header */
351 lump = &header->lumps[ lumpNum ];
352 lump->offset = LittleLong( ftell( file ) );
353 lump->length = LittleLong( length );
355 /* write lump to file */
356 SafeWrite( file, data, ( length + 3 ) & ~3 );
363 loads a bsp file into memory
366 void LoadBSPFile( const char *filename ){
368 if ( game == NULL || game->load == NULL ) {
369 Error( "LoadBSPFile: unsupported BSP file format" );
372 /* load it, then byte swap the in-memory version */
373 game->load( filename );
384 void WriteBSPFile( const char *filename ){
385 char tempname[ 1024 ];
390 if ( game == NULL || game->write == NULL ) {
391 Error( "WriteBSPFile: unsupported BSP file format" );
394 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
396 sprintf( tempname, "%s.%08X", filename, (int) tm );
398 /* byteswap, write the bsp, then swap back so it can be manipulated further */
400 game->write( tempname );
403 /* replace existing bsp file */
405 rename( tempname, filename );
412 dumps info about current file
415 void PrintBSPFileSizes( void ){
416 /* parse entities first */
417 if ( numEntities <= 0 ) {
421 /* note that this is abstracted */
422 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
424 /* print various and sundry bits */
425 Sys_Printf( "%9d models %9d\n",
426 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
427 Sys_Printf( "%9d shaders %9d\n",
428 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
429 Sys_Printf( "%9d brushes %9d\n",
430 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
431 Sys_Printf( "%9d brushsides %9d *\n",
432 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
433 Sys_Printf( "%9d fogs %9d\n",
434 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
435 Sys_Printf( "%9d planes %9d\n",
436 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
437 Sys_Printf( "%9d entdata %9d\n",
438 numEntities, bspEntDataSize );
441 Sys_Printf( "%9d nodes %9d\n",
442 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
443 Sys_Printf( "%9d leafs %9d\n",
444 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
445 Sys_Printf( "%9d leafsurfaces %9d\n",
446 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
447 Sys_Printf( "%9d leafbrushes %9d\n",
448 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
451 Sys_Printf( "%9d drawsurfaces %9d *\n",
452 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
453 Sys_Printf( "%9d drawverts %9d *\n",
454 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
455 Sys_Printf( "%9d drawindexes %9d\n",
456 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
459 Sys_Printf( "%9d lightmaps %9d\n",
460 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
461 Sys_Printf( "%9d lightgrid %9d *\n",
462 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
463 Sys_Printf( " visibility %9d\n",
469 /* -------------------------------------------------------------------------------
473 ------------------------------------------------------------------------------- */
478 strips low byte chars off the end of a string
481 void StripTrailing( char *e ){
485 s = e + strlen( e ) - 1;
486 while ( s >= e && *s <= 32 )
497 parses a single quoted "key" "value" pair into an epair struct
500 epair_t *ParseEPair( void ){
504 /* allocate and clear new epair */
505 e = safe_malloc( sizeof( epair_t ) );
506 memset( e, 0, sizeof( epair_t ) );
509 if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
510 Error( "ParseEPair: token too long" );
513 e->key = copystring( token );
517 if ( strlen( token ) >= MAX_VALUE - 1 ) {
518 Error( "ParseEpar: token too long" );
520 e->value = copystring( token );
522 /* strip trailing spaces that sometimes get accidentally added in the editor */
523 StripTrailing( e->key );
524 StripTrailing( e->value );
534 parses an entity's epairs
537 qboolean ParseEntity( void ){
542 if ( !GetToken( qtrue ) ) {
545 if ( strcmp( token, "{" ) ) {
546 Error( "ParseEntity: { not found" );
548 AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
550 /* create new entity */
551 mapEnt = &entities[ numEntities ];
553 memset( mapEnt, 0, sizeof( *mapEnt ) );
558 if ( !GetToken( qtrue ) ) {
559 Error( "ParseEntity: EOF without closing brace" );
561 if ( !EPAIR_STRCMP( token, "}" ) ) {
565 e->next = mapEnt->epairs;
569 /* return to sender */
577 parses the bsp entity data string into entities
580 void ParseEntities( void ){
582 ParseFromMemory( bspEntData, bspEntDataSize );
583 while ( ParseEntity() ) ;
585 /* ydnar: set number of bsp entities in case a map is loaded on top */
586 numBSPEntities = numEntities;
592 * must be called before UnparseEntities
594 void InjectCommandLine( char **argv, int beginArgs, int endArgs ){
595 const char *previousCommandLine;
596 char newCommandLine[1024];
598 char *outpos = newCommandLine;
599 char *sentinel = newCommandLine + sizeof( newCommandLine ) - 1;
606 previousCommandLine = ValueForKey( &entities[0], "_q3map2_cmdline" );
607 if ( previousCommandLine && *previousCommandLine ) {
608 inpos = previousCommandLine;
609 while ( outpos != sentinel && *inpos )
610 *outpos++ = *inpos++;
611 if ( outpos != sentinel ) {
614 if ( outpos != sentinel ) {
619 for ( i = beginArgs; i < endArgs; ++i )
621 if ( outpos != sentinel && i != beginArgs ) {
625 while ( outpos != sentinel && *inpos )
626 if ( *inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ' ) {
627 *outpos++ = *inpos++;
632 SetKeyValue( &entities[0], "_q3map2_cmdline", newCommandLine );
633 SetKeyValue( &entities[0], "_q3map2_version", Q3MAP_VERSION );
640 generates the dentdata string from all the entities.
641 this allows the utilities to add or remove key/value
642 pairs to the data created by the map editor
645 void UnparseEntities( void ){
650 char key[ 1024 ], value[ 1024 ];
655 AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
661 /* run through entity list */
662 for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
666 AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
672 ep = entities[ i ].epairs;
674 continue; /* ent got removed */
677 /* ydnar: certain entities get stripped from bsp file */
678 value2 = ValueForKey( &entities[ i ], "classname" );
679 if ( !Q_stricmp( value2, "misc_model" ) ||
680 !Q_stricmp( value2, "_decal" ) ||
681 !Q_stricmp( value2, "_skybox" ) ) {
685 /* add beginning brace */
686 strcat( end, "{\n" );
689 /* walk epair list */
690 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
693 strcpy( key, ep->key );
694 StripTrailing( key );
695 strcpy( value, ep->value );
696 StripTrailing( value );
699 sprintf( line, "\"%s\" \"%s\"\n", key, value );
701 end += strlen( line );
704 /* add trailing brace */
708 /* check for overflow */
709 if ( end > buf + allocatedBSPEntData ) {
710 Error( "Entity text too long" );
715 bspEntDataSize = end - buf + 1;
722 prints an entity's epairs to the console
725 void PrintEntity( const entity_t *ent ){
729 Sys_Printf( "------- entity %p -------\n", ent );
730 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
731 Sys_Printf( "%s = %s\n", ep->key, ep->value );
739 sets an epair in an entity
742 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
746 /* check for existing epair */
747 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
749 if ( !EPAIR_STRCMP( ep->key, key ) ) {
751 ep->value = copystring( value );
756 /* create new epair */
757 ep = safe_malloc( sizeof( *ep ) );
758 ep->next = ent->epairs;
760 ep->key = copystring( key );
761 ep->value = copystring( value );
768 returns true if entity has this key
771 qboolean KeyExists( const entity_t *ent, const char *key ){
774 /* walk epair list */
775 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
777 if ( !EPAIR_STRCMP( ep->key, key ) ) {
790 gets the value for an entity key
793 const char *ValueForKey( const entity_t *ent, const char *key ){
802 /* walk epair list */
803 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
805 if ( !EPAIR_STRCMP( ep->key, key ) ) {
810 /* if no match, return empty string */
818 gets the integer point value for an entity key
821 int IntForKey( const entity_t *ent, const char *key ){
825 k = ValueForKey( ent, key );
833 gets the floating point value for an entity key
836 vec_t FloatForKey( const entity_t *ent, const char *key ){
840 k = ValueForKey( ent, key );
848 gets a 3-element vector value for an entity key
851 qboolean GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
857 k = ValueForKey( ent, key );
859 /* scanf into doubles, then assign, so it is vec_t size independent */
861 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
866 /* true if the key is found, false otherwise */
874 finds an entity target
877 entity_t *FindTargetEntity( const char *target ){
882 /* walk entity list */
883 for ( i = 0; i < numEntities; i++ )
885 n = ValueForKey( &entities[ i ], "targetname" );
886 if ( !strcmp( n, target ) ) {
887 return &entities[ i ];
898 GetEntityShadowFlags() - ydnar
899 gets an entity's shadow flags
900 note: does not set them to defaults if the keys are not found!
903 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
906 /* get cast shadows */
907 if ( castShadows != NULL ) {
908 value = ValueForKey( ent, "_castShadows" );
909 if ( value[ 0 ] == '\0' ) {
910 value = ValueForKey( ent, "_cs" );
912 if ( value[ 0 ] == '\0' ) {
913 value = ValueForKey( ent2, "_castShadows" );
915 if ( value[ 0 ] == '\0' ) {
916 value = ValueForKey( ent2, "_cs" );
918 if ( value[ 0 ] != '\0' ) {
919 *castShadows = atoi( value );
924 if ( recvShadows != NULL ) {
925 value = ValueForKey( ent, "_receiveShadows" );
926 if ( value[ 0 ] == '\0' ) {
927 value = ValueForKey( ent, "_rs" );
929 if ( value[ 0 ] == '\0' ) {
930 value = ValueForKey( ent2, "_receiveShadows" );
932 if ( value[ 0 ] == '\0' ) {
933 value = ValueForKey( ent2, "_rs" );
935 if ( value[ 0 ] != '\0' ) {
936 *recvShadows = atoi( value );
940 /* vortex: game-specific default eneity keys */
941 value = ValueForKey( ent, "classname" );
942 if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
943 /* vortex: deluxe quake default shadow flags */
944 if ( !Q_stricmp( value, "func_wall" ) ) {
945 if ( recvShadows != NULL ) {
948 if ( castShadows != NULL ) {