Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

647 lines
16 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "mathlib/mathlib.h"
  9. #include "bsplib.h"
  10. #include "tier0/icommandline.h"
  11. #include "iscratchpad3d.h"
  12. #include "filesystem_tools.h"
  13. #include "tier2/fileutils.h"
  14. #include "gamebspfile.h"
  15. #include "tier1/utlstringmap.h"
  16. #include "tools_minidump.h"
  17. #include "cmdlib.h"
  18. bool g_bTreeInfo = false;
  19. bool g_bDrawTree = false;
  20. float g_nOptimumDepth;
  21. int g_nMinTreeDepth;
  22. int g_nMaxTreeDepth;
  23. int g_TotalTreeDepth;
  24. float g_TotalVariance;
  25. float g_ySpacing = -1; // (set by code)
  26. double g_xSpacing = 1.0;
  27. void CalculateTreeInfo_R( int iNode, int depth )
  28. {
  29. dnode_t *pNode = &dnodes[iNode];
  30. if ( iNode < 0 ) // (is this a leaf)
  31. {
  32. g_nMinTreeDepth = MIN( g_nMinTreeDepth, depth );
  33. g_nMaxTreeDepth = MAX( g_nMaxTreeDepth, depth );
  34. g_TotalTreeDepth += depth;
  35. g_TotalVariance += fabs( depth - g_nOptimumDepth );
  36. }
  37. else
  38. {
  39. CalculateTreeInfo_R( pNode->children[0], depth+1 );
  40. CalculateTreeInfo_R( pNode->children[1], depth+1 );
  41. }
  42. }
  43. void DrawTreeToScratchPad_R(
  44. IScratchPad3D *pPad,
  45. int iNode, // Which node we're drawing.
  46. int iLevel, // (used to get Y coordinate)
  47. float flXMin,
  48. float flXMax,
  49. const Vector *pParentPos // Parent node position to draw connecting line (if there is a parent).
  50. )
  51. {
  52. float flMyX = (flXMin + flXMax) * 0.5f;
  53. Vector vMyPos;
  54. vMyPos.x = 0;
  55. vMyPos.y = flMyX;
  56. vMyPos.z = -iLevel * g_ySpacing;
  57. // Draw the connecting line.
  58. if ( pParentPos )
  59. {
  60. pPad->DrawLine( CSPVert( *pParentPos, Vector(1,1,1) ), CSPVert( vMyPos, Vector(1,0,0) ) );
  61. }
  62. dnode_t *pNode = &dnodes[iNode];
  63. if ( iNode < 0 )
  64. {
  65. // This is a leaf.
  66. pPad->DrawPoint( CSPVert( vMyPos, Vector(1,0,0) ), 6 );
  67. }
  68. else
  69. {
  70. pPad->DrawPoint( CSPVert( vMyPos, Vector(1,1,1) ), 2 );
  71. DrawTreeToScratchPad_R(
  72. pPad,
  73. pNode->children[0],
  74. iLevel+1,
  75. flXMin,
  76. flMyX,
  77. &vMyPos );
  78. DrawTreeToScratchPad_R(
  79. pPad,
  80. pNode->children[1],
  81. iLevel+1,
  82. flMyX,
  83. flXMax,
  84. &vMyPos );
  85. }
  86. }
  87. void CalcTreeDepth_R( int iNode, int iLevel, int &iMaxDepth )
  88. {
  89. iMaxDepth = MAX( iLevel, iMaxDepth );
  90. if ( iNode < 0 )
  91. return;
  92. CalcTreeDepth_R( dnodes[iNode].children[0], iLevel+1, iMaxDepth );
  93. CalcTreeDepth_R( dnodes[iNode].children[1], iLevel+1, iMaxDepth );
  94. }
  95. void DrawTreeToScratchPad()
  96. {
  97. IScratchPad3D *pPad = ScratchPad3D_Create();
  98. pPad->SetAutoFlush( false );
  99. int maxDepth = 0;
  100. CalcTreeDepth_R( dmodels[0].headnode, 0, maxDepth );
  101. float flXSpace = (1 << MIN( maxDepth, 14 )) * g_xSpacing;
  102. g_ySpacing = (flXSpace / maxDepth) / 4;
  103. DrawTreeToScratchPad_R(
  104. pPad,
  105. dmodels[0].headnode,
  106. 0, // start on level 0
  107. -flXSpace/2,
  108. flXSpace/2,
  109. NULL );
  110. pPad->Release();
  111. }
  112. struct WorldTextureStats_t
  113. {
  114. int texdataID;
  115. int refCount;
  116. };
  117. int WorldTextureCompareFunc( const void *t1, const void *t2 )
  118. {
  119. WorldTextureStats_t *pStat1 = ( WorldTextureStats_t * )t1;
  120. WorldTextureStats_t *pStat2 = ( WorldTextureStats_t * )t2;
  121. if( pStat1->refCount < pStat2->refCount )
  122. {
  123. return 1;
  124. }
  125. if( pStat1->refCount > pStat2->refCount )
  126. {
  127. return -1;
  128. }
  129. return 0;
  130. }
  131. void PrintWorldTextureStats( FILE *fp )
  132. {
  133. static WorldTextureStats_t stats[MAX_MAP_TEXDATA];
  134. int i;
  135. for( i = 0; i < numtexdata; i++ )
  136. {
  137. stats[i].texdataID = i;
  138. stats[i].refCount = 0;
  139. }
  140. for( i = 0; i < numfaces; i++ )
  141. {
  142. dface_t *pFace = &dfaces[i];
  143. int texinfoID = pFace->texinfo;
  144. Assert( texinfoID >= 0 && texinfoID < texinfo.Count() );
  145. int texdataID = texinfo[texinfoID].texdata;
  146. Assert( texdataID >= 0 && texdataID < numtexdata );
  147. stats[texdataID].refCount++;
  148. }
  149. qsort( stats, numtexdata, sizeof( WorldTextureStats_t ), WorldTextureCompareFunc );
  150. for( i = 0; i < numtexdata; i++ )
  151. {
  152. const char *pTextureName = TexDataStringTable_GetString( dtexdata[stats[i].texdataID].nameStringTableID );
  153. fprintf( fp, "%5d surface(s) use material \"%s\"\n", stats[i].refCount, pTextureName );
  154. }
  155. }
  156. void PrintModelStats( FILE *fp )
  157. {
  158. CUtlStringMap<int> modelMap;
  159. // -------------------------------------------------------
  160. // Deal with static props
  161. // -------------------------------------------------------
  162. GameLumpHandle_t handle = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
  163. int nLumpVersion = g_GameLumps.GetGameLumpVersion( handle );
  164. if ( nLumpVersion == GAMELUMP_STATIC_PROPS_VERSION )
  165. {
  166. // int nLumpSize = g_GameLumps.GameLumpSize( handle );
  167. void *pStaticPropLump = g_GameLumps.GetGameLump( handle );
  168. unsigned char *pScan = ( unsigned char * )pStaticPropLump;
  169. // fprintf( fp, "nLumpSize: %d\n", nLumpSize );
  170. // read dictionary
  171. int nDictCount = ( ( int * )pScan )[0];
  172. pScan += sizeof( int );
  173. StaticPropDictLump_t *pDictLump = ( StaticPropDictLump_t * )pScan;
  174. pScan += nDictCount * sizeof( StaticPropDictLump_t );
  175. // read leaves
  176. int nLeafCount = ( ( int * )pScan )[0];
  177. pScan += sizeof( int );
  178. // StaticPropLeafLump_t *pLeafLump = ( StaticPropLeafLump_t * )pScan;
  179. pScan += nLeafCount * sizeof( StaticPropLeafLump_t );
  180. // read objects
  181. int nObjCount = ( ( int * )pScan )[0];
  182. pScan += sizeof( int );
  183. StaticPropLump_t *pStaticPropLumpData = ( StaticPropLump_t * )pScan;
  184. pScan += nObjCount * sizeof( StaticPropLump_t );
  185. int i;
  186. for( i = 0; i < nObjCount; i++ )
  187. {
  188. StaticPropLump_t &pData = pStaticPropLumpData[i];
  189. const char *pName = pDictLump[pData.m_PropType].m_Name;
  190. if( modelMap.Defined( pName ) )
  191. {
  192. modelMap[pName]++;
  193. }
  194. else
  195. {
  196. modelMap[pName] = 1;
  197. }
  198. }
  199. }
  200. else if ( nLumpVersion == 6 )
  201. {
  202. // int nLumpSize = g_GameLumps.GameLumpSize( handle );
  203. void *pStaticPropLump = g_GameLumps.GetGameLump( handle );
  204. unsigned char *pScan = ( unsigned char * )pStaticPropLump;
  205. // fprintf( fp, "nLumpSize: %d\n", nLumpSize );
  206. // read dictionary
  207. int nDictCount = ( ( int * )pScan )[0];
  208. pScan += sizeof( int );
  209. StaticPropDictLump_t *pDictLump = ( StaticPropDictLump_t * )pScan;
  210. pScan += nDictCount * sizeof( StaticPropDictLump_t );
  211. // read leaves
  212. int nLeafCount = ( ( int * )pScan )[0];
  213. pScan += sizeof( int );
  214. // StaticPropLeafLump_t *pLeafLump = ( StaticPropLeafLump_t * )pScan;
  215. pScan += nLeafCount * sizeof( StaticPropLeafLump_t );
  216. // read objects
  217. int nObjCount = ( ( int * )pScan )[0];
  218. pScan += sizeof( int );
  219. StaticPropLumpV6_t *pStaticPropLumpData = ( StaticPropLumpV6_t * )pScan;
  220. pScan += nObjCount * sizeof( StaticPropLumpV6_t );
  221. int i;
  222. for( i = 0; i < nObjCount; i++ )
  223. {
  224. StaticPropLumpV6_t &pData = pStaticPropLumpData[i];
  225. const char *pName = pDictLump[pData.m_PropType].m_Name;
  226. if( modelMap.Defined( pName ) )
  227. {
  228. modelMap[pName]++;
  229. }
  230. else
  231. {
  232. modelMap[pName] = 1;
  233. }
  234. }
  235. }
  236. else if ( nLumpVersion == 5 )
  237. {
  238. // int nLumpSize = g_GameLumps.GameLumpSize( handle );
  239. void *pStaticPropLump = g_GameLumps.GetGameLump( handle );
  240. unsigned char *pScan = ( unsigned char * )pStaticPropLump;
  241. // fprintf( fp, "nLumpSize: %d\n", nLumpSize );
  242. // read dictionary
  243. int nDictCount = ( ( int * )pScan )[0];
  244. pScan += sizeof( int );
  245. StaticPropDictLump_t *pDictLump = ( StaticPropDictLump_t * )pScan;
  246. pScan += nDictCount * sizeof( StaticPropDictLump_t );
  247. // read leaves
  248. int nLeafCount = ( ( int * )pScan )[0];
  249. pScan += sizeof( int );
  250. // StaticPropLeafLump_t *pLeafLump = ( StaticPropLeafLump_t * )pScan;
  251. pScan += nLeafCount * sizeof( StaticPropLeafLump_t );
  252. // read objects
  253. int nObjCount = ( ( int * )pScan )[0];
  254. pScan += sizeof( int );
  255. StaticPropLumpV5_t *pStaticPropLumpData = ( StaticPropLumpV5_t * )pScan;
  256. pScan += nObjCount * sizeof( StaticPropLumpV5_t );
  257. int i;
  258. for( i = 0; i < nObjCount; i++ )
  259. {
  260. StaticPropLumpV5_t &pData = pStaticPropLumpData[i];
  261. const char *pName = pDictLump[pData.m_PropType].m_Name;
  262. if( modelMap.Defined( pName ) )
  263. {
  264. modelMap[pName]++;
  265. }
  266. else
  267. {
  268. modelMap[pName] = 1;
  269. }
  270. }
  271. }
  272. extern int num_entities;
  273. extern entity_t entities[MAX_MAP_ENTITIES];
  274. ParseEntities();
  275. int i;
  276. for( i = 0; i < num_entities; i++ )
  277. {
  278. const entity_t *pEnt = &entities[i];
  279. const epair_t *pEPair = pEnt->epairs;
  280. const char *pClassName = NULL;
  281. const char *pModelName = NULL;
  282. for( ; pEPair; pEPair = pEPair->next )
  283. {
  284. if ( Q_stricmp( pEPair->key, "classname" ) == 0 )
  285. {
  286. pClassName = pEPair->value;
  287. }
  288. else if( Q_stricmp( pEPair->key, "model" ) == 0 )
  289. {
  290. if( StringHasPrefix( pEPair->value, "models" ) )
  291. {
  292. pModelName = pEPair->value;
  293. }
  294. }
  295. }
  296. if( pClassName && pModelName )
  297. {
  298. if( modelMap.Defined( pModelName ) )
  299. {
  300. modelMap[pModelName]++;
  301. }
  302. else
  303. {
  304. modelMap[pModelName] = 1;
  305. }
  306. }
  307. }
  308. for( i = 0; i < modelMap.GetNumStrings(); i++ )
  309. {
  310. printf( "%s,%d\n", modelMap.String( i ), modelMap[modelMap.String( i )] );
  311. }
  312. }
  313. void PrintListStaticProps( FILE *fp )
  314. {
  315. // -------------------------------------------------------
  316. // Deal with static props
  317. // -------------------------------------------------------
  318. GameLumpHandle_t handle = g_GameLumps.GetGameLumpHandle( GAMELUMP_STATIC_PROPS );
  319. // int nLumpSize = g_GameLumps.GameLumpSize( handle );
  320. void *pStaticPropLump = g_GameLumps.GetGameLump( handle );
  321. unsigned char *pScan = ( unsigned char * )pStaticPropLump;
  322. // fprintf( fp, "nLumpSize: %d\n", nLumpSize );
  323. // read dictionary
  324. int nDictCount = ( ( int * )pScan )[0];
  325. pScan += sizeof( int );
  326. StaticPropDictLump_t *pDictLump = ( StaticPropDictLump_t * )pScan;
  327. pScan += nDictCount * sizeof( StaticPropDictLump_t );
  328. // read leaves
  329. int nLeafCount = ( ( int * )pScan )[0];
  330. pScan += sizeof( int );
  331. // StaticPropLeafLump_t *pLeafLump = ( StaticPropLeafLump_t * )pScan;
  332. pScan += nLeafCount * sizeof( StaticPropLeafLump_t );
  333. // read objects
  334. int nObjCount = ( ( int * )pScan )[0];
  335. pScan += sizeof( int );
  336. StaticPropLump_t *pStaticPropLumpData = ( StaticPropLump_t * )pScan;
  337. pScan += nObjCount * sizeof( StaticPropLump_t );
  338. int i;
  339. for( i = 0; i < nObjCount; i++ )
  340. {
  341. StaticPropLump_t &pData = pStaticPropLumpData[i];
  342. const char *pName = pDictLump[pData.m_PropType].m_Name;
  343. printf( "%03d %s\n", i, pName );
  344. }
  345. }
  346. void PrintCommandLine( int argc, char **argv )
  347. {
  348. Warning( "Command line: " );
  349. for ( int z=0; z < argc; z++ )
  350. {
  351. Warning( "\"%s\" ", argv[z] );
  352. }
  353. Warning( "\n\n" );
  354. }
  355. void main (int argc, char **argv)
  356. {
  357. // Install an exception handler.
  358. SetupDefaultToolsMinidumpHandler();
  359. int i;
  360. char source[1024];
  361. int size;
  362. FILE *f;
  363. bool extractlumps[HEADER_LUMPS];
  364. memset( extractlumps, 0, sizeof(extractlumps) );
  365. bool bHaveAnyToExtract = false;
  366. ::SetHDRMode( false );
  367. CommandLine()->CreateCmdLine( argc, argv );
  368. InitCommandLineProgram( argc, argv );
  369. g_pFileSystem = g_pFullFileSystem;
  370. MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
  371. PrintCommandLine( argc, argv );
  372. if (argc == 1)
  373. {
  374. printf( "vbspinfo: build date(" __DATE__ ")\n" );
  375. printf("usage: vbspinfo [parameters] bspfile [bspfiles]\n");
  376. printf(" -treeinfo \n");
  377. // printf(" -drawtree \n"); Remove for now until the option can be fixed
  378. printf(" -worldtexturestats \n");
  379. printf(" -modelstats \n");
  380. printf(" -liststaticprops \n");
  381. printf(" -X[lump ID] Extract BSP lump to file. i.e -X0 extracts entity lump.\n");
  382. printf(" -size Show .bsp worldmodel bounds\n");
  383. Warning("Incorrect syntax.");
  384. }
  385. bool bWorldTextureStats = false;
  386. bool bModelStats = false;
  387. bool bListStaticProps = false;
  388. bool bShowMapBounds = false;
  389. for (i=1 ; i<argc ; i++)
  390. {
  391. if ( stricmp( argv[i], "-treeinfo" ) == 0 )
  392. {
  393. g_bTreeInfo = true;
  394. continue;
  395. }
  396. else if ( stricmp( argv[i], "-drawtree" ) == 0 )
  397. {
  398. g_bDrawTree = true;
  399. continue;
  400. }
  401. else if( stricmp( argv[i], "-worldtexturestats" ) == 0 )
  402. {
  403. bWorldTextureStats = true;
  404. continue;
  405. }
  406. else if( stricmp( argv[i], "-modelstats" ) == 0 )
  407. {
  408. bModelStats = true;
  409. continue;
  410. }
  411. else if( stricmp( argv[i], "-liststaticprops" ) == 0 )
  412. {
  413. bListStaticProps = true;
  414. continue;
  415. }
  416. else if( stricmp( argv[i], "-steamlocal" ) == 0 )
  417. {
  418. continue;
  419. }
  420. else if( stricmp( argv[i], "-steam" ) == 0 )
  421. {
  422. continue;
  423. }
  424. else if( strnicmp( argv[i], "-X", 2 ) == 0 )
  425. {
  426. int iLump = atoi( argv[i]+2 );
  427. extractlumps[iLump] = true;
  428. bHaveAnyToExtract = true;
  429. continue;
  430. }
  431. else if ( stricmp( argv[ i ], "-size" ) == 0 )
  432. {
  433. bShowMapBounds = true;
  434. continue;
  435. }
  436. if( !bWorldTextureStats && !bModelStats && !bListStaticProps )
  437. {
  438. printf ("---------------------\n");
  439. }
  440. strcpy (source, argv[i]);
  441. Q_DefaultExtension (source, ".bsp", sizeof( source ) );
  442. strcpy( source, ExpandPath( source ) );
  443. f = fopen (source, "rb");
  444. if (f)
  445. {
  446. fseek( f, 0, SEEK_END );
  447. size = ftell( f );
  448. fclose (f);
  449. }
  450. else
  451. size = 0;
  452. if( !bWorldTextureStats && !bModelStats && !bListStaticProps )
  453. {
  454. Msg ("reading %s (%d)\n", source, size);
  455. }
  456. // If we're extracting, do that and quit.
  457. if ( bHaveAnyToExtract )
  458. {
  459. OpenBSPFile(source);
  460. // If the filename doesn't have a path, prepend with the current directory
  461. char fullbspname[MAX_PATH];
  462. _fullpath( fullbspname, source, sizeof( fullbspname ) );
  463. for ( int extract = 0; extract < HEADER_LUMPS; extract++ )
  464. {
  465. if ( extractlumps[extract] )
  466. {
  467. printf ("Extracting lump %d.\n", extract );
  468. WriteLumpToFile( fullbspname, extract );
  469. }
  470. }
  471. CloseBSPFile();
  472. printf ("Finished extraction.\n" );
  473. return;
  474. }
  475. LoadBSPFile (source);
  476. if( bWorldTextureStats )
  477. {
  478. PrintWorldTextureStats( stdout );
  479. }
  480. else if( bModelStats )
  481. {
  482. PrintModelStats( stdout );
  483. }
  484. else if( bListStaticProps )
  485. {
  486. PrintListStaticProps( stdout );
  487. }
  488. else if ( bShowMapBounds )
  489. {
  490. dmodel_t *world = &dmodels[ 0 ];
  491. printf( "Full : (%8.3f %8.3f %8.3f) - (%8.3f %8.3f %8.3f)\n",
  492. world->mins.x,
  493. world->mins.y,
  494. world->mins.z,
  495. world->maxs.x,
  496. world->maxs.y,
  497. world->maxs.z );
  498. if ( !num_entities )
  499. ParseEntities();
  500. for ( int e = 0; e < num_entities; ++i )
  501. {
  502. char* pEntity = ValueForKey(&entities[e], "classname");
  503. if ( strcmp(pEntity, "worldspawn" ) )
  504. continue;
  505. Vector wmins;
  506. Vector wmaxs;
  507. wmins.Init();
  508. wmaxs.Init();
  509. char* pchMins = ValueForKey(&entities[e], "world_mins");
  510. sscanf( pchMins, "%f %f %f", &wmins.x, &wmins.y, &wmins.z );
  511. char* pchMaxs = ValueForKey(&entities[e], "world_maxs");
  512. sscanf( pchMaxs, "%f %f %f", &wmaxs.x, &wmaxs.y, &wmaxs.z );
  513. printf( "No Skybox: (%8.3f %8.3f %8.3f) - (%8.3f %8.3f %8.3f)\n",
  514. wmins.x,
  515. wmins.y,
  516. wmins.z,
  517. wmaxs.x,
  518. wmaxs.y,
  519. wmaxs.z );
  520. break;
  521. }
  522. }
  523. else
  524. {
  525. PrintBSPFileSizes ();
  526. }
  527. if ( g_bTreeInfo )
  528. {
  529. g_nOptimumDepth = (int)( log( ( float )numnodes ) / log( 2.0f ) );
  530. g_nMinTreeDepth = 999999;
  531. g_nMaxTreeDepth = -999999;
  532. g_TotalTreeDepth = 0;
  533. g_TotalVariance = 0;
  534. CalculateTreeInfo_R( dmodels[0].headnode, 0 );
  535. printf( "\n"
  536. "\t-------------------\n"
  537. "\tTREE INFO:\n"
  538. "\t-------------------\n"
  539. "\tNumber of nodes ------------------ : %d\n"
  540. "\tOptimum tree depth (logN) -------- : %.3f\n"
  541. "\tMinimum tree depth --------------- : %d\n"
  542. "\tMaximum tree depth --------------- : %d\n"
  543. "\tAverage tree depth --------------- : %.3f\n"
  544. "\tAverage leaf variance from optimum : %.3f\n\n",
  545. numnodes,
  546. g_nOptimumDepth,
  547. g_nMinTreeDepth,
  548. g_nMaxTreeDepth,
  549. (float)g_TotalTreeDepth / numnodes,
  550. (float)g_TotalVariance / numnodes );
  551. }
  552. if ( g_bDrawTree )
  553. {
  554. DrawTreeToScratchPad();
  555. }
  556. if( !bWorldTextureStats && !bModelStats && !bListStaticProps )
  557. {
  558. printf ("---------------------\n");
  559. }
  560. }
  561. }