]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake3/q3map2/bspfile_abstract.c
rebuilt gtk binary dependencies file
[xonotic/netradiant.git] / tools / quake3 / q3map2 / bspfile_abstract.c
index db34dd61f7045c693e521ff3d73e7f7a6b801cd2..31b6f171bd4a425d9fe586ada8b2e122ed62ab5b 100644 (file)
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-\r
-----------------------------------------------------------------------------------\r
-\r
-This code has been altered significantly from its original form, to support\r
-several games based on the Quake III Arena engine, in the form of "Q3Map2."\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-\r
-\r
-/* marker */\r
-#define BSPFILE_ABSTRACT_C\r
-\r
-\r
-\r
-/* dependencies */\r
-#include "q3map2.h"\r
-\r
-\r
-\r
-\r
-/* -------------------------------------------------------------------------------\r
-\r
-this file was copied out of the common directory in order to not break\r
-compatibility with the q3map 1.x tree. it was moved out in order to support\r
-the raven bsp format (RBSP) used in soldier of fortune 2 and jedi knight 2.\r
-\r
-since each game has its own set of particular features, the data structures\r
-below no longer directly correspond to the binary format of a particular game.\r
-\r
-the translation will be done at bsp load/save time to keep any sort of\r
-special-case code messiness out of the rest of the program.\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-\r
-\r
-/* FIXME: remove the functions below that handle memory management of bsp file chunks */\r
-\r
-int numBSPDrawVertsBuffer = 0;\r
-void IncDrawVerts()\r
-{\r
-       numBSPDrawVerts++;\r
-\r
-       if(bspDrawVerts == 0)\r
-       {\r
-               numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS / 37;\r
-               \r
-               bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");\r
-\r
-       }\r
-       else if(numBSPDrawVerts > numBSPDrawVertsBuffer)\r
-       {\r
-               numBSPDrawVertsBuffer *= 3; // multiply by 1.5\r
-               numBSPDrawVertsBuffer /= 2;\r
-\r
-               if(numBSPDrawVertsBuffer > MAX_MAP_DRAW_VERTS)\r
-                       numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS;\r
-\r
-               bspDrawVerts = realloc(bspDrawVerts, sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer);\r
-\r
-               if(!bspDrawVerts)\r
-                       Error( "realloc() failed (IncDrawVerts)");\r
-       }\r
-\r
-       memset(bspDrawVerts + (numBSPDrawVerts - 1), 0, sizeof(bspDrawVert_t));\r
-}\r
-\r
-void SetDrawVerts(int n)\r
-{\r
-       if(bspDrawVerts != 0)\r
-               free(bspDrawVerts);\r
-\r
-       numBSPDrawVerts = n;\r
-       numBSPDrawVertsBuffer = numBSPDrawVerts;\r
-\r
-       bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");\r
-\r
-       memset(bspDrawVerts, 0, n * sizeof(bspDrawVert_t));\r
-}\r
-\r
-int numBSPDrawSurfacesBuffer = 0;\r
-void SetDrawSurfacesBuffer()\r
-{\r
-       if(bspDrawSurfaces != 0)\r
-               free(bspDrawSurfaces);\r
-\r
-       numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;\r
-\r
-       bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");\r
-\r
-       memset(bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof(bspDrawVert_t));\r
-}\r
-\r
-void SetDrawSurfaces(int n)\r
-{\r
-       if(bspDrawSurfaces != 0)\r
-               free(bspDrawSurfaces);\r
-\r
-       numBSPDrawSurfaces = n;\r
-       numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;\r
-\r
-       bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");\r
-\r
-       memset(bspDrawSurfaces, 0, n * sizeof(bspDrawVert_t));\r
-}\r
-\r
-void BSPFilesCleanup()\r
-{\r
-       if(bspDrawVerts != 0)\r
-               free(bspDrawVerts);\r
-       if(bspDrawSurfaces != 0)\r
-               free(bspDrawSurfaces);\r
-       if(bspLightBytes != 0)\r
-               free(bspLightBytes);\r
-       if(bspGridPoints != 0)\r
-               free(bspGridPoints);\r
-}\r
-\r
-\r
-\r
-\r
-\r
-\r
-/*\r
-SwapBlock()\r
-if all values are 32 bits, this can be used to swap everything\r
-*/\r
-\r
-void SwapBlock( int *block, int size )\r
-{\r
-       int             i;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( block == NULL )\r
-               return;\r
-       \r
-       /* swap */\r
-       size >>= 2;\r
-       for( i = 0; i < size; i++ )\r
-               block[ i ] = LittleLong( block[ i ] );\r
-}\r
-\r
-\r
-\r
-/*\r
-SwapBSPFile()\r
-byte swaps all data in the abstract bsp\r
-*/\r
-\r
-void SwapBSPFile( void )\r
-{\r
-       int             i, j;\r
-       \r
-       \r
-       /* models */\r
-       SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) );\r
-\r
-       /* shaders (don't swap the name) */\r
-       for( i = 0; i < numBSPShaders ; i++ )\r
-       {\r
-               bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );\r
-               bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );\r
-       }\r
-\r
-       /* planes */\r
-       SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );\r
-       \r
-       /* nodes */\r
-       SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );\r
-\r
-       /* leafs */\r
-       SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );\r
-\r
-       /* leaffaces */\r
-       SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );\r
-\r
-       /* leafbrushes */\r
-       SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );\r
-\r
-       // brushes\r
-       SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );\r
-\r
-       // brushsides\r
-       SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );\r
-\r
-       // vis\r
-       ((int*) &bspVisBytes)[ 0 ] = LittleLong( ((int*) &bspVisBytes)[ 0 ] );\r
-       ((int*) &bspVisBytes)[ 1 ] = LittleLong( ((int*) &bspVisBytes)[ 1 ] );\r
-\r
-       /* drawverts (don't swap colors) */\r
-       for( i = 0; i < numBSPDrawVerts; i++ )\r
-       {\r
-               bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );\r
-               bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );\r
-               bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );\r
-               bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );\r
-               bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );\r
-               bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );\r
-               bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );\r
-               bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );\r
-               for( j = 0; j < MAX_LIGHTMAPS; j++ )\r
-               {\r
-                       bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );\r
-                       bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );\r
-               }\r
-       }\r
-       \r
-       /* drawindexes */\r
-       SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );\r
-\r
-       /* drawsurfs */\r
-       /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */\r
-       SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );\r
-\r
-       /* fogs */\r
-       for( i = 0; i < numBSPFogs; i++ )\r
-       {\r
-               bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );\r
-               bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-GetLumpElements()\r
-gets the number of elements in a bsp lump\r
-*/\r
-\r
-int GetLumpElements( bspHeader_t *header, int lump, int size )\r
-{\r
-       /* check for odd size */\r
-       if( header->lumps[ lump ].length % size )\r
-       {\r
-               if( force )\r
-               {\r
-                       Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );\r
-                       return 0;\r
-               }\r
-               else\r
-                       Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );\r
-       }\r
-       \r
-       /* return element count */\r
-       return header->lumps[ lump ].length / size;\r
-}\r
-\r
-\r
-\r
-/*\r
-GetLump()\r
-returns a pointer to the specified lump\r
-*/\r
-\r
-void *GetLump( bspHeader_t *header, int lump )\r
-{\r
-       return (void*)( (byte*) header + header->lumps[ lump ].offset);\r
-}\r
-\r
-\r
-\r
-/*\r
-CopyLump()\r
-copies a bsp file lump into a destination buffer\r
-*/\r
-\r
-int CopyLump( bspHeader_t *header, int lump, void *dest, int size )\r
-{\r
-       int             length, offset;\r
-       \r
-       \r
-       /* get lump length and offset */\r
-       length = header->lumps[ lump ].length;\r
-       offset = header->lumps[ lump ].offset;\r
-       \r
-       /* handle erroneous cases */\r
-       if( length == 0 )\r
-               return 0;\r
-       if( length % size )\r
-       {\r
-               if( force )\r
-               {\r
-                       Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );\r
-                       return 0;\r
-               }\r
-               else\r
-                       Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );\r
-       }\r
-       \r
-       /* copy block of memory and return */\r
-       memcpy( dest, (byte*) header + offset, length );\r
-       return length / size;\r
-}\r
-\r
-\r
-\r
-/*\r
-AddLump()\r
-adds a lump to an outgoing bsp file\r
-*/\r
-\r
-void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length )\r
-{\r
-       bspLump_t       *lump;\r
-       \r
-       \r
-       /* add lump to bsp file header */\r
-       lump = &header->lumps[ lumpNum ];\r
-       lump->offset = LittleLong( ftell( file ) );\r
-       lump->length = LittleLong( length );\r
-       \r
-       /* write lump to file */\r
-       SafeWrite( file, data, (length + 3) & ~3 );\r
-}\r
-\r
-\r
-\r
-/*\r
-LoadBSPFile()\r
-loads a bsp file into memory\r
-*/\r
-\r
-void LoadBSPFile( const char *filename )\r
-{\r
-       /* dummy check */\r
-       if( game == NULL || game->load == NULL )\r
-               Error( "LoadBSPFile: unsupported BSP file format" );\r
-       \r
-       /* load it, then byte swap the in-memory version */\r
-       game->load( filename );\r
-       SwapBSPFile();\r
-}\r
-\r
-\r
-\r
-/*\r
-WriteBSPFile()\r
-writes a bsp file\r
-*/\r
-\r
-void WriteBSPFile( const char *filename )\r
-{\r
-       char    tempname[ 1024 ];\r
-       time_t  tm;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( game == NULL || game->write == NULL )\r
-               Error( "WriteBSPFile: unsupported BSP file format" );\r
-       \r
-       /* make fake temp name so existing bsp file isn't damaged in case write process fails */\r
-       time( &tm );\r
-       sprintf( tempname, "%s.%08X", filename, (int) tm );\r
-       \r
-       /* byteswap, write the bsp, then swap back so it can be manipulated further */\r
-       SwapBSPFile();\r
-       game->write( tempname );\r
-       SwapBSPFile();\r
-       \r
-       /* replace existing bsp file */\r
-       remove( filename );\r
-       rename( tempname, filename );\r
-}\r
-\r
-\r
-\r
-/*\r
-PrintBSPFileSizes()\r
-dumps info about current file\r
-*/\r
-\r
-void PrintBSPFileSizes( void )\r
-{\r
-       /* parse entities first */\r
-       if( numEntities <= 0 )\r
-               ParseEntities();\r
-       \r
-       /* note that this is abstracted */\r
-       Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );\r
-       \r
-       /* print various and sundry bits */\r
-       Sys_Printf( "%9d models        %9d\n",\r
-               numBSPModels, (int) (numBSPModels * sizeof( bspModel_t )) );\r
-       Sys_Printf( "%9d shaders       %9d\n",\r
-               numBSPShaders, (int) (numBSPShaders * sizeof( bspShader_t )) );\r
-       Sys_Printf( "%9d brushes       %9d\n",\r
-               numBSPBrushes, (int) (numBSPBrushes * sizeof( bspBrush_t )) );\r
-       Sys_Printf( "%9d brushsides    %9d *\n",\r
-               numBSPBrushSides, (int) (numBSPBrushSides * sizeof( bspBrushSide_t )) );\r
-       Sys_Printf( "%9d fogs          %9d\n",\r
-               numBSPFogs, (int) (numBSPFogs * sizeof( bspFog_t ) ) );\r
-       Sys_Printf( "%9d planes        %9d\n",\r
-               numBSPPlanes, (int) (numBSPPlanes * sizeof( bspPlane_t )) );\r
-       Sys_Printf( "%9d entdata       %9d\n",\r
-               numEntities, bspEntDataSize );\r
-       Sys_Printf( "\n");\r
-       \r
-       Sys_Printf( "%9d nodes         %9d\n",\r
-               numBSPNodes, (int) (numBSPNodes * sizeof( bspNode_t)) );\r
-       Sys_Printf( "%9d leafs         %9d\n",\r
-               numBSPLeafs, (int) (numBSPLeafs * sizeof( bspLeaf_t )) );\r
-       Sys_Printf( "%9d leafsurfaces  %9d\n",\r
-               numBSPLeafSurfaces, (int) (numBSPLeafSurfaces * sizeof( *bspLeafSurfaces )) );\r
-       Sys_Printf( "%9d leafbrushes   %9d\n",\r
-               numBSPLeafBrushes, (int) (numBSPLeafBrushes * sizeof( *bspLeafBrushes )) );\r
-       Sys_Printf( "\n");\r
-       \r
-       Sys_Printf( "%9d drawsurfaces  %9d *\n",\r
-               numBSPDrawSurfaces, (int) (numBSPDrawSurfaces * sizeof( *bspDrawSurfaces )) );\r
-       Sys_Printf( "%9d drawverts     %9d *\n",\r
-               numBSPDrawVerts, (int) (numBSPDrawVerts * sizeof( *bspDrawVerts )) );\r
-       Sys_Printf( "%9d drawindexes   %9d\n",\r
-               numBSPDrawIndexes, (int) (numBSPDrawIndexes * sizeof( *bspDrawIndexes )) );\r
-       Sys_Printf( "\n");\r
-       \r
-       Sys_Printf( "%9d lightmaps     %9d\n",\r
-               numBSPLightBytes / (LIGHTMAP_WIDTH * LIGHTMAP_HEIGHT * 3), numBSPLightBytes );\r
-       Sys_Printf( "%9d lightgrid     %9d *\n",\r
-               numBSPGridPoints, (int) (numBSPGridPoints * sizeof( *bspGridPoints )) );\r
-       Sys_Printf( "          visibility    %9d\n",\r
-               numBSPVisBytes );\r
-}\r
-\r
-\r
-\r
-/* -------------------------------------------------------------------------------\r
-\r
-entity data handling\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-\r
-/*\r
-StripTrailing()\r
-strips low byte chars off the end of a string\r
-*/\r
-\r
-void StripTrailing( char *e )\r
-{\r
-       char    *s;\r
-       \r
-       \r
-       s = e + strlen( e ) - 1;\r
-       while( s >= e && *s <= 32 )\r
-       {\r
-               *s = 0;\r
-               s--;\r
-       }\r
-}\r
-\r
-\r
-\r
-/*\r
-ParseEpair()\r
-parses a single quoted "key" "value" pair into an epair struct\r
-*/\r
-\r
-epair_t *ParseEPair( void )\r
-{\r
-       epair_t         *e;\r
-       \r
-       \r
-       /* allocate and clear new epair */\r
-       e = safe_malloc( sizeof( epair_t ) );\r
-       memset( e, 0, sizeof( epair_t ) );\r
-       \r
-       /* handle key */\r
-       if( strlen( token ) >= (MAX_KEY - 1) )\r
-               Error( "ParseEPair: token too long" );\r
-       \r
-       e->key = copystring( token );\r
-       GetToken( qfalse );\r
-       \r
-       /* handle value */\r
-       if( strlen( token ) >= MAX_VALUE - 1 )\r
-               Error( "ParseEpar: token too long" );\r
-       e->value = copystring( token );\r
-       \r
-       /* strip trailing spaces that sometimes get accidentally added in the editor */\r
-       StripTrailing( e->key );\r
-       StripTrailing( e->value );\r
-       \r
-       /* return it */\r
-       return e;\r
-}\r
-\r
-\r
-\r
-/*\r
-ParseEntity()\r
-parses an entity's epairs\r
-*/\r
-\r
-qboolean ParseEntity( void )\r
-{\r
-       epair_t         *e;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( !GetToken( qtrue ) )\r
-               return qfalse;\r
-       if( strcmp( token, "{" ) )\r
-               Error( "ParseEntity: { not found" );\r
-       if( numEntities == MAX_MAP_ENTITIES )\r
-               Error( "numEntities == MAX_MAP_ENTITIES" );\r
-       \r
-       /* create new entity */\r
-       mapEnt = &entities[ numEntities ];\r
-       numEntities++;\r
-       \r
-       /* parse */\r
-       while( 1 )\r
-       {\r
-               if( !GetToken( qtrue ) )\r
-                       Error( "ParseEntity: EOF without closing brace" );\r
-               if( !EPAIR_STRCMP( token, "}" ) )\r
-                       break;\r
-               e = ParseEPair();\r
-               e->next = mapEnt->epairs;\r
-               mapEnt->epairs = e;\r
-       }\r
-       \r
-       /* return to sender */\r
-       return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-ParseEntities()\r
-parses the bsp entity data string into entities\r
-*/\r
-\r
-void ParseEntities( void )\r
-{\r
-       numEntities = 0;\r
-       ParseFromMemory( bspEntData, bspEntDataSize );\r
-       while( ParseEntity() );\r
-       \r
-       /* ydnar: set number of bsp entities in case a map is loaded on top */\r
-       numBSPEntities = numEntities;\r
-}\r
-\r
-\r
-\r
-/*\r
-UnparseEntities()\r
-generates the dentdata string from all the entities.\r
-this allows the utilities to add or remove key/value\r
-pairs to the data created by the map editor\r
-*/\r
-\r
-void UnparseEntities( void )\r
-{\r
-       int                     i;\r
-       char            *buf, *end;\r
-       epair_t         *ep;\r
-       char            line[ 2048 ];\r
-       char            key[ 1024 ], value[ 1024 ];\r
-       const char      *value2;\r
-       \r
-       \r
-       /* setup */\r
-       buf = bspEntData;\r
-       end = buf;\r
-       *end = 0;\r
-       \r
-       /* run through entity list */\r
-       for( i = 0; i < numBSPEntities && i < numEntities; i++ )\r
-       {\r
-               /* get epair */\r
-               ep = entities[ i ].epairs;\r
-               if( ep == NULL )\r
-                       continue;       /* ent got removed */\r
-               \r
-               /* ydnar: certain entities get stripped from bsp file */\r
-               value2 = ValueForKey( &entities[ i ], "classname" );\r
-               if( !Q_stricmp( value2, "misc_model" ) ||\r
-                       !Q_stricmp( value2, "_decal" ) ||\r
-                       !Q_stricmp( value2, "_skybox" ) )\r
-                       continue;\r
-               \r
-               /* add beginning brace */\r
-               strcat( end, "{\n" );\r
-               end += 2;\r
-               \r
-               /* walk epair list */\r
-               for( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )\r
-               {\r
-                       /* copy and clean */\r
-                       strcpy( key, ep->key );\r
-                       StripTrailing( key );\r
-                       strcpy( value, ep->value );\r
-                       StripTrailing( value );\r
-                       \r
-                       /* add to buffer */\r
-                       sprintf( line, "\"%s\" \"%s\"\n", key, value );\r
-                       strcat( end, line );\r
-                       end += strlen( line );\r
-               }\r
-               \r
-               /* add trailing brace */\r
-               strcat( end,"}\n" );\r
-               end += 2;\r
-               \r
-               /* check for overflow */\r
-               if( end > buf + MAX_MAP_ENTSTRING )\r
-                       Error( "Entity text too long" );\r
-       }\r
-       \r
-       /* set size */\r
-       bspEntDataSize = end - buf + 1;\r
-}\r
-\r
-\r
-\r
-/*\r
-PrintEntity()\r
-prints an entity's epairs to the console\r
-*/\r
-\r
-void PrintEntity( const entity_t *ent )\r
-{\r
-       epair_t *ep;\r
-       \r
-\r
-       Sys_Printf( "------- entity %p -------\n", ent );\r
-       for( ep = ent->epairs; ep != NULL; ep = ep->next )\r
-               Sys_Printf( "%s = %s\n", ep->key, ep->value );\r
-\r
-}\r
-\r
-\r
-\r
-/*\r
-SetKeyValue()\r
-sets an epair in an entity\r
-*/\r
-\r
-void SetKeyValue( entity_t *ent, const char *key, const char *value )\r
-{\r
-       epair_t *ep;\r
-       \r
-       \r
-       /* check for existing epair */\r
-       for( ep = ent->epairs; ep != NULL; ep = ep->next )\r
-       {\r
-               if( !EPAIR_STRCMP( ep->key, key ) )\r
-               {\r
-                       free( ep->value );\r
-                       ep->value = copystring( value );\r
-                       return;\r
-               }\r
-       }\r
-       \r
-       /* create new epair */\r
-       ep = safe_malloc( sizeof( *ep ) );\r
-       ep->next = ent->epairs;\r
-       ent->epairs = ep;\r
-       ep->key = copystring( key );\r
-       ep->value = copystring( value );\r
-}\r
-\r
-\r
-\r
-/*\r
-ValueForKey()\r
-gets the value for an entity key\r
-*/\r
-\r
-const char *ValueForKey( const entity_t *ent, const char *key )\r
-{\r
-       epair_t *ep;\r
-       \r
-       \r
-       /* dummy check */\r
-       if( ent == NULL )\r
-               return "";\r
-       \r
-       /* walk epair list */\r
-       for( ep = ent->epairs; ep != NULL; ep = ep->next )\r
-       {\r
-               if( !EPAIR_STRCMP( ep->key, key ) )\r
-                       return ep->value;\r
-       }\r
-       \r
-       /* if no match, return empty string */\r
-       return "";\r
-}\r
-\r
-\r
-\r
-/*\r
-IntForKey()\r
-gets the integer point value for an entity key\r
-*/\r
-\r
-int IntForKey( const entity_t *ent, const char *key )\r
-{\r
-       const char      *k;\r
-       \r
-       \r
-       k = ValueForKey( ent, key );\r
-       return atoi( k );\r
-}\r
-\r
-\r
-\r
-/*\r
-FloatForKey()\r
-gets the floating point value for an entity key\r
-*/\r
-\r
-vec_t FloatForKey( const entity_t *ent, const char *key )\r
-{\r
-       const char      *k;\r
-       \r
-       \r
-       k = ValueForKey( ent, key );\r
-       return atof( k );\r
-}\r
-\r
-\r
-\r
-/*\r
-GetVectorForKey()\r
-gets a 3-element vector value for an entity key\r
-*/\r
-\r
-void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec )\r
-{\r
-       const char      *k;\r
-       double          v1, v2, v3;\r
-       \r
-\r
-       /* get value */\r
-       k = ValueForKey( ent, key );\r
-       \r
-       /* scanf into doubles, then assign, so it is vec_t size independent */\r
-       v1 = v2 = v3 = 0.0;\r
-       sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );\r
-       vec[ 0 ] = v1;\r
-       vec[ 1 ] = v2;\r
-       vec[ 2 ] = v3;\r
-}\r
-\r
-\r
-\r
-/*\r
-FindTargetEntity()\r
-finds an entity target\r
-*/\r
-\r
-entity_t *FindTargetEntity( const char *target )\r
-{\r
-       int                     i;\r
-       const char      *n;\r
-\r
-       \r
-       /* walk entity list */\r
-       for( i = 0; i < numEntities; i++ )\r
-       {\r
-               n = ValueForKey( &entities[ i ], "targetname" );\r
-               if ( !strcmp( n, target ) )\r
-                       return &entities[ i ];\r
-       }\r
-       \r
-       /* nada */\r
-       return NULL;\r
-}\r
-\r
-\r
-\r
-/*\r
-GetEntityShadowFlags() - ydnar\r
-gets an entity's shadow flags\r
-note: does not set them to defaults if the keys are not found!\r
-*/\r
-\r
-void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows )\r
-{\r
-       const char      *value;\r
-       \r
-       \r
-       /* get cast shadows */\r
-       if( castShadows != NULL )\r
-       {\r
-               value = ValueForKey( ent, "_castShadows" );\r
-               if( value[ 0 ] == '\0' )\r
-                       value = ValueForKey( ent, "_cs" );\r
-               if( value[ 0 ] == '\0' )\r
-                       value = ValueForKey( ent2, "_castShadows" );\r
-               if( value[ 0 ] == '\0' )\r
-                       value = ValueForKey( ent2, "_cs" );\r
-               if( value[ 0 ] != '\0' )\r
-                       *castShadows = atoi( value );\r
-       }\r
-       \r
-       /* receive */\r
-       if( recvShadows != NULL )\r
-       {\r
-               value = ValueForKey( ent, "_receiveShadows" );\r
-               if( value[ 0 ] == '\0' )\r
-                       value = ValueForKey( ent, "_rs" );\r
-               if( value[ 0 ] == '\0' )\r
-                       value = ValueForKey( ent2, "_receiveShadows" );\r
-               if( value[ 0 ] == '\0' )\r
-                       value = ValueForKey( ent2, "_rs" );\r
-               if( value[ 0 ] != '\0' )\r
-                       *recvShadows = atoi( value );\r
-       }\r
-}\r
-\r
+/* -------------------------------------------------------------------------------
+
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+----------------------------------------------------------------------------------
+
+This code has been altered significantly from its original form, to support
+several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#define BSPFILE_ABSTRACT_C
+
+
+
+/* dependencies */
+#include "q3map2.h"
+
+
+
+
+/* -------------------------------------------------------------------------------
+
+this file was copied out of the common directory in order to not break
+compatibility with the q3map 1.x tree. it was moved out in order to support
+the raven bsp format (RBSP) used in soldier of fortune 2 and jedi knight 2.
+
+since each game has its own set of particular features, the data structures
+below no longer directly correspond to the binary format of a particular game.
+
+the translation will be done at bsp load/save time to keep any sort of
+special-case code messiness out of the rest of the program.
+
+------------------------------------------------------------------------------- */
+
+
+
+/* FIXME: remove the functions below that handle memory management of bsp file chunks */
+
+int numBSPDrawVertsBuffer = 0;
+void IncDrawVerts()
+{
+       numBSPDrawVerts++;
+
+       if(bspDrawVerts == 0)
+       {
+               numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS / 37;
+               
+               bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");
+
+       }
+       else if(numBSPDrawVerts > numBSPDrawVertsBuffer)
+       {
+               numBSPDrawVertsBuffer *= 3; // multiply by 1.5
+               numBSPDrawVertsBuffer /= 2;
+
+               if(numBSPDrawVertsBuffer > MAX_MAP_DRAW_VERTS)
+                       numBSPDrawVertsBuffer = MAX_MAP_DRAW_VERTS;
+
+               bspDrawVerts = realloc(bspDrawVerts, sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer);
+
+               if(!bspDrawVerts)
+                       Error( "realloc() failed (IncDrawVerts)");
+       }
+
+       memset(bspDrawVerts + (numBSPDrawVerts - 1), 0, sizeof(bspDrawVert_t));
+}
+
+void SetDrawVerts(int n)
+{
+       if(bspDrawVerts != 0)
+               free(bspDrawVerts);
+
+       numBSPDrawVerts = n;
+       numBSPDrawVertsBuffer = numBSPDrawVerts;
+
+       bspDrawVerts = safe_malloc_info(sizeof(bspDrawVert_t) * numBSPDrawVertsBuffer, "IncDrawVerts");
+
+       memset(bspDrawVerts, 0, n * sizeof(bspDrawVert_t));
+}
+
+int numBSPDrawSurfacesBuffer = 0;
+void SetDrawSurfacesBuffer()
+{
+       if(bspDrawSurfaces != 0)
+               free(bspDrawSurfaces);
+
+       numBSPDrawSurfacesBuffer = MAX_MAP_DRAW_SURFS;
+
+       bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");
+
+       memset(bspDrawSurfaces, 0, MAX_MAP_DRAW_SURFS * sizeof(bspDrawVert_t));
+}
+
+void SetDrawSurfaces(int n)
+{
+       if(bspDrawSurfaces != 0)
+               free(bspDrawSurfaces);
+
+       numBSPDrawSurfaces = n;
+       numBSPDrawSurfacesBuffer = numBSPDrawSurfaces;
+
+       bspDrawSurfaces = safe_malloc_info(sizeof(bspDrawSurface_t) * numBSPDrawSurfacesBuffer, "IncDrawSurfaces");
+
+       memset(bspDrawSurfaces, 0, n * sizeof(bspDrawVert_t));
+}
+
+void BSPFilesCleanup()
+{
+       if(bspDrawVerts != 0)
+               free(bspDrawVerts);
+       if(bspDrawSurfaces != 0)
+               free(bspDrawSurfaces);
+       if(bspLightBytes != 0)
+               free(bspLightBytes);
+       if(bspGridPoints != 0)
+               free(bspGridPoints);
+}
+
+
+
+
+
+
+/*
+SwapBlock()
+if all values are 32 bits, this can be used to swap everything
+*/
+
+void SwapBlock( int *block, int size )
+{
+       int             i;
+       
+       
+       /* dummy check */
+       if( block == NULL )
+               return;
+       
+       /* swap */
+       size >>= 2;
+       for( i = 0; i < size; i++ )
+               block[ i ] = LittleLong( block[ i ] );
+}
+
+
+
+/*
+SwapBSPFile()
+byte swaps all data in the abstract bsp
+*/
+
+void SwapBSPFile( void )
+{
+       int             i, j;
+       
+       
+       /* models */
+       SwapBlock( (int*) bspModels, numBSPModels * sizeof( bspModels[ 0 ] ) );
+
+       /* shaders (don't swap the name) */
+       for( i = 0; i < numBSPShaders ; i++ )
+       {
+               bspShaders[ i ].contentFlags = LittleLong( bspShaders[ i ].contentFlags );
+               bspShaders[ i ].surfaceFlags = LittleLong( bspShaders[ i ].surfaceFlags );
+       }
+
+       /* planes */
+       SwapBlock( (int*) bspPlanes, numBSPPlanes * sizeof( bspPlanes[ 0 ] ) );
+       
+       /* nodes */
+       SwapBlock( (int*) bspNodes, numBSPNodes * sizeof( bspNodes[ 0 ] ) );
+
+       /* leafs */
+       SwapBlock( (int*) bspLeafs, numBSPLeafs * sizeof( bspLeafs[ 0 ] ) );
+
+       /* leaffaces */
+       SwapBlock( (int*) bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
+
+       /* leafbrushes */
+       SwapBlock( (int*) bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
+
+       // brushes
+       SwapBlock( (int*) bspBrushes, numBSPBrushes * sizeof( bspBrushes[ 0 ] ) );
+
+       // brushsides
+       SwapBlock( (int*) bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
+
+       // vis
+       ((int*) &bspVisBytes)[ 0 ] = LittleLong( ((int*) &bspVisBytes)[ 0 ] );
+       ((int*) &bspVisBytes)[ 1 ] = LittleLong( ((int*) &bspVisBytes)[ 1 ] );
+
+       /* drawverts (don't swap colors) */
+       for( i = 0; i < numBSPDrawVerts; i++ )
+       {
+               bspDrawVerts[ i ].xyz[ 0 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 0 ] );
+               bspDrawVerts[ i ].xyz[ 1 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 1 ] );
+               bspDrawVerts[ i ].xyz[ 2 ] = LittleFloat( bspDrawVerts[ i ].xyz[ 2 ] );
+               bspDrawVerts[ i ].normal[ 0 ] = LittleFloat( bspDrawVerts[ i ].normal[ 0 ] );
+               bspDrawVerts[ i ].normal[ 1 ] = LittleFloat( bspDrawVerts[ i ].normal[ 1 ] );
+               bspDrawVerts[ i ].normal[ 2 ] = LittleFloat( bspDrawVerts[ i ].normal[ 2 ] );
+               bspDrawVerts[ i ].st[ 0 ] = LittleFloat( bspDrawVerts[ i ].st[ 0 ] );
+               bspDrawVerts[ i ].st[ 1 ] = LittleFloat( bspDrawVerts[ i ].st[ 1 ] );
+               for( j = 0; j < MAX_LIGHTMAPS; j++ )
+               {
+                       bspDrawVerts[ i ].lightmap[ j ][ 0 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 0 ] );
+                       bspDrawVerts[ i ].lightmap[ j ][ 1 ] = LittleFloat( bspDrawVerts[ i ].lightmap[ j ][ 1 ] );
+               }
+       }
+       
+       /* drawindexes */
+       SwapBlock( (int*) bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[0] ) );
+
+       /* drawsurfs */
+       /* note: rbsp files (and hence q3map2 abstract bsp) have byte lightstyles index arrays, this follows sof2map convention */
+       SwapBlock( (int*) bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
+
+       /* fogs */
+       for( i = 0; i < numBSPFogs; i++ )
+       {
+               bspFogs[ i ].brushNum = LittleLong( bspFogs[ i ].brushNum );
+               bspFogs[ i ].visibleSide = LittleLong( bspFogs[ i ].visibleSide );
+       }
+
+       /* advertisements */
+       for( i = 0; i < numBSPAds; i++ )
+       {
+               bspAds[ i ].cellId = LittleLong( bspAds[ i ].cellId );
+               bspAds[ i ].normal[ 0 ] = LittleFloat( bspAds[ i ].normal[ 0 ] );
+               bspAds[ i ].normal[ 1 ] = LittleFloat( bspAds[ i ].normal[ 1 ] );
+               bspAds[ i ].normal[ 2 ] = LittleFloat( bspAds[ i ].normal[ 2 ] );
+
+               for( j = 0; j < 4; j++ ) 
+               {
+                       bspAds[ i ].rect[j][ 0 ] = LittleFloat( bspAds[ i ].rect[j][ 0 ] );
+                       bspAds[ i ].rect[j][ 1 ] = LittleFloat( bspAds[ i ].rect[j][ 1 ] );
+                       bspAds[ i ].rect[j][ 2 ] = LittleFloat( bspAds[ i ].rect[j][ 2 ] );
+               }
+
+               //bspAds[ i ].model[ MAX_QPATH ];
+       }
+}
+
+
+
+/*
+GetLumpElements()
+gets the number of elements in a bsp lump
+*/
+
+int GetLumpElements( bspHeader_t *header, int lump, int size )
+{
+       /* check for odd size */
+       if( header->lumps[ lump ].length % size )
+       {
+               if( force )
+               {
+                       Sys_Printf( "WARNING: GetLumpElements: odd lump size (%d) in lump %d\n", header->lumps[ lump ].length, lump );
+                       return 0;
+               }
+               else
+                       Error( "GetLumpElements: odd lump size (%d) in lump %d", header->lumps[ lump ].length, lump );
+       }
+       
+       /* return element count */
+       return header->lumps[ lump ].length / size;
+}
+
+
+
+/*
+GetLump()
+returns a pointer to the specified lump
+*/
+
+void *GetLump( bspHeader_t *header, int lump )
+{
+       return (void*)( (byte*) header + header->lumps[ lump ].offset);
+}
+
+
+
+/*
+CopyLump()
+copies a bsp file lump into a destination buffer
+*/
+
+int CopyLump( bspHeader_t *header, int lump, void *dest, int size )
+{
+       int             length, offset;
+       
+       
+       /* get lump length and offset */
+       length = header->lumps[ lump ].length;
+       offset = header->lumps[ lump ].offset;
+       
+       /* handle erroneous cases */
+       if( length == 0 )
+               return 0;
+       if( length % size )
+       {
+               if( force )
+               {
+                       Sys_Printf( "WARNING: CopyLump: odd lump size (%d) in lump %d\n", length, lump );
+                       return 0;
+               }
+               else
+                       Error( "CopyLump: odd lump size (%d) in lump %d", length, lump );
+       }
+       
+       /* copy block of memory and return */
+       memcpy( dest, (byte*) header + offset, length );
+       return length / size;
+}
+
+
+
+/*
+AddLump()
+adds a lump to an outgoing bsp file
+*/
+
+void AddLump( FILE *file, bspHeader_t *header, int lumpNum, const void *data, int length )
+{
+       bspLump_t       *lump;
+       
+       
+       /* add lump to bsp file header */
+       lump = &header->lumps[ lumpNum ];
+       lump->offset = LittleLong( ftell( file ) );
+       lump->length = LittleLong( length );
+       
+       /* write lump to file */
+       SafeWrite( file, data, (length + 3) & ~3 );
+}
+
+
+
+/*
+LoadBSPFile()
+loads a bsp file into memory
+*/
+
+void LoadBSPFile( const char *filename )
+{
+       /* dummy check */
+       if( game == NULL || game->load == NULL )
+               Error( "LoadBSPFile: unsupported BSP file format" );
+       
+       /* load it, then byte swap the in-memory version */
+       game->load( filename );
+       SwapBSPFile();
+}
+
+
+
+/*
+WriteBSPFile()
+writes a bsp file
+*/
+
+void WriteBSPFile( const char *filename )
+{
+       char    tempname[ 1024 ];
+       time_t  tm;
+       
+       
+       /* dummy check */
+       if( game == NULL || game->write == NULL )
+               Error( "WriteBSPFile: unsupported BSP file format" );
+       
+       /* make fake temp name so existing bsp file isn't damaged in case write process fails */
+       time( &tm );
+       sprintf( tempname, "%s.%08X", filename, (int) tm );
+       
+       /* byteswap, write the bsp, then swap back so it can be manipulated further */
+       SwapBSPFile();
+       game->write( tempname );
+       SwapBSPFile();
+       
+       /* replace existing bsp file */
+       remove( filename );
+       rename( tempname, filename );
+}
+
+
+
+/*
+PrintBSPFileSizes()
+dumps info about current file
+*/
+
+void PrintBSPFileSizes( void )
+{
+       /* parse entities first */
+       if( numEntities <= 0 )
+               ParseEntities();
+       
+       /* note that this is abstracted */
+       Sys_Printf( "Abstracted BSP file components (*actual sizes may differ)\n" );
+       
+       /* print various and sundry bits */
+       Sys_Printf( "%9d models        %9d\n",
+               numBSPModels, (int) (numBSPModels * sizeof( bspModel_t )) );
+       Sys_Printf( "%9d shaders       %9d\n",
+               numBSPShaders, (int) (numBSPShaders * sizeof( bspShader_t )) );
+       Sys_Printf( "%9d brushes       %9d\n",
+               numBSPBrushes, (int) (numBSPBrushes * sizeof( bspBrush_t )) );
+       Sys_Printf( "%9d brushsides    %9d *\n",
+               numBSPBrushSides, (int) (numBSPBrushSides * sizeof( bspBrushSide_t )) );
+       Sys_Printf( "%9d fogs          %9d\n",
+               numBSPFogs, (int) (numBSPFogs * sizeof( bspFog_t ) ) );
+       Sys_Printf( "%9d planes        %9d\n",
+               numBSPPlanes, (int) (numBSPPlanes * sizeof( bspPlane_t )) );
+       Sys_Printf( "%9d entdata       %9d\n",
+               numEntities, bspEntDataSize );
+       Sys_Printf( "\n");
+       
+       Sys_Printf( "%9d nodes         %9d\n",
+               numBSPNodes, (int) (numBSPNodes * sizeof( bspNode_t)) );
+       Sys_Printf( "%9d leafs         %9d\n",
+               numBSPLeafs, (int) (numBSPLeafs * sizeof( bspLeaf_t )) );
+       Sys_Printf( "%9d leafsurfaces  %9d\n",
+               numBSPLeafSurfaces, (int) (numBSPLeafSurfaces * sizeof( *bspLeafSurfaces )) );
+       Sys_Printf( "%9d leafbrushes   %9d\n",
+               numBSPLeafBrushes, (int) (numBSPLeafBrushes * sizeof( *bspLeafBrushes )) );
+       Sys_Printf( "\n");
+       
+       Sys_Printf( "%9d drawsurfaces  %9d *\n",
+               numBSPDrawSurfaces, (int) (numBSPDrawSurfaces * sizeof( *bspDrawSurfaces )) );
+       Sys_Printf( "%9d drawverts     %9d *\n",
+               numBSPDrawVerts, (int) (numBSPDrawVerts * sizeof( *bspDrawVerts )) );
+       Sys_Printf( "%9d drawindexes   %9d\n",
+               numBSPDrawIndexes, (int) (numBSPDrawIndexes * sizeof( *bspDrawIndexes )) );
+       Sys_Printf( "\n");
+       
+       Sys_Printf( "%9d lightmaps     %9d\n",
+               numBSPLightBytes / (game->lightmapSize * game->lightmapSize * 3), numBSPLightBytes );
+       Sys_Printf( "%9d lightgrid     %9d *\n",
+               numBSPGridPoints, (int) (numBSPGridPoints * sizeof( *bspGridPoints )) );
+       Sys_Printf( "          visibility    %9d\n",
+               numBSPVisBytes );
+}
+
+
+
+/* -------------------------------------------------------------------------------
+
+entity data handling
+
+------------------------------------------------------------------------------- */
+
+
+/*
+StripTrailing()
+strips low byte chars off the end of a string
+*/
+
+void StripTrailing( char *e )
+{
+       char    *s;
+       
+       
+       s = e + strlen( e ) - 1;
+       while( s >= e && *s <= 32 )
+       {
+               *s = 0;
+               s--;
+       }
+}
+
+
+
+/*
+ParseEpair()
+parses a single quoted "key" "value" pair into an epair struct
+*/
+
+epair_t *ParseEPair( void )
+{
+       epair_t         *e;
+       
+       
+       /* allocate and clear new epair */
+       e = safe_malloc( sizeof( epair_t ) );
+       memset( e, 0, sizeof( epair_t ) );
+       
+       /* handle key */
+       if( strlen( token ) >= (MAX_KEY - 1) )
+               Error( "ParseEPair: token too long" );
+       
+       e->key = copystring( token );
+       GetToken( qfalse );
+       
+       /* handle value */
+       if( strlen( token ) >= MAX_VALUE - 1 )
+               Error( "ParseEpar: token too long" );
+       e->value = copystring( token );
+       
+       /* strip trailing spaces that sometimes get accidentally added in the editor */
+       StripTrailing( e->key );
+       StripTrailing( e->value );
+       
+       /* return it */
+       return e;
+}
+
+
+
+/*
+ParseEntity()
+parses an entity's epairs
+*/
+
+qboolean ParseEntity( void )
+{
+       epair_t         *e;
+       
+       
+       /* dummy check */
+       if( !GetToken( qtrue ) )
+               return qfalse;
+       if( strcmp( token, "{" ) )
+               Error( "ParseEntity: { not found" );
+       if( numEntities == MAX_MAP_ENTITIES )
+               Error( "numEntities == MAX_MAP_ENTITIES" );
+       
+       /* create new entity */
+       mapEnt = &entities[ numEntities ];
+       numEntities++;
+       
+       /* parse */
+       while( 1 )
+       {
+               if( !GetToken( qtrue ) )
+                       Error( "ParseEntity: EOF without closing brace" );
+               if( !EPAIR_STRCMP( token, "}" ) )
+                       break;
+               e = ParseEPair();
+               e->next = mapEnt->epairs;
+               mapEnt->epairs = e;
+       }
+       
+       /* return to sender */
+       return qtrue;
+}
+
+
+
+/*
+ParseEntities()
+parses the bsp entity data string into entities
+*/
+
+void ParseEntities( void )
+{
+       numEntities = 0;
+       ParseFromMemory( bspEntData, bspEntDataSize );
+       while( ParseEntity() );
+       
+       /* ydnar: set number of bsp entities in case a map is loaded on top */
+       numBSPEntities = numEntities;
+}
+
+
+
+/*
+UnparseEntities()
+generates the dentdata string from all the entities.
+this allows the utilities to add or remove key/value
+pairs to the data created by the map editor
+*/
+
+void UnparseEntities( void )
+{
+       int                     i;
+       char            *buf, *end;
+       epair_t         *ep;
+       char            line[ 2048 ];
+       char            key[ 1024 ], value[ 1024 ];
+       const char      *value2;
+       
+       
+       /* setup */
+       buf = bspEntData;
+       end = buf;
+       *end = 0;
+       
+       /* run through entity list */
+       for( i = 0; i < numBSPEntities && i < numEntities; i++ )
+       {
+               /* get epair */
+               ep = entities[ i ].epairs;
+               if( ep == NULL )
+                       continue;       /* ent got removed */
+               
+               /* ydnar: certain entities get stripped from bsp file */
+               value2 = ValueForKey( &entities[ i ], "classname" );
+               if( !Q_stricmp( value2, "misc_model" ) ||
+                       !Q_stricmp( value2, "_decal" ) ||
+                       !Q_stricmp( value2, "_skybox" ) )
+                       continue;
+               
+               /* add beginning brace */
+               strcat( end, "{\n" );
+               end += 2;
+               
+               /* walk epair list */
+               for( ep = entities[ i ].epairs; ep != NULL; ep = ep->next )
+               {
+                       /* copy and clean */
+                       strcpy( key, ep->key );
+                       StripTrailing( key );
+                       strcpy( value, ep->value );
+                       StripTrailing( value );
+                       
+                       /* add to buffer */
+                       sprintf( line, "\"%s\" \"%s\"\n", key, value );
+                       strcat( end, line );
+                       end += strlen( line );
+               }
+               
+               /* add trailing brace */
+               strcat( end,"}\n" );
+               end += 2;
+               
+               /* check for overflow */
+               if( end > buf + MAX_MAP_ENTSTRING )
+                       Error( "Entity text too long" );
+       }
+       
+       /* set size */
+       bspEntDataSize = end - buf + 1;
+}
+
+
+
+/*
+PrintEntity()
+prints an entity's epairs to the console
+*/
+
+void PrintEntity( const entity_t *ent )
+{
+       epair_t *ep;
+       
+
+       Sys_Printf( "------- entity %p -------\n", ent );
+       for( ep = ent->epairs; ep != NULL; ep = ep->next )
+               Sys_Printf( "%s = %s\n", ep->key, ep->value );
+
+}
+
+
+
+/*
+SetKeyValue()
+sets an epair in an entity
+*/
+
+void SetKeyValue( entity_t *ent, const char *key, const char *value )
+{
+       epair_t *ep;
+       
+       
+       /* check for existing epair */
+       for( ep = ent->epairs; ep != NULL; ep = ep->next )
+       {
+               if( !EPAIR_STRCMP( ep->key, key ) )
+               {
+                       free( ep->value );
+                       ep->value = copystring( value );
+                       return;
+               }
+       }
+       
+       /* create new epair */
+       ep = safe_malloc( sizeof( *ep ) );
+       ep->next = ent->epairs;
+       ent->epairs = ep;
+       ep->key = copystring( key );
+       ep->value = copystring( value );
+}
+
+
+
+/*
+ValueForKey()
+gets the value for an entity key
+*/
+
+const char *ValueForKey( const entity_t *ent, const char *key )
+{
+       epair_t *ep;
+       
+       
+       /* dummy check */
+       if( ent == NULL )
+               return "";
+       
+       /* walk epair list */
+       for( ep = ent->epairs; ep != NULL; ep = ep->next )
+       {
+               if( !EPAIR_STRCMP( ep->key, key ) )
+                       return ep->value;
+       }
+       
+       /* if no match, return empty string */
+       return "";
+}
+
+
+
+/*
+IntForKey()
+gets the integer point value for an entity key
+*/
+
+int IntForKey( const entity_t *ent, const char *key )
+{
+       const char      *k;
+       
+       
+       k = ValueForKey( ent, key );
+       return atoi( k );
+}
+
+
+
+/*
+FloatForKey()
+gets the floating point value for an entity key
+*/
+
+vec_t FloatForKey( const entity_t *ent, const char *key )
+{
+       const char      *k;
+       
+       
+       k = ValueForKey( ent, key );
+       return atof( k );
+}
+
+
+
+/*
+GetVectorForKey()
+gets a 3-element vector value for an entity key
+*/
+
+void GetVectorForKey( const entity_t *ent, const char *key, vec3_t vec )
+{
+       const char      *k;
+       double          v1, v2, v3;
+       
+
+       /* get value */
+       k = ValueForKey( ent, key );
+       
+       /* scanf into doubles, then assign, so it is vec_t size independent */
+       v1 = v2 = v3 = 0.0;
+       sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
+       vec[ 0 ] = v1;
+       vec[ 1 ] = v2;
+       vec[ 2 ] = v3;
+}
+
+
+
+/*
+FindTargetEntity()
+finds an entity target
+*/
+
+entity_t *FindTargetEntity( const char *target )
+{
+       int                     i;
+       const char      *n;
+
+       
+       /* walk entity list */
+       for( i = 0; i < numEntities; i++ )
+       {
+               n = ValueForKey( &entities[ i ], "targetname" );
+               if ( !strcmp( n, target ) )
+                       return &entities[ i ];
+       }
+       
+       /* nada */
+       return NULL;
+}
+
+
+
+/*
+GetEntityShadowFlags() - ydnar
+gets an entity's shadow flags
+note: does not set them to defaults if the keys are not found!
+*/
+
+void GetEntityShadowFlags( const entity_t *ent, const entity_t *ent2, int *castShadows, int *recvShadows )
+{
+       const char      *value;
+       
+       
+       /* get cast shadows */
+       if( castShadows != NULL )
+       {
+               value = ValueForKey( ent, "_castShadows" );
+               if( value[ 0 ] == '\0' )
+                       value = ValueForKey( ent, "_cs" );
+               if( value[ 0 ] == '\0' )
+                       value = ValueForKey( ent2, "_castShadows" );
+               if( value[ 0 ] == '\0' )
+                       value = ValueForKey( ent2, "_cs" );
+               if( value[ 0 ] != '\0' )
+                       *castShadows = atoi( value );
+       }
+       
+       /* receive */
+       if( recvShadows != NULL )
+       {
+               value = ValueForKey( ent, "_receiveShadows" );
+               if( value[ 0 ] == '\0' )
+                       value = ValueForKey( ent, "_rs" );
+               if( value[ 0 ] == '\0' )
+                       value = ValueForKey( ent2, "_receiveShadows" );
+               if( value[ 0 ] == '\0' )
+                       value = ValueForKey( ent2, "_rs" );
+               if( value[ 0 ] != '\0' )
+                       *recvShadows = atoi( value );
+       }
+}
+