diff options
Diffstat (limited to 'utils/vbspinfo')
| -rw-r--r-- | utils/vbspinfo/vbspinfo.cpp | 561 | ||||
| -rw-r--r-- | utils/vbspinfo/vbspinfo.vpc | 61 |
2 files changed, 622 insertions, 0 deletions
diff --git a/utils/vbspinfo/vbspinfo.cpp b/utils/vbspinfo/vbspinfo.cpp new file mode 100644 index 0000000..69567b5 --- /dev/null +++ b/utils/vbspinfo/vbspinfo.cpp @@ -0,0 +1,561 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// + +#include "mathlib/mathlib.h" +#include "bsplib.h" +#include "tier0/icommandline.h" +#include "iscratchpad3d.h" +#include "filesystem_tools.h" +#include "tier2/fileutils.h" +#include "gamebspfile.h" +#include "tier1/utlstringmap.h" +#include "tools_minidump.h" +#include "cmdlib.h" + +bool g_bTreeInfo = false; +bool g_bDrawTree = false; + + +float g_nOptimumDepth; +int g_nMinTreeDepth; +int g_nMaxTreeDepth; +int g_TotalTreeDepth; +float g_TotalVariance; + +float g_ySpacing = -1; // (set by code) +double g_xSpacing = 1.0; + + +void CalculateTreeInfo_R( int iNode, int depth ) +{ + dnode_t *pNode = &dnodes[iNode]; + if ( iNode < 0 ) // (is this a leaf) + { + g_nMinTreeDepth = min( g_nMinTreeDepth, depth ); + g_nMaxTreeDepth = max( g_nMaxTreeDepth, depth ); + g_TotalTreeDepth += depth; + g_TotalVariance += fabs( depth - g_nOptimumDepth ); + } + else + { + CalculateTreeInfo_R( pNode->children[0], depth+1 ); + CalculateTreeInfo_R( pNode->children[1], depth+1 ); + } +} + + +void DrawTreeToScratchPad_R( + IScratchPad3D *pPad, + int iNode, // Which node we're drawing. + int iLevel, // (used to get Y coordinate) + float flXMin, + float flXMax, + const Vector *pParentPos // Parent node position to draw connecting line (if there is a parent). + ) +{ + float flMyX = (flXMin + flXMax) * 0.5f; + + Vector vMyPos; + vMyPos.x = 0; + vMyPos.y = flMyX; + vMyPos.z = -iLevel * g_ySpacing; + + // Draw the connecting line. + if ( pParentPos ) + { + pPad->DrawLine( CSPVert( *pParentPos, Vector(1,1,1) ), CSPVert( vMyPos, Vector(1,0,0) ) ); + } + + dnode_t *pNode = &dnodes[iNode]; + if ( iNode < 0 ) + { + // This is a leaf. + pPad->DrawPoint( CSPVert( vMyPos, Vector(1,0,0) ), 6 ); + } + else + { + pPad->DrawPoint( CSPVert( vMyPos, Vector(1,1,1) ), 2 ); + + DrawTreeToScratchPad_R( + pPad, + pNode->children[0], + iLevel+1, + flXMin, + flMyX, + &vMyPos ); + + DrawTreeToScratchPad_R( + pPad, + pNode->children[1], + iLevel+1, + flMyX, + flXMax, + &vMyPos ); + } +} + + +void CalcTreeDepth_R( int iNode, int iLevel, int &iMaxDepth ) +{ + iMaxDepth = max( iLevel, iMaxDepth ); + if ( iNode < 0 ) + return; + + CalcTreeDepth_R( dnodes[iNode].children[0], iLevel+1, iMaxDepth ); + CalcTreeDepth_R( dnodes[iNode].children[1], iLevel+1, iMaxDepth ); +} + + +void DrawTreeToScratchPad() +{ + IScratchPad3D *pPad = ScratchPad3D_Create(); + pPad->SetAutoFlush( false ); + + int maxDepth = 0; + CalcTreeDepth_R( dmodels[0].headnode, 0, maxDepth ); + float flXSpace = (1 << min( maxDepth, 14 )) * g_xSpacing; + g_ySpacing = (flXSpace / maxDepth) / 4; + + DrawTreeToScratchPad_R( + pPad, + dmodels[0].headnode, + 0, // start on level 0 + -flXSpace/2, + flXSpace/2, + NULL ); + + pPad->Release(); +} + +struct WorldTextureStats_t +{ + int texdataID; + int refCount; +}; + +int WorldTextureCompareFunc( const void *t1, const void *t2 ) +{ + WorldTextureStats_t *pStat1 = ( WorldTextureStats_t * )t1; + WorldTextureStats_t *pStat2 = ( WorldTextureStats_t * )t2; + + if( pStat1->refCount < pStat2->refCount ) + { + return 1; + } + if( pStat1->refCount > pStat2->refCount ) + { + return -1; + } + return 0; +} + +void PrintWorldTextureStats( FILE *fp ) +{ + static WorldTextureStats_t stats[MAX_MAP_TEXDATA]; + int i; + for( i = 0; i < numtexdata; i++ ) + { + stats[i].texdataID = i; + stats[i].refCount = 0; + } + + for( i = 0; i < numfaces; i++ ) + { + dface_t *pFace = &dfaces[i]; + int texinfoID = pFace->texinfo; + Assert( texinfoID >= 0 && texinfoID < texinfo.Count() ); + int texdataID = texinfo[texinfoID].texdata; + Assert( texdataID >= 0 && texdataID < numtexdata ); + stats[texdataID].refCount++; + } + + qsort( stats, numtexdata, sizeof( WorldTextureStats_t ), WorldTextureCompareFunc ); + for( i = 0; i < numtexdata; i++ ) + { + const char *pTextureName = TexDataStringTable_GetString( dtexdata[stats[i].texdataID].nameStringTableID ); + fprintf( fp, "%5d surface(s) use material \"%s\"\n", stats[i].refCount, pTextureName ); + } +} + +void PrintModelStats( FILE *fp ) +{ + CUtlStringMap<int> modelMap; + + // ------------------------------------------------------- + // Deal with static props + // ------------------------------------------------------- + GameLumpHandle_t handle = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS ); +// int nLumpSize = g_GameLumps.GameLumpSize( handle ); + void *pStaticPropLump = g_GameLumps.GetGameLump( handle ); + unsigned char *pScan = ( unsigned char * )pStaticPropLump; + // fprintf( fp, "nLumpSize: %d\n", nLumpSize ); + + // read dictionary + int nDictCount = ( ( int * )pScan )[0]; + pScan += sizeof( int ); + StaticPropDictLump_t *pDictLump = ( StaticPropDictLump_t * )pScan; + pScan += nDictCount * sizeof( StaticPropDictLump_t ); + + // read leaves + int nLeafCount = ( ( int * )pScan )[0]; + pScan += sizeof( int ); +// StaticPropLeafLump_t *pLeafLump = ( StaticPropLeafLump_t * )pScan; + pScan += nLeafCount * sizeof( StaticPropLeafLump_t ); + + // read objects + int nObjCount = ( ( int * )pScan )[0]; + pScan += sizeof( int ); + StaticPropLump_t *pStaticPropLumpData = ( StaticPropLump_t * )pScan; + pScan += nObjCount * sizeof( StaticPropLump_t ); + + int i; + for( i = 0; i < nObjCount; i++ ) + { + StaticPropLump_t &pData = pStaticPropLumpData[i]; + const char *pName = pDictLump[pData.m_PropType].m_Name; + if( modelMap.Defined( pName ) ) + { + modelMap[pName]++; + } + else + { + modelMap[pName] = 1; + } + } + + extern int num_entities; + extern entity_t entities[MAX_MAP_ENTITIES]; + + ParseEntities(); + + for( i = 0; i < num_entities; i++ ) + { + const entity_t *pEnt = &entities[i]; + const epair_t *pEPair = pEnt->epairs; + const char *pClassName = NULL; + const char *pModelName = NULL; + for( ; pEPair; pEPair = pEPair->next ) + { + if ( Q_stricmp( pEPair->key, "classname" ) == 0 ) + { + pClassName = pEPair->value; + } + else if( Q_stricmp( pEPair->key, "model" ) == 0 ) + { + if( StringHasPrefix( pEPair->value, "models" ) ) + { + pModelName = pEPair->value; + } + } + } + if( pClassName && pModelName ) + { + if( modelMap.Defined( pModelName ) ) + { + modelMap[pModelName]++; + } + else + { + modelMap[pModelName] = 1; + } + } + } + for( i = 0; i < modelMap.GetNumStrings(); i++ ) + { + printf( "%s,%d\n", modelMap.String( i ), modelMap[modelMap.String( i )] ); + } +} + +void PrintListStaticProps( FILE *fp ) +{ + // ------------------------------------------------------- + // Deal with static props + // ------------------------------------------------------- + GameLumpHandle_t handle = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS ); + // int nLumpSize = g_GameLumps.GameLumpSize( handle ); + void *pStaticPropLump = g_GameLumps.GetGameLump( handle ); + unsigned char *pScan = ( unsigned char * )pStaticPropLump; + // fprintf( fp, "nLumpSize: %d\n", nLumpSize ); + + // read dictionary + int nDictCount = ( ( int * )pScan )[0]; + pScan += sizeof( int ); + StaticPropDictLump_t *pDictLump = ( StaticPropDictLump_t * )pScan; + pScan += nDictCount * sizeof( StaticPropDictLump_t ); + + // read leaves + int nLeafCount = ( ( int * )pScan )[0]; + pScan += sizeof( int ); + // StaticPropLeafLump_t *pLeafLump = ( StaticPropLeafLump_t * )pScan; + pScan += nLeafCount * sizeof( StaticPropLeafLump_t ); + + // read objects + int nObjCount = ( ( int * )pScan )[0]; + pScan += sizeof( int ); + StaticPropLump_t *pStaticPropLumpData = ( StaticPropLump_t * )pScan; + pScan += nObjCount * sizeof( StaticPropLump_t ); + + int i; + for( i = 0; i < nObjCount; i++ ) + { + StaticPropLump_t &pData = pStaticPropLumpData[i]; + const char *pName = pDictLump[pData.m_PropType].m_Name; + + printf( "%03d %s\n", i, pName ); + } +} +void PrintCommandLine( int argc, char **argv ) +{ + Warning( "Command line: " ); + for ( int z=0; z < argc; z++ ) + { + Warning( "\"%s\" ", argv[z] ); + } + Warning( "\n\n" ); +} + +void main (int argc, char **argv) +{ + // Install an exception handler. + SetupDefaultToolsMinidumpHandler(); + + int i; + char source[1024]; + int size; + FILE *f; + + bool extractlumps[HEADER_LUMPS]; + memset( extractlumps, 0, sizeof(extractlumps) ); + bool bHaveAnyToExtract = false; + + ::SetHDRMode( false ); + + CommandLine()->CreateCmdLine( argc, argv ); + InitCommandLineProgram( argc, argv ); + g_pFileSystem = g_pFullFileSystem; + + MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false ); + PrintCommandLine( argc, argv ); + if (argc == 1) + { + printf( "vbspinfo: build date(" __DATE__ ")\n" ); + + printf("usage: vbspinfo [parameters] bspfile [bspfiles]\n"); + printf(" -treeinfo \n"); +// printf(" -drawtree \n"); Remove for now until the option can be fixed + printf(" -worldtexturestats \n"); + printf(" -modelstats \n"); + printf(" -liststaticprops \n"); + printf(" -X[lump ID] Extract BSP lump to file. i.e -X0 extracts entity lump.\n"); + printf(" -size Show .bsp worldmodel bounds\n"); + Error("Incorrect syntax."); + } + + bool bWorldTextureStats = false; + bool bModelStats = false; + bool bListStaticProps = false; + bool bShowMapBounds = false; + + for (i=1 ; i<argc ; i++) + { + if ( stricmp( argv[i], "-treeinfo" ) == 0 ) + { + g_bTreeInfo = true; + continue; + } + else if ( stricmp( argv[i], "-drawtree" ) == 0 ) + { + g_bDrawTree = true; + continue; + } + else if( stricmp( argv[i], "-worldtexturestats" ) == 0 ) + { + bWorldTextureStats = true; + continue; + } + else if( stricmp( argv[i], "-modelstats" ) == 0 ) + { + bModelStats = true; + continue; + } + else if( stricmp( argv[i], "-liststaticprops" ) == 0 ) + { + bListStaticProps = true; + continue; + } + else if( stricmp( argv[i], "-steamlocal" ) == 0 ) + { + continue; + } + else if( stricmp( argv[i], "-steam" ) == 0 ) + { + continue; + } + else if( strnicmp( argv[i], "-X", 2 ) == 0 ) + { + int iLump = atoi( argv[i]+2 ); + extractlumps[iLump] = true; + bHaveAnyToExtract = true; + continue; + } + else if ( stricmp( argv[ i ], "-size" ) == 0 ) + { + bShowMapBounds = true; + continue; + } + + if( !bWorldTextureStats && !bModelStats && !bListStaticProps ) + { + printf ("---------------------\n"); + } + strcpy (source, argv[i]); + Q_DefaultExtension (source, ".bsp", sizeof( source ) ); + + strcpy( source, ExpandPath( source ) ); + f = fopen (source, "rb"); + if (f) + { + fseek( f, 0, SEEK_END ); + size = ftell( f ); + fclose (f); + } + else + size = 0; + + if( !bWorldTextureStats && !bModelStats && !bListStaticProps ) + { + Msg ("reading %s (%d)\n", source, size); + } + + + // If we're extracting, do that and quit. + if ( bHaveAnyToExtract ) + { + OpenBSPFile(source); + + // If the filename doesn't have a path, prepend with the current directory + char fullbspname[MAX_PATH]; + _fullpath( fullbspname, source, sizeof( fullbspname ) ); + + for ( int extract = 0; extract < HEADER_LUMPS; extract++ ) + { + if ( extractlumps[extract] ) + { + printf ("Extracting lump %d.\n", extract ); + WriteLumpToFile( fullbspname, extract ); + } + } + + CloseBSPFile(); + + printf ("Finished extraction.\n" ); + return; + } + + + + LoadBSPFile (source); + + if( bWorldTextureStats ) + { + PrintWorldTextureStats( stdout ); + } + else if( bModelStats ) + { + PrintModelStats( stdout ); + } + else if( bListStaticProps ) + { + PrintListStaticProps( stdout ); + } + else if ( bShowMapBounds ) + { + dmodel_t *world = &dmodels[ 0 ]; + printf( "Full : (%8.3f %8.3f %8.3f) - (%8.3f %8.3f %8.3f)\n", + world->mins.x, + world->mins.y, + world->mins.z, + world->maxs.x, + world->maxs.y, + world->maxs.z ); + + if ( !num_entities ) + ParseEntities(); + + for ( int e = 0; e < num_entities; ++i ) + { + char* pEntity = ValueForKey(&entities[e], "classname"); + if ( strcmp(pEntity, "worldspawn" ) ) + continue; + + Vector wmins; + Vector wmaxs; + wmins.Init(); + wmaxs.Init(); + + char* pchMins = ValueForKey(&entities[e], "world_mins"); + sscanf( pchMins, "%f %f %f", &wmins.x, &wmins.y, &wmins.z ); + char* pchMaxs = ValueForKey(&entities[e], "world_maxs"); + sscanf( pchMaxs, "%f %f %f", &wmaxs.x, &wmaxs.y, &wmaxs.z ); + + + printf( "No Skybox: (%8.3f %8.3f %8.3f) - (%8.3f %8.3f %8.3f)\n", + wmins.x, + wmins.y, + wmins.z, + wmaxs.x, + wmaxs.y, + wmaxs.z ); + break; + } + } + else + { + PrintBSPFileSizes (); + } + + + + if ( g_bTreeInfo ) + { + g_nOptimumDepth = (int)( log( ( float )numnodes ) / log( 2.0f ) ); + g_nMinTreeDepth = 999999; + g_nMaxTreeDepth = -999999; + g_TotalTreeDepth = 0; + g_TotalVariance = 0; + CalculateTreeInfo_R( dmodels[0].headnode, 0 ); + + printf( "\n" + "\t-------------------\n" + "\tTREE INFO:\n" + "\t-------------------\n" + "\tNumber of nodes ------------------ : %d\n" + "\tOptimum tree depth (logN) -------- : %.3f\n" + "\tMinimum tree depth --------------- : %d\n" + "\tMaximum tree depth --------------- : %d\n" + "\tAverage tree depth --------------- : %.3f\n" + "\tAverage leaf variance from optimum : %.3f\n\n", + numnodes, + g_nOptimumDepth, + g_nMinTreeDepth, + g_nMaxTreeDepth, + (float)g_TotalTreeDepth / numnodes, + (float)g_TotalVariance / numnodes ); + } + + if ( g_bDrawTree ) + { + DrawTreeToScratchPad(); + } + + if( !bWorldTextureStats && !bModelStats && !bListStaticProps ) + { + printf ("---------------------\n"); + } + } +} diff --git a/utils/vbspinfo/vbspinfo.vpc b/utils/vbspinfo/vbspinfo.vpc new file mode 100644 index 0000000..f53e87a --- /dev/null +++ b/utils/vbspinfo/vbspinfo.vpc @@ -0,0 +1,61 @@ +//----------------------------------------------------------------------------- +// VBSPINFO.VPC +// +// Project Script +//----------------------------------------------------------------------------- + +$Macro SRCDIR "..\.." +$Macro OUTBINDIR "$SRCDIR\..\game\bin" + +$Include "$SRCDIR\vpc_scripts\source_exe_con_base.vpc" + +$Configuration +{ + $Compiler + { + $AdditionalIncludeDirectories "$BASE,..\common" + $PreprocessorDefinitions "$BASE;DONT_PROTECT_FILEIO_FUNCTIONS" + } + + $Linker + { + $AdditionalDependencies "$BASE odbc32.lib odbccp32.lib" + } +} + +$Project "Vbspinfo" +{ + $Folder "Source Files" + { + -$File "$SRCDIR\public\tier0\memoverride.cpp" + + $File "..\common\tools_minidump.cpp" + $File "..\common\bsplib.cpp" + $File "..\common\cmdlib.cpp" + $File "$SRCDIR\public\filesystem_helpers.cpp" + $File "$SRCDIR\public\filesystem_init.cpp" + $File "..\common\filesystem_tools.cpp" + $File "$SRCDIR\public\iscratchpad3d.h" + $File "$SRCDIR\public\lumpfiles.cpp" + $File "$SRCDIR\public\scratchpad3d.cpp" + $File "..\common\scriplib.cpp" + $File "vbspinfo.cpp" + $File "$SRCDIR\public\zip_utils.cpp" + } + + $Folder "Header Files" + { + $File "..\common\bsplib.h" + $File "$SRCDIR\public\tier1\characterset.h" + $File "$SRCDIR\public\tier1\checksum_crc.h" + $File "$SRCDIR\public\filesystem_helpers.h" + $File "$SRCDIR\public\lumpfiles.h" + } + + $Folder "Link Libraries" + { + $Lib mathlib + $Lib tier2 + $Lib "$LIBCOMMON/lzma" + } +} |