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 char zeros[3] = { 0, 0, 0 };
348 SafeWrite( file, zeros, ( ( length + 3 ) & ~3 ) - length );
355 loads a bsp file into memory
358 void LoadBSPFile( const char *filename ){
360 if ( game == NULL || game->load == NULL ) {
361 Error( "LoadBSPFile: unsupported BSP file format" );
364 /* load it, then byte swap the in-memory version */
365 game->load( filename );
376 void WriteBSPFile( const char *filename ){
377 char tempname[ 1024 ];
382 if ( game == NULL || game->write == NULL ) {
383 Error( "WriteBSPFile: unsupported BSP file format" );
386 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
388 sprintf( tempname, "%s.%08X", filename, (int) tm );
390 /* byteswap, write the bsp, then swap back so it can be manipulated further */
392 game->write( tempname );
395 /* replace existing bsp file */
397 rename( tempname, filename );
404 dumps info about current file
407 void PrintBSPFileSizes( void ){
408 /* parse entities first */
409 if ( numEntities <= 0 ) {
413 /* note that this is abstracted */
414 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
416 /* print various and sundry bits */
417 Sys_Printf( "%9d models %9d\n",
418 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
419 Sys_Printf( "%9d shaders %9d\n",
420 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
421 Sys_Printf( "%9d brushes %9d\n",
422 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
423 Sys_Printf( "%9d brushsides %9d *\n",
424 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
425 Sys_Printf( "%9d fogs %9d\n",
426 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
427 Sys_Printf( "%9d planes %9d\n",
428 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
429 Sys_Printf( "%9d entdata %9d\n",
430 numEntities, bspEntDataSize );
433 Sys_Printf( "%9d nodes %9d\n",
434 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
435 Sys_Printf( "%9d leafs %9d\n",
436 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
437 Sys_Printf( "%9d leafsurfaces %9d\n",
438 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
439 Sys_Printf( "%9d leafbrushes %9d\n",
440 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
443 Sys_Printf( "%9d drawsurfaces %9d *\n",
444 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
445 Sys_Printf( "%9d drawverts %9d *\n",
446 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
447 Sys_Printf( "%9d drawindexes %9d\n",
448 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
451 Sys_Printf( "%9d lightmaps %9d\n",
452 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
453 Sys_Printf( "%9d lightgrid %9d *\n",
454 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
455 Sys_Printf( " visibility %9d\n",
461 /* -------------------------------------------------------------------------------
465 ------------------------------------------------------------------------------- */
470 strips low byte chars off the end of a string
473 void StripTrailing( char *e ){
477 s = e + strlen( e ) - 1;
478 while ( s >= e && *s <= 32 )
489 parses a single quoted "key" "value" pair into an epair struct
492 epair_t *ParseEPair( void ){
496 /* allocate and clear new epair */
497 e = safe_malloc0( sizeof( epair_t ) );
500 if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
501 Error( "ParseEPair: token too long" );
504 e->key = copystring( token );
508 if ( strlen( token ) >= MAX_VALUE - 1 ) {
509 Error( "ParseEpar: token too long" );
511 e->value = copystring( token );
513 /* strip trailing spaces that sometimes get accidentally added in the editor */
514 StripTrailing( e->key );
515 StripTrailing( e->value );
525 parses an entity's epairs
528 qboolean ParseEntity( void ){
533 if ( !GetToken( qtrue ) ) {
536 if ( strcmp( token, "{" ) ) {
537 Error( "ParseEntity: { not found" );
539 AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
541 /* create new entity */
542 mapEnt = &entities[ numEntities ];
544 memset( mapEnt, 0, sizeof( *mapEnt ) );
549 if ( !GetToken( qtrue ) ) {
550 Error( "ParseEntity: EOF without closing brace" );
552 if ( !EPAIR_STRCMP( token, "}" ) ) {
556 e->next = mapEnt->epairs;
560 /* return to sender */
568 parses the bsp entity data string into entities
571 void ParseEntities( void ){
573 ParseFromMemory( bspEntData, bspEntDataSize );
574 while ( ParseEntity() ) ;
576 /* ydnar: set number of bsp entities in case a map is loaded on top */
577 numBSPEntities = numEntities;
583 * must be called before UnparseEntities
585 void InjectCommandLine( char **argv, int beginArgs, int endArgs ){
586 const char *previousCommandLine;
587 char newCommandLine[1024];
589 char *outpos = newCommandLine;
590 char *sentinel = newCommandLine + sizeof( newCommandLine ) - 1;
593 previousCommandLine = ValueForKey( &entities[0], "_q3map2_cmdline" );
594 if ( previousCommandLine && *previousCommandLine ) {
595 inpos = previousCommandLine;
596 while ( outpos != sentinel && *inpos )
597 *outpos++ = *inpos++;
598 if ( outpos != sentinel ) {
601 if ( outpos != sentinel ) {
606 for ( i = beginArgs; i < endArgs; ++i )
608 if ( outpos != sentinel && i != beginArgs ) {
612 while ( outpos != sentinel && *inpos )
613 if ( *inpos != '\\' && *inpos != '"' && *inpos != ';' && (unsigned char) *inpos >= ' ' ) {
614 *outpos++ = *inpos++;
619 SetKeyValue( &entities[0], "_q3map2_cmdline", newCommandLine );
620 SetKeyValue( &entities[0], "_q3map2_version", Q3MAP_VERSION );
627 generates the dentdata string from all the entities.
628 this allows the utilities to add or remove key/value
629 pairs to the data created by the map editor
632 void UnparseEntities( void ){
637 char key[ 1024 ], value[ 1024 ];
642 AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
648 /* run through entity list */
649 for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
653 AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
659 ep = entities[ i ].epairs;
661 continue; /* ent got removed */
664 /* ydnar: certain entities get stripped from bsp file */
665 value2 = ValueForKey( &entities[ i ], "classname" );
666 if ( !Q_stricmp( value2, "misc_model" ) ||
667 !Q_stricmp( value2, "_decal" ) ||
668 !Q_stricmp( value2, "_skybox" ) ) {
672 /* add beginning brace */
673 strcat( end, "{\n" );
676 /* walk epair list */
677 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
680 strcpy( key, ep->key );
681 StripTrailing( key );
682 strcpy( value, ep->value );
683 StripTrailing( value );
686 sprintf( line, "\"%s\" \"%s\"\n", key, value );
688 end += strlen( line );
691 /* add trailing brace */
695 /* check for overflow */
696 if ( end > buf + allocatedBSPEntData ) {
697 Error( "Entity text too long" );
702 bspEntDataSize = end - buf + 1;
709 prints an entity's epairs to the console
712 void PrintEntity( const entity_t *ent ){
716 Sys_Printf( "------- entity %p -------\n", ent );
717 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
718 Sys_Printf( "%s = %s\n", ep->key, ep->value );
726 sets an epair in an entity
729 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
733 /* check for existing epair */
734 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
736 if ( !EPAIR_STRCMP( ep->key, key ) ) {
738 ep->value = copystring( value );
743 /* create new epair */
744 ep = safe_malloc( sizeof( *ep ) );
745 ep->next = ent->epairs;
747 ep->key = copystring( key );
748 ep->value = copystring( value );
755 returns true if entity has this key
758 qboolean KeyExists( const entity_t *ent, const char *key ){
761 /* walk epair list */
762 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
764 if ( !EPAIR_STRCMP( ep->key, key ) ) {
777 gets the value for an entity key
780 const char *ValueForKey( const entity_t *ent, const char *key ){
789 /* walk epair list */
790 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
792 if ( !EPAIR_STRCMP( ep->key, key ) ) {
797 /* if no match, return empty string */
805 gets the integer point value for an entity key
808 int IntForKey( const entity_t *ent, const char *key ){
812 k = ValueForKey( ent, key );
820 gets the floating point value for an entity key
823 vec_t FloatForKey( const entity_t *ent, const char *key ){
827 k = ValueForKey( ent, key );
835 gets a 3-element vector value for an entity key
838 qboolean GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
844 k = ValueForKey( ent, key );
846 /* scanf into doubles, then assign, so it is vec_t size independent */
848 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
853 /* true if the key is found, false otherwise */
861 finds an entity target
864 entity_t *FindTargetEntity( const char *target ){
869 /* walk entity list */
870 for ( i = 0; i < numEntities; i++ )
872 n = ValueForKey( &entities[ i ], "targetname" );
873 if ( !strcmp( n, target ) ) {
874 return &entities[ i ];
885 GetEntityShadowFlags() - ydnar
886 gets an entity's shadow flags
887 note: does not set them to defaults if the keys are not found!
890 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
893 /* get cast shadows */
894 if ( castShadows != NULL ) {
895 value = ValueForKey( ent, "_castShadows" );
896 if ( value[ 0 ] == '\0' ) {
897 value = ValueForKey( ent, "_cs" );
899 if ( value[ 0 ] == '\0' ) {
900 value = ValueForKey( ent2, "_castShadows" );
902 if ( value[ 0 ] == '\0' ) {
903 value = ValueForKey( ent2, "_cs" );
905 if ( value[ 0 ] != '\0' ) {
906 *castShadows = atoi( value );
911 if ( recvShadows != NULL ) {
912 value = ValueForKey( ent, "_receiveShadows" );
913 if ( value[ 0 ] == '\0' ) {
914 value = ValueForKey( ent, "_rs" );
916 if ( value[ 0 ] == '\0' ) {
917 value = ValueForKey( ent2, "_receiveShadows" );
919 if ( value[ 0 ] == '\0' ) {
920 value = ValueForKey( ent2, "_rs" );
922 if ( value[ 0 ] != '\0' ) {
923 *recvShadows = atoi( value );
927 /* vortex: game-specific default eneity keys */
928 value = ValueForKey( ent, "classname" );
929 if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
930 /* vortex: deluxe quake default shadow flags */
931 if ( !Q_stricmp( value, "func_wall" ) ) {
932 if ( recvShadows != NULL ) {
935 if ( castShadows != NULL ) {