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 = MAX_MAP_DRAW_VERTS / 37;
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 if ( numBSPDrawVertsBuffer > MAX_MAP_DRAW_VERTS ) {
75 numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS;
78 bspDrawVerts = realloc( bspDrawVerts, sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer );
80 if ( !bspDrawVerts ) {
81 Error( "realloc() failed (IncDrawVerts)" );
85 memset( bspDrawVerts + ( numBSPDrawVerts - 1 ), 0, sizeof( bspDrawVert_t ) );
88 void SetDrawVerts( int n ){
89 if ( bspDrawVerts != 0 ) {
94 numBSPDrawVertsBuffer = numBSPDrawVerts;
96 bspDrawVerts = safe_malloc_info( sizeof( bspDrawVert_t ) * numBSPDrawVertsBuffer, "IncDrawVerts" );
98 memset( bspDrawVerts, 0, n * sizeof( bspDrawVert_t ) );
101 int numBSPDrawSurfacesBuffer = 0;
102 void SetDrawSurfacesBuffer(){
103 if ( bspDrawSurfaces != 0 ) {
104 free( bspDrawSurfaces );
107 numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
109 bspDrawSurfaces = safe_malloc_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
111 memset( bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof( bspDrawVert_t ) );
114 void SetDrawSurfaces( int n ){
115 if ( bspDrawSurfaces != 0 ) {
116 free( bspDrawSurfaces );
119 numBSPDrawSurfaces = n;
120 numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
122 bspDrawSurfaces = safe_malloc_info( sizeof( bspDrawSurface_t ) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces" );
124 memset( bspDrawSurfaces, 0, n * sizeof( bspDrawVert_t ) );
127 void BSPFilesCleanup(){
128 if ( bspDrawVerts != 0 ) {
129 free( bspDrawVerts );
131 if ( bspDrawSurfaces != 0 ) {
132 free( bspDrawSurfaces );
134 if ( bspLightBytes != 0 ) {
135 free( bspLightBytes );
137 if ( bspGridPoints != 0 ) {
138 free( bspGridPoints );
149 if all values are 32 bits, this can be used to swap everything
152 void SwapBlock( int *block, int size ){
157 if ( block == NULL ) {
163 for ( i = 0; i < size; i++ )
164 block[ i ] = LittleLong( block[ i ] );
171 byte swaps all data in the abstract bsp
174 void SwapBSPFile( void ){
179 SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) );
181 /* shaders (don't swap the name) */
182 for ( i = 0; i < numBSPShaders ; i++ )
184 bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
185 bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
189 SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
192 SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
195 SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
198 SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
201 SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
204 SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
207 SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
210 ( (int*) &bspVisBytes )[ 0 ] = LittleLong( ( (int*) &bspVisBytes )[ 0 ] );
211 ( (int*) &bspVisBytes )[ 1 ] = LittleLong( ( (int*) &bspVisBytes )[ 1 ] );
213 /* drawverts (don't swap colors) */
214 for ( i = 0; i < numBSPDrawVerts; i++ )
216 bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
217 bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
218 bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
219 bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
220 bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
221 bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
222 bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
223 bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
224 for ( j = 0; j < MAX_LIGHTMAPS; j++ )
226 bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
227 bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
232 SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
235 /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
236 SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
239 for ( i = 0; i < numBSPFogs; i++ )
241 bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
242 bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
246 for ( i = 0; i < numBSPAds; i++ )
248 bspAds[ i ].cellId = LittleLong( bspAds[ i ].cellId );
249 bspAds[ i ].normal[ 0 ] = LittleFloat( bspAds[ i ].normal[ 0 ] );
250 bspAds[ i ].normal[ 1 ] = LittleFloat( bspAds[ i ].normal[ 1 ] );
251 bspAds[ i ].normal[ 2 ] = LittleFloat( bspAds[ i ].normal[ 2 ] );
253 for ( j = 0; j < 4; j++ )
255 bspAds[ i ].rect[j][ 0 ] = LittleFloat( bspAds[ i ].rect[j][ 0 ] );
256 bspAds[ i ].rect[j][ 1 ] = LittleFloat( bspAds[ i ].rect[j][ 1 ] );
257 bspAds[ i ].rect[j][ 2 ] = LittleFloat( bspAds[ i ].rect[j][ 2 ] );
260 //bspAds[ i ].model[ MAX_QPATH ];
268 gets the number of elements in a bsp lump
271 int GetLumpElements( bspHeader_t *header, int lump, int size ){
272 /* check for odd size */
273 if ( header->lumps[ lump ].length % size ) {
275 Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
279 Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
283 /* return element count */
284 return header->lumps[ lump ].length / size;
291 returns a pointer to the specified lump
294 void *GetLump( bspHeader_t *header, int lump ){
295 return (void*)( (byte*) header + header->lumps[ lump ].offset );
302 copies a bsp file lump into a destination buffer
305 int CopyLump( bspHeader_t *header, int lump, void *dest, int size ){
309 /* get lump length and offset */
310 length = header->lumps[ lump ].length;
311 offset = header->lumps[ lump ].offset;
313 /* handle erroneous cases */
317 if ( length % size ) {
319 Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
323 Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
327 /* copy block of memory and return */
328 memcpy( dest, (byte*) header + offset, length );
329 return length / size;
336 adds a lump to an outgoing bsp file
339 void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length ){
343 /* add lump to bsp file header */
344 lump = &header->lumps[ lumpNum ];
345 lump->offset = LittleLong( ftell( file ) );
346 lump->length = LittleLong( length );
348 /* write lump to file */
349 SafeWrite( file, data, ( length + 3 ) & ~3 );
356 loads a bsp file into memory
359 void LoadBSPFile( const char *filename ){
361 if ( game == NULL || game->load == NULL ) {
362 Error( "LoadBSPFile: unsupported BSP file format" );
365 /* load it, then byte swap the in-memory version */
366 game->load( filename );
377 void WriteBSPFile( const char *filename ){
378 char tempname[ 1024 ];
383 if ( game == NULL || game->write == NULL ) {
384 Error( "WriteBSPFile: unsupported BSP file format" );
387 /* make fake temp name so existing bsp file isn't damaged in case write process fails */
389 sprintf( tempname, "%s.%08X", filename, (int) tm );
391 /* byteswap, write the bsp, then swap back so it can be manipulated further */
393 game->write( tempname );
396 /* replace existing bsp file */
398 rename( tempname, filename );
405 dumps info about current file
408 void PrintBSPFileSizes( void ){
409 /* parse entities first */
410 if ( numEntities <= 0 ) {
414 /* note that this is abstracted */
415 Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
417 /* print various and sundry bits */
418 Sys_Printf( "%9d models %9d\n",
419 numBSPModels, (int) ( numBSPModels * sizeof( bspModel_t ) ) );
420 Sys_Printf( "%9d shaders %9d\n",
421 numBSPShaders, (int) ( numBSPShaders * sizeof( bspShader_t ) ) );
422 Sys_Printf( "%9d brushes %9d\n",
423 numBSPBrushes, (int) ( numBSPBrushes * sizeof( bspBrush_t ) ) );
424 Sys_Printf( "%9d brushsides %9d *\n",
425 numBSPBrushSides, (int) ( numBSPBrushSides * sizeof( bspBrushSide_t ) ) );
426 Sys_Printf( "%9d fogs %9d\n",
427 numBSPFogs, (int) ( numBSPFogs * sizeof( bspFog_t ) ) );
428 Sys_Printf( "%9d planes %9d\n",
429 numBSPPlanes, (int) ( numBSPPlanes * sizeof( bspPlane_t ) ) );
430 Sys_Printf( "%9d entdata %9d\n",
431 numEntities, bspEntDataSize );
434 Sys_Printf( "%9d nodes %9d\n",
435 numBSPNodes, (int) ( numBSPNodes * sizeof( bspNode_t ) ) );
436 Sys_Printf( "%9d leafs %9d\n",
437 numBSPLeafs, (int) ( numBSPLeafs * sizeof( bspLeaf_t ) ) );
438 Sys_Printf( "%9d leafsurfaces %9d\n",
439 numBSPLeafSurfaces, (int) ( numBSPLeafSurfaces * sizeof( *bspLeafSurfaces ) ) );
440 Sys_Printf( "%9d leafbrushes %9d\n",
441 numBSPLeafBrushes, (int) ( numBSPLeafBrushes * sizeof( *bspLeafBrushes ) ) );
444 Sys_Printf( "%9d drawsurfaces %9d *\n",
445 numBSPDrawSurfaces, (int) ( numBSPDrawSurfaces * sizeof( *bspDrawSurfaces ) ) );
446 Sys_Printf( "%9d drawverts %9d *\n",
447 numBSPDrawVerts, (int) ( numBSPDrawVerts * sizeof( *bspDrawVerts ) ) );
448 Sys_Printf( "%9d drawindexes %9d\n",
449 numBSPDrawIndexes, (int) ( numBSPDrawIndexes * sizeof( *bspDrawIndexes ) ) );
452 Sys_Printf( "%9d lightmaps %9d\n",
453 numBSPLightBytes / ( game->lightmapSize * game->lightmapSize * 3 ), numBSPLightBytes );
454 Sys_Printf( "%9d lightgrid %9d *\n",
455 numBSPGridPoints, (int) ( numBSPGridPoints * sizeof( *bspGridPoints ) ) );
456 Sys_Printf( " visibility %9d\n",
462 /* -------------------------------------------------------------------------------
466 ------------------------------------------------------------------------------- */
471 strips low byte chars off the end of a string
474 void StripTrailing( char *e ){
478 s = e + strlen( e ) - 1;
479 while ( s >= e && *s <= 32 )
490 parses a single quoted "key" "value" pair into an epair struct
493 epair_t *ParseEPair( void ){
497 /* allocate and clear new epair */
498 e = safe_malloc( sizeof( epair_t ) );
499 memset( e, 0, sizeof( epair_t ) );
502 if ( strlen( token ) >= ( MAX_KEY - 1 ) ) {
503 Error( "ParseEPair: token too long" );
506 e->key = copystring( token );
510 if ( strlen( token ) >= MAX_VALUE - 1 ) {
511 Error( "ParseEpar: token too long" );
513 e->value = copystring( token );
515 /* strip trailing spaces that sometimes get accidentally added in the editor */
516 StripTrailing( e->key );
517 StripTrailing( e->value );
527 parses an entity's epairs
530 qboolean ParseEntity( void ){
535 if ( !GetToken( qtrue ) ) {
538 if ( strcmp( token, "{" ) ) {
539 Error( "ParseEntity: { not found" );
541 if ( numEntities == MAX_MAP_ENTITIES ) {
542 Error( "numEntities == MAX_MAP_ENTITIES" );
545 /* create new entity */
546 mapEnt = &entities[ numEntities ];
552 if ( !GetToken( qtrue ) ) {
553 Error( "ParseEntity: EOF without closing brace" );
555 if ( !EPAIR_STRCMP( token, "}" ) ) {
559 e->next = mapEnt->epairs;
563 /* return to sender */
571 parses the bsp entity data string into entities
574 void ParseEntities( void ){
576 ParseFromMemory( bspEntData, bspEntDataSize );
577 while ( ParseEntity() ) ;
579 /* ydnar: set number of bsp entities in case a map is loaded on top */
580 numBSPEntities = numEntities;
587 generates the dentdata string from all the entities.
588 this allows the utilities to add or remove key/value
589 pairs to the data created by the map editor
592 void UnparseEntities( void ){
597 char key[ 1024 ], value[ 1024 ];
606 /* run through entity list */
607 for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
610 ep = entities[ i ].epairs;
612 continue; /* ent got removed */
615 /* ydnar: certain entities get stripped from bsp file */
616 value2 = ValueForKey( &entities[ i ], "classname" );
617 if ( !Q_stricmp( value2, "misc_model" ) ||
618 !Q_stricmp( value2, "_decal" ) ||
619 !Q_stricmp( value2, "_skybox" ) ) {
623 /* add beginning brace */
624 strcat( end, "{\n" );
627 /* walk epair list */
628 for ( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
631 strcpy( key, ep->key );
632 StripTrailing( key );
633 strcpy( value, ep->value );
634 StripTrailing( value );
637 sprintf( line, "\"%s\" \"%s\"\n", key, value );
639 end += strlen( line );
642 /* add trailing brace */
646 /* check for overflow */
647 if ( end > buf + MAX_MAP_ENTSTRING ) {
648 Error( "Entity text too long" );
653 bspEntDataSize = end - buf + 1;
660 prints an entity's epairs to the console
663 void PrintEntity( const entity_t *ent ){
667 Sys_Printf( "------- entity %p -------\n", ent );
668 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
669 Sys_Printf( "%s = %s\n", ep->key, ep->value );
677 sets an epair in an entity
680 void SetKeyValue( entity_t *ent, const char *key, const char *value ){
684 /* check for existing epair */
685 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
687 if ( !EPAIR_STRCMP( ep->key, key ) ) {
689 ep->value = copystring( value );
694 /* create new epair */
695 ep = safe_malloc( sizeof( *ep ) );
696 ep->next = ent->epairs;
698 ep->key = copystring( key );
699 ep->value = copystring( value );
706 gets the value for an entity key
709 const char *ValueForKey( const entity_t *ent, const char *key ){
718 /* walk epair list */
719 for ( ep = ent->epairs; ep != NULL; ep = ep->next )
721 if ( !EPAIR_STRCMP( ep->key, key ) ) {
726 /* if no match, return empty string */
734 gets the integer point value for an entity key
737 int IntForKey( const entity_t *ent, const char *key ){
741 k = ValueForKey( ent, key );
749 gets the floating point value for an entity key
752 vec_t FloatForKey( const entity_t *ent, const char *key ){
756 k = ValueForKey( ent, key );
764 gets a 3-element vector value for an entity key
767 void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec ){
773 k = ValueForKey( ent, key );
775 /* scanf into doubles, then assign, so it is vec_t size independent */
777 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
787 finds an entity target
790 entity_t *FindTargetEntity( const char *target ){
795 /* walk entity list */
796 for ( i = 0; i < numEntities; i++ )
798 n = ValueForKey( &entities[ i ], "targetname" );
799 if ( !strcmp( n, target ) ) {
800 return &entities[ i ];
811 GetEntityShadowFlags() - ydnar
812 gets an entity's shadow flags
813 note: does not set them to defaults if the keys are not found!
816 void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows ){
820 /* get cast shadows */
821 if ( castShadows != NULL ) {
822 value = ValueForKey( ent, "_castShadows" );
823 if ( value[ 0 ] == '\0' ) {
824 value = ValueForKey( ent, "_cs" );
826 if ( value[ 0 ] == '\0' ) {
827 value = ValueForKey( ent2, "_castShadows" );
829 if ( value[ 0 ] == '\0' ) {
830 value = ValueForKey( ent2, "_cs" );
832 if ( value[ 0 ] != '\0' ) {
833 *castShadows = atoi( value );
838 if ( recvShadows != NULL ) {
839 value = ValueForKey( ent, "_receiveShadows" );
840 if ( value[ 0 ] == '\0' ) {
841 value = ValueForKey( ent, "_rs" );
843 if ( value[ 0 ] == '\0' ) {
844 value = ValueForKey( ent2, "_receiveShadows" );
846 if ( value[ 0 ] == '\0' ) {
847 value = ValueForKey( ent2, "_rs" );
849 if ( value[ 0 ] != '\0' ) {
850 *recvShadows = atoi( value );