//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- const char* CClientTools::GetModelName( HTOOLHANDLE handle ) { int idx = m_Handles.Find( HToolEntry_t( handle ) ); if ( idx == m_Handles.InvalidIndex() ) return NULL; HToolEntry_t &entry = m_Handles[ idx ]; if ( entry.m_hEntity ) { return STRING( entry.m_hEntity->GetModelName() ); } Assert( 0 ); return NULL; }
//----------------------------------------------------------------------------- // Purpose: Takes the texinfo_t referenced by the .vmt and the computed depth for the // surface and looks up or creates a texdata/texinfo for the mangled one-off water .vmt file // Input : *pBaseInfo - // depth - // Output : int //----------------------------------------------------------------------------- int FindOrCreateWaterTexInfo( texinfo_t *pBaseInfo, float depth ) { char fullname[ 512 ]; char materialname[ 512 ]; // Get the base texture/material name char const *name = TexDataStringTable_GetString( GetTexData( pBaseInfo->texdata )->nameStringTableID ); GetWaterTextureName( mapbase, name, (int)depth, fullname ); // See if we already have an entry for this depth WaterTexInfo lookup; lookup.m_FullName = fullname; int idx = g_WaterTexInfos.Find( lookup ); // If so, return the existing entry texinfo index if ( idx != g_WaterTexInfos.InvalidIndex() ) { return g_WaterTexInfos[ idx ].m_nTexInfo; } // Otherwise, fill in the rest of the data lookup.m_nWaterDepth = (int)depth; // Remember the current material name sprintf( materialname, "%s", name ); strlwr( materialname ); lookup.m_MaterialName = materialname; texinfo_t ti; // Make a copy ti = *pBaseInfo; // Create a texdata that is based on the underlying existing entry ti.texdata = FindAliasedTexData( fullname, GetTexData( pBaseInfo->texdata ) ); // Find or create a new index lookup.m_nTexInfo = FindOrCreateTexInfo( ti ); // Add the new texinfo to the RB tree idx = g_WaterTexInfos.Insert( lookup ); // Msg( "created texinfo for %s\n", lookup.m_FullName.String() ); // Go ahead and create the new vmt file. EmitWaterMaterialFile( &g_WaterTexInfos[idx] ); // Return the new texinfo return g_WaterTexInfos[ idx ].m_nTexInfo; }
//----------------------------------------------------------------------------- // Use this to turn on/off the presence of an underlying game entity //----------------------------------------------------------------------------- void CClientTools::SetEnabled( HTOOLHANDLE handle, bool enabled ) { int idx = m_Handles.Find( HToolEntry_t( handle ) ); if ( idx == m_Handles.InvalidIndex() ) return; HToolEntry_t *slot = &m_Handles[ idx ]; Assert( slot ); if ( slot == NULL ) return; C_BaseEntity *ent = slot->m_hEntity.Get(); if ( ent == NULL || ent->entindex() == 0 ) return; // Don't disable/enable the "world" ent->EnableInToolView( enabled ); }
//----------------------------------------------------------------------------- // Make sure the details are compiled with static prop //----------------------------------------------------------------------------- static bool IsModelValid( const char* pModelName ) { StaticPropLookup_t lookup; lookup.m_ModelName = pModelName; int i = s_StaticPropLookup.Find( lookup ); if (i != s_StaticPropLookup.InvalidIndex() ) return s_StaticPropLookup[i].m_IsValid; CUtlBuffer buf; lookup.m_IsValid = LoadStudioModel( pModelName, "detail_prop", buf ); if (!lookup.m_IsValid) { Warning("Error loading studio model \"%s\"!\n", pModelName ); } s_StaticPropLookup.Insert( lookup ); return lookup.m_IsValid; }
//----------------------------------------------------------------------------- // Purpose: Recursively determine directory tree //----------------------------------------------------------------------------- static void RecurseFileTree_r( const char *pBasePath, const char *pDirPath, int depth, CUtlVector< CUtlString > &dirList, bool bIsModPath ) { if ( depth >= 2 ) { // too much unecessary detail return; } // ignore path roots, only interested in subdirs const char *pSubName = pDirPath + strlen( pBasePath ); if ( pSubName[0] ) { GamePath_t gamePath; gamePath.pathName = pSubName; gamePath.bIsModPath = bIsModPath; int iIndex = g_PathTable.Find( gamePath ); if ( iIndex == g_PathTable.InvalidIndex() ) { g_PathTable.Insert( gamePath ); } } // recurse from source directory, get directories only CUtlVector< CUtlString > fileList; int dirCount = GetFileList( pDirPath, "\\", fileList ); if ( !dirCount ) { // add directory name to search tree int j = dirList.AddToTail(); dirList[j].Set( pDirPath ); return; } for ( int i=0; i<dirCount; i++ ) { // form new path name, recurse into RecurseFileTree_r( pBasePath, fileList[i].String(), depth+1, dirList, bIsModPath ); } int j = dirList.AddToTail(); dirList[j].Set( pDirPath ); }
void RemoveFromWhiteList( char const *path ) { vprint( 2, "-\t'%s'\n", path ); char dir[ 512 ]; Q_strncpy( dir, path, sizeof( dir ) ); // Get the base filename from the path _strlwr( dir ); Q_FixSlashes( dir ); CUtlVector< FileEntry > files; char *lastslash = strrchr( dir, '\\' ); if ( lastslash == 0 ) { BuildFileListWildcard( 1, files, "", dir, 0 ); } else { char *wild = lastslash + 1; *lastslash = 0; BuildFileListWildcard( 1, files, dir, wild, 0 ); } int c = files.Count(); for ( int i = 0; i < c; ++i ) { UnusedContent::CUtlSymbol sym = files[ i ].sym; int idx = g_WhiteList.Find( sym ); if ( idx != g_WhiteList.InvalidIndex() ) { g_WhiteList.RemoveAt( idx ); ++wl_removed; } } }
void logprint( char const *logfile, const char *fmt, ... ) { char string[ 8192 ]; va_list va; va_start( va, fmt ); vsprintf( string, fmt, va ); va_end( va ); FILE *fp = NULL; UnusedContent::CUtlSymbol sym = g_Analysis.symbols.Find( logfile ); static CUtlRBTree< UnusedContent::CUtlSymbol, int > previousfiles( 0, 0, DefLessFunc( UnusedContent::CUtlSymbol ) ); if ( previousfiles.Find( sym ) == previousfiles.InvalidIndex() ) { previousfiles.Insert( sym ); fp = fopen( logfile, "wb" ); } else { fp = fopen( logfile, "ab" ); } if ( fp ) { char *p = string; while ( *p ) { if ( *p == '\n' ) { fputc( '\r', fp ); } fputc( *p, fp ); p++; } fclose( fp ); } }
//----------------------------------------------------------------------------- // Purpose: // Input : handle - //----------------------------------------------------------------------------- bool CClientTools::IsValidHandle( HTOOLHANDLE handle ) { return m_Handles.Find( HToolEntry_t( handle ) ) != m_Handles.InvalidIndex(); }
void CPlayerLogoProxy::OnBind( void *pC_BaseEntity ) { // Decal's are bound with the player index as the passed in paramter int playerindex = (int)pC_BaseEntity; if ( playerindex <= 0 ) return; if ( playerindex > gpGlobals->maxClients ) return; if ( !m_pBaseTextureVar ) return; // Find player player_info_t info; engine->GetPlayerInfo( playerindex, &info ); if ( !info.customFiles[0] ) return; // So we don't trash this too hard ITexture *texture = NULL; PlayerLogo logo; logo.crc = (unsigned int)info.customFiles[0]; logo.texture = NULL; int lookup = m_Logos.Find( logo ); if ( lookup == m_Logos.InvalidIndex() ) { char crcfilename[ 512 ]; char logohex[ 16 ]; Q_binarytohex( (byte *)&info.customFiles[0], sizeof( info.customFiles[0] ), logohex, sizeof( logohex ) ); Q_snprintf( crcfilename, sizeof( crcfilename ), "temp/%s", logohex ); texture = materials->FindTexture( crcfilename, TEXTURE_GROUP_DECAL, false ); if ( texture ) { // Make sure it doesn't get flushed texture->IncrementReferenceCount(); logo.texture = texture; } m_Logos.Insert( logo ); } else { texture = m_Logos[ lookup ].texture; } if ( texture ) { m_pBaseTextureVar->SetTextureValue( texture ); } else if ( m_pDefaultTexture ) { m_pBaseTextureVar->SetTextureValue( m_pDefaultTexture ); } if ( ToolsEnabled() ) { ToolFramework_RecordMaterialParams( GetMaterial() ); } }
void BuildWhiteList() { // Search for unusedcontent.cfg file if ( !g_pFileSystem->FileExists( WHITELIST_FILE ) ) { vprint( 1, "Running with no whitelist.cfg file!!!\n" ); return; } vprint( 1, "\nBuilding whitelist\n" ); KeyValues *kv = new KeyValues( WHITELIST_FILE ); if ( kv ) { if ( kv->LoadFromFile( g_pFileSystem, WHITELIST_FILE, NULL ) ) { for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() ) { if ( !Q_stricmp( sub->GetName(), "add" ) ) { AddToWhiteList( sub->GetString() ); } else if ( !Q_stricmp( sub->GetName(), "remove" ) ) { RemoveFromWhiteList( sub->GetString() ); } else { vprint( 1, "Unknown subkey '%s' in %s\n", sub->GetName(), WHITELIST_FILE ); } } } kv->deleteThis(); } if ( verbose || printwhitelist ) { vprint( 1, "Whitelist:\n\n" ); for ( int i = g_WhiteList.FirstInorder(); i != g_WhiteList.InvalidIndex(); i = g_WhiteList.NextInorder( i ) ) { UnusedContent::CUtlSymbol& sym = g_WhiteList[ i ]; char const *resolved = g_Analysis.symbols.String( sym ); vprint( 2, " %s\n", resolved ); } } // dump the whitelist file list anyway { filesystem->RemoveFile( "whitelist_files.txt", "GAME" ); for ( int i = g_WhiteList.FirstInorder(); i != g_WhiteList.InvalidIndex(); i = g_WhiteList.NextInorder( i ) ) { UnusedContent::CUtlSymbol& sym = g_WhiteList[ i ]; char const *resolved = g_Analysis.symbols.String( sym ); logprint( "whitelist_files.txt", "\"%s\"\n", resolved ); } } vprint( 1, "Whitelist resolves to %d files (added %i/removed %i)\n\n", g_WhiteList.Count(), wl_added, wl_removed ); }
void Correlate( CUtlRBTree< ReferencedFile, int >& referencedfiles, CUtlVector< FileEntry >& contentfiles, const char *modname ) { int i; int c = contentfiles.Count(); double totalDiskSize = 0; double totalReferencedDiskSize = 0; double totalWhiteListDiskSize = 0; for ( i = 0; i < c; ++i ) { totalDiskSize += contentfiles [ i ].size; } vprint( 0, "Content tree size on disk %s\n", Q_pretifymem( totalDiskSize, 3 ) ); // Analysis is to walk tree and see which files on disk are referenced in the .lst files // Need a fast lookup from file symbol to referenced list CUtlRBTree< ReferencedFile, int > tree( 0, 0, ReferencedFileLessFunc ); c = referencedfiles.Count(); for ( i = 0 ; i < c; ++i ) { tree.Insert( referencedfiles[ i ] ); } // Now walk the on disk file and see check off resources which are in referenced c = contentfiles.Count(); int invalidindex = tree.InvalidIndex(); unsigned int refcounted = 0; unsigned int whitelisted = 0; filesystem->RemoveFile( CFmtStr( "%swhitelist.lst", g_szReslistDir ), "GAME" ); for ( i = 0; i < c; ++i ) { FileEntry & entry = contentfiles[ i ]; ReferencedFile foo; foo.sym = entry.sym; bool gameref = tree.Find( foo ) != invalidindex; char const *fn = g_Analysis.symbols.String( entry.sym ); bool whitelist = g_WhiteList.Find( entry.sym ) != g_WhiteList.InvalidIndex(); if ( gameref || whitelist ) { entry.referenced = gameref ? REFERENCED_GAME : REFERENCED_WHITELIST; totalReferencedDiskSize += entry.size; if ( entry.referenced == REFERENCED_WHITELIST ) { logprint( CFmtStr( "%swhitelist.lst", g_szReslistDir ), "\"%s\\%s\"\n", modname, fn ); totalWhiteListDiskSize += entry.size; ++whitelisted; } ++refcounted; } } vprint( 0, "Found %i referenced (%i whitelist) files in tree, %s\n", refcounted, whitelisted, Q_pretifymem( totalReferencedDiskSize, 2 ) ); vprint( 0, "%s appear unused\n", Q_pretifymem( totalDiskSize - totalReferencedDiskSize, 2 ) ); // Now sort and dump the unreferenced ones.. vprint( 0, "Sorting unreferenced files list...\n" ); CUtlRBTree< FileEntry, int > unreftree( 0, 0, FileEntryLessFunc ); for ( i = 0; i < c; ++i ) { FileEntry & entry = contentfiles[ i ]; if ( entry.referenced != REFERENCED_NO ) continue; unreftree.Insert( entry ); } // Now walk the unref tree in order i = unreftree.FirstInorder(); invalidindex = unreftree.InvalidIndex(); int index = 0; while ( i != invalidindex ) { FileEntry & entry = unreftree[ i ]; if ( showreferencedfiles ) { vprint( 1, "%6i %12s: %s\n", ++index, Q_pretifymem( entry.size, 2 ), g_Analysis.symbols.String( entry.sym ) ); } i = unreftree.NextInorder( i ); } if ( showmapfileusage ) { vprint( 0, "Writing referenced.csv...\n" ); // Now walk the list of referenced files and print out how many and which maps reference them i = tree.FirstInorder(); invalidindex = tree.InvalidIndex(); index = 0; while ( i != invalidindex ) { ReferencedFile & entry = tree[ i ]; char ext[ 32 ]; Q_ExtractFileExtension( g_Analysis.symbols.String( entry.sym ), ext, sizeof( ext ) ); logprint( "referenced.csv", "\"%s\",\"%s\",%d", g_Analysis.symbols.String( entry.sym ), ext, entry.maplist.Count() ); int mapcount = entry.maplist.Count(); for ( int j = 0 ; j < mapcount; ++j ) { char basemap[ 128 ]; Q_FileBase( g_Analysis.symbols.String( entry.maplist[ j ] ), basemap, sizeof( basemap ) ); logprint( "referenced.csv", ",\"%s\"", basemap ); } logprint( "referenced.csv", "\n" ); i = tree.NextInorder( i ); } } vprint( 0, "\nBuilding directory summary list...\n" ); // Now build summaries by root branch off of gamedir (e.g., for sound, materials, models, etc.) CUtlDict< DirEntry, int > directories; invalidindex = directories.InvalidIndex(); for ( i = 0; i < c; ++i ) { FileEntry & entry = contentfiles[ i ]; // Get the dir name char const *dirname = g_Analysis.symbols.String( entry.sym ); const char *backslash = strstr( dirname, "\\" ); char dir[ 256 ]; if ( !backslash ) { dir[0] = 0; } else { Q_strncpy( dir, dirname, backslash - dirname + 1); } int idx = directories.Find( dir ); if ( idx == invalidindex ) { DirEntry foo; idx = directories.Insert( dir, foo ); } DirEntry & de = directories[ idx ]; de.total += entry.size; if ( entry.referenced == REFERENCED_NO ) { de.unreferenced += entry.size; } if ( entry.referenced == REFERENCED_WHITELIST ) { de.whitelist += entry.size; } } if ( spewdeletions ) { // Spew deletion commands to console if ( immediatedelete ) { vprint( 0, "\n\nDeleting files...\n" ); } else { vprint( 0, "\n\nGenerating deletions.bat\n" ); } i = unreftree.FirstInorder(); invalidindex = unreftree.InvalidIndex(); float deletionSize = 0.0f; int deletionCount = 0; while ( i != invalidindex ) { FileEntry & entry = unreftree[ i ]; i = unreftree.NextInorder( i ); // Don't delete stuff that's in the white list if ( g_WhiteList.Find( entry.sym ) != g_WhiteList.InvalidIndex() ) { if ( verbose ) { vprint( 0, "whitelist blocked deletion of %s\n", g_Analysis.symbols.String( entry.sym ) ); } continue; } ++deletionCount; deletionSize += entry.size; if ( immediatedelete ) { if ( _chmod( g_Analysis.symbols.String( entry.sym ), _S_IWRITE ) == -1 ) { vprint( 0, "Could not find file %s\n", g_Analysis.symbols.String( entry.sym ) ); } if ( _unlink( g_Analysis.symbols.String( entry.sym ) ) == -1 ) { vprint( 0, "Could not delete file %s\n", g_Analysis.symbols.String( entry.sym ) ); } if ( deletionCount % 1000 == 0 ) { vprint( 0, "...deleted %i files\n", deletionCount ); } } else { logprint( "deletions.bat", "del \"%s\" /f\n", g_Analysis.symbols.String( entry.sym ) ); } } vprint( 0, "\nFile deletion (%d files, %s)\n\n", deletionCount, Q_pretifymem(deletionSize, 2) ); } double grand_total = 0; double grand_total_unref = 0; double grand_total_white = 0; char totalstring[ 20 ]; char unrefstring[ 20 ]; char refstring[ 20 ]; char whiteliststring[ 20 ]; vprint( 0, "---------------------------------------- Summary ----------------------------------------\n" ); vprint( 0, "% 15s % 15s % 15s % 15s %12s\n", "Referenced", "WhiteListed", "Unreferenced", "Total", "Directory" ); // Now walk the dictionary in order i = directories.First(); while ( i != invalidindex ) { DirEntry & de = directories[ i ]; double remainder = de.total - de.unreferenced; float percent_unref = 0.0f; float percent_white = 0.0f; if ( de.total > 0 ) { percent_unref = 100.0f * (float)de.unreferenced / (float)de.total; percent_white = 100.0f * (float)de.whitelist / (float)de.total; } Q_strncpy( totalstring, Q_pretifymem( de.total, 2 ), sizeof( totalstring ) ); Q_strncpy( unrefstring, Q_pretifymem( de.unreferenced, 2 ), sizeof( unrefstring ) ); Q_strncpy( refstring, Q_pretifymem( remainder, 2 ), sizeof( refstring ) ); Q_strncpy( whiteliststring, Q_pretifymem( de.whitelist, 2 ), sizeof( whiteliststring ) ); vprint( 0, "%15s (%8.3f%%) %15s (%8.3f%%) %15s (%8.3f%%) %15s => dir: %s\n", refstring, 100.0f - percent_unref, whiteliststring, percent_white, unrefstring, percent_unref, totalstring, directories.GetElementName( i ) ); grand_total += de.total; grand_total_unref += de.unreferenced; grand_total_white += de.whitelist; i = directories.Next( i ); } Q_strncpy( totalstring, Q_pretifymem( grand_total, 2 ), sizeof( totalstring ) ); Q_strncpy( unrefstring, Q_pretifymem( grand_total_unref, 2 ), sizeof( unrefstring ) ); Q_strncpy( refstring, Q_pretifymem( grand_total - grand_total_unref, 2 ), sizeof( refstring ) ); Q_strncpy( whiteliststring, Q_pretifymem( grand_total_white, 2 ), sizeof( whiteliststring ) ); double percent_unref = 100.0 * grand_total_unref / grand_total; double percent_white = 100.0 * grand_total_white / grand_total; vprint( 0, "-----------------------------------------------------------------------------------------\n" ); vprint( 0, "%15s (%8.3f%%) %15s (%8.3f%%) %15s (%8.3f%%) %15s\n", refstring, 100.0f - percent_unref, whiteliststring, percent_white, unrefstring, percent_unref, totalstring ); }
void ParseFilesFromResList( UnusedContent::CUtlSymbol & resfilesymbol, CUtlRBTree< ReferencedFile, int >& files, char const *resfile ) { int addedStrings = 0; int resourcesConsidered = 0; int offset = Q_strlen( gamedir ); char basedir[MAX_PATH]; Q_strncpy( basedir, gamedir, sizeof( basedir ) ); if ( !Q_StripLastDir( basedir, sizeof( basedir ) ) ) Error( "Can't get basedir from %s.", gamedir ); FileHandle_t resfilehandle; resfilehandle = g_pFileSystem->Open( resfile, "rb" ); if ( FILESYSTEM_INVALID_HANDLE != resfilehandle ) { // Read in the entire file int length = g_pFileSystem->Size(resfilehandle); if ( length > 0 ) { char *pStart = (char *)new char[ length + 1 ]; if ( pStart && ( length == g_pFileSystem->Read(pStart, length, resfilehandle) ) ) { pStart[ length ] = 0; char *pFileList = pStart; char token[512]; while ( 1 ) { pFileList = ParseFile( pFileList, token, NULL ); if ( !pFileList ) break; if ( strlen( token ) > 0 ) { char szFileName[ 256 ]; Q_snprintf( szFileName, sizeof( szFileName ), "%s%s", basedir, token ); _strlwr( szFileName ); Q_FixSlashes( szFileName ); while ( szFileName[ strlen( szFileName ) - 1 ] == '\n' || szFileName[ strlen( szFileName ) - 1 ] == '\r' ) { szFileName[ strlen( szFileName ) - 1 ] = 0; } if ( Q_strnicmp( szFileName, gamedir, offset ) ) continue; char *pFile = szFileName + offset; ++resourcesConsidered; ReferencedFile rf; rf.sym = g_Analysis.symbols.AddString( pFile ); int idx = files.Find( rf ); if ( idx == files.InvalidIndex() ) { ++addedStrings; rf.maplist.AddToTail( resfilesymbol ); files.Insert( rf ); } else { // ReferencedFile & slot = files[ idx ]; if ( slot.maplist.Find( resfilesymbol ) == slot.maplist.InvalidIndex() ) { slot.maplist.AddToTail( resfilesymbol ); } } } } } delete[] pStart; } g_pFileSystem->Close(resfilehandle); } int filesFound = addedStrings; vprint( 1, "Found %i new resources (%i total) in %s\n", filesFound, resourcesConsidered, resfile ); }
//----------------------------------------------------------------------------- // ExcludePathsDlg_Populate // // Generate a path table. //----------------------------------------------------------------------------- void ExcludePathsDlg_Populate( HWND hWnd, bool bRefresh ) { struct GamePath_t { CUtlString pathName; bool bIsModPath; }; CUtlVector< GamePath_t > gamePaths; // can skip the time consuming directory scan, unless forced if ( bRefresh || !g_PathTable.Count() ) { g_PathTable.Purge(); for ( int i = 0; i < ARRAYSIZE( g_GameNames ); i++ ) { char szTargetPath[MAX_PATH]; V_strncpy( szTargetPath, g_localPath, sizeof( szTargetPath ) ); V_AppendSlash( szTargetPath, sizeof( szTargetPath ) ); V_strncat( szTargetPath, g_GameNames[i].pName, sizeof( szTargetPath ) ); GamePath_t gamePath; gamePath.pathName = szTargetPath; gamePath.bIsModPath = g_GameNames[i].bIsModPath; gamePaths.AddToTail( gamePath ); } // iterate all game paths for ( int i = 0; i < gamePaths.Count(); i++ ) { CUtlVector< CUtlString > dirList; RecurseFileTree_r( g_localPath, gamePaths[i].pathName.String(), 0, dirList, gamePaths[i].bIsModPath ); } } // reset the tree HWND hWndTree = GetDlgItem( hWnd, IDC_PATHS_TREE ); TreeView_DeleteAllItems( hWndTree ); // reset and add root // only the root is at depth 0 AddItemToTree( hWndTree, ROOT_NAME, 0, false ); // build the tree view for ( int iIndex = g_PathTable.FirstInorder(); iIndex != g_PathTable.InvalidIndex(); iIndex = g_PathTable.NextInorder( iIndex ) ) { // due to sorting, number of slashes is depth const char *pString = g_PathTable[iIndex].pathName.String(); int depth = 0; for ( int j = 0; j < (int)strlen( pString ); j++ ) { if ( pString[j] == '\\' ) { depth++; } } if ( !depth ) { depth = 1; } char szPath[MAX_PATH]; V_FileBase( pString, szPath, sizeof( szPath ) ); AddItemToTree( hWndTree, szPath, depth, g_PathTable[iIndex].bIsModPath ); } HTREEITEM hTreeRoot = TreeView_GetRoot( hWndTree ); for ( int i = 0; i < g_ExcludePaths.Count(); i++ ) { HTREEITEM hTree = ExcludePathsDlg_Find_r( hWndTree, hTreeRoot, 0, "", g_ExcludePaths[i].String() ); if ( hTree ) { ExcludePathsDlg_SetCheckState_r( hWndTree, hTree, 0, true ); } } // expand the root node to show state ExcludePathsDlg_ExpandToShowState_r( hWndTree, hTreeRoot, 0 ); }
//----------------------------------------------------------------------------- // Add, find collision model in cache //----------------------------------------------------------------------------- static CPhysCollide* GetCollisionModel( char const* pModelName ) { // Convert to a common string char* pTemp = (char*)_alloca(strlen(pModelName) + 1); strcpy( pTemp, pModelName ); _strlwr( pTemp ); char* pSlash = strchr( pTemp, '\\' ); while( pSlash ) { *pSlash = '/'; pSlash = strchr( pTemp, '\\' ); } // Find it in the cache ModelCollisionLookup_t lookup; lookup.m_Name = pTemp; int i = s_ModelCollisionCache.Find( lookup ); if (i != s_ModelCollisionCache.InvalidIndex()) return s_ModelCollisionCache[i].m_pCollide; // Load the studio model file CUtlBuffer buf; if (!LoadStudioModel(pModelName, "prop_static", buf)) { Warning("Error loading studio model \"%s\"!\n", pModelName ); // This way we don't try to load it multiple times lookup.m_pCollide = 0; s_ModelCollisionCache.Insert( lookup ); return 0; } // Compute the convex hull of the model... studiohdr_t* pStudioHdr = (studiohdr_t*)buf.PeekGet(); // necessary for vertex access SetCurrentModel( pStudioHdr ); lookup.m_pCollide = ComputeConvexHull( pStudioHdr ); s_ModelCollisionCache.Insert( lookup ); if ( !lookup.m_pCollide ) { Warning("Bad geometry on \"%s\"!\n", pModelName ); } // Debugging if (g_DumpStaticProps) { static int propNum = 0; char tmp[128]; sprintf( tmp, "staticprop%03d.txt", propNum ); DumpCollideToGlView( lookup.m_pCollide, tmp ); ++propNum; } FreeCurrentModelVertexes(); // Insert into cache... return lookup.m_pCollide; }