summaryrefslogtreecommitdiff
path: root/engine/cl_texturelistpanel.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /engine/cl_texturelistpanel.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'engine/cl_texturelistpanel.cpp')
-rw-r--r--engine/cl_texturelistpanel.cpp3380
1 files changed, 3380 insertions, 0 deletions
diff --git a/engine/cl_texturelistpanel.cpp b/engine/cl_texturelistpanel.cpp
new file mode 100644
index 0000000..066067f
--- /dev/null
+++ b/engine/cl_texturelistpanel.cpp
@@ -0,0 +1,3380 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "client_pch.h"
+#include "ivideomode.h"
+#include "client_class.h"
+#include "icliententitylist.h"
+#include "vgui_basepanel.h"
+#include <vgui_controls/Controls.h>
+#include <vgui/ISurface.h>
+#include <vgui/IScheme.h>
+#include <vgui/IVGui.h>
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/TreeView.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/ListViewPanel.h>
+#include <vgui_controls/TreeViewListControl.h>
+#include <vgui/ISystem.h>
+#include "tier0/vprof.h"
+#include "KeyValues.h"
+#include "vgui_helpers.h"
+#include "utlsymbol.h"
+#include "tier1/UtlStringMap.h"
+#include "bitvec.h"
+#include "utldict.h"
+#include "vgui/ILocalize.h"
+#include "con_nprint.h"
+#include "gl_matsysiface.h"
+
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imaterialvar.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/idebugtextureinfo.h"
+#include "materialsystem/itexture.h"
+#include "vtf/vtf.h"
+#include "tier2/tier2.h"
+#include "smartptr.h"
+
+#include "igame.h"
+
+#include "client.h"
+
+#include "tier2/p4helpers.h"
+#include "p4lib/ip4.h"
+#include "ivtex.h"
+#include "tier2/fileutils.h"
+
+// For character manipulations isupper/tolower
+#include <ctype.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define KEYNAME_NAME "Name"
+#define KEYNAME_PATH "Path"
+#define KEYNAME_BINDS_MAX "BindsMax"
+#define KEYNAME_BINDS_FRAME "BindsFrame"
+#define KEYNAME_SIZE "Size"
+#define KEYNAME_FORMAT "Format"
+#define KEYNAME_WIDTH "Width"
+#define KEYNAME_HEIGHT "Height"
+#define KEYNAME_TEXTURE_GROUP "TexGroup"
+
+#define COPYTOCLIPBOARD_CMDNAME "CopyToClipboard"
+
+#if defined( _X360 )
+CON_COMMAND( mat_get_textures, "VXConsole command" )
+{
+ g_pMaterialSystemDebugTextureInfo->EnableDebugTextureList( true );
+ g_pMaterialSystemDebugTextureInfo->EnableGetAllTextures( args.ArgC() >= 2 && ( Q_stricmp( args[1], "all" ) == 0 ) );
+}
+#endif
+
+static ConVar mat_texture_list( "mat_texture_list", "0", FCVAR_CHEAT, "For debugging, show a list of used textures per frame" );
+
+static enum TxListPanelRequest
+{
+ TXR_NONE,
+ TXR_SHOW,
+ TXR_RUNNING,
+ TXR_HIDE
+} s_eTxListPanelRequest = TXR_NONE;
+
+IVTex* VTex_Load( CSysModule** pModule );
+void VTex_Unload( CSysModule *pModule );
+void* CubemapsFSFactory( const char *pName, int *pReturnCode );
+bool StripDirName( char *pFilename );
+
+// These are here so you can bind a key to +mat_texture_list and toggle it on and off.
+void mat_texture_list_on_f();
+void mat_texture_list_off_f();
+
+ConCommand mat_texture_list_on( "+mat_texture_list", mat_texture_list_on_f );
+ConCommand mat_texture_list_off( "-mat_texture_list", mat_texture_list_off_f );
+
+ConVar mat_texture_list_all( "mat_texture_list_all", "0", FCVAR_NEVER_AS_STRING|FCVAR_CHEAT, "If this is nonzero, then the texture list panel will show all currently-loaded textures." );
+
+ConVar mat_texture_list_view( "mat_texture_list_view", "1", FCVAR_NEVER_AS_STRING|FCVAR_CHEAT, "If this is nonzero, then the texture list panel will render thumbnails of currently-loaded textures." );
+
+ConVar mat_show_texture_memory_usage( "mat_show_texture_memory_usage", "0", FCVAR_NEVER_AS_STRING|FCVAR_CHEAT, "Display the texture memory usage on the HUD." );
+
+
+static int g_warn_texkbytes = 1499;
+static int g_warn_texdimensions = 1024;
+static bool g_warn_enable = true;
+static bool g_cursorset = false;
+
+class CTextureListPanel;
+static CTextureListPanel *g_pTextureListPanel = NULL;
+static bool g_bRecursiveRequestToShowTextureList = false;
+static int g_nSaveQueueState = INT_MIN;
+
+
+//
+// A class to mimic a list view
+//
+
+namespace vgui
+{
+
+
+class TileViewPanelEx : public Panel
+{
+ DECLARE_CLASS_SIMPLE( TileViewPanelEx, Panel );
+
+public:
+ TileViewPanelEx( Panel *parent, const char *panelName );
+ ~TileViewPanelEx();
+
+public:
+ virtual void SetFont( HFont hFont );
+ virtual HFont GetFont();
+
+public:
+ enum HitTest_t
+ {
+ HT_NOTHING = 0,
+ HT_TILE
+ };
+ virtual int HitTest( int x, int y, int &iTile );
+ virtual bool GetTileOrg( int iTile, int &x, int &y );
+
+protected: // Overrides for contents
+ virtual int GetNumTiles() = 0;
+ virtual void GetTileSize( int &wide, int &tall ) = 0;
+ virtual void RenderTile( int iTile, int x, int y ) = 0;
+
+protected:
+ // Handlers
+ virtual void OnMouseWheeled( int delta );
+ virtual void OnSizeChanged( int wide, int tall );
+ virtual void PerformLayout();
+ virtual void Paint();
+ virtual void ApplySchemeSettings( IScheme *pScheme );
+ MESSAGE_FUNC( OnSliderMoved, "ScrollBarSliderMoved" );
+
+protected:
+ virtual bool ComputeLayoutInfo();
+ int m_li_numTiles; //!< Total number of tiles
+ int m_li_numVisibleTiles; //!< Number of tiles fitting in the client area
+ int m_li_wide, m_li_tall; //!< Tile area width/height
+ int m_li_wideItem, m_li_tallItem; //!< Every item width/height
+ int m_li_colVisible, m_li_rowVisible; //!< Num columns/rows fitting in the client area
+ int m_li_rowNeeded; //!< Num rows required to fit all numTiles
+ int m_li_startTile, m_li_endTile; //!< Start/end tile that are rendered in the client area
+
+private:
+ ScrollBar *m_hbar;
+ HFont m_hFont;
+};
+
+
+
+//
+// Implementation details
+//
+
+TileViewPanelEx::TileViewPanelEx( Panel *parent, const char *panelName ) :
+ Panel( parent, panelName ),
+ m_hbar( NULL ),
+ m_hFont( INVALID_FONT )
+{
+ m_hbar = new ScrollBar( this, "VerticalScrollBar", true );
+ m_hbar->AddActionSignalTarget( this );
+ m_hbar->SetVisible( true );
+}
+
+TileViewPanelEx::~TileViewPanelEx()
+{
+ delete m_hbar;
+}
+
+void TileViewPanelEx::SetFont( HFont hFont )
+{
+ m_hFont = hFont;
+ Repaint();
+}
+
+HFont TileViewPanelEx::GetFont()
+{
+ return m_hFont;
+}
+
+int TileViewPanelEx::HitTest( int x, int y, int &iTile )
+{
+ iTile = -1;
+
+ if ( !ComputeLayoutInfo() )
+ return HT_NOTHING;
+
+ int hitCol = ( x / m_li_wideItem );
+ int hitRow = ( y / m_li_tallItem );
+
+ if ( hitCol >= m_li_colVisible )
+ return HT_NOTHING;
+ if ( hitRow > m_li_rowVisible )
+ return HT_NOTHING;
+
+ int hitTile = m_li_startTile + hitCol + hitRow * m_li_colVisible;
+ if ( hitTile >= m_li_endTile )
+ return HT_NOTHING;
+
+ // Hit tile
+ iTile = hitTile;
+ return HT_TILE;
+}
+
+bool TileViewPanelEx::GetTileOrg( int iTile, int &x, int &y )
+{
+ if ( m_li_colVisible <= 0 )
+ return false;
+ if ( iTile < m_li_startTile || iTile >= m_li_endTile )
+ return false;
+
+ x = 0 + ( ( iTile - m_li_startTile ) % m_li_colVisible ) * m_li_wideItem;
+ y = 0 + ( ( iTile - m_li_startTile ) / m_li_colVisible ) * m_li_tallItem;
+
+ return true;
+}
+
+void TileViewPanelEx::OnMouseWheeled( int delta )
+{
+ if ( m_hbar->IsVisible() )
+ {
+ int val = m_hbar->GetValue();
+ val -= delta;
+ m_hbar->SetValue( val );
+ }
+}
+
+void TileViewPanelEx::OnSizeChanged( int wide, int tall )
+{
+ BaseClass::OnSizeChanged( wide, tall );
+ InvalidateLayout();
+ Repaint();
+}
+
+void TileViewPanelEx::PerformLayout()
+{
+ int numTiles = GetNumTiles();
+ m_hbar->SetVisible( false );
+
+ int wide, tall;
+ GetSize( wide, tall );
+ wide -= m_hbar->GetWide();
+
+ m_hbar->SetPos( wide - 2, 0 );
+ m_hbar->SetTall( tall );
+
+ if ( !numTiles )
+ return;
+
+ int wideItem = 1, tallItem = 1;
+ GetTileSize( wideItem, tallItem );
+ if ( !wideItem || !tallItem )
+ return;
+
+ int colVisible = wide / wideItem;
+ int rowVisible = tall / tallItem;
+ if ( rowVisible <= 0 || colVisible <= 0 )
+ return;
+
+ int rowNeeded = ( numTiles + colVisible - 1 ) / colVisible;
+
+ int startTile = 0;
+ if ( rowNeeded > rowVisible )
+ {
+ m_hbar->SetRange( 0, rowNeeded );
+ m_hbar->SetRangeWindow( rowVisible );
+ m_hbar->SetButtonPressedScrollValue( 1 );
+
+ m_hbar->SetVisible( true );
+ m_hbar->InvalidateLayout();
+
+ int val = m_hbar->GetValue();
+ startTile = val * colVisible;
+ }
+}
+
+bool TileViewPanelEx::ComputeLayoutInfo()
+{
+ m_li_numTiles = GetNumTiles();
+ if ( !m_li_numTiles )
+ return false;
+
+ GetSize( m_li_wide, m_li_tall );
+ m_li_wide -= m_hbar->GetWide();
+
+ m_li_wideItem = 1, m_li_tallItem = 1;
+ GetTileSize( m_li_wideItem, m_li_tallItem );
+ if ( !m_li_wideItem || !m_li_tallItem )
+ return false;
+
+ m_li_colVisible = m_li_wide / m_li_wideItem;
+ m_li_rowVisible = m_li_tall / m_li_tallItem;
+ if ( m_li_rowVisible <= 0 || m_li_colVisible <= 0 )
+ return false;
+
+ m_li_rowNeeded = ( m_li_numTiles + m_li_colVisible - 1 ) / m_li_colVisible;
+ m_li_numVisibleTiles = m_li_colVisible * m_li_rowVisible;
+
+ m_li_startTile = 0;
+ if ( m_li_rowNeeded > m_li_rowVisible )
+ {
+ int val = m_hbar->GetValue();
+ m_li_startTile = val * m_li_colVisible;
+ }
+
+ if ( m_li_startTile >= m_li_numTiles )
+ m_li_startTile = m_li_numTiles - m_li_numVisibleTiles;
+ if ( m_li_startTile < 0 )
+ m_li_startTile = 0;
+
+ m_li_endTile = m_li_startTile + m_li_numVisibleTiles + m_li_colVisible; // draw the partly visible items
+ if ( m_li_endTile > m_li_numTiles )
+ m_li_endTile = m_li_numTiles;
+
+ return true;
+}
+
+void TileViewPanelEx::Paint()
+{
+ BaseClass::Paint();
+
+ // Now render all our tiles
+ if ( !ComputeLayoutInfo() )
+ return;
+
+ for ( int iRenderTile = m_li_startTile; iRenderTile < m_li_endTile; ++ iRenderTile )
+ {
+ int x = 0 + ( ( iRenderTile - m_li_startTile ) % m_li_colVisible ) * m_li_wideItem;
+ int y = 0 + ( ( iRenderTile - m_li_startTile ) / m_li_colVisible ) * m_li_tallItem;
+ RenderTile( iRenderTile, x, y );
+ }
+}
+
+void TileViewPanelEx::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetBgColor( GetSchemeColor( "ListPanel.BgColor", pScheme ) );
+ SetBorder( pScheme->GetBorder("ButtonDepressedBorder" ) );
+
+ SetFont( pScheme->GetFont( "Default", IsProportional() ) );
+}
+
+void TileViewPanelEx::OnSliderMoved()
+{
+ InvalidateLayout();
+ Repaint();
+}
+
+
+
+}; // namespace vgui
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Material access
+//
+//////////////////////////////////////////////////////////////////////////
+
+class CAutoMatSysDebugMode
+{
+public:
+ CAutoMatSysDebugMode();
+ ~CAutoMatSysDebugMode();
+
+ void ScheduleCleanupTextureVar( IMaterialVar *pVar );
+
+protected:
+ bool bOldDebugMode;
+ CUtlRBTree< IMaterialVar * > arrCleanupVars;
+};
+
+CAutoMatSysDebugMode::CAutoMatSysDebugMode() :
+ arrCleanupVars( DefLessFunc(IMaterialVar *) )
+{
+ g_pMaterialSystem->Flush();
+ bOldDebugMode = g_pMaterialSystemDebugTextureInfo->SetDebugTextureRendering( true );
+}
+
+CAutoMatSysDebugMode::~CAutoMatSysDebugMode()
+{
+ g_pMaterialSystem->Flush();
+ g_pMaterialSystemDebugTextureInfo->SetDebugTextureRendering( bOldDebugMode );
+
+ for ( uint32 k = 0; k < arrCleanupVars.Count(); ++ k )
+ {
+ IMaterialVar *pVar = arrCleanupVars.Element( k );
+ pVar->SetUndefined();
+ }
+}
+
+void CAutoMatSysDebugMode::ScheduleCleanupTextureVar( IMaterialVar *pVar )
+{
+ if ( !pVar )
+ return;
+
+ arrCleanupVars.InsertIfNotFound( pVar );
+}
+
+static IMaterial * UseDebugMaterial( char const *szMaterial, ITexture *pMatTexture, CAutoMatSysDebugMode *pRestoreVars )
+{
+ if ( !szMaterial || !pMatTexture )
+ return NULL;
+
+ bool foundVar;
+
+ IMaterial *pMaterial = materials->FindMaterial( szMaterial, TEXTURE_GROUP_OTHER, false );
+ // IMaterial *pMaterial = materials->FindMaterial( "debug/debugempty", TEXTURE_GROUP_OTHER, false );
+ if ( !pMaterial )
+ return NULL;
+
+ IMaterialVar *BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
+ // IMaterialVar *BaseTextureVar = pMaterial->FindVar( "$basetexture", &foundVar, false );
+ if ( !foundVar || !BaseTextureVar )
+ return NULL;
+
+ IMaterialVar *FrameVar = pMaterial->FindVar( "$frame", &foundVar, false );
+ if ( foundVar && FrameVar )
+ {
+ int numAnimFrames = pMatTexture->GetNumAnimationFrames();
+
+ if ( pMatTexture->IsRenderTarget() || pMatTexture->IsProcedural() )
+ numAnimFrames = 0; // Cannot use the stencil parts of the render targets and shouldn't use the other frames of procedural textures
+
+ FrameVar->SetIntValue( ( numAnimFrames > 0 ) ? ( g_ClientGlobalVariables.tickcount % numAnimFrames ) : 0 );
+ }
+
+ BaseTextureVar->SetTextureValue( pMatTexture );
+
+ if ( pRestoreVars )
+ {
+ pRestoreVars->ScheduleCleanupTextureVar( BaseTextureVar );
+ }
+
+ return pMaterial;
+}
+
+static void RenderTexturedRect( vgui::Panel *pPanel, IMaterial *pMaterial, int x, int y, int x1, int y1, int xoff = 0, int yoff = 0 )
+{
+ CAutoMatSysDebugMode auto_matsysdebugmode;
+
+ int tall = pPanel->GetTall();
+ float fHeightUV = 1.0f;
+ if ( y1 > tall )
+ {
+ fHeightUV = float( tall - y ) / float( y1 - y );
+ y1 = tall;
+ }
+ if ( y1 <= y )
+ return;
+
+ pPanel->LocalToScreen( x, y );
+ pPanel->LocalToScreen( x1, y1 );
+
+ x += xoff; x1 += xoff; y += yoff; y1 += yoff;
+
+ CMatRenderContextPtr pRenderContext( materials );
+ pRenderContext->Bind( pMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ meshBuilder.Position3f( x, y, 0.0f );
+ meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( x1, y, 0.0f );
+ meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( x1, y1, 0.0f );
+ meshBuilder.TexCoord2f( 0, 1.0f, fHeightUV );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( x, y1, 0.0f );
+ meshBuilder.TexCoord2f( 0, 0.0f, fHeightUV );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+static bool ShallWarnTx( KeyValues *kv, ITexture *tx )
+{
+ if ( !tx )
+ {
+ return false;
+ }
+
+ if ( tx->GetFlags() & ( TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_ONEBITALPHA ) )
+ return true;
+
+ if ( stricmp( "DXT1", kv->GetString( KEYNAME_FORMAT ) ) && stricmp( "DXT5", kv->GetString( KEYNAME_FORMAT ) ) &&
+ stricmp( "ATI1N", kv->GetString( KEYNAME_FORMAT ) ) && stricmp( "ATI2N", kv->GetString( KEYNAME_FORMAT ) ) &&
+ stricmp( "DXT5_RUNTIME", kv->GetString( KEYNAME_FORMAT ) ) )
+ return true;
+
+ if ( kv->GetInt( KEYNAME_SIZE ) > g_warn_texkbytes )
+ return true;
+
+ if ( kv->GetInt( KEYNAME_WIDTH ) > g_warn_texdimensions )
+ return true;
+
+ if ( kv->GetInt( KEYNAME_HEIGHT ) > g_warn_texdimensions )
+ return true;
+
+ return false;
+}
+
+static void FmtCommaNumber( char *pchBuffer, unsigned int uiNumber )
+{
+ pchBuffer[0] = 0;
+ for ( unsigned int uiDivisor = 1000 * 1000 * 1000; uiDivisor > 0; uiDivisor /= 1000 )
+ {
+ if ( uiNumber > uiDivisor )
+ {
+ unsigned int uiPrint = ( uiNumber / uiDivisor ) % 1000;
+ sprintf( pchBuffer + strlen( pchBuffer ), ( uiNumber / uiDivisor < 1000 ) ? "%d," : "%03d,", uiPrint );
+ }
+ }
+
+ int len = strlen( pchBuffer );
+ if ( !len )
+ sprintf( pchBuffer, "0" );
+ else if ( pchBuffer[ len - 1 ] == ',' )
+ pchBuffer[ len - 1 ] = 0;
+}
+
+namespace
+{
+
+ char s_chLastViewedTextureBuffer[ 0x200 ] = {0};
+
+}; // end `anonymous` namespace
+
+bool CanAdjustTextureSize( char const *szTextureName, bool bMoveSizeUp )
+{
+ ITexture *pMatTexture = materials->FindTexture( szTextureName, "", false );
+ if ( !pMatTexture )
+ return false;
+
+ // Determine the texture current size
+ if ( !bMoveSizeUp )
+ {
+ return ( pMatTexture->GetActualWidth() > 4 || pMatTexture->GetActualHeight() > 4 );
+ }
+ else
+ {
+ return ( pMatTexture->GetActualWidth() < pMatTexture->GetMappingWidth() ||
+ pMatTexture->GetActualHeight() < pMatTexture->GetMappingHeight() );
+ }
+}
+
+bool AdjustTextureSize( char const *szTextureName, bool bMoveSizeUp )
+{
+ ITexture *pMatTexture = materials->FindTexture( szTextureName, "", false );
+
+ if ( !pMatTexture )
+ return false;
+
+ pMatTexture->ForceLODOverride( bMoveSizeUp ? +1 : -1 );
+ return true;
+}
+
+CON_COMMAND_F( mat_texture_list_txlod, "Adjust LOD of the last viewed texture +1 to inc resolution, -1 to dec resolution", FCVAR_DONTRECORD )
+{
+ if ( args.ArgC() == 2 )
+ {
+ int iAdjustment = atoi( args.Arg( 1 ) );
+ switch ( iAdjustment )
+ {
+ case 1:
+ case -1:
+ if ( !CanAdjustTextureSize( s_chLastViewedTextureBuffer, iAdjustment > 0 ) )
+ Warning( "mat_texture_list_txlod cannot adjust lod for '%s'\n", s_chLastViewedTextureBuffer );
+ else if ( !AdjustTextureSize( s_chLastViewedTextureBuffer, iAdjustment > 0 ) )
+ Warning( "mat_texture_list_txlod failed adjusting lod for '%s'\n", s_chLastViewedTextureBuffer );
+ else
+ Msg( "mat_texture_list_txlod adjusted lod %c1 for '%s'\n", ( iAdjustment > 0 ) ? '+' : '-' , s_chLastViewedTextureBuffer );
+ return;
+ default:
+ break;
+
+ }
+ }
+ Warning( "Usage: 'mat_texture_list_txlod +1' to inc lod | 'mat_texture_list_txlod -1' to dec lod\n" );
+}
+
+static bool SaveTextureImage( char const *szTextureName )
+{
+ bool bRet;
+ char fileName[ MAX_PATH ];
+ char baseName[ MAX_PATH ];
+ ITexture *pMatTexture = materials->FindTexture( szTextureName, "", false );
+
+ if ( !pMatTexture )
+ {
+ Msg( "materials->FindTexture( '%s' ) failed.\n", szTextureName );
+ return false;
+ }
+
+ V_FileBase( szTextureName, baseName, ARRAYSIZE( baseName ) );
+ Q_snprintf( fileName, ARRAYSIZE( fileName ), "//MOD/tex_%s.tga", baseName );
+
+ bRet = pMatTexture->SaveToFile( fileName );
+
+ Msg( "SaveTextureImage( '%s' ): %s\n", fileName, bRet ? "succeeded" : "failed" );
+ return bRet;
+}
+
+namespace MatViewOverride
+{
+
+
+//
+// View override parameters request
+//
+struct ViewParamsReq
+{
+ CUtlVector< UtlSymId_t > lstMaterials;
+}
+s_viewParamsReq;
+
+void RequestSelectNone( void )
+{
+ s_viewParamsReq.lstMaterials.RemoveAll();
+}
+void RequestSelected( int nCount, UtlSymId_t const *pNameIds )
+{
+ s_viewParamsReq.lstMaterials.AddMultipleToTail( nCount, pNameIds );
+}
+
+//
+// View override last parameters
+//
+struct ViewParamsLast
+{
+ ViewParamsLast() : lstMaterials( DefLessFunc( UtlSymId_t ) ), flTime( 0.f ), bHighlighted( false ) {}
+
+ float flTime;
+ bool bHighlighted;
+
+ struct TxInfo
+ {
+ ITexture *pTx;
+ CUtlSymbol name;
+ };
+
+ struct VarMap : public CUtlMap< UtlSymId_t, TxInfo >
+ {
+ VarMap() : CUtlMap< UtlSymId_t, TxInfo >( DefLessFunc( UtlSymId_t ) ) {}
+ VarMap( VarMap const &x ) { const_cast< VarMap & >( x ).Swap( *this ); m_matInfo = x.m_matInfo; } // Fast-swap data
+
+ struct MatInfo
+ {
+// MatInfo() : ignorez( false ) {}
+// bool ignorez;
+ MatInfo() {}
+ } m_matInfo;
+ };
+
+ CUtlMap< UtlSymId_t, VarMap > lstMaterials;
+}
+s_viewParamsLast;
+
+//
+// DisplaySelectedTextures
+// Executed every frame to toggle the selected/unselected
+// textures for a list of materials.
+//
+void DisplaySelectedTextures()
+{
+ // Nothing selected
+ if ( !s_viewParamsLast.lstMaterials.Count() &&
+ !s_viewParamsReq.lstMaterials.Count() )
+ return;
+
+ if ( !s_viewParamsLast.lstMaterials.Count() &&
+ s_viewParamsReq.lstMaterials.Count() )
+ {
+ // First time selection
+ s_viewParamsLast.flTime = Plat_FloatTime();
+ s_viewParamsLast.bHighlighted = false;
+ }
+ else
+ {
+ // Wait for the flash-time
+ float fCurTime = Plat_FloatTime();
+ if ( fCurTime >= s_viewParamsLast.flTime &&
+ fCurTime < s_viewParamsLast.flTime + 0.4 )
+ return;
+
+ s_viewParamsLast.flTime = fCurTime;
+ s_viewParamsLast.bHighlighted = !s_viewParamsLast.bHighlighted;
+ }
+
+ // Find the empty texture
+ ITexture *txEmpty = materials->FindTexture( "debugempty", "", false );
+
+ typedef unsigned short MapIdx;
+
+ // Now walk over all the materials in the req list and push them to the params
+ for ( int k = 0, kEnd = s_viewParamsReq.lstMaterials.Count(); k < kEnd; ++ k )
+ {
+ UtlSymId_t idMat = s_viewParamsReq.lstMaterials[ k ];
+ MapIdx idx = s_viewParamsLast.lstMaterials.Find( idMat );
+ if ( idx == s_viewParamsLast.lstMaterials.InvalidIndex() )
+ {
+ // Insert the new material
+ idx = s_viewParamsLast.lstMaterials.Insert( idMat );
+ ViewParamsLast::VarMap &vars = s_viewParamsLast.lstMaterials.Element( idx );
+
+ // Locate the material
+ char const *szMaterialName = CUtlSymbol( idMat ).String();
+ IMaterial *pMat = materials->FindMaterial( szMaterialName, TEXTURE_GROUP_OTHER, false );
+ if ( pMat )
+ {
+ int numParams = pMat->ShaderParamCount();
+ IMaterialVar **arrVars = pMat->GetShaderParams();
+ for ( int idxParam = 0; idxParam < numParams; ++ idxParam )
+ {
+// if ( !stricmp( arrVars[ idxParam ]->GetName(), "$ignorez" ) )
+// {
+// vars.m_matInfo.ignorez = arrVars[ idxParam ]->GetIntValue() ? true : false;
+// arrVars[ idxParam ]->SetIntValue( 1 );
+// continue;
+// }
+
+ if ( !arrVars[ idxParam ]->IsTexture() )
+ continue;
+
+ ITexture *pTex = arrVars[ idxParam ]->GetTextureValue();
+ if ( !pTex || pTex->IsError() )
+ continue;
+
+ ViewParamsLast::TxInfo txinfo;
+ txinfo.name = CUtlSymbol( pTex->GetName() );
+ txinfo.pTx = pTex;
+ vars.Insert( CUtlSymbol( arrVars[ idxParam ]->GetName() ), txinfo );
+ }
+ }
+ }
+ }
+
+ // Now walk over all the materials that we have to highlight or unhighlight
+ for ( MapIdx idx = s_viewParamsLast.lstMaterials.FirstInorder();
+ idx != s_viewParamsLast.lstMaterials.InvalidIndex();
+ /* advance inside */ )
+ {
+ UtlSymId_t idMat = s_viewParamsLast.lstMaterials.Key( idx );
+ ViewParamsLast::VarMap &vars = s_viewParamsLast.lstMaterials.Element( idx );
+
+ bool bRemovedSelection = ( s_viewParamsReq.lstMaterials.Find( idMat ) < 0 );
+
+ char const *szMaterialName = CUtlSymbol( idMat ).String();
+ IMaterial *pMat = materials->FindMaterial( szMaterialName, TEXTURE_GROUP_OTHER, false );
+ if ( pMat )
+ {
+ int numParams = pMat->ShaderParamCount();
+ IMaterialVar **arrVars = pMat->GetShaderParams();
+ for ( int idxParam = 0; idxParam < numParams; ++ idxParam )
+ {
+// if ( bRemovedSelection && !stricmp( arrVars[ idxParam ]->GetName(), "$ignorez" ) )
+// {
+// arrVars[ idxParam ]->SetIntValue( vars.m_matInfo.ignorez ? 1 : 0 );
+// continue;
+// }
+
+ char const *szVarName = arrVars[ idxParam ]->GetName();
+ CUtlSymbol symVarName( szVarName );
+ MapIdx idxVarsTxInfo = vars.Find( symVarName );
+ if ( idxVarsTxInfo != vars.InvalidIndex() )
+ {
+ ViewParamsLast::TxInfo &ti = vars.Element( idxVarsTxInfo );
+
+ ITexture *pTx = ( s_viewParamsLast.bHighlighted && !bRemovedSelection ) ? txEmpty : ti.pTx;
+ Assert( ti.pTx && !ti.pTx->IsError() );
+
+ arrVars[ idxParam ]->SetTextureValue( pTx );
+ }
+ }
+ }
+
+ // Index advance
+ if ( bRemovedSelection )
+ {
+ MapIdx idxRemove = idx;
+ idx = s_viewParamsLast.lstMaterials.NextInorder( idx );
+ s_viewParamsLast.lstMaterials.RemoveAt( idxRemove );
+ }
+ else
+ {
+ idx = s_viewParamsLast.lstMaterials.NextInorder( idx );
+ }
+ }
+}
+
+}; // end namespace MatViewOverride
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Custom text entry with "Open" for vmt's
+//
+//////////////////////////////////////////////////////////////////////////
+
+class CVmtTextEntry : public vgui::TextEntry
+{
+ DECLARE_CLASS_SIMPLE( CVmtTextEntry, vgui::TextEntry );
+
+public:
+ CVmtTextEntry( vgui::Panel *parent, char const *szName ) : BaseClass( parent, szName ) {}
+
+public:
+ MESSAGE_FUNC( OpenVmtSelected, "DoOpenVmtSelected" );
+
+ virtual void OpenEditMenu();
+};
+
+void CVmtTextEntry::OpenEditMenu()
+{
+ vgui::Menu *pEditMenu = BaseClass::GetEditMenu();
+
+ int pos = pEditMenu->AddMenuItem( "Open VMT", new KeyValues("DoOpenVmtSelected"), this );
+ pEditMenu->MoveMenuItem( pos, 0 );
+
+ int x0, x1;
+ pEditMenu->SetItemEnabled( "Open VMT", GetSelectedRange(x0, x1) );
+
+ BaseClass::OpenEditMenu();
+}
+
+void CVmtTextEntry::OpenVmtSelected()
+{
+ int x0, x1;
+ if ( !GetSelectedRange(x0, x1) )
+ return;
+
+ CUtlVector<char> buf;
+ buf.SetCount( x1 - x0 + 1 );
+ GetTextRange( buf.Base(), x0, x1 - x0 );
+
+ for ( char *pchName = buf.Base(), *pchNext = NULL; pchName; pchName = pchNext )
+ {
+ if ( ( pchNext = strchr( pchName, '\n' ) ) != NULL )
+ *( pchNext ++ ) = 0;
+
+ char chResolveName[ 256 ] = {0}, chResolveNameArg[ 256 ] = {0};
+ Q_snprintf( chResolveNameArg, sizeof( chResolveNameArg ) - 1, "materials/%s.vmt", pchName );
+ char const *szResolvedName = g_pFileSystem->RelativePathToFullPath( chResolveNameArg, "game", chResolveName, sizeof( chResolveName ) - 1 );
+
+ if ( szResolvedName )
+ vgui::system()->ShellExecuteEx( "open", szResolvedName, "" );
+ }
+}
+
+#ifdef IS_WINDOWS_PC
+bool IsSpaceOrQuote( char val )
+{
+ return (isspace(val) || val == '\"');
+}
+
+static bool SetBufferValue( char *chTxtFileBuffer, char const *szLookupKey, char const *szNewValue )
+{
+ bool bResult = false;
+
+ size_t lenTmp = strlen( szNewValue );
+ size_t nTxtFileBufferLen = strlen( chTxtFileBuffer );
+
+ for ( char *pch = chTxtFileBuffer;
+ ( NULL != ( pch = strstr( pch, szLookupKey ) ) );
+ ++ pch )
+ {
+ char *val = pch + strlen( szLookupKey );
+ if ( !IsSpaceOrQuote( *val ) )
+ continue;
+ else
+ ++ val;
+
+ // Skip over the whitespace and quotes
+ while ( *val && IsSpaceOrQuote( *val ) )
+ ++ val;
+ char *pValStart = val;
+
+ // Okay, here comes the value
+ while ( *val && IsSpaceOrQuote( *val ) )
+ ++ val;
+ while ( *val && !IsSpaceOrQuote( *val ) )
+ ++ val;
+
+ char *pValEnd = val; // Okay, here ends the value
+
+ memmove( pValStart + lenTmp, pValEnd, chTxtFileBuffer + nTxtFileBufferLen + 1 - pValEnd );
+ memcpy( pValStart, szNewValue, lenTmp );
+
+ nTxtFileBufferLen += ( lenTmp - ( pValEnd - pValStart ) );
+ bResult = true;
+ }
+
+ if ( !bResult )
+ {
+ char *pchAdd = chTxtFileBuffer + nTxtFileBufferLen;
+ strcpy( pchAdd + strlen( pchAdd ), "\n" );
+ strcpy( pchAdd + strlen( pchAdd ), szLookupKey );
+ strcpy( pchAdd + strlen( pchAdd ), " " );
+ strcpy( pchAdd + strlen( pchAdd ), szNewValue );
+ strcpy( pchAdd + strlen( pchAdd ), "\n" );
+ bResult = true;
+ }
+
+ return bResult;
+}
+
+// Replaces the first occurrence of "szFindData" with "szNewData"
+// Returns the remaining buffer past the replaced data or NULL if
+// no replacement occurred.
+static char * BufferReplace( char *buf, char const *szFindData, char const *szNewData )
+{
+ size_t len = strlen( buf ), lFind = strlen( szFindData ), lNew = strlen( szNewData );
+ if ( char *pBegin = strstr( buf, szFindData ) )
+ {
+ memmove( pBegin + lNew, pBegin + lFind, buf + len - ( pBegin + lFind ) );
+ memmove( pBegin, szNewData, lNew );
+ return pBegin + lNew;
+ }
+ return NULL;
+}
+
+class CP4Requirement
+{
+public:
+ CP4Requirement();
+ ~CP4Requirement();
+
+protected:
+ bool m_bLoadedModule;
+ CSysModule *m_pP4Module;
+};
+
+CP4Requirement::CP4Requirement() :
+ m_bLoadedModule( false ),
+ m_pP4Module( NULL )
+{
+#ifdef STAGING_ONLY
+ if ( p4 )
+ return;
+
+ // load the p4 lib
+ m_pP4Module = Sys_LoadModule( "p4lib" );
+ m_bLoadedModule = true;
+
+ if ( m_pP4Module )
+ {
+ CreateInterfaceFn factory = Sys_GetFactory( m_pP4Module );
+ if ( factory )
+ {
+ p4 = ( IP4 * )factory( P4_INTERFACE_VERSION, NULL );
+
+ if ( p4 )
+ {
+ extern CreateInterfaceFn g_AppSystemFactory;
+ p4->Connect( g_AppSystemFactory );
+ p4->Init();
+ }
+ }
+ }
+#endif // STAGING_ONLY
+
+ if ( !p4 )
+ {
+ Warning( "Can't load p4lib.dll\n" );
+ }
+}
+
+CP4Requirement::~CP4Requirement()
+{
+ if ( m_bLoadedModule && m_pP4Module )
+ {
+ if ( p4 )
+ {
+ p4->Shutdown();
+ p4->Disconnect();
+ }
+
+ Sys_UnloadModule( m_pP4Module );
+ m_pP4Module = NULL;
+ p4 = NULL;
+ }
+}
+#endif // #ifdef IS_WINDOWS_PC
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Render textures edit panel
+//
+//////////////////////////////////////////////////////////////////////////
+
+class CRenderTextureEditor : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CRenderTextureEditor, vgui::Frame );
+
+public:
+ CRenderTextureEditor( vgui::Panel *parent, char const *szName );
+ ~CRenderTextureEditor();
+
+public:
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void PerformLayout();
+ virtual void OnCommand( const char *command );
+ virtual void SetFont( vgui::HFont hFont ) { m_hFont = hFont; Repaint(); }
+ virtual vgui::HFont GetFont() { return m_hFont; }
+
+public:
+ virtual void OnMousePressed( vgui::MouseCode code );
+ virtual void OnMouseDoublePressed( vgui::MouseCode code ) { OnMousePressed( code ); }
+ virtual void Activate();
+ virtual void Close();
+
+public:
+ void SetDispInfo( KeyValues *kv, int iHint );
+ void GetDispInfo( KeyValues *&kv, int &iHint );
+
+public:
+ virtual void Paint();
+
+ enum
+ {
+ TILE_BORDER = 10,
+ TILE_SIZE = 550,
+ TILE_TEXTURE_SIZE = 256,
+ TILE_TEXT = 70
+ };
+
+protected:
+ vgui::HFont m_hFont;
+ CVmtTextEntry *m_pMaterials;
+ vgui::Button *m_pExplore;
+ vgui::Button *m_pReload;
+ vgui::Button *m_pRebuild;
+ vgui::Button *m_pToggleNoMip;
+ vgui::Button *m_pCopyTxt;
+#ifndef POSIX
+ vgui::Button *m_pCopyImg;
+#endif
+ vgui::Button *m_pSaveImg;
+ vgui::Button *m_pSizeControls[2];
+ vgui::Button *m_pFlashBtn;
+ KeyValues *m_pInfo;
+ CUtlBuffer m_bufInfoText;
+ CUtlVector< UtlSymId_t > m_lstMaterials;
+ int m_iInfoHint;
+};
+
+CRenderTextureEditor::CRenderTextureEditor( vgui::Panel *parent, char const *szName ) :
+ BaseClass( parent, szName ),
+ m_pInfo( NULL ),
+ m_iInfoHint( 0 ),
+ m_hFont( vgui::INVALID_FONT ),
+ m_bufInfoText( 0, 0, CUtlBuffer::TEXT_BUFFER )
+{
+ m_pMaterials = vgui::SETUP_PANEL( new CVmtTextEntry( this, "Materials" ) );
+ m_pMaterials->SetMultiline( true );
+ m_pMaterials->SetEditable( false );
+ m_pMaterials->SetEnabled( false );
+ m_pMaterials->SetVerticalScrollbar( true );
+ m_pMaterials->SetVisible( true );
+
+ m_pExplore = vgui::SETUP_PANEL( new vgui::Button( this, "Explore", "Open", this, "Explore" ) );
+ m_pExplore->SetVisible( true );
+
+ m_pReload = vgui::SETUP_PANEL( new vgui::Button( this, "Reload", "Reload", this, "Reload" ) );
+ m_pReload->SetVisible( true );
+
+ m_pRebuild = vgui::SETUP_PANEL( new vgui::Button( this, "RebuildVTF", "Rebuild VTF", this, "RebuildVTF" ) );
+ m_pRebuild->SetVisible( true );
+
+ m_pToggleNoMip = vgui::SETUP_PANEL( new vgui::Button( this, "ToggleNoMip", "ToggleNoMip", this, "ToggleNoMip" ) );
+ m_pToggleNoMip->SetVisible( true );
+
+ m_pCopyTxt = vgui::SETUP_PANEL( new vgui::Button( this, "CopyTxt", "Copy Text", this, "CopyTxt" ) );
+ m_pCopyTxt->SetVisible( true );
+
+#ifndef POSIX
+ m_pCopyImg = vgui::SETUP_PANEL( new vgui::Button( this, "CopyImg", "Copy Image", this, "CopyImg" ) );
+ m_pCopyImg->SetVisible( true );
+#endif
+
+ m_pSaveImg = vgui::SETUP_PANEL( new vgui::Button( this, "SaveImg", "Save Image", this, "SaveImg" ) );
+ m_pSaveImg->SetVisible( true );
+
+ m_pFlashBtn = vgui::SETUP_PANEL( new vgui::Button( this, "FlashBtn", "Flash in Game", this, "FlashBtn" ) );
+ m_pFlashBtn->SetVisible( true );
+
+ m_pSizeControls[0] = vgui::SETUP_PANEL( new vgui::Button( this, "--", "--", this, "size-" ) );
+ m_pSizeControls[1] = vgui::SETUP_PANEL( new vgui::Button( this, "+", "+", this, "size+" ) );
+}
+
+CRenderTextureEditor::~CRenderTextureEditor()
+{
+ SetDispInfo( NULL, 0 );
+}
+
+void CRenderTextureEditor::GetDispInfo( KeyValues *&kv, int &iHint )
+{
+ iHint = m_iInfoHint;
+ kv = m_pInfo;
+}
+
+void CRenderTextureEditor::SetDispInfo( KeyValues *kv, int iHint )
+{
+ m_iInfoHint = iHint;
+
+ if ( m_pInfo )
+ m_pInfo->deleteThis();
+
+ m_pInfo = kv ? kv->MakeCopy() : NULL;
+
+
+ CUtlStringMap< bool > arrMaterials, arrMaterialsFullNames;
+
+ if ( kv )
+ {
+ char const *szTextureName = kv->GetString( KEYNAME_NAME );
+ for ( MaterialHandle_t hm = materials->FirstMaterial();
+ hm != materials->InvalidMaterial(); hm = materials->NextMaterial( hm ) )
+ {
+ IMaterial *pMat = materials->GetMaterial( hm );
+ if ( !pMat )
+ continue;
+
+ int numParams = pMat->ShaderParamCount();
+ IMaterialVar **arrVars = pMat->GetShaderParams();
+ for ( int idxParam = 0; idxParam < numParams; ++ idxParam )
+ {
+ if ( !arrVars[ idxParam ]->IsTexture() )
+ continue;
+
+ ITexture *pTex = arrVars[ idxParam ]->GetTextureValue();
+ if ( !pTex || pTex->IsError() )
+ continue;
+
+ if ( !stricmp( pTex->GetName(), szTextureName ) )
+ {
+ bool bRealMaterial = true;
+
+ if ( StringHasPrefix( pMat->GetName(), "debug/debugtexture" ) )
+ bRealMaterial = false;
+
+ if ( StringHasPrefix( pMat->GetName(), "maps/" ) )
+ {
+ // Format: maps/mapname/[matname]_x_y_z
+ bRealMaterial = false;
+
+ char chName[ MAX_PATH ];
+ Q_strncpy( chName, pMat->GetName() + 5, sizeof( chName ) - 1 );
+
+ if ( char *szMatName = strchr( chName, '/' ) )
+ {
+ ++ szMatName;
+ for ( int k = 0; k < 3; ++ k )
+ {
+ if ( char *rUnderscore = strrchr( szMatName, '_' ) )
+ *rUnderscore = 0;
+ }
+
+ sprintf( szMatName + strlen( szMatName ), " (cubemap)" );
+ arrMaterials[ szMatName ] = true;
+ }
+ arrMaterialsFullNames[ pMat->GetName() ] = true;
+ }
+
+ if ( bRealMaterial )
+ {
+ arrMaterials[ pMat->GetName() ] = true;
+ arrMaterialsFullNames[ pMat->GetName() ] = true;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ // Now that we have a list of materials make a printable version
+ CUtlBuffer bufText( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ if ( !arrMaterials.GetNumStrings() )
+ {
+ bufText.Printf( "-- no materials --" );
+ }
+ else
+ {
+ int c = arrMaterials.GetNumStrings();
+ bufText.Printf( " %d material%s:", c, ( c%10 == 1 && c != 11 ) ? "" : "s" );
+ }
+
+ for ( int k = 0; k < arrMaterials.GetNumStrings(); ++ k )
+ {
+ bufText.Printf( "\n%s", arrMaterials.String( k ) );
+ }
+
+ m_pSaveImg->SetVisible( false );
+
+ // Set text except for the cases when m_pInfo and no materials found
+ if ( !( m_pInfo && !arrMaterials.GetNumStrings() ) )
+ {
+ if ( kv )
+ {
+ int iTxWidth = kv->GetInt( KEYNAME_WIDTH );
+ int iTxHeight = kv->GetInt( KEYNAME_HEIGHT );
+ char const *szTxFormat = kv->GetString( KEYNAME_FORMAT );
+
+ bufText.Printf( "\n%dx%d Format:%s", iTxWidth, iTxHeight, szTxFormat );
+
+ // We support saving the 8888 formats right now: "RGBA8888", "ABGR8888", "ARGB8888", "BGRA8888", "BGRX8888"
+ if( Q_strstr( szTxFormat, "8888" ) )
+ {
+ m_pSaveImg->SetVisible( true );
+ }
+ }
+
+ m_pMaterials->SetText( ( char const * ) bufText.Base() );
+
+ m_lstMaterials.RemoveAll();
+ m_lstMaterials.EnsureCapacity( arrMaterialsFullNames.GetNumStrings() );
+ for ( int k = 0; k < arrMaterialsFullNames.GetNumStrings(); ++ k )
+ {
+ m_lstMaterials.AddToTail( CUtlSymbol( arrMaterialsFullNames.String( k ) ) );
+ }
+ }
+
+ m_bufInfoText.Clear();
+
+ InvalidateLayout();
+}
+
+void CRenderTextureEditor::Close()
+{
+ BaseClass::Close();
+
+ SetDispInfo( NULL, 0 );
+}
+
+void CRenderTextureEditor::Activate()
+{
+ BaseClass::Activate();
+}
+
+void CRenderTextureEditor::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int iRenderedHeight = 4 * TILE_BORDER + TILE_TEXT + TILE_SIZE;
+
+ SetSize( 4 * TILE_BORDER + TILE_SIZE,
+ iRenderedHeight + 90 + TILE_BORDER );
+
+ m_pMaterials->SetPos( TILE_BORDER, iRenderedHeight + 2 );
+ m_pMaterials->SetSize( 2 * TILE_BORDER + TILE_SIZE, 90 );
+
+ m_pExplore->SetPos( 2 * TILE_BORDER + TILE_SIZE - 50, 2 * TILE_BORDER );
+ m_pExplore->SetWide( 50 );
+
+ m_pReload->SetPos( 2 * TILE_BORDER + TILE_SIZE - 50 - 65, 2 * TILE_BORDER );
+ m_pReload->SetWide( 60 );
+ m_pReload->SetVisible( m_lstMaterials.Count() > 0 );
+
+ m_pRebuild->SetPos( 2 * TILE_BORDER + TILE_SIZE - 50 - 65 - 95, 2 * TILE_BORDER );
+ m_pRebuild->SetWide( 90 );
+ m_pRebuild->SetVisible( m_lstMaterials.Count() > 0 );
+
+ m_pToggleNoMip->SetPos( 2 * TILE_BORDER + TILE_SIZE - 50 - 95, (2 * TILE_BORDER) + m_pReload->GetTall() + 1 );
+ m_pToggleNoMip->SetWide( 90 );
+ m_pToggleNoMip->SetVisible( m_lstMaterials.Count() > 0 );
+
+ m_pExplore->SetVisible( false );
+ m_pSizeControls[0]->SetVisible( false );
+ m_pSizeControls[1]->SetVisible( false );
+
+ if ( m_pInfo )
+ {
+ char chResolveName[ 256 ] = {0}, chResolveNameArg[ 256 ] = {0};
+ Q_snprintf( chResolveNameArg, sizeof( chResolveNameArg ) - 1, "materials/%s.vtf", m_pInfo->GetString( KEYNAME_NAME ) );
+ char const *szResolvedName = g_pFileSystem->RelativePathToFullPath( chResolveNameArg, "game", chResolveName, sizeof( chResolveName ) - 1 );
+ if ( szResolvedName )
+ {
+ m_pExplore->SetVisible( true );
+ }
+
+ if ( !m_pInfo->GetInt( "SpecialTx" ) )
+ {
+ m_pSizeControls[0]->SetVisible( true );
+ m_pSizeControls[1]->SetVisible( true );
+
+ m_pSizeControls[0]->SetEnabled( CanAdjustTextureSize( m_pInfo->GetString( KEYNAME_NAME ), false ) );
+ m_pSizeControls[1]->SetEnabled( CanAdjustTextureSize( m_pInfo->GetString( KEYNAME_NAME ), true ) );
+
+ int posX, posY;
+ m_pExplore->GetPos( posX, posY );
+ m_pSizeControls[0]->SetPos( posX, posY + m_pExplore->GetTall() + 1 );
+ m_pSizeControls[0]->SetWide( m_pExplore->GetWide() / 2 );
+ m_pSizeControls[1]->SetPos( posX + m_pSizeControls[0]->GetWide() + 1, posY + m_pExplore->GetTall() + 1 );
+ m_pSizeControls[1]->SetWide( m_pExplore->GetWide() - ( m_pSizeControls[0]->GetWide() + 1 ) );
+ }
+ }
+
+ {
+ int posX, posY;
+ m_pExplore->GetPos( posX, posY );
+ posY += m_pExplore->GetTall() * 2 + 2;
+ posX += m_pExplore->GetWide();
+
+ posX -= 80;
+ m_pSaveImg->SetPos( posX, posY );
+ m_pSaveImg->SetWide( 80 );
+
+#ifndef POSIX
+ posX -= 80 + 5;
+ m_pCopyImg->SetPos( posX, posY );
+ m_pCopyImg->SetWide( 80 );
+#endif
+
+ posX -= 80 + 5;
+ m_pCopyTxt->SetPos( posX, posY );
+ m_pCopyTxt->SetWide( 80 );
+
+ posX -= 95 + 5;
+ m_pFlashBtn->SetPos( posX, posY );
+ m_pFlashBtn->SetWide( 95 );
+ }
+}
+
+#ifdef IS_WINDOWS_PC
+bool GetTextureContentPath( const char *pszVTF, char *szTextureContentPath, int nBufSize )
+{
+ char vhRelVTF[MAX_PATH];
+ Q_snprintf( vhRelVTF, sizeof( vhRelVTF ) - 1, "materials/%s.vtf", pszVTF );
+
+ ConVarRef mat_texture_list_content_path( "mat_texture_list_content_path" );
+ if ( !mat_texture_list_content_path.GetString()[0] )
+ {
+ szTextureContentPath = const_cast< char * >( g_pFileSystem->RelativePathToFullPath( vhRelVTF, "game", szTextureContentPath, nBufSize - 1 ) );
+
+ if ( !szTextureContentPath )
+ {
+ Warning( " texture '%s' is not loaded from file system.\n", pszVTF );
+ return false;
+ }
+ if ( !BufferReplace( szTextureContentPath, "\\game\\", "\\content\\" ) ||
+ !BufferReplace( szTextureContentPath, "\\materials\\", "\\materialsrc\\" ) )
+ {
+ Warning( " texture '%s' cannot be mapped to content directory.\n", pszVTF );
+ return false;
+ }
+ }
+ else
+ {
+ V_strncpy( szTextureContentPath, mat_texture_list_content_path.GetString(), MAX_PATH );
+ V_strncat( szTextureContentPath, "/", MAX_PATH );
+ V_strncat( szTextureContentPath, pszVTF, MAX_PATH );
+ V_strncat( szTextureContentPath, ".vtf", MAX_PATH );
+ }
+
+ return true;
+}
+#endif // #ifdef IS_WINDOWS_PC
+
+void CRenderTextureEditor::OnCommand( const char *command )
+{
+ BaseClass::OnCommand( command );
+
+ if ( !stricmp( command, "Explore" ) && m_pInfo )
+ {
+ char chResolveName[ 256 ] = {0}, chResolveNameArg[ 256 ] = {0};
+ Q_snprintf( chResolveNameArg, sizeof( chResolveNameArg ) - 1, "materials/%s.vtf", m_pInfo->GetString( KEYNAME_NAME ) );
+ char const *szResolvedName = g_pFileSystem->RelativePathToFullPath( chResolveNameArg, "game", chResolveName, sizeof( chResolveName ) - 1 );
+
+ char params[256];
+ Q_snprintf( params, sizeof( params ) - 1, "/E,/SELECT,%s", szResolvedName );
+ vgui::system()->ShellExecuteEx( "open", "explorer.exe", params );
+ }
+
+ if ( !stricmp( command, "Reload" ) && m_lstMaterials.Count() )
+ {
+ CUtlBuffer bufCommand( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ int idxMaterial = 0;
+
+ //
+ // Issue the console command several times in case we overflow the
+ // console command buffer size.
+ //
+ Cbuf_Execute();
+ for ( ; idxMaterial < m_lstMaterials.Count(); )
+ {
+ int iOldIdx = idxMaterial;
+ bufCommand.Printf( "mat_reloadmaterial \"" );
+
+ for ( ; idxMaterial < m_lstMaterials.Count(); ++ idxMaterial )
+ {
+ int iOldSize = bufCommand.TellPut();
+ int const iSizeLimit = CCommand::MaxCommandLength() - 3;
+
+ char const *szString = CUtlSymbol( m_lstMaterials[idxMaterial] ).String();
+ bufCommand.Printf( "%s%s", ( idxMaterial > iOldIdx ) ? "*" : "", szString );
+
+ if ( bufCommand.TellPut() > iSizeLimit &&
+ idxMaterial > iOldIdx )
+ {
+ bufCommand.SeekPut( CUtlBuffer::SEEK_HEAD, iOldSize );
+ break;
+ }
+ }
+
+ bufCommand.Printf( "\"\n" );
+ bufCommand.PutChar( 0 );
+
+ Cbuf_AddText( ( char const * ) bufCommand.Base() );
+ bufCommand.Clear();
+ Cbuf_Execute();
+ }
+ }
+
+ if ( !stricmp( command, "CopyTxt" ) )
+ {
+ char const *szName = ( char const * ) m_bufInfoText.Base();
+ if ( !m_bufInfoText.TellPut() || !szName )
+ szName = "";
+ vgui::system()->SetClipboardText( szName, strlen( szName ) + 1 );
+ }
+
+ if ( !stricmp( command, "CopyImg" ) )
+ {
+ int x = 0, y = 0;
+ this->LocalToScreen( x, y );
+
+ void *pMainWnd = game->GetMainWindow();
+ vgui::system()->SetClipboardImage( pMainWnd, x, y, x + GetWide(), y + GetTall() );
+ }
+
+ if ( !stricmp( command, "SaveImg" ) )
+ {
+ SaveTextureImage( m_pInfo->GetString( KEYNAME_NAME ) );
+ }
+
+ if ( !stricmp( command, "FlashBtn" ) )
+ {
+ MatViewOverride::RequestSelectNone();
+ MatViewOverride::RequestSelected( m_lstMaterials.Count(), m_lstMaterials.Base() );
+ mat_texture_list_off_f();
+ }
+
+ if ( ( !stricmp( command, "size-" ) || !stricmp( command, "size+" ) ) && m_pInfo )
+ {
+ bool bSizeUp = ( command[4] == '+' );
+ bool bResult = AdjustTextureSize( m_pInfo->GetString( KEYNAME_NAME ), bSizeUp );
+ if ( bResult )
+ {
+ CAutoPushPop<bool> auto_g_bRecursiveRequestToShowTextureList( g_bRecursiveRequestToShowTextureList, true );
+ mat_texture_list_on_f();
+ }
+
+ InvalidateLayout();
+ }
+
+ if ( !stricmp( command, "ToggleNoMip" ) )
+ {
+#ifdef IS_WINDOWS_PC
+ CP4Requirement p4req;
+ if ( !p4 )
+ g_p4factory->SetDummyMode( true );
+
+ char const *szTextureFile = m_pInfo->GetString( KEYNAME_NAME );
+ char const *szTextureGroup = m_pInfo->GetString( KEYNAME_TEXTURE_GROUP );
+
+ ITexture *pMatTexture = NULL;
+ if ( *szTextureFile )
+ pMatTexture = materials->FindTexture( szTextureFile, szTextureGroup, false );
+ if ( !pMatTexture )
+ pMatTexture = materials->FindTexture( "debugempty", "", false );
+
+ bool bNewNoMip = !(pMatTexture->GetFlags() & TEXTUREFLAGS_NOMIP);
+
+ char szFileName[MAX_PATH];
+ if ( !GetTextureContentPath( szTextureFile, szFileName, sizeof(szFileName) ) )
+ return;
+
+ // Figure out what kind of source content is there:
+ // 1. look for TGA - if found, get the txt file (if txt file missing, create one)
+ // 2. otherwise look for PSD - affecting psdinfo
+ // 3. else error
+ char *pExtPut = szFileName + strlen( szFileName ) - strlen( ".vtf" ); // compensating the TEXTURE_FNAME_EXTENSION(.vtf) extension
+
+ // 1.tga
+ sprintf( pExtPut, ".tga" );
+ if ( g_pFullFileSystem->FileExists( szFileName ) )
+ {
+ // Have tga - pump in the txt file
+ sprintf( pExtPut, ".txt" );
+
+ CUtlBuffer bufTxtFileBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ g_pFullFileSystem->ReadFile( szFileName, 0, bufTxtFileBuffer );
+ for ( int k = 0; k < 1024; ++ k ) bufTxtFileBuffer.PutChar( 0 );
+
+ // Now fix maxwidth/maxheight settings
+ SetBufferValue( ( char * ) bufTxtFileBuffer.Base(), "nomip", bNewNoMip ? "1" : "0" );
+ bufTxtFileBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, strlen( ( char * ) bufTxtFileBuffer.Base() ) );
+
+ // Check out or add the file
+ g_p4factory->SetOpenFileChangeList( "Texture LOD Autocheckout" );
+ CP4AutoEditFile autop4_edit( szFileName );
+
+ // Save the file contents
+ if ( g_pFullFileSystem->WriteFile( szFileName, 0, bufTxtFileBuffer ) )
+ {
+ Msg(" '%s' : saved.\n", szFileName );
+ CP4AutoAddFile autop4_add( szFileName );
+ }
+ else
+ {
+ Warning( " '%s' : failed to save - toggle \"nomip\" manually.\n",
+ szFileName );
+ }
+ }
+ else
+ {
+ // 2.psd
+ sprintf( pExtPut, ".psd" );
+ if ( g_pFullFileSystem->FileExists( szFileName ) )
+ {
+ char chCommand[MAX_PATH];
+ char szTxtFileName[MAX_PATH] = {0};
+ GetModSubdirectory( "tmp_lod_psdinfo.txt", szTxtFileName, sizeof( szTxtFileName ) );
+ sprintf( chCommand, "/C psdinfo \"%s\" > \"%s\"", szFileName, szTxtFileName);
+ vgui::system()->ShellExecuteEx( "open", "cmd.exe", chCommand );
+ Sys_Sleep( 200 );
+
+ CUtlBuffer bufTxtFileBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ g_pFullFileSystem->ReadFile( szTxtFileName, 0, bufTxtFileBuffer );
+ for ( int k = 0; k < 1024; ++ k ) bufTxtFileBuffer.PutChar( 0 );
+
+ // Now fix maxwidth/maxheight settings
+ SetBufferValue( ( char * ) bufTxtFileBuffer.Base(), "nomip", bNewNoMip ? "1" : "0" );
+ bufTxtFileBuffer.SeekPut( CUtlBuffer::SEEK_HEAD, strlen( ( char * ) bufTxtFileBuffer.Base() ) );
+
+ // Check out or add the file
+ // Save the file contents
+ if ( g_pFullFileSystem->WriteFile( szTxtFileName, 0, bufTxtFileBuffer ) )
+ {
+ g_p4factory->SetOpenFileChangeList( "Texture LOD Autocheckout" );
+ CP4AutoEditFile autop4_edit( szFileName );
+
+ sprintf( chCommand, "/C psdinfo -write \"%s\" < \"%s\"", szFileName, szTxtFileName );
+ Sys_Sleep( 200 );
+ vgui::system()->ShellExecuteEx( "open", "cmd.exe", chCommand );
+ Sys_Sleep( 200 );
+
+ Msg(" '%s' : saved.\n", szFileName );
+ CP4AutoAddFile autop4_add( szFileName );
+ }
+ else
+ {
+ Warning( " '%s' : failed to save - toggle \"nomip\" manually.\n",
+ szFileName );
+ }
+ }
+ else
+ {
+ // 3. - error
+ sprintf( pExtPut, "" );
+ Warning( " '%s' : doesn't specify a valid TGA or PSD file!\n", szFileName );
+ return;
+ }
+ }
+
+ // Now reload the texture
+ OnCommand( "RebuildVTF" );
+#endif // #ifdef IS_WINDOWS_PC
+ }
+
+ if ( !stricmp( command, "RebuildVTF" ) )
+ {
+#ifdef IS_WINDOWS_PC
+ CP4Requirement p4req;
+ if ( !p4 )
+ g_p4factory->SetDummyMode( true );
+
+ CSysModule *pModule;
+ IVTex *pIVTex = VTex_Load( &pModule );
+ if ( !pIVTex )
+ return;
+
+ char const *szTextureFile = m_pInfo->GetString( KEYNAME_NAME );
+
+ char szContentFilename[MAX_PATH];
+ if ( !GetTextureContentPath( szTextureFile, szContentFilename, sizeof(szContentFilename) ) )
+ return;
+
+ char pGameDir[MAX_OSPATH];
+ COM_GetGameDir( pGameDir, sizeof( pGameDir ) );
+
+ // Check out the VTF
+ char szVTFFilename[MAX_PATH];
+ Q_snprintf( szVTFFilename, sizeof( szVTFFilename ) - 1, "%s/materials/%s.vtf", pGameDir, szTextureFile );
+ g_p4factory->SetOpenFileChangeList( "Texture LOD Autocheckout" );
+ CP4AutoEditFile autop4_edit( szVTFFilename );
+
+ // Get the directory for the outdir
+ StripDirName( szVTFFilename );
+
+ // Now we've modified the source, rebuild the texture
+ char *argv[64];
+ int iArg = 0;
+ argv[iArg++] = "";
+ argv[iArg++] = "-quiet";
+ argv[iArg++] = "-UseStandardError"; // These are only here for the -currently released- version of vtex.dll.
+ argv[iArg++] = "-WarningsAsErrors";
+ argv[iArg++] = "-outdir";
+ argv[iArg++] = szVTFFilename;
+ argv[iArg++] = szContentFilename;
+ pIVTex->VTex( CubemapsFSFactory, pGameDir, iArg, argv );
+
+ VTex_Unload( pModule );
+
+ Sys_Sleep( 200 );
+
+ // Now reload the texture
+ OnCommand( "Reload" );
+#endif // #ifdef IS_WINDOWS_PC
+ }
+}
+
+void CRenderTextureEditor::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetFont( pScheme->GetFont( "Default", IsProportional() ) );
+}
+
+void CRenderTextureEditor::OnMousePressed( vgui::MouseCode code )
+{
+ Close();
+}
+
+void CRenderTextureEditor::Paint()
+{
+ CAutoMatSysDebugMode auto_matsysdebugmode;
+
+ DisableFadeEffect();
+ SetBgColor( Color( 10, 50, 10, 255 ) );
+
+ BaseClass::Paint();
+
+ KeyValues *kv = m_pInfo;
+ if ( !kv )
+ return;
+
+ char const *szTextureFile = kv->GetString( KEYNAME_NAME );
+ Q_strncpy( s_chLastViewedTextureBuffer, szTextureFile, sizeof( s_chLastViewedTextureBuffer ) );
+ char const *szTextureGroup = kv->GetString( KEYNAME_TEXTURE_GROUP );
+
+ ITexture *pMatTexture = NULL;
+ if ( *szTextureFile )
+ pMatTexture = materials->FindTexture( szTextureFile, szTextureGroup, false );
+ if ( !pMatTexture )
+ pMatTexture = materials->FindTexture( "debugempty", "", false );
+
+ // Determine the texture size
+ int iTxWidth = kv->GetInt( KEYNAME_WIDTH );
+ int iTxHeight = kv->GetInt( KEYNAME_HEIGHT );
+ int iTxSize = kv->GetInt( KEYNAME_SIZE );
+ char const *szTxFormat = kv->GetString( KEYNAME_FORMAT );
+
+ int x = TILE_BORDER, y = TILE_BORDER;
+
+ // Dimensions to draw
+ int iDrawWidth = iTxWidth;
+ int iDrawHeight = iTxHeight;
+
+ if ( pMatTexture && pMatTexture->IsCubeMap() )
+ {
+ iDrawWidth = 1024;
+ iDrawHeight = 1024;
+ }
+
+ if ( iDrawHeight >= iDrawWidth )
+ {
+ if ( iDrawHeight > TILE_TEXTURE_SIZE )
+ {
+ iDrawWidth = iDrawWidth * ( float( TILE_TEXTURE_SIZE ) / iDrawHeight );
+ iDrawHeight = TILE_TEXTURE_SIZE;
+ }
+
+ if ( iDrawHeight < 64 )
+ {
+ iDrawWidth = iDrawWidth * ( float( 64 ) / iDrawHeight );
+ iDrawHeight = 64;
+ }
+ }
+ else
+ {
+ if ( iDrawWidth > TILE_TEXTURE_SIZE )
+ {
+ iDrawHeight = iDrawHeight * ( float( TILE_TEXTURE_SIZE ) / iDrawWidth );
+ iDrawWidth = TILE_TEXTURE_SIZE;
+ }
+
+ if ( iDrawWidth < 64 )
+ {
+ iDrawHeight = iDrawHeight * ( float( 64 ) / iDrawWidth );
+ iDrawWidth = 64;
+ }
+ }
+
+ iDrawHeight = iDrawHeight / ( float( TILE_TEXTURE_SIZE ) / float( TILE_SIZE ) );
+ iDrawWidth = iDrawWidth / ( float( TILE_TEXTURE_SIZE ) / float( TILE_SIZE ) );
+
+ iDrawHeight = max( iDrawHeight, 4 );
+ iDrawWidth = max( iDrawWidth, 4 );
+
+ //
+ // Draw frame
+ //
+ {
+ int tileWidth = 2 * TILE_BORDER + TILE_SIZE;
+ int tileHeight = 3 * TILE_BORDER + TILE_SIZE + TILE_TEXT;
+
+ g_pMatSystemSurface->DrawSetColor( 255, 255, 255, 255 );
+ g_pMatSystemSurface->DrawOutlinedRect( x + 1, y + 1,
+ x + tileWidth - 2 , y + tileHeight - 2 );
+ }
+
+ //
+ // Draw all
+ //
+
+ x += TILE_BORDER;
+ y += TILE_BORDER;
+
+ char chResolveName[ 256 ] = {0}, chResolveNameArg[ 256 ] = {0};
+ Q_snprintf( chResolveNameArg, sizeof( chResolveNameArg ) - 1, "materials/%s.vtf", szTextureFile );
+ char const *szResolvedName = g_pFileSystem->RelativePathToFullPath( chResolveNameArg, "game", chResolveName, sizeof( chResolveName ) - 1 );
+
+ char const *szPrintFilePrefix = szResolvedName ? "" : "[?]/";
+ char const *szPrintFileName = szResolvedName ? szResolvedName : szTextureFile;
+
+ char chSizeBuf[20] = { 0 };
+ if ( iTxSize >= 0 )
+ FmtCommaNumber( chSizeBuf, iTxSize );
+ else
+ chSizeBuf[0] = '-';
+
+ g_pMatSystemSurface->DrawColoredTextRect( GetFont(), x, y, TILE_SIZE, TILE_TEXT / 2,
+ 255, 255, 255, 255,
+ "%s%s\n"
+ "%s Kb %dx%d %s",
+ szPrintFilePrefix, szPrintFileName,
+ chSizeBuf,
+ iTxWidth, iTxHeight,
+ szTxFormat
+ );
+
+ if ( !m_bufInfoText.TellPut() )
+ {
+ m_bufInfoText.Printf(
+ "%s%s\r\n"
+ "%s Kb %dx%d %s",
+ szPrintFilePrefix, szPrintFileName,
+ chSizeBuf,
+ iTxWidth, iTxHeight,
+ szTxFormat );
+ }
+
+ if ( !kv->GetInt( "SpecialTx" ) )
+ {
+ char chLine1[256] = {0};
+ char chLine2[256] = {0};
+
+ //
+ // Line 1
+ //
+ if ( iTxSize > g_warn_texkbytes )
+ sprintf( chLine1 + strlen( chLine1 ), " Size(%s Kb)", chSizeBuf );
+ if ( ( iTxWidth > g_warn_texdimensions ) ||
+ ( iTxHeight > g_warn_texdimensions ) )
+ sprintf( chLine1 + strlen( chLine1 ), " Dimensions(%dx%d)", iTxWidth, iTxHeight );
+ if ( stricmp( szTxFormat, "DXT1" ) &&
+ stricmp( szTxFormat, "DXT5" ) )
+ sprintf( chLine1 + strlen( chLine1 ), " Format(%s)", szTxFormat );
+ if ( pMatTexture->GetFlags() & TEXTUREFLAGS_NOLOD )
+ sprintf( chLine1 + strlen( chLine1 ), " NoLod" );
+ if ( pMatTexture->GetFlags() & TEXTUREFLAGS_NOMIP )
+ sprintf( chLine1 + strlen( chLine1 ), " NoMip" );
+ if ( pMatTexture->GetFlags() & TEXTUREFLAGS_ONEBITALPHA )
+ sprintf( chLine1 + strlen( chLine1 ), " OneBitAlpha" );
+
+ //
+ // Line 2
+ //
+ // Always show stats for higher/lower mips
+ {
+ int wmap = pMatTexture->GetMappingWidth(), hmap = pMatTexture->GetMappingHeight(), dmap = pMatTexture->GetMappingDepth();
+ int wact = pMatTexture->GetActualWidth(), hact = pMatTexture->GetActualHeight(), dact = pMatTexture->GetActualDepth();
+ ImageFormat fmt = pMatTexture->GetImageFormat();
+
+ if ( wact > 4 || hact > 4 )
+ {
+ char chbuf[50];
+ int mem = ImageLoader::GetMemRequired( max( min( wact, 4 ), wact / 2 ), max( min( hact, 4 ), hact / 2 ), max( 1, dact / 2 ), fmt, true );
+ mem = ( mem + 511 ) / 1024;
+ FmtCommaNumber( chbuf, mem );
+
+ sprintf ( chLine2 + strlen( chLine2 ), " %s Kb @ lower mip", chbuf );
+ }
+
+ if ( wmap > wact || hmap > hact || dmap > dact )
+ {
+ char chbuf[ 50 ];
+ int mem = ImageLoader::GetMemRequired( min( wmap, wact * 2 ), min( hmap, hact * 2 ), min( dmap, dact * 2 ), fmt, true );
+ mem = ( mem + 511 ) / 1024;
+ FmtCommaNumber( chbuf, mem );
+
+ sprintf ( chLine2 + strlen( chLine2 ), " %s Kb @ higher mip", chbuf );
+ }
+ }
+
+ if ( chLine1[0] )
+ {
+ g_pMatSystemSurface->DrawSetColor( 200, 0, 0, 255 );
+ g_pMatSystemSurface->DrawFilledRect( x - TILE_BORDER/2, y + TILE_TEXT/2, x + TILE_BORDER/2 + (TILE_SIZE * 0.5), y + TILE_TEXT/2 + TILE_TEXT/4 );
+ g_pMatSystemSurface->DrawColoredTextRect( GetFont(), x, y + TILE_TEXT/2, TILE_SIZE, TILE_TEXT / 4,
+ 255, 255, 255, 255,
+ "%s", chLine1 );
+ }
+ if ( chLine2[0] )
+ {
+ // g_pMatSystemSurface->DrawSetColor( 200, 0, 0, 255 );
+ // g_pMatSystemSurface->DrawFilledRect( x - TILE_BORDER/2, y + TILE_TEXT/2 + TILE_TEXT/4, x + TILE_BORDER/2 + TILE_SIZE, y + TILE_TEXT );
+ g_pMatSystemSurface->DrawColoredTextRect( GetFont(), x, y + TILE_TEXT/2 + TILE_TEXT/4, TILE_SIZE, TILE_TEXT / 4,
+ 255, 255, 255, 255,
+ "%s", chLine2 );
+ }
+ }
+
+ y += TILE_TEXT + TILE_BORDER;
+
+ // Images placement
+ bool bHasAlpha = !!stricmp( szTxFormat, "DXT1" );
+
+ int extTxWidth = TILE_SIZE;
+ int extTxHeight = TILE_SIZE;
+
+ int orgTxX = 0, orgTxXA = 0;
+ int orgTxY = 0, orgTxYA = 0;
+
+ if ( bHasAlpha )
+ {
+ if ( iTxWidth >= iTxHeight * 2 )
+ {
+ extTxHeight /= 2;
+ orgTxYA = extTxHeight + TILE_BORDER/2;
+ extTxHeight -= 1;
+ }
+ else if ( iTxHeight >= iTxWidth * 2 )
+ {
+ extTxWidth /= 2;
+ orgTxXA = extTxWidth + TILE_BORDER/2;
+ extTxWidth -= 3;
+ }
+ else
+ {
+ extTxHeight /= 2;
+ orgTxYA = extTxHeight + TILE_BORDER/2;
+ orgTxX = extTxWidth / 4;
+ extTxWidth /= 2;
+
+ if ( iDrawWidth > extTxWidth )
+ {
+ iDrawWidth /= 2;
+ iDrawHeight /= 2;
+ }
+ extTxWidth -= 1;
+ extTxHeight -= 1;
+ }
+ }
+
+ enum { IMG_FRAME_OFF = 2 };
+ if ( IMaterial *pMaterial = UseDebugMaterial( "debug/debugtexturecolor", pMatTexture, &auto_matsysdebugmode ) )
+ {
+ g_pMatSystemSurface->DrawSetColor( 255, 255, 255, 255 );
+ g_pMatSystemSurface->DrawOutlinedRect( x + orgTxX + ( extTxWidth - iDrawWidth ) / 2 - IMG_FRAME_OFF, y + orgTxY + ( extTxHeight - iDrawHeight ) / 2 - IMG_FRAME_OFF,
+ x + orgTxX + ( extTxWidth + iDrawWidth ) / 2 + IMG_FRAME_OFF, y + orgTxY + ( extTxHeight + iDrawHeight ) / 2 + IMG_FRAME_OFF );
+ RenderTexturedRect( this, pMaterial,
+ x + orgTxX + ( extTxWidth - iDrawWidth ) / 2, y + orgTxY + ( extTxHeight - iDrawHeight ) / 2,
+ x + orgTxX + ( extTxWidth + iDrawWidth ) / 2, y + orgTxY + ( extTxHeight + iDrawHeight ) / 2 );
+
+ if ( bHasAlpha )
+ {
+ orgTxX += orgTxXA;
+ orgTxY += orgTxYA;
+ if ( IMaterial *pMaterialDebug = UseDebugMaterial( "debug/debugtexturealpha", pMatTexture, &auto_matsysdebugmode ) )
+ {
+ g_pMatSystemSurface->DrawOutlinedRect( x + orgTxX + ( extTxWidth - iDrawWidth ) / 2 - IMG_FRAME_OFF, y + orgTxY + ( extTxHeight - iDrawHeight ) / 2 - IMG_FRAME_OFF,
+ x + orgTxX + ( extTxWidth + iDrawWidth ) / 2 + IMG_FRAME_OFF, y + orgTxY + ( extTxHeight + iDrawHeight ) / 2 + IMG_FRAME_OFF );
+ RenderTexturedRect( this, pMaterialDebug,
+ x + orgTxX + ( extTxWidth - iDrawWidth ) / 2, y + orgTxY + ( extTxHeight - iDrawHeight ) / 2,
+ x + orgTxX + ( extTxWidth + iDrawWidth ) / 2, y + orgTxY + ( extTxHeight + iDrawHeight ) / 2 );
+ }
+ }
+ }
+ else
+ {
+ g_pMatSystemSurface->DrawSetColor( 255, 0, 255, 100 );
+ g_pMatSystemSurface->DrawFilledRect(
+ x + orgTxX + ( extTxWidth - iDrawWidth ) / 2, y + orgTxY + ( extTxWidth - iDrawHeight ) / 2,
+ x + orgTxX + ( extTxWidth + iDrawWidth ) / 2, y + orgTxY + ( extTxWidth + iDrawHeight ) / 2 );
+ }
+
+ y += TILE_SIZE + TILE_BORDER;
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+// Render textures view panel
+//
+//////////////////////////////////////////////////////////////////////////
+
+class CRenderTexturesListViewPanel : public vgui::TileViewPanelEx
+{
+ DECLARE_CLASS_SIMPLE( CRenderTexturesListViewPanel, vgui::TileViewPanelEx );
+
+public:
+ CRenderTexturesListViewPanel( vgui::Panel *parent, char const *szName );
+ ~CRenderTexturesListViewPanel();
+
+protected:
+ virtual int GetNumTiles();
+ virtual void GetTileSize( int &wide, int &tall );
+ virtual void RenderTile( int iTile, int x, int y );
+
+protected:
+ virtual void PerformLayout();
+ virtual void OnMousePressed( vgui::MouseCode code );
+ virtual void OnMouseDoublePressed( vgui::MouseCode code ) { OnMousePressed( code ); }
+
+public:
+ void SetDataListPanel( vgui::ListPanel *pPanel );
+ void SetPaintAlpha( bool bPaintAlpha );
+
+ CRenderTextureEditor * GetRenderTxEditor() const { return m_pRenderTxEditor; }
+
+protected:
+ vgui::ListPanel *m_pListPanel;
+ KeyValues * GetTileData( int iTile );
+
+protected:
+ CRenderTextureEditor *m_pRenderTxEditor;
+
+protected:
+ enum
+ {
+ TILE_BORDER = 20,
+ TILE_SIZE = 192,
+ TILE_TEXTURE_SIZE = 256,
+ TILE_TEXT = 35
+ };
+
+ bool m_bPaintAlpha;
+};
+
+CRenderTexturesListViewPanel::CRenderTexturesListViewPanel( vgui::Panel *parent, char const *szName ) :
+ vgui::TileViewPanelEx( parent, szName ),
+ m_pListPanel( NULL ),
+ m_bPaintAlpha( false )
+{
+ m_pRenderTxEditor = new CRenderTextureEditor( this, "TxEdt" );
+ m_pRenderTxEditor->SetPos( 10, 10 );
+ m_pRenderTxEditor->PerformLayout();
+ m_pRenderTxEditor->SetMoveable( true );
+ m_pRenderTxEditor->SetSizeable( false );
+ m_pRenderTxEditor->SetClipToParent( true );
+ m_pRenderTxEditor->SetTitle( "", true );
+ m_pRenderTxEditor->SetCloseButtonVisible( false );
+ m_pRenderTxEditor->SetVisible( false );
+}
+
+CRenderTexturesListViewPanel::~CRenderTexturesListViewPanel()
+{
+ NULL;
+}
+
+void CRenderTexturesListViewPanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+}
+
+void CRenderTexturesListViewPanel::OnMousePressed( vgui::MouseCode code )
+{
+ BaseClass::OnMousePressed( code );
+
+ // Figure out which tile got hit and pass its data for preview
+ m_pRenderTxEditor->Close();
+
+ if ( !m_pListPanel )
+ return;
+
+ int x, y;
+ vgui::input()->GetCursorPos( x, y );
+ this->ScreenToLocal( x, y );
+
+ // Hit test the click
+ int iTile, tileX, tileY;
+ int htResult = HitTest( x, y, iTile );
+ if ( HT_NOTHING == htResult )
+ return;
+ if ( !GetTileOrg( iTile, tileX, tileY ) )
+ return;
+
+ // Now having the tile retrieve the keyvalues
+ int itemId = m_pListPanel->GetItemIDFromRow( iTile );
+ if ( itemId < 0 )
+ return;
+ KeyValues *kv = m_pListPanel->GetItem( itemId );
+ if ( !kv )
+ return;
+
+ // Display the tx editor
+ m_pRenderTxEditor->SetDispInfo( kv, itemId );
+
+ if ( tileX + m_pRenderTxEditor->GetWide() > m_li_wide - 2 )
+ tileX -= tileX + m_pRenderTxEditor->GetWide() - ( m_li_wide - 2 );
+ if ( tileY + m_pRenderTxEditor->GetTall() > m_li_tall - 2 )
+ tileY -= tileY + m_pRenderTxEditor->GetTall() - ( m_li_tall - 2 );
+
+ int iTopLeftX = 0, iTopLeftY = 0;
+ for ( vgui::Panel *pPanel = this; ( pPanel = pPanel->GetParent() ) != NULL; )
+ {
+ iTopLeftX = iTopLeftY = 0;
+ pPanel->LocalToScreen( iTopLeftX, iTopLeftY );
+ }
+
+ LocalToScreen( tileX, tileY );
+ if ( tileX < iTopLeftX ) tileX = iTopLeftX;
+ if ( tileY < iTopLeftY ) tileY = iTopLeftY;
+
+ m_pRenderTxEditor->SetPos( tileX, tileY );
+ m_pRenderTxEditor->Activate();
+}
+
+int CRenderTexturesListViewPanel::GetNumTiles()
+{
+ return m_pListPanel ? m_pListPanel->GetItemCount() : 0;
+}
+
+void CRenderTexturesListViewPanel::GetTileSize( int &wide, int &tall )
+{
+ wide = 2 * TILE_BORDER + TILE_SIZE;
+ tall = 2 * TILE_BORDER + TILE_SIZE + TILE_TEXT;
+};
+
+KeyValues * CRenderTexturesListViewPanel::GetTileData( int iTile )
+{
+ int iData = m_pListPanel->GetItemIDFromRow( iTile );
+ if ( iData < 0 )
+ return NULL;
+
+ return m_pListPanel->GetItem( iData );
+}
+
+void CRenderTexturesListViewPanel::RenderTile( int iTile, int x, int y )
+{
+ CAutoMatSysDebugMode auto_matsysdebugmode;
+
+ KeyValues *kv = GetTileData( iTile );
+ if ( !kv )
+ return;
+
+ char const *szTextureFile = kv->GetString( KEYNAME_NAME );
+ char const *szTextureGroup = kv->GetString( KEYNAME_TEXTURE_GROUP );
+ ITexture *pMatTexture = NULL;
+ if ( *szTextureFile )
+ pMatTexture = materials->FindTexture( szTextureFile, szTextureGroup, false );
+ if ( !pMatTexture )
+ pMatTexture = materials->FindTexture( "debugempty", "", false );
+
+ // Determine the texture size
+ int iTxWidth = kv->GetInt( KEYNAME_WIDTH );
+ int iTxHeight = kv->GetInt( KEYNAME_HEIGHT );
+ int iTxSize = kv->GetInt( KEYNAME_SIZE );
+ char const *szTxFormat = kv->GetString( KEYNAME_FORMAT );
+
+ int iTxFormatLen = strlen( szTxFormat );
+ char *szTxFormatSuffix = "";
+ if ( iTxFormatLen > 4 )
+ {
+fmtlenreduce:
+ switch ( szTxFormat[ iTxFormatLen - 1 ] )
+ {
+ case '8':
+ {
+ while ( ( iTxFormatLen > 4 ) &&
+ ( szTxFormat[ iTxFormatLen - 2 ] == '8' ) )
+ -- iTxFormatLen;
+ }
+ break;
+ case '6':
+ {
+ while ( ( iTxFormatLen > 4 ) &&
+ ( szTxFormat[ iTxFormatLen - 2 ] == '1' ) &&
+ ( szTxFormat[ iTxFormatLen - 3 ] == '6' ) )
+ iTxFormatLen -= 2;
+ }
+ break;
+ case 'F':
+ if ( !*szTxFormatSuffix )
+ {
+ iTxFormatLen --;
+ szTxFormatSuffix = "F";
+ goto fmtlenreduce;
+ }
+ break;
+ }
+ }
+
+ // Dimensions to draw
+ int iDrawWidth = iTxWidth;
+ int iDrawHeight = iTxHeight;
+
+ if ( pMatTexture && pMatTexture->IsCubeMap() )
+ {
+ iDrawWidth = 1024;
+ iDrawHeight = 1024;
+ }
+
+ if ( iDrawHeight >= iDrawWidth )
+ {
+ if ( iDrawHeight > TILE_TEXTURE_SIZE )
+ {
+ iDrawWidth = iDrawWidth * ( float( TILE_TEXTURE_SIZE ) / iDrawHeight );
+ iDrawHeight = TILE_TEXTURE_SIZE;
+ }
+
+ if ( iDrawHeight < 64 )
+ {
+ iDrawWidth = iDrawWidth * ( float( 64 ) / iDrawHeight );
+ iDrawHeight = 64;
+ }
+ }
+ else
+ {
+ if ( iDrawWidth > TILE_TEXTURE_SIZE )
+ {
+ iDrawHeight = iDrawHeight * ( float( TILE_TEXTURE_SIZE ) / iDrawWidth );
+ iDrawWidth = TILE_TEXTURE_SIZE;
+ }
+
+ if ( iDrawWidth < 64 )
+ {
+ iDrawHeight = iDrawHeight * ( float( 64 ) / iDrawWidth );
+ iDrawWidth = 64;
+ }
+ }
+
+ iDrawHeight = iDrawHeight / ( float( TILE_TEXTURE_SIZE ) / float( TILE_SIZE ) );
+ iDrawWidth = iDrawWidth / ( float( TILE_TEXTURE_SIZE ) / float( TILE_SIZE ) );
+
+ iDrawHeight = max( iDrawHeight, 4 );
+ iDrawWidth = max( iDrawWidth, 4 );
+
+ //
+ // Draw frame
+ //
+ {
+ int tileWidth, tileHeight;
+ GetTileSize( tileWidth, tileHeight );
+ g_pMatSystemSurface->DrawSetColor( 255, 255, 255, 255 );
+ g_pMatSystemSurface->DrawOutlinedRect( x + 1, y + 1,
+ x + tileWidth - 2 , y + tileHeight - 2 );
+ }
+
+ //
+ // Draw all
+ //
+
+ x += TILE_BORDER;
+ y += TILE_BORDER/2;
+
+ int iLenFile = strlen( szTextureFile );
+ char const *szPrintFilePrefix = ( iLenFile > 22 ) ? "..." : "";
+ char const *szPrintFileName = ( iLenFile > 22 ) ? ( szTextureFile + iLenFile - 22 ) : szTextureFile;
+
+ char chSizeBuf[20] = {0};
+ if ( iTxSize >= 0 )
+ {
+ FmtCommaNumber( chSizeBuf, iTxSize );
+ }
+ else
+ {
+ chSizeBuf[0] = '-';
+ }
+
+ static Color clrLblNormal( 25, 50, 25, 255 );
+ static Color clrLblWarn( 75, 75, 0, 255 );
+ static Color clrLblError( 200, 0, 0, 255 );
+ bool bWarnTile = ( !kv->GetInt( "SpecialTx" ) ) && ( g_warn_enable && ShallWarnTx( kv, pMatTexture ) );
+ g_pMatSystemSurface->DrawSetColor( bWarnTile ? clrLblWarn : clrLblNormal );
+ g_pMatSystemSurface->DrawFilledRect( x - TILE_BORDER/2, y, x + TILE_BORDER/2 + TILE_SIZE, y + TILE_TEXT );
+
+ char chInfoText[256] = { 0 };
+ sprintf( chInfoText, "%s Kb %dx%d %.*s%s %s",
+ chSizeBuf,
+ iTxWidth, iTxHeight,
+ iTxFormatLen, szTxFormat, szTxFormatSuffix,
+ ( pMatTexture->GetFlags() & (
+ TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_ONEBITALPHA
+ ) ) ? "***" : "" );
+ int iTextMargins[4] = { 0 };
+ int iTextHeight = g_pMatSystemSurface->GetFontTall( GetFont() );
+ {
+ // Compute text extents
+ int iTextLen[4] = { 0 };
+ iTextLen[0] = 5 + strlen( chSizeBuf );
+ iTextLen[1] = strchr( chInfoText, 'x' ) + 1 - chInfoText;
+ while ( chInfoText[ iTextLen[1] ] != ' ' )
+ ++ iTextLen[1];
+ ++ iTextLen[1];
+ iTextLen[2] = 2 + iTextLen[1] + iTxFormatLen + strlen( szTxFormatSuffix );
+ iTextLen[3] = strlen( chInfoText );
+ for ( int k = 0; k < 4; ++ k )
+ iTextMargins[k] = g_pMatSystemSurface->DrawTextLen( GetFont(), "%.*s", iTextLen[k], chInfoText );
+ }
+
+ // Highlights
+ if ( bWarnTile )
+ {
+ g_pMatSystemSurface->DrawSetColor( clrLblError );
+ if ( iTxSize > g_warn_texkbytes )
+ g_pMatSystemSurface->DrawFilledRect( x - 2, y + iTextHeight + 1, x + iTextMargins[0] - 5, y + TILE_TEXT );
+ if ( iTxWidth > g_warn_texdimensions || iTxHeight > g_warn_texdimensions )
+ g_pMatSystemSurface->DrawFilledRect( x + iTextMargins[0] - 2, y + iTextHeight + 1, x + iTextMargins[1] - 1, y + TILE_TEXT );
+ if ( strcmp( szTxFormat, "DXT1" ) && strcmp( szTxFormat, "DXT5" ) )
+ g_pMatSystemSurface->DrawFilledRect( x + iTextMargins[1] + 2, y + iTextHeight + 1, x + iTextMargins[2] - 1, y + TILE_TEXT );
+ if ( pMatTexture->GetFlags() & (
+ TEXTUREFLAGS_NOLOD | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_ONEBITALPHA
+ ) )
+ g_pMatSystemSurface->DrawFilledRect( x + iTextMargins[2] + 3, y + iTextHeight + 1, x + iTextMargins[3] + 2, y + TILE_TEXT );
+ }
+
+ g_pMatSystemSurface->DrawColoredTextRect( GetFont(), x, y, TILE_SIZE, TILE_TEXT,
+ 255, 255, 255, 255,
+ "%s%s\n"
+ "%s",
+ szPrintFilePrefix, szPrintFileName,
+ chInfoText
+ );
+
+ y += TILE_TEXT + TILE_BORDER/2;
+
+ // Images placement
+ bool bHasAlpha = m_bPaintAlpha && stricmp( szTxFormat, "DXT1" );
+
+ int extTxWidth = TILE_SIZE;
+ int extTxHeight = TILE_SIZE;
+
+ int orgTxX = 0, orgTxXA = 0;
+ int orgTxY = 0, orgTxYA = 0;
+
+ if ( bHasAlpha )
+ {
+ if ( iTxWidth >= iTxHeight * 2 )
+ {
+ extTxHeight /= 2;
+ orgTxYA = extTxHeight + TILE_BORDER/2;
+ }
+ else if ( iTxHeight >= iTxWidth * 2 )
+ {
+ extTxWidth /= 2;
+ orgTxXA = extTxWidth + TILE_BORDER/2;
+ x -= TILE_BORDER/4 + 1;
+ }
+ else
+ {
+ extTxHeight /= 2;
+ orgTxYA = extTxHeight + TILE_BORDER/2;
+ orgTxX = extTxWidth / 4;
+ extTxWidth /= 2;
+ x -= TILE_BORDER/4 + 1;
+
+ if ( iDrawWidth > extTxWidth )
+ {
+ iDrawWidth /= 2;
+ iDrawHeight /= 2;
+ }
+ }
+ }
+
+ enum { IMG_FRAME_OFF = 2 };
+ if ( IMaterial *pMaterial = UseDebugMaterial( "debug/debugtexturecolor", pMatTexture, &auto_matsysdebugmode ) )
+ {
+ g_pMatSystemSurface->DrawSetColor( 255, 255, 255, 255 );
+ g_pMatSystemSurface->DrawOutlinedRect( x + orgTxX + ( extTxWidth - iDrawWidth ) / 2 - IMG_FRAME_OFF, y + orgTxY + ( extTxHeight - iDrawHeight ) / 2 - IMG_FRAME_OFF,
+ x + orgTxX + ( extTxWidth + iDrawWidth ) / 2 + IMG_FRAME_OFF, y + orgTxY + ( extTxHeight + iDrawHeight ) / 2 + IMG_FRAME_OFF );
+ RenderTexturedRect( this, pMaterial,
+ x + orgTxX + ( extTxWidth - iDrawWidth ) / 2, y + orgTxY + ( extTxHeight - iDrawHeight ) / 2,
+ x + orgTxX + ( extTxWidth + iDrawWidth ) / 2, y + orgTxY + ( extTxHeight + iDrawHeight ) / 2,
+ 2, 1 );
+
+ if ( bHasAlpha )
+ {
+ orgTxX += orgTxXA;
+ orgTxY += orgTxYA;
+ if ( IMaterial *pMaterialDebug = UseDebugMaterial( "debug/debugtexturealpha", pMatTexture, &auto_matsysdebugmode ) )
+ {
+ g_pMatSystemSurface->DrawOutlinedRect( x + orgTxX + ( extTxWidth - iDrawWidth ) / 2 - IMG_FRAME_OFF, y + orgTxY + ( extTxHeight - iDrawHeight ) / 2 - IMG_FRAME_OFF,
+ x + orgTxX + ( extTxWidth + iDrawWidth ) / 2 + IMG_FRAME_OFF, y + orgTxY + ( extTxHeight + iDrawHeight ) / 2 + IMG_FRAME_OFF );
+ RenderTexturedRect( this, pMaterialDebug,
+ x + orgTxX + ( extTxWidth - iDrawWidth ) / 2, y + orgTxY + ( extTxHeight - iDrawHeight ) / 2,
+ x + orgTxX + ( extTxWidth + iDrawWidth ) / 2, y + orgTxY + ( extTxHeight + iDrawHeight ) / 2,
+ 2, 1 );
+ }
+ }
+ }
+ else
+ {
+ g_pMatSystemSurface->DrawSetColor( 255, 0, 255, 100 );
+ g_pMatSystemSurface->DrawFilledRect(
+ x + orgTxX + ( extTxWidth - iDrawWidth ) / 2, y + orgTxY + ( extTxWidth - iDrawHeight ) / 2,
+ x + orgTxX + ( extTxWidth + iDrawWidth ) / 2, y + orgTxY + ( extTxWidth + iDrawHeight ) / 2 );
+ }
+
+ y += TILE_SIZE + TILE_BORDER;
+}
+
+void CRenderTexturesListViewPanel::SetDataListPanel( vgui::ListPanel *pPanel )
+{
+ m_pListPanel = pPanel;
+ InvalidateLayout();
+}
+
+void CRenderTexturesListViewPanel::SetPaintAlpha( bool bPaintAlpha )
+{
+ m_bPaintAlpha = bPaintAlpha;
+ Repaint();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Shows entity status report if cl_entityreport cvar is set
+//-----------------------------------------------------------------------------
+class CTextureListPanel : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CTextureListPanel, vgui::Frame );
+
+public:
+ // Construction
+ CTextureListPanel( vgui::Panel *parent );
+ virtual ~CTextureListPanel( void );
+
+ // Refresh
+ virtual void Paint();
+ void EndPaint(); // Still inside paint
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual bool ShouldDraw();
+ virtual void PerformLayout();
+ virtual void Close();
+
+ void OnTurnedOn();
+
+private:
+
+ void UpdateTotalUsageLabel();
+ virtual void OnCommand( const char *command );
+ MESSAGE_FUNC( OnTextChanged, "TextChanged" );
+
+ int AddListItem( KeyValues *kv );
+
+ bool UpdateDisplayedItem( KeyValues *pDispData, KeyValues *kv );
+
+
+private:
+
+ // Font to use for drawing
+ vgui::HFont m_hFont;
+ vgui::ListPanel *m_pListPanel;
+ CRenderTexturesListViewPanel *m_pViewPanel;
+
+ vgui::CheckButton *m_pSpecialTexs;
+ vgui::CheckButton *m_pResolveTexturePath;
+ CConVarCheckButton *m_pShowTextureMemoryUsageOption;
+ CConVarCheckButton *m_pAllTextures;
+ CConVarCheckButton *m_pViewTextures;
+ vgui::Button *m_pCopyToClipboardButton;
+ vgui::ToggleButton *m_pCollapse;
+ vgui::CheckButton *m_pAlpha;
+ vgui::CheckButton *m_pThumbWarnings;
+
+ vgui::CheckButton *m_pHideMipped;
+ vgui::CheckButton *m_pFilteringChk;
+ vgui::TextEntry *m_pFilteringText;
+ int m_numDisplayedSizeKB;
+
+ vgui::Button *m_pReloadAllMaterialsButton;
+ vgui::Button *m_pCommitChangesButton;
+ vgui::Button *m_pDiscardChangesButton;
+
+ vgui::Label *m_pCVarListLabel;
+ vgui::Label *m_pTotalUsageLabel;
+};
+
+
+static int __cdecl KilobytesSortFunc( vgui::ListPanel *pPanel, const vgui::ListPanelItem &item1, const vgui::ListPanelItem &item2 )
+{
+ // Reverse sort order so the bigger textures show up first
+ const char *string1 = item1.kv->GetString( KEYNAME_SIZE );
+ const char *string2 = item2.kv->GetString( KEYNAME_SIZE );
+ int a = atoi( string1 );
+ int b = atoi( string2 );
+ if( a < b )
+ {
+ return 1;
+ }
+ if( a > b )
+ {
+ return -1;
+ }
+ return 0;
+}
+
+
+//
+// Smart texture list
+//
+class CSmartTextureKeyValues
+{
+private:
+ CSmartTextureKeyValues( CSmartTextureKeyValues const &x );
+ CSmartTextureKeyValues& operator = ( CSmartTextureKeyValues const &x );
+
+public:
+ CSmartTextureKeyValues() : m_p( NULL ) { if ( KeyValues *p = g_pMaterialSystemDebugTextureInfo->GetDebugTextureList() ) m_p = p->MakeCopy(); }
+ ~CSmartTextureKeyValues() { if ( m_p ) m_p->deleteThis(); m_p = NULL; }
+
+ KeyValues * Get() const { return m_p; };
+
+protected:
+ KeyValues *m_p;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Instances the entity report panel
+// Input : *parent -
+//-----------------------------------------------------------------------------
+CTextureListPanel::CTextureListPanel( vgui::Panel *parent ) :
+ BaseClass( parent, "CTextureListPanel" ),
+ m_numDisplayedSizeKB( 0 )
+{
+ // Need parent here, before loading up textures, so getSurfaceBase
+ // will work on this panel ( it's null otherwise )
+ SetSize( videomode->GetModeStereoWidth() - 20, videomode->GetModeStereoHeight() - 20 );
+ SetPos( 10, 10 );
+ SetVisible( true );
+ SetCursor( null );
+
+ SetTitle( "Texture list", false );
+ SetMenuButtonVisible( false );
+
+ m_hFont = vgui::INVALID_FONT;
+
+ SetFgColor( Color( 0, 0, 0, 255 ) );
+ SetPaintBackgroundEnabled( true );
+
+ // Init the buttons.
+ m_pCVarListLabel = vgui::SETUP_PANEL( new vgui::Label( this, "m_pCVarListLabel",
+ "cvars: mat_texture_limit, mat_texture_list, mat_picmip, mat_texture_list_txlod, mat_texture_list_txlod_sync" ) );
+ m_pCVarListLabel->SetVisible( false ); // m_pCVarListLabel->SetVisible( true );
+
+ m_pTotalUsageLabel = vgui::SETUP_PANEL( new vgui::Label( this, "m_pTotalUsageLabel", "" ) );
+ m_pTotalUsageLabel->SetVisible( true );
+
+ m_pSpecialTexs = vgui::SETUP_PANEL( new vgui::CheckButton( this, "service", "Render Targets and Special Textures" ) );
+ m_pSpecialTexs->SetVisible( true );
+ m_pSpecialTexs->AddActionSignalTarget( this );
+ m_pSpecialTexs->SetCommand( "service" );
+
+ m_pResolveTexturePath = vgui::SETUP_PANEL( new vgui::CheckButton( this, "resolvepath", "Resolve Full Texture Path" ) );
+ m_pResolveTexturePath->SetVisible( true );
+ m_pResolveTexturePath->AddActionSignalTarget( this );
+ m_pResolveTexturePath->SetCommand( "resolvepath" );
+
+ m_pShowTextureMemoryUsageOption = vgui::SETUP_PANEL( new CConVarCheckButton( this, "m_pShowTextureMemoryUsageOption", "Show Memory Usage on HUD" ) );
+ m_pShowTextureMemoryUsageOption->SetVisible( true );
+ m_pShowTextureMemoryUsageOption->SetConVar( &mat_show_texture_memory_usage );
+
+ m_pAllTextures = vgui::SETUP_PANEL( new CConVarCheckButton( this, "m_pAllTextures", "Show ALL textures" ) );
+ m_pAllTextures->SetVisible( true );
+ m_pAllTextures->SetConVar( &mat_texture_list_all );
+ m_pAllTextures->AddActionSignalTarget( this );
+ m_pAllTextures->SetCommand( "AllTextures" );
+
+ m_pViewTextures = vgui::SETUP_PANEL( new CConVarCheckButton( this, "m_pViewTextures", "View textures thumbnails" ) );
+ m_pViewTextures->SetVisible( true );
+ m_pViewTextures->SetConVar( &mat_texture_list_view );
+ m_pViewTextures->AddActionSignalTarget( this );
+ m_pViewTextures->SetCommand( "ViewThumbnails" );
+
+ m_pCopyToClipboardButton = vgui::SETUP_PANEL( new vgui::Button( this, "CopyToClipboard", "Copy to Clipboard" ) );
+ if ( m_pCopyToClipboardButton )
+ {
+ m_pCopyToClipboardButton->AddActionSignalTarget( this );
+ m_pCopyToClipboardButton->SetCommand( COPYTOCLIPBOARD_CMDNAME );
+ }
+
+ m_pCollapse = vgui::SETUP_PANEL( new vgui::ToggleButton( this, "Collapse", " " ) );
+ m_pCollapse->AddActionSignalTarget( this );
+ m_pCollapse->SetCommand( "Collapse" );
+ m_pCollapse->SetSelected( true );
+
+ m_pAlpha = vgui::SETUP_PANEL( new vgui::CheckButton( this, "ShowAlpha", "Alpha" ) );
+ m_pAlpha->AddActionSignalTarget( this );
+ m_pAlpha->SetCommand( "ShowAlpha" );
+ bool bDefaultTxAlphaOn = true;
+ m_pAlpha->SetSelected( bDefaultTxAlphaOn );
+
+ m_pThumbWarnings = vgui::SETUP_PANEL( new vgui::CheckButton( this, "ThumbWarnings", "Warns" ) );
+ m_pThumbWarnings->AddActionSignalTarget( this );
+ m_pThumbWarnings->SetCommand( "ThumbWarnings" );
+ m_pThumbWarnings->SetSelected( g_warn_enable );
+
+ // Filtering
+ m_pHideMipped = vgui::SETUP_PANEL( new vgui::CheckButton( this, "HideMipped", "Hide Mipped" ) );
+ m_pHideMipped->AddActionSignalTarget( this );
+ m_pHideMipped->SetCommand( "HideMipped" );
+ m_pHideMipped->SetSelected( false );
+
+ // Filtering
+ m_pFilteringChk = vgui::SETUP_PANEL( new vgui::CheckButton( this, "FilteringChk", "Filter: " ) );
+ m_pFilteringChk->AddActionSignalTarget( this );
+ m_pFilteringChk->SetCommand( "FilteringChk" );
+ m_pFilteringChk->SetSelected( true );
+
+ m_pFilteringText = vgui::SETUP_PANEL( new vgui::TextEntry( this, "FilteringTxt" ) );
+ m_pFilteringText->AddActionSignalTarget( this );
+
+ m_pReloadAllMaterialsButton = vgui::SETUP_PANEL( new vgui::Button( this, "ReloadAllMaterials", "Reload All Materials" ) );
+ if ( m_pReloadAllMaterialsButton )
+ {
+ m_pReloadAllMaterialsButton->AddActionSignalTarget( this );
+ m_pReloadAllMaterialsButton->SetCommand( "ReloadAllMaterials" );
+ }
+ m_pCommitChangesButton = vgui::SETUP_PANEL( new vgui::Button( this, "CommitChanges", "Commit Changes" ) );
+ if ( m_pCommitChangesButton )
+ {
+ m_pCommitChangesButton->AddActionSignalTarget( this );
+ m_pCommitChangesButton->SetCommand( "CommitChanges" );
+ }
+ m_pDiscardChangesButton = vgui::SETUP_PANEL( new vgui::Button( this, "DiscardChanges", "Discard Changes" ) );
+ if ( m_pDiscardChangesButton )
+ {
+ m_pDiscardChangesButton->AddActionSignalTarget( this );
+ m_pDiscardChangesButton->SetCommand( "DiscardChanges" );
+ }
+
+ // Create the tree control itself.
+ m_pListPanel = vgui::SETUP_PANEL( new vgui::ListPanel( this, "List Panel" ) );
+ m_pListPanel->SetVisible( !mat_texture_list_view.GetBool() );
+
+ int col = -1;
+ m_pListPanel->AddColumnHeader( ++ col, KEYNAME_NAME, "Texture Name", 200, 100, 700, vgui::ListPanel::COLUMN_RESIZEWITHWINDOW );
+ m_pListPanel->AddColumnHeader( ++ col, KEYNAME_PATH, "Path", 50, 50, 300, 0 );
+ m_pListPanel->AddColumnHeader( ++ col, KEYNAME_SIZE, "Kilobytes", 50, 50, 50, 0 );
+ m_pListPanel->SetSortFunc( col, KilobytesSortFunc );
+ m_pListPanel->SetSortColumnEx( col, 0, true ); // advanced sorting setup
+ m_pListPanel->AddColumnHeader( ++ col, KEYNAME_TEXTURE_GROUP, "Group", 100, 100, 300, 0 );
+ m_pListPanel->AddColumnHeader( ++ col, KEYNAME_FORMAT, "Format", 250, 50, 300, 0 );
+ m_pListPanel->AddColumnHeader( ++ col, KEYNAME_WIDTH, "Width", 50, 50, 50, 0 );
+ m_pListPanel->AddColumnHeader( ++ col, KEYNAME_HEIGHT, "Height", 50, 50, 50, 0 );
+ m_pListPanel->AddColumnHeader( ++ col, KEYNAME_BINDS_FRAME, "# Binds", 50, 50, 50, 0 );
+ m_pListPanel->AddColumnHeader( ++ col, KEYNAME_BINDS_MAX, "BindsMax", 50, 50, 50, 0 );
+
+ SetBgColor( Color( 0, 0, 0, 100 ) );
+
+ m_pListPanel->SetBgColor( Color( 0, 0, 0, 100 ) );
+
+ // Create the view control itself
+ m_pViewPanel = vgui::SETUP_PANEL( new CRenderTexturesListViewPanel( this, "View Panel" ) );
+ m_pViewPanel->SetVisible( mat_texture_list_view.GetBool() );
+ m_pViewPanel->SetBgColor( Color( 0, 0, 0, 255 ) );
+
+ m_pViewPanel->SetDragEnabled( false );
+ m_pViewPanel->SetDropEnabled( false );
+ m_pViewPanel->SetPaintAlpha( bDefaultTxAlphaOn );
+
+ m_pViewPanel->SetDataListPanel( m_pListPanel );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTextureListPanel::~CTextureListPanel( void )
+{
+ g_pTextureListPanel = NULL;
+}
+
+void CTextureListPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ // If you change this font, be sure to mark it with
+ // $use_in_fillrate_mode in its .vmt file
+ m_hFont = pScheme->GetFont( "DefaultVerySmall", false );
+ Assert( m_hFont );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CTextureListPanel::ShouldDraw( void )
+{
+ if ( mat_texture_list.GetInt() )
+ return true;
+ if ( s_eTxListPanelRequest == TXR_SHOW ||
+ s_eTxListPanelRequest == TXR_RUNNING )
+ return true;
+
+ return false;
+}
+
+void CTextureListPanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // Put the collapse button in the corner
+ m_pCollapse->SetPos( 2, 10 );
+ m_pCollapse->SetSize( 10, 10 );
+ m_pCollapse->SetVisible( true );
+
+ bool bCollapsed = m_pCollapse->IsSelected();
+
+ int x, y, w, t;
+ GetClientArea( x, y, w, t );
+
+ int yOffset = y;
+
+ // The cvar reminder goes on the top.
+ m_pCVarListLabel->SetPos( x, yOffset );
+ m_pCVarListLabel->SetWide( w );
+ NULL; // yOffset += m_pCVarListLabel->GetTall();
+ m_pCVarListLabel->SetVisible( false ); // m_pCVarListLabel->SetVisible( !bCollapsed );
+
+ m_pTotalUsageLabel->SetPos( x, yOffset );
+ m_pTotalUsageLabel->SetWide( w );
+ yOffset += m_pTotalUsageLabel->GetTall();
+ m_pTotalUsageLabel->SetVisible( !bCollapsed );
+
+ // Align the check boxes.
+ vgui::Panel *buttons[] = {
+ m_pSpecialTexs,
+ m_pShowTextureMemoryUsageOption,
+ m_pAllTextures,
+ m_pViewTextures,
+ m_pFilteringChk,
+ m_pHideMipped,
+ m_pResolveTexturePath,
+ m_pCopyToClipboardButton };
+
+ for ( int i=0; i < ARRAYSIZE( buttons ); i++ )
+ {
+ buttons[i]->SetPos( x, yOffset );
+ buttons[i]->SetWide( w/2 );
+ yOffset += buttons[i]->GetTall();
+ buttons[i]->SetVisible( !bCollapsed );
+
+ if ( buttons[i] == m_pViewTextures )
+ {
+ m_pViewTextures->SetWide( 170 );
+ int accumw = 170;
+
+ m_pAlpha->SetPos( x + accumw + 5, yOffset - m_pViewTextures->GetTall() );
+ m_pAlpha->SetWide( (accumw += 85, 85) );
+
+ m_pThumbWarnings->SetPos( x + accumw + 5, yOffset - m_pViewTextures->GetTall() );
+ m_pThumbWarnings->SetWide( (accumw += 85, 85) );
+ }
+
+ if ( buttons[i] == m_pFilteringChk )
+ {
+ m_pFilteringChk->SetWide( 60 );
+ int accumw = 60;
+
+ m_pFilteringText->SetPos( x + accumw + 5, yOffset - m_pFilteringChk->GetTall() );
+ m_pFilteringText->SetWide( ( accumw += 170, 170 ) );
+ m_pFilteringText->SetTall( m_pFilteringChk->GetTall() );
+ m_pFilteringText->SetVisible( !bCollapsed );
+ }
+ }
+
+ if ( bCollapsed )
+ {
+ int xOffset = 85, iWidth;
+
+ struct LayoutHorz_t
+ {
+ vgui::Panel *pPanel;
+ int iWidth;
+ }
+ layout[] =
+ {
+ { m_pTotalUsageLabel, 290 },
+ { m_pViewTextures, 170 },
+ { m_pAlpha, 60 },
+ { m_pAllTextures, 135 },
+ { m_pHideMipped, 100 },
+ { m_pFilteringChk, 60 },
+ { m_pFilteringText, 130 },
+ { m_pReloadAllMaterialsButton, 130 },
+ { m_pCommitChangesButton, 130 },
+ { m_pDiscardChangesButton, 130 },
+ };
+
+ for ( int k = 0; k < ARRAYSIZE( layout ); ++ k )
+ {
+ layout[ k ].pPanel->SetPos( xOffset, 2 );
+ iWidth = layout[ k ].iWidth;
+ iWidth = min( w - xOffset - 30, iWidth );
+ layout[ k ].pPanel->SetWide( iWidth );
+ layout[ k ].pPanel->SetVisible( iWidth > 50 );
+
+ if ( iWidth > 50 )
+ xOffset += iWidth + 5;
+ }
+
+ yOffset = y;
+ }
+
+ m_pAlpha->SetVisible( m_pViewTextures->IsSelected() );
+ m_pThumbWarnings->SetVisible( !bCollapsed && m_pViewTextures->IsSelected() );
+
+ m_pListPanel->SetBounds( x, yOffset, w, t - (yOffset - y) );
+ m_pViewPanel->SetBounds( x, yOffset, w, t - (yOffset - y) );
+
+ m_pListPanel->SetVisible( !mat_texture_list_view.GetBool() );
+ m_pViewPanel->SetVisible( mat_texture_list_view.GetBool() );
+}
+
+
+bool StripDirName( char *pFilename )
+{
+ if ( pFilename[0] == 0 )
+ return false;
+
+ char *pLastSlash = pFilename;
+ while ( 1 )
+ {
+ char *pTestSlash = strchr( pLastSlash, '/' );
+ if ( !pTestSlash )
+ {
+ pTestSlash = strchr( pLastSlash, '\\' );
+ if ( !pTestSlash )
+ break;
+ }
+
+ pTestSlash++; // Skip past the slash.
+ pLastSlash = pTestSlash;
+ }
+
+ if ( pLastSlash == pFilename )
+ {
+ return false;
+ }
+ else
+ {
+ Assert( pLastSlash[-1] == '/' || pLastSlash[-1] == '\\' );
+ pLastSlash[-1] = 0;
+ return true;
+ }
+}
+
+static inline void ToLowerInplace( char *chBuffer )
+{
+ for ( char *pch = chBuffer; *pch; ++ pch )
+ {
+ if ( V_isupper( *pch ) )
+ *pch = tolower( *pch );
+ }
+}
+
+void KeepSpecialKeys( KeyValues *textureList, bool bServiceKeys )
+{
+ KeyValues *pNext;
+
+ for ( KeyValues *pCur = textureList->GetFirstSubKey(); pCur; pCur=pNext )
+ {
+ pNext = pCur->GetNextKey();
+
+ bool bIsServiceKey = false;
+
+ char const *szName = pCur->GetString( KEYNAME_NAME );
+ if ( StringHasPrefix( szName, "_" ) ||
+ StringHasPrefix( szName, "[" ) ||
+ !stricmp( szName, "backbuffer" ) ||
+ StringHasPrefix( szName, "colorcorrection" ) ||
+ !stricmp( szName, "depthbuffer" ) ||
+ !stricmp( szName, "frontbuffer" ) ||
+ !stricmp( szName, "normalize" ) ||
+ !*szName )
+ {
+ bIsServiceKey = true;
+ }
+
+ if ( bIsServiceKey != bServiceKeys )
+ {
+ textureList->RemoveSubKey( pCur );
+ }
+ else if ( bIsServiceKey )
+ {
+ pCur->SetInt( "SpecialTx", 1 );
+ }
+ }
+}
+
+void KeepKeysMatchingFilter( KeyValues *textureList, char const *szFilter )
+{
+ if ( !szFilter || !*szFilter )
+ return;
+
+ char chFilter[MAX_PATH] = {0}, chName[MAX_PATH] = {0};
+
+ Q_strncpy( chFilter, szFilter, sizeof( chFilter ) - 1 );
+ ToLowerInplace( chFilter );
+
+ KeyValues *pNext;
+ for ( KeyValues *pCur=textureList->GetFirstSubKey(); pCur; pCur=pNext )
+ {
+ pNext = pCur->GetNextKey();
+
+ char const *szName = pCur->GetString( KEYNAME_NAME );
+
+ Q_strncpy( chName, szName, sizeof( chName ) - 1 );
+ ToLowerInplace( chName );
+
+ if ( !strstr( chName, chFilter ) )
+ {
+ textureList->RemoveSubKey( pCur );
+ }
+ }
+}
+
+void KeepKeysMarkedNoMip( KeyValues *textureList )
+{
+ KeyValues *pNext;
+ for ( KeyValues *pCur=textureList->GetFirstSubKey(); pCur; pCur=pNext )
+ {
+ pNext = pCur->GetNextKey();
+
+ char const *szTextureFile = pCur->GetString( KEYNAME_NAME );
+ char const *szTextureGroup = pCur->GetString( KEYNAME_TEXTURE_GROUP );
+ if ( *szTextureFile )
+ {
+ ITexture *pMatTexture = materials->FindTexture( szTextureFile, szTextureGroup, false );
+ if ( pMatTexture && !(pMatTexture->GetFlags() & TEXTUREFLAGS_NOMIP) )
+ {
+ textureList->RemoveSubKey( pCur );
+ }
+ }
+ }
+}
+
+void CTextureListPanel::UpdateTotalUsageLabel()
+{
+ char data[1024], kb1[20], kb2[20], kb3[20];
+ FmtCommaNumber( kb1, (g_pMaterialSystemDebugTextureInfo->GetTextureMemoryUsed( IDebugTextureInfo::MEMORY_BOUND_LAST_FRAME ) + 511) / 1024 );
+ FmtCommaNumber( kb2, (g_pMaterialSystemDebugTextureInfo->GetTextureMemoryUsed( IDebugTextureInfo::MEMORY_TOTAL_LOADED ) + 511) / 1024 );
+ FmtCommaNumber( kb3, m_numDisplayedSizeKB );
+
+ if ( bool bCollapsed = m_pCollapse->IsSelected() )
+ {
+ char const *szTitle = "";
+ Q_snprintf( data, sizeof( data ), "%s[F %s Kb] / [T %s Kb] / [S %s Kb]", szTitle, kb1, kb2, kb3 );
+ }
+ else
+ {
+ char const *szTitle = "Texture Memory Usage";
+ char kbMip1[ 20 ], kbMip2[ 20 ];
+ FmtCommaNumber( kbMip1, (g_pMaterialSystemDebugTextureInfo->GetTextureMemoryUsed( IDebugTextureInfo::MEMORY_ESTIMATE_PICMIP_1 ) + 511) / 1024 );
+ FmtCommaNumber( kbMip2, (g_pMaterialSystemDebugTextureInfo->GetTextureMemoryUsed( IDebugTextureInfo::MEMORY_ESTIMATE_PICMIP_2 ) + 511) / 1024 );
+ Q_snprintf( data, sizeof( data ), "%s: frame %s Kb / total %s Kb ( picmip1 = %s Kb, picmip2 = %s Kb ) / shown %s Kb", szTitle, kb1, kb2, kbMip1, kbMip2, kb3 );
+ }
+
+ wchar_t unicodeString[1024];
+ g_pVGuiLocalize->ConvertANSIToUnicode( data, unicodeString, sizeof( unicodeString ) );
+
+ m_pTotalUsageLabel->SetText( unicodeString );
+}
+
+void CTextureListPanel::OnTextChanged( void )
+{
+ OnCommand( "FilteringTxt" );
+}
+
+void CTextureListPanel::OnCommand( const char *command )
+{
+ if ( !Q_stricmp( command, "Close" ) )
+ {
+ vgui::Frame::OnCommand( command );
+ return;
+ }
+
+ if ( !Q_stricmp( command, "Collapse" ) )
+ {
+ InvalidateLayout();
+ return;
+ }
+
+ if ( !Q_stricmp( command, "ShowAlpha" ) )
+ {
+ m_pViewPanel->SetPaintAlpha( m_pAlpha->IsSelected() );
+ return;
+ }
+
+ if ( !Q_stricmp( command, "ThumbWarnings" ) )
+ {
+ g_warn_enable = m_pThumbWarnings->IsSelected();
+ return;
+ }
+
+ if ( !Q_stricmp( command, "ViewThumbnails" ) )
+ {
+ InvalidateLayout();
+ return;
+ }
+
+ if ( !Q_stricmp( command, COPYTOCLIPBOARD_CMDNAME ) )
+ {
+ CopyListPanelToClipboard( m_pListPanel );
+ return;
+ }
+
+ if ( !Q_stricmp( command, "ReloadAllMaterials" ) )
+ {
+ Cbuf_AddText( "mat_reloadallmaterials" );
+ Cbuf_Execute();
+ return;
+ }
+
+ if ( !Q_stricmp( command, "CommitChanges" ) )
+ {
+ Cbuf_AddText( "mat_texture_list_txlod_sync save" );
+ Cbuf_Execute();
+ return;
+ }
+
+ if ( !Q_stricmp( command, "DiscardChanges" ) )
+ {
+ Cbuf_AddText( "mat_texture_list_txlod_sync reset" );
+ Cbuf_Execute();
+ return;
+ }
+
+ mat_texture_list_on_f();
+ InvalidateLayout();
+}
+
+
+bool CTextureListPanel::UpdateDisplayedItem( KeyValues *pDispData, KeyValues *kv )
+{
+ // Update the item?
+ bool bUpdate = false;
+
+ // do the stuff that changes often separately.
+ if ( pDispData->GetInt( KEYNAME_BINDS_FRAME ) != kv->GetInt( KEYNAME_BINDS_FRAME ) )
+ {
+ pDispData->SetInt( KEYNAME_BINDS_FRAME, kv->GetInt( KEYNAME_BINDS_FRAME ) );
+ bUpdate = true;
+ }
+ if ( pDispData->GetInt( KEYNAME_BINDS_MAX ) != kv->GetInt( KEYNAME_BINDS_MAX ) )
+ {
+ pDispData->SetInt( KEYNAME_BINDS_MAX, kv->GetInt( KEYNAME_BINDS_MAX ) );
+ bUpdate = true;
+ }
+
+ // stuff that changes less frequently
+ if( pDispData->GetInt( KEYNAME_SIZE ) != kv->GetInt( KEYNAME_SIZE ) ||
+ pDispData->GetInt( KEYNAME_WIDTH ) != kv->GetInt( KEYNAME_WIDTH ) ||
+ pDispData->GetInt( KEYNAME_HEIGHT ) != kv->GetInt( KEYNAME_HEIGHT ) ||
+ Q_stricmp( pDispData->GetString( KEYNAME_FORMAT ), kv->GetString( KEYNAME_FORMAT ) ) != 0 ||
+ Q_stricmp( pDispData->GetString( KEYNAME_PATH ), kv->GetString( KEYNAME_PATH ) ) != 0 ||
+ Q_stricmp( pDispData->GetString( KEYNAME_TEXTURE_GROUP ), kv->GetString( KEYNAME_TEXTURE_GROUP ) ) != 0 )
+ {
+ pDispData->SetInt( KEYNAME_SIZE, kv->GetInt( KEYNAME_SIZE ) );
+ pDispData->SetInt( KEYNAME_WIDTH, kv->GetInt( KEYNAME_WIDTH ) );
+ pDispData->SetInt( KEYNAME_HEIGHT, kv->GetInt( KEYNAME_HEIGHT ) );
+ pDispData->SetString( KEYNAME_FORMAT, kv->GetString( KEYNAME_FORMAT ) );
+ pDispData->SetString( KEYNAME_PATH, kv->GetString( KEYNAME_PATH ) );
+ pDispData->SetString( KEYNAME_TEXTURE_GROUP, kv->GetString( KEYNAME_TEXTURE_GROUP ) );
+ bUpdate = true;
+ }
+
+ return bUpdate;
+}
+
+int CTextureListPanel::AddListItem( KeyValues *kv )
+{
+ int iItem = m_pListPanel->GetItem( kv->GetString( KEYNAME_NAME ) );
+ if ( iItem == -1 )
+ {
+ // Set this so the GetItem() call above can use the key's name (as opposed to the value of its
+ // "Name" subkey) to find this texture again.
+ kv->SetName( kv->GetString( KEYNAME_NAME ) );
+
+ // Add this one.
+ iItem = m_pListPanel->AddItem( kv, 0, false, false );
+ m_pViewPanel->InvalidateLayout();
+ }
+ else
+ {
+ KeyValues *pValues = m_pListPanel->GetItem( iItem );
+ bool bNeedUpdate = UpdateDisplayedItem( pValues, kv );
+
+ if( bNeedUpdate )
+ {
+ m_pListPanel->ApplyItemChanges( iItem );
+ m_pViewPanel->Repaint();
+ }
+ }
+
+ return iItem;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+
+void CTextureListPanel::OnTurnedOn()
+{
+ if ( g_bRecursiveRequestToShowTextureList )
+ return;
+
+ if ( m_pListPanel )
+ m_pListPanel->DeleteAllItems();
+
+ if ( CRenderTextureEditor *pRe = m_pViewPanel->GetRenderTxEditor() )
+ pRe->Close();
+
+ MakePopup( false, false );
+ MoveToFront();
+}
+
+void CTextureListPanel::Close()
+{
+ mat_texture_list_off_f();
+}
+
+void CTextureListPanel::EndPaint()
+{
+ UpdateTotalUsageLabel();
+}
+
+void CTextureListPanel::Paint()
+{
+ VPROF( "CTextureListPanel::Paint" );
+
+ if ( !m_hFont )
+ return;
+
+ struct EndPaint_t
+ {
+ CTextureListPanel *m_p;
+ EndPaint_t( CTextureListPanel *p ) : m_p( p ) {}
+ ~EndPaint_t()
+ {
+ m_p->EndPaint();
+ }
+ } endpaint( this );
+
+ if ( !mat_texture_list.GetBool() )
+ return;
+
+ if ( !g_pMaterialSystemDebugTextureInfo->IsDebugTextureListFresh( 1 ) )
+ return;
+
+ CSmartTextureKeyValues textureList;
+ if ( !textureList.Get() )
+ return;
+
+ CRenderTextureEditor *pRte = m_pViewPanel->GetRenderTxEditor();
+ if ( ( s_eTxListPanelRequest == TXR_RUNNING ) &&
+ pRte->IsVisible() )
+ {
+ KeyValues *kv = NULL;
+ int iHint = 0;
+ pRte->GetDispInfo( kv, iHint );
+ if ( kv && iHint )
+ {
+ KeyValues *plv = ( m_pListPanel->IsValidItemID( iHint ) ? m_pListPanel->GetItem( iHint ) : NULL );
+ if ( plv && !strcmp( plv->GetString( KEYNAME_NAME ), kv->GetString( KEYNAME_NAME ) ) )
+ {
+ KeyValues *pValData = plv->GetFirstValue(), *pValRendered = kv->GetFirstValue();
+ for ( ; pValData && pValRendered; pValData = pValData->GetNextValue(), pValRendered = pValRendered->GetNextValue() )
+ {
+ if ( strcmp( pValData->GetString(), pValRendered->GetString() ) )
+ break;
+ }
+ if ( pValData || pValRendered ) // Difference found
+ pRte->SetDispInfo( plv, iHint );
+ }
+ else
+ kv = NULL;
+ }
+
+ if ( 0 ) // if ( !kv )
+ {
+ pRte->Close();
+ pRte->SetDispInfo( NULL, 0 );
+ }
+ }
+
+ // If we are fetching all textures, then stop loading material system:
+ if ( mat_texture_list_all.GetBool() )
+ {
+ if ( s_eTxListPanelRequest == TXR_RUNNING )
+ {
+ mat_texture_list.SetValue( 0 );
+ s_eTxListPanelRequest = TXR_SHOW; // Keep displaying our panel
+ }
+ else
+ {
+ s_eTxListPanelRequest = TXR_RUNNING;
+ }
+ }
+ else
+ {
+ if ( s_eTxListPanelRequest == TXR_SHOW )
+ {
+ // Either first show or turned off "all textures"
+ m_pListPanel->RemoveAll();
+ m_pViewPanel->InvalidateLayout();
+ s_eTxListPanelRequest = TXR_RUNNING;
+ return;
+ }
+ }
+
+ CBitVec<4096 * 8> itemsTouched;
+
+ // Remove the textures we don't care for
+ KeepSpecialKeys( textureList.Get(), m_pSpecialTexs->IsSelected() );
+
+ // If filtering is enabled, then do filtering
+ if ( m_pFilteringChk->IsSelected() && m_pFilteringText->GetTextLength() )
+ {
+ char chFilterString[ MAX_PATH ];
+ m_pFilteringText->GetText( chFilterString, sizeof( chFilterString ) - 1 );
+ chFilterString[ sizeof( chFilterString ) - 1 ] = 0;
+ KeepKeysMatchingFilter( textureList.Get(), chFilterString );
+ }
+
+ // If we're to hide mipped, remove anything that isn't marked nomip
+ if ( m_pHideMipped->IsSelected() )
+ {
+ KeepKeysMarkedNoMip( textureList.Get() );
+ }
+
+ // Compute the total size of the displayed textures
+ int cbTotalDisplayedSizeInBytes = 0;
+
+ for ( KeyValues *pCur = textureList.Get()->GetFirstSubKey(); pCur; pCur=pCur->GetNextKey() )
+ {
+ int sizeInBytes = pCur->GetInt( KEYNAME_SIZE );
+
+ // Accumulate
+ cbTotalDisplayedSizeInBytes += sizeInBytes;
+
+ // Factor in frames
+ int numCount = pCur->GetInt( "Count" );
+ if ( numCount > 1 )
+ sizeInBytes *= numCount;
+
+ // Size is in kilobytes.
+ int sizeInKilo = ( sizeInBytes + 511 ) / 1024;
+ pCur->SetInt( KEYNAME_SIZE, sizeInKilo );
+
+ if ( m_pResolveTexturePath->IsSelected() )
+ {
+ char chResolveName[ 256 ] = {0}, chResolveNameArg[ 256 ] = {0};
+ Q_snprintf( chResolveNameArg, sizeof( chResolveNameArg ) - 1, "materials/%s.vtf", pCur->GetString( KEYNAME_NAME ) );
+ char const *szResolvedName = g_pFileSystem->RelativePathToFullPath( chResolveNameArg, "game", chResolveName, sizeof( chResolveName ) - 1 );
+ if ( szResolvedName )
+ {
+ pCur->SetString( KEYNAME_PATH, szResolvedName );
+ }
+ }
+
+ int iItem = AddListItem( pCur );
+
+ if ( iItem < itemsTouched.GetNumBits() )
+ itemsTouched.Set( iItem );
+ }
+
+ // Set the displayed size
+ m_numDisplayedSizeKB = ( cbTotalDisplayedSizeInBytes + 511 ) / 1024;
+
+ // Now remove from view items that weren't used.
+ int iNext, numRemoved = 0;
+ for ( int iCur=m_pListPanel->FirstItem(); iCur != m_pListPanel->InvalidItemID(); iCur=iNext )
+ {
+ iNext = m_pListPanel->NextItem( iCur );
+
+ if ( iCur >= itemsTouched.GetNumBits() || !itemsTouched.Get( iCur ) )
+ {
+ m_pListPanel->RemoveItem( iCur );
+ ++ numRemoved;
+ }
+ }
+
+ // Sorting in list panel
+ {
+ int iPri, iSec;
+ bool bAsc;
+ m_pListPanel->GetSortColumnEx( iPri, iSec, bAsc );
+ iSec = 0; // always secondary sort by name
+ m_pListPanel->SetSortColumnEx( iPri, iSec, bAsc );
+ m_pListPanel->SortList();
+ }
+
+ if ( numRemoved )
+ {
+ m_pViewPanel->InvalidateLayout();
+ }
+}
+
+
+
+// ------------------------------------------------------------------------------ //
+// Global functions.
+// ------------------------------------------------------------------------------ //
+
+void VGui_UpdateTextureListPanel()
+{
+ if ( mat_show_texture_memory_usage.GetInt() )
+ {
+ con_nprint_t info;
+ info.index = 4;
+ info.time_to_live = 0.2;
+ info.color[0] = 1;
+ info.color[1] = 0.5;
+ info.color[2] = 0;
+ info.fixed_width_font = true;
+
+ char kb1[20], kb2[20];
+ FmtCommaNumber( kb1, (g_pMaterialSystemDebugTextureInfo->GetTextureMemoryUsed( IDebugTextureInfo::MEMORY_BOUND_LAST_FRAME ) + 511) / 1024 );
+ FmtCommaNumber( kb2, (g_pMaterialSystemDebugTextureInfo->GetTextureMemoryUsed( IDebugTextureInfo::MEMORY_TOTAL_LOADED ) + 511) / 1024 );
+
+ Con_NXPrintf( &info, "Texture Memory Usage: %s Kb / %s Kb", kb1, kb2 );
+ }
+
+ MatViewOverride::DisplaySelectedTextures();
+
+ if ( IsX360() )
+ return;
+
+ g_pMaterialSystemDebugTextureInfo->EnableGetAllTextures( mat_texture_list_all.GetBool() );
+
+ g_pMaterialSystemDebugTextureInfo->EnableDebugTextureList( ( mat_texture_list.GetInt() <= 0 ) ? false : true );
+
+ bool bShouldDrawTxListPanel = g_pTextureListPanel->ShouldDraw();
+ if ( g_pTextureListPanel->IsVisible() != bShouldDrawTxListPanel )
+ {
+ g_pTextureListPanel->SetVisible( bShouldDrawTxListPanel );
+ bShouldDrawTxListPanel ? mat_texture_list_on_f() : mat_texture_list_off_f();
+ }
+}
+
+
+void CL_CreateTextureListPanel( vgui::Panel *parent )
+{
+ g_pTextureListPanel = new CTextureListPanel( parent );
+}
+
+CON_COMMAND( mat_texture_save_fonts, "Save all font textures" )
+{
+ for( int i = 0; i < 8192; i++ )
+ {
+ char szTextureName[ MAX_PATH ];
+
+ Q_snprintf( szTextureName, ARRAYSIZE( szTextureName ), "__font_page_%d.tga", i );
+
+ if( !materials->IsTextureLoaded( szTextureName ) )
+ break;
+
+ ITexture *pMatTexture = materials->FindTexture( szTextureName, "", false );
+ if( pMatTexture && !pMatTexture->IsError() )
+ {
+ bool bRet = SaveTextureImage( szTextureName );
+ Msg( "SaveTextureImage( '%s' ): %s\n", szTextureName, bRet ? "succeeded" : "failed" );
+ }
+ }
+}
+
+void mat_texture_list_on_f()
+{
+ ConVarRef sv_cheats( "sv_cheats" );
+ if ( sv_cheats.IsValid() && !sv_cheats.GetBool() )
+ return;
+
+ ConVarRef mat_queue_mode( "mat_queue_mode" );
+
+ if( mat_queue_mode.IsValid() && ( g_nSaveQueueState == INT_MIN ) )
+ {
+ g_nSaveQueueState = mat_queue_mode.GetInt();
+ mat_queue_mode.SetValue( 0 );
+ }
+
+ mat_texture_list.SetValue( 1 );
+ s_eTxListPanelRequest = TXR_SHOW;
+
+ g_pTextureListPanel->OnTurnedOn();
+
+ MatViewOverride::RequestSelectNone();
+
+ // On Linux, the mouse gets recentered when it's hidden. So if you bring up the texture list
+ // dialog while the game is running, we need to make sure the mouse is shown. Otherwise it's
+ // very tough to use when your mouse keeps getting recentered.
+ if( !g_cursorset && g_pVGuiSurface )
+ {
+ g_pVGuiSurface->SetCursorAlwaysVisible( true );
+ g_cursorset = true;
+ }
+}
+void mat_texture_list_off_f()
+{
+ mat_texture_list.SetValue( 0 );
+ s_eTxListPanelRequest = TXR_HIDE;
+
+ if( g_cursorset )
+ {
+ g_pVGuiSurface->SetCursorAlwaysVisible( false );
+ g_cursorset = false;
+ }
+
+ if( g_nSaveQueueState != INT_MIN )
+ {
+ ConVarRef mat_queue_mode( "mat_queue_mode" );
+
+ mat_queue_mode.SetValue( g_nSaveQueueState );
+ g_nSaveQueueState = INT_MIN;
+ }
+}
+
+