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++ )
175 si = ShaderInfoForShader( bspShaders[ i ].shader );
176 if ( si->remapShader && si->remapShader[ 0 ] ) {
177 strcpy( bspShaders[ i ].shader, si->remapShader );
180 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
181 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
185 SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
188 SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
191 SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
194 SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
197 SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
200 SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
203 SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
206 ( (int*) &bspVisBytes )[ 0 ] = LittleLong( ( (int*) &bspVisBytes )[ 0 ] );
207 ( (int*) &bspVisBytes )[ 1 ] = LittleLong( ( (int*) &bspVisBytes )[ 1 ] );
209 /* drawverts (don't swap colors) */
210 for ( i = 0; i < numBSPDrawVerts; i++ )
212 bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
213 bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
214 bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
215 bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
216 bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
217 bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
218 bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
219 bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
220 for ( j = 0; j < MAX_LIGHTMAPS; j++ )
222 bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
223 bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
228 SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
231 /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
232 SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
235 for ( i = 0; i < numBSPFogs; i++ )
237 bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
238 bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
242 for ( i = 0; i < numBSPAds; i++ )
244 bspAds[ i ].cellId = LittleLong( bspAds[ i ].cellId );
245 bspAds[ i ].normal[ 0 ] = LittleFloat( bspAds[ i ].normal[ 0 ] );
246 bspAds[ i ].normal[ 1 ] = LittleFloat( bspAds[ i ].normal[ 1 ] );
247 bspAds[ i ].normal[ 2 ] = LittleFloat( bspAds[ i ].normal[ 2 ] );
249 for ( j = 0; j < 4; j++ )
251 bspAds[ i ].rect[j][ 0 ] = LittleFloat( bspAds[ i ].rect[j][ 0 ] );
252 bspAds[ i ].rect[j][ 1 ] = LittleFloat( bspAds[ i ].rect[j][ 1 ] );
253 bspAds[ i ].rect[j][ 2 ] = LittleFloat( bspAds[ i ].rect[j][ 2 ] );
256 //bspAds[ i ].model[ MAX_QPATH ];
264 gets the number of elements in a bsp lump
267 int GetLumpElements( bspHeader_t *header, int lump, int size ){
268 /* check for odd size */
269 if ( header->lumps[ lump ].length % size ) {
271 Sys_FPrintf( SYS_WRN, "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
275 Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
279 /* return element count */
280 return header->lumps[ lump ].length / size;
287 returns a pointer to the specified lump
290 void *GetLump( bspHeader_t *header, int lump ){
291 return (void*)( (byte*) header + header->lumps[ lump ].offset );
298 copies a bsp file lump into a destination buffer
301 int CopyLump( bspHeader_t *header, int lump, void *dest, int size ){
305 /* get lump length and offset */
306 length = header->lumps[ lump ].length;
307 offset = header->lumps[ lump ].offset;
309 /* handle erroneous cases */
313 if ( length % size ) {
315 Sys_FPrintf( SYS_WRN, "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
319 Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
323 /* copy block of memory and return */
324 memcpy( dest, (byte*) header + offset, length );
325 return length / size;
328 int CopyLump_Allocate( bspHeader_t *header, int lump, void **dest, int size, int *allocationVariable ){
329 /* get lump length and offset */
330 *allocationVariable = header->lumps[ lump ].length / size;
331 *dest = realloc( *dest, size * *allocationVariable );
332 return CopyLump( header, lump, *dest, size );
338 adds a lump to an outgoing bsp file
341 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
344 /* add lump to bsp file header */
345 lump = &header->lumps[ lumpNum ];
346 lump->offset = LittleLong( ftell( file ) );
347 lump->length = LittleLong( length );
349 /* write lump to file */
350 SafeWrite( file, data, length );
352 /* write padding zeros */
353 SafeWrite( file, (const byte[3]){ 0, 0, 0 }, ( ( length + 3 ) & ~3 ) - length );
360 loads a bsp file into memory
363 void LoadBSPFile( const char *filename ){
365 if ( game == NULL || game->load == NULL ) {
366 Error( "LoadBSPFile: unsupported BSP file format" );
369 /* load it, then byte swap the in-memory version */
370 game->load( filename );
381 void WriteBSPFile( const char *filename ){
382 char tempname[ 1024 ];
387 if ( game == NULL || game->write == NULL ) {
388 Error( "WriteBSPFile: unsupported BSP file format" );
391 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
393 sprintf( tempname, "%s.%08X", filename, (int) tm );
395 /* byteswap, write the bsp, then swap back so it can be manipulated further */
397 game->write( tempname );
400 /* replace existing bsp file */
402 rename( tempname, filename );
409 dumps info about current file
412 void PrintBSPFileSizes( void ){
413 /* parse entities first */
414 if ( numEntities <= 0 ) {
418 /* note that this is abstracted */
419 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
421 /* print various and sundry bits */
422 Sys_Printf( "%9d models %9d\n",
423 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
424 Sys_Printf( "%9d shaders %9d\n",
425 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
426 Sys_Printf( "%9d brushes %9d\n",
427 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
428 Sys_Printf( "%9d brushsides %9d *\n",
429 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
430 Sys_Printf( "%9d fogs %9d\n",
431 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
432 Sys_Printf( "%9d planes %9d\n",
433 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
434 Sys_Printf( "%9d entdata %9d\n",
435 numEntities, bspEntDataSize );
438 Sys_Printf( "%9d nodes %9d\n",
439 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
440 Sys_Printf( "%9d leafs %9d\n",
441 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
442 Sys_Printf( "%9d leafsurfaces %9d\n",
443 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
444 Sys_Printf( "%9d leafbrushes %9d\n",
445 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
448 Sys_Printf( "%9d drawsurfaces %9d *\n",
449 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
450 Sys_Printf( "%9d drawverts %9d *\n",
451 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
452 Sys_Printf( "%9d drawindexes %9d\n",
453 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
456 Sys_Printf( "%9d lightmaps %9d\n",
457 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
458 Sys_Printf( "%9d lightgrid %9d *\n",
459 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
460 Sys_Printf( " visibility %9d\n",
466 /* -------------------------------------------------------------------------------
470 ------------------------------------------------------------------------------- */
475 strips low byte chars off the end of a string
478 void StripTrailing( char *e ){
482 s = e + strlen( e ) - 1;
483 while ( s >= e && *s <= 32 )
494 parses a single quoted "key" "value" pair into an epair struct
497 epair_t *ParseEPair( void ){
501 /* allocate and clear new epair */
502 e = safe_malloc0( sizeof( epair_t ) );
505 if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
506 Error( "ParseEPair: token too long" );
509 e->key = copystring( token );
513 if ( strlen( token ) >= MAX_VALUE - 1 ) {
514 Error( "ParseEpar: token too long" );
516 e->value = copystring( token );
518 /* strip trailing spaces that sometimes get accidentally added in the editor */
519 StripTrailing( e->key );
520 StripTrailing( e->value );
530 parses an entity's epairs
533 qboolean ParseEntity( void ){
538 if ( !GetToken( qtrue ) ) {
541 if ( strcmp( token, "{" ) ) {
542 Error( "ParseEntity: { not found" );
544 AUTOEXPAND_BY_REALLOC( entities, numEntities, allocatedEntities, 32 );
546 /* create new entity */
547 mapEnt = &entities[ numEntities ];
549 memset( mapEnt, 0, sizeof( *mapEnt ) );
554 if ( !GetToken( qtrue ) ) {
555 Error( "ParseEntity: EOF without closing brace" );
557 if ( !EPAIR_STRCMP( token, "}" ) ) {
561 e->next = mapEnt->epairs;
565 /* return to sender */
573 parses the bsp entity data string into entities
576 void ParseEntities( void ){
578 ParseFromMemory( bspEntData, bspEntDataSize );
579 while ( ParseEntity() ) ;
581 /* ydnar: set number of bsp entities in case a map is loaded on top */
582 numBSPEntities = numEntities;
588 * must be called before UnparseEntities
590 void InjectCommandLine( char **argv, int beginArgs, int endArgs ){
591 const char *previousCommandLine;
592 char newCommandLine[1024];
594 char *outpos = newCommandLine;
595 char *sentinel = newCommandLine + sizeof( newCommandLine ) - 1;
602 previousCommandLine = ValueForKey( &entities[0], "_q3map2_cmdline" );
603 if ( previousCommandLine && *previousCommandLine ) {
604 inpos = previousCommandLine;
605 while ( outpos != sentinel && *inpos )
606 *outpos++ = *inpos++;
607 if ( outpos != sentinel ) {
610 if ( outpos != sentinel ) {
615 for ( i = beginArgs; i < endArgs; ++i )
617 if ( argv[i] == NULL ) {
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 );
639 generates the dentdata string from all the entities.
640 this allows the utilities to add or remove key/value
641 pairs to the data created by the map editor
644 void UnparseEntities( void ){
649 char key[ 1024 ], value[ 1024 ];
654 AUTOEXPAND_BY_REALLOC( bspEntData, 0, allocatedBSPEntData, 1024 );
660 /* run through entity list */
661 for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
665 AUTOEXPAND_BY_REALLOC( bspEntData, sz + 65536, allocatedBSPEntData, 1024 );
671 ep = entities[ i ].epairs;
673 continue; /* ent got removed */
676 /* ydnar: certain entities get stripped from bsp file */
677 value2 = ValueForKey( &entities[ i ], "classname" );
678 if ( !Q_stricmp( value2, "misc_model" ) ||
679 !Q_stricmp( value2, "_decal" ) ||
680 !Q_stricmp( value2, "_skybox" ) ) {
684 /* add beginning brace */
685 strcat( end, "{\n" );
688 /* walk epair list */
689 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
692 strcpy( key, ep->key );
693 StripTrailing( key );
694 strcpy( value, ep->value );
695 StripTrailing( value );
698 sprintf( line, "\"%s\" \"%s\"\n", key, value );
700 end += strlen( line );
703 /* add trailing brace */
707 /* check for overflow */
708 if ( end > buf + allocatedBSPEntData ) {
709 Error( "Entity text too long" );
714 bspEntDataSize = end - buf + 1;
721 prints an entity's epairs to the console
724 void PrintEntity( const entity_t *ent ){
728 Sys_Printf( "------- entity %p -------\n", ent );
729 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
730 Sys_Printf( "%s = %s\n", ep->key, ep->value );
738 sets an epair in an entity
741 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
745 /* check for existing epair */
746 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
748 if ( !EPAIR_STRCMP( ep->key, key ) ) {
750 ep->value = copystring( value );
755 /* create new epair */
756 ep = safe_malloc( sizeof( *ep ) );
757 ep->next = ent->epairs;
759 ep->key = copystring( key );
760 ep->value = copystring( value );
767 returns true if entity has this key
770 qboolean KeyExists( const entity_t *ent, const char *key ){
773 /* walk epair list */
774 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
776 if ( !EPAIR_STRCMP( ep->key, key ) ) {
789 gets the value for an entity key
792 const char *ValueForKey( const entity_t *ent, const char *key ){
801 /* walk epair list */
802 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
804 if ( !EPAIR_STRCMP( ep->key, key ) ) {
809 /* if no match, return empty string */
817 gets the integer point value for an entity key
820 int IntForKey( const entity_t *ent, const char *key ){
824 k = ValueForKey( ent, key );
832 gets the floating point value for an entity key
835 vec_t FloatForKey( const entity_t *ent, const char *key ){
839 k = ValueForKey( ent, key );
847 gets a 3-element vector value for an entity key
850 qboolean GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
856 k = ValueForKey( ent, key );
858 /* scanf into doubles, then assign, so it is vec_t size independent */
860 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
865 /* true if the key is found, false otherwise */
873 finds an entity target
876 entity_t *FindTargetEntity( const char *target ){
881 /* walk entity list */
882 for ( i = 0; i < numEntities; i++ )
884 n = ValueForKey( &entities[ i ], "targetname" );
885 if ( !strcmp( n, target ) ) {
886 return &entities[ i ];
897 GetEntityShadowFlags() - ydnar
898 gets an entity's shadow flags
899 note: does not set them to defaults if the keys are not found!
902 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
905 /* get cast shadows */
906 if ( castShadows != NULL ) {
907 value = ValueForKey( ent, "_castShadows" );
908 if ( value[ 0 ] == '\0' ) {
909 value = ValueForKey( ent, "_cs" );
911 if ( value[ 0 ] == '\0' ) {
912 value = ValueForKey( ent2, "_castShadows" );
914 if ( value[ 0 ] == '\0' ) {
915 value = ValueForKey( ent2, "_cs" );
917 if ( value[ 0 ] != '\0' ) {
918 *castShadows = atoi( value );
923 if ( recvShadows != NULL ) {
924 value = ValueForKey( ent, "_receiveShadows" );
925 if ( value[ 0 ] == '\0' ) {
926 value = ValueForKey( ent, "_rs" );
928 if ( value[ 0 ] == '\0' ) {
929 value = ValueForKey( ent2, "_receiveShadows" );
931 if ( value[ 0 ] == '\0' ) {
932 value = ValueForKey( ent2, "_rs" );
934 if ( value[ 0 ] != '\0' ) {
935 *recvShadows = atoi( value );
939 /* vortex: game-specific default eneity keys */
940 value = ValueForKey( ent, "classname" );
941 if ( !Q_stricmp( game->magic, "dq" ) || !Q_stricmp( game->magic, "prophecy" ) ) {
942 /* vortex: deluxe quake default shadow flags */
943 if ( !Q_stricmp( value, "func_wall" ) ) {
944 if ( recvShadows != NULL ) {
947 if ( castShadows != NULL ) {