summaryrefslogtreecommitdiff
path: root/tools/vmt
diff options
context:
space:
mode:
Diffstat (limited to 'tools/vmt')
-rw-r--r--tools/vmt/vmt.vpc59
-rw-r--r--tools/vmt/vmtdoc.cpp1078
-rw-r--r--tools/vmt/vmtdoc.h133
-rw-r--r--tools/vmt/vmttool.cpp1337
-rw-r--r--tools/vmt/vmttool.h50
5 files changed, 2657 insertions, 0 deletions
diff --git a/tools/vmt/vmt.vpc b/tools/vmt/vmt.vpc
new file mode 100644
index 0000000..920503e
--- /dev/null
+++ b/tools/vmt/vmt.vpc
@@ -0,0 +1,59 @@
+//-----------------------------------------------------------------------------
+// VMT.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin\tools"
+
+$Include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,../common"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Psapi.lib"
+ }
+}
+
+$Project "Vmt"
+{
+ $Folder "Source Files"
+ {
+ $File "$SRCDIR\public\interpolatortypes.cpp"
+ $File "$SRCDIR\public\movieobjects\movieobjects.cpp"
+ $File "$SRCDIR\public\registry.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ $File "vmtdoc.cpp"
+ $File "vmttool.cpp"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "$SRCDIR\public\interpolatortypes.h"
+ $File "vmtdoc.h"
+ $File "vmttool.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib datamodel
+ $Lib dmxloader
+ $Lib dme_controls
+ $Lib dmserializers
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib movieobjects
+ $Lib sfmobjects
+ $Lib tier2
+ $Lib tier3
+ $Lib toolutils
+ $Lib vgui_controls
+ }
+}
diff --git a/tools/vmt/vmtdoc.cpp b/tools/vmt/vmtdoc.cpp
new file mode 100644
index 0000000..665d932
--- /dev/null
+++ b/tools/vmt/vmtdoc.cpp
@@ -0,0 +1,1078 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "vmtdoc.h"
+#include "tier1/KeyValues.h"
+#include "tier1/utlbuffer.h"
+#include "datamodel/dmelement.h"
+#include "vmttool.h"
+#include "materialsystem/imaterialsystem.h"
+#include "materialsystem/ishader.h"
+#include "toolutils/enginetools_int.h"
+#include "filesystem.h"
+
+
+//-----------------------------------------------------------------------------
+// Standard properties
+//-----------------------------------------------------------------------------
+struct StandardParam_t
+{
+ const char *m_pParamName;
+ ShaderParamType_t m_ParamType;
+ const char *m_pDefaultValue;
+ const char *m_pWidgetType;
+ const char *m_pTextType;
+};
+
+// NOTE: All entries in here must have all-lowercase param names!
+static StandardParam_t g_pStandardParams[] =
+{
+ { "$surfaceprop", SHADER_PARAM_TYPE_STRING, "default", "surfacepropertypicker", "surfacePropertyName" },
+ { "%detailtype", SHADER_PARAM_TYPE_STRING, "", "detailtypepicker", "detailTypeName" },
+ { "%compilesky", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilehint", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileskip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileorigin", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%playerclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilenpcclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilenochop", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compiletrigger", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilenolight", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileplayercontrolclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileladder", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilewet", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilenodraw", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileinvisible", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilenonsolid", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compiledetail", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compilewater", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { "%compileslime", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
+ { NULL, SHADER_PARAM_TYPE_BOOL, NULL, NULL, NULL }
+};
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CVMTDoc::CVMTDoc( IVMTDocCallback *pCallback ) : m_pCallback( pCallback )
+{
+ m_hRoot = NULL;
+ m_pFileName[0] = 0;
+ m_bDirty = false;
+ m_pCurrentIShader = NULL;
+
+ KeyValues *pKeyValues = new KeyValues( "Wireframe" );
+ m_pScratchMaterial.Init( "VMT Preview", pKeyValues );
+ g_pDataModel->InstallNotificationCallback( this );
+}
+
+CVMTDoc::~CVMTDoc()
+{
+ if ( m_hRoot.Get() )
+ {
+ RemoveAllShaderParams( m_hRoot );
+ }
+ g_pDataModel->RemoveNotificationCallback( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from INotifyUI
+//-----------------------------------------------------------------------------
+void CVMTDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ OnDataChanged( pReason, nNotifySource, nNotifyFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the file name
+//-----------------------------------------------------------------------------
+const char *CVMTDoc::GetFileName()
+{
+ return m_pFileName;
+}
+
+void CVMTDoc::SetFileName( const char *pFileName )
+{
+ Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
+ Q_FixSlashes( m_pFileName );
+ SetDirty( true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Dirty bits
+//-----------------------------------------------------------------------------
+void CVMTDoc::SetDirty( bool bDirty )
+{
+ m_bDirty = bDirty;
+}
+
+bool CVMTDoc::IsDirty() const
+{
+ return m_bDirty;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the root element
+//-----------------------------------------------------------------------------
+bool CVMTDoc::CreateRootElement()
+{
+ Assert( !m_hRoot.Get() );
+
+ DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( GetFileName() );
+
+ // Create the main element
+ m_hRoot = g_pDataModel->CreateElement( "DmElement", GetFileName(), fileid );
+ if ( m_hRoot == DMELEMENT_HANDLE_INVALID )
+ return false;
+
+ g_pDataModel->SetFileRoot( fileid, m_hRoot );
+
+ // Each VMT list needs to have an editortype associated with it so it displays nicely in editors
+ m_hRoot->SetValue( "editorType", "vmt" );
+ m_hRoot->AddAttribute( "proxies", AT_ELEMENT_ARRAY );
+ m_hRoot->AddAttribute( "fallbacks", AT_ELEMENT_ARRAY );
+
+ m_pCallback->RemoveAllToolParameters();
+
+ // Add standard parameters
+ for ( int i = 0; g_pStandardParams[i].m_pParamName; ++i )
+ {
+ AddNewShaderParam( m_hRoot, g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_ParamType,
+ g_pStandardParams[i].m_pDefaultValue );
+
+ if ( g_pStandardParams[i].m_pParamName[0] == '%' )
+ {
+ m_pCallback->AddToolParameter( g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_pWidgetType, g_pStandardParams[i].m_pTextType );
+ }
+ else if ( g_pStandardParams[i].m_pWidgetType || g_pStandardParams[i].m_pTextType )
+ {
+ m_pCallback->RemoveShaderParameter( g_pStandardParams[i].m_pParamName );
+ m_pCallback->AddShaderParameter( g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_pWidgetType, g_pStandardParams[i].m_pTextType );
+ }
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates a new VMT
+//-----------------------------------------------------------------------------
+void CVMTDoc::CreateNew()
+{
+ Assert( !m_hRoot.Get() );
+
+ // This is not undoable
+ CAppDisableUndoScopeGuard guard( "CVMTDoc::CreateNew", NOTIFY_CHANGE_OTHER );
+
+ Q_strncpy( m_pFileName, "untitled", sizeof( m_pFileName ) );
+
+ // Create the main element
+ if ( !CreateRootElement() )
+ return;
+
+ m_pPreviewMaterial.Init( m_pScratchMaterial );
+
+ SetShader( "wireframe" );
+ SetDirty( false );
+}
+
+
+//-----------------------------------------------------------------------------
+// Copies VMT parameters into the root
+//-----------------------------------------------------------------------------
+void CVMTDoc::CopyParamsFromVMT( CDmElement *pVMT )
+{
+ // First, set the shader parameters
+ SetShader( pVMT->GetValueString( "shader" ) );
+
+ // Now, copy the shader parameters over
+ CDmAttribute* pSrc;
+ CDmAttribute* pDst;
+ for ( pSrc = pVMT->FirstAttribute(); pSrc; pSrc = pSrc->NextAttribute() )
+ {
+ // Only copy shader parameters
+ if ( !IsShaderParam( pSrc ) )
+ continue;
+
+ // Adds the attribute if it doesn't exist
+ const char *pSrcName = pSrc->GetName();
+ if ( !m_hRoot->HasAttribute( pSrcName ) )
+ {
+ m_hRoot->AddAttribute( pSrcName, pSrc->GetType() );
+ }
+ pDst = m_hRoot->GetAttribute( pSrcName );
+ pDst->AddFlag( FATTRIB_USERDEFINED );
+
+ DmAttributeType_t srcType = pSrc->GetType();
+ DmAttributeType_t dstType = pDst->GetType();
+ if ( dstType == srcType )
+ {
+ pDst->SetValue( pSrc );
+ continue;
+ }
+
+ // Certain type conversions are allowed
+ switch( dstType )
+ {
+ case AT_BOOL:
+ if ( srcType == AT_INT )
+ {
+ pDst->SetValue( pSrc );
+ }
+ break;
+
+ case AT_INT:
+ if ( srcType == AT_BOOL )
+ {
+ pDst->SetValue( pSrc );
+ }
+ break;
+
+ case AT_COLOR:
+ if ( srcType == AT_VECTOR3 )
+ {
+ Color c;
+ int r, g, b;
+ Vector v = pSrc->GetValue<Vector>( );
+ v *= 255.0f;
+ r = clamp( v[0], 0, 255 );
+ g = clamp( v[1], 0, 255 );
+ b = clamp( v[2], 0, 255 );
+ c.SetColor( r, g, b, 255 );
+ pDst->SetValue( c );
+ }
+ break;
+ }
+ }
+
+ // Any shader parameter that isn't in the VMT make undefined
+ for ( pDst = m_hRoot->FirstAttribute(); pDst; pDst = pDst->NextAttribute() )
+ {
+ if ( !IsShaderParam( pDst ) )
+ continue;
+
+ if ( !pVMT->HasAttribute( pDst->GetName() ) )
+ {
+ // Special hack for alpha + colors
+ if ( !Q_stricmp( pDst->GetName(), "$alpha" ) )
+ {
+ pDst->SetValue( 1.0f );
+ }
+ else if ( pDst->GetType() == AT_COLOR )
+ {
+ Color c( 255, 255, 255, 255 );
+ pDst->SetValue( c );
+ }
+ else
+ {
+ pDst->SetToDefaultValue();
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Hooks the preview to an existing material, if there is one
+//-----------------------------------------------------------------------------
+void CVMTDoc::SetupPreviewMaterial( )
+{
+ // Extract a material name from the material
+ char pLocalName[MAX_PATH];
+
+ // relative paths can be passed in for in-game material picking
+ if ( !g_pFileSystem->FullPathToRelativePath( m_pFileName, pLocalName, sizeof(pLocalName) ) )
+ {
+ Q_strcpy( pLocalName, m_pFileName );
+ }
+
+ if ( Q_strnicmp( pLocalName, "materials", 9 ) )
+ goto noMaterialConnection;
+
+ // Skip the '/' also
+ char pMaterialName[MAX_PATH];
+ Q_StripExtension( pLocalName + 10, pMaterialName, sizeof(pMaterialName) );
+ IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( pMaterialName, "Editable material", false );
+ if ( !pMaterial || pMaterial->IsErrorMaterial() )
+ goto noMaterialConnection;
+
+ m_pPreviewMaterial.Init( pMaterial );
+ return;
+
+noMaterialConnection:
+ m_pPreviewMaterial.Init( m_pScratchMaterial );
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves/loads from file
+//-----------------------------------------------------------------------------
+bool CVMTDoc::LoadFromFile( const char *pFileName )
+{
+ Assert( !m_hRoot.Get() );
+
+ SetDirty( false );
+
+ Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
+ if ( !m_pFileName[0] )
+ return false;
+
+ // This is not undoable
+ CAppDisableUndoScopeGuard guard( "CVMTDoc::LoadFromFile", NOTIFY_CHANGE_OTHER );
+
+ // Create the main element
+ if ( !CreateRootElement() )
+ return false;
+
+ // change the filename of all the elements under the root, so we can unload the imported elements later
+ DmFileId_t rootFileId = g_pDataModel->GetFileId( m_pFileName );
+ g_pDataModel->SetFileName( rootFileId, "<temp>" );
+
+ // This will allow us to edit in context!
+ SetupPreviewMaterial( );
+
+ CDmElement *pIVMT = NULL;
+ g_pDataModel->RestoreFromFile( m_pFileName, NULL, "vmt", &pIVMT );
+ CDmElement *pVMT = CastElement< CDmElement >( pIVMT );
+ if ( !pVMT )
+ return false;
+
+ // FIXME: This is necessary so that all shader parameters appear in
+ // the same order, with the same type, as what you'd get using File->New.
+ // If we added a dependency to the material system into dmserializers,
+ // we could avoid this work here (I think!).
+ CopyParamsFromVMT( pVMT );
+
+ // unload the imported elements and change the root's filename back
+ DmFileId_t vmtFileId = g_pDataModel->GetFileId( m_pFileName );
+ g_pDataModel->RemoveFileId( vmtFileId );
+ g_pDataModel->SetFileName( rootFileId, m_pFileName );
+
+ SetDirty( false );
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Prior to saving to disk, extract all shader parameters which == the default
+//-----------------------------------------------------------------------------
+CDmElement* CVMTDoc::ExtractDefaultParameters( )
+{
+ CDmElement *pMaterial = m_hRoot->Copy( );
+
+ CDmAttribute* pAttribute = pMaterial->FirstAttribute();
+ CDmAttribute* pNextAttribute = NULL;
+ for ( ; pAttribute; pAttribute = pNextAttribute )
+ {
+ pNextAttribute = pAttribute->NextAttribute();
+
+ const char *pShaderParam = pAttribute->GetName();
+
+ // Check for standard params
+ int i;
+ for ( i = 0; g_pStandardParams[i].m_pParamName != NULL; ++i )
+ {
+ if ( !Q_stricmp( g_pStandardParams[i].m_pParamName, pShaderParam ) )
+ {
+ char temp[512];
+ CUtlBuffer buf( temp, sizeof(temp), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ pAttribute->Serialize( buf );
+
+ if ( !Q_stricmp( (char*)buf.Base(), g_pStandardParams[i].m_pDefaultValue ) )
+ {
+ // Buffers match! Therefore it's still using the default parameter
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ }
+ break;
+ }
+ }
+
+ // Standard attribute found, continue
+ if ( g_pStandardParams[i].m_pParamName )
+ continue;
+
+ // Only remove shader parameters
+ if ( !IsShaderParam( pAttribute ) )
+ continue;
+
+ // Remove flags whose value is 0
+ int nCount = g_pMaterialSystem->ShaderFlagCount();
+ for ( i = 0; i < nCount; ++i )
+ {
+ const char *pFlagName = g_pMaterialSystem->ShaderFlagName( i );
+ if ( !Q_stricmp( pShaderParam, pFlagName ) )
+ break;
+ }
+
+ // It's a flag! Remove the attribute if its value is 0
+ if ( i != nCount )
+ {
+ if ( pAttribute->GetValue<bool>( ) == 0 )
+ {
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ }
+ continue;
+ }
+
+ // FIXME: We can't do this.. the defaults in the strings need to be changed to
+ // make it so they actually match the true defaults
+ continue;
+
+ // Remove parameters which match the default value
+ nCount = m_pCurrentIShader->GetNumParams();
+ for ( i = 0; i < nCount; ++i )
+ {
+ // FIXME: Check type matches
+ if ( Q_stricmp( pShaderParam, m_pCurrentIShader->GetParamName( i ) ) )
+ continue;
+
+ // NOTE: This isn't particularly efficient. Too bad!
+ // It's hard to do efficiently owing to all the import conversion
+ char temp[512];
+ char temp2[512];
+ CUtlBuffer buf( temp, sizeof(temp), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ CUtlBuffer buf2( temp2, sizeof(temp2), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ pAttribute->Serialize( buf );
+ SetAttributeValueFromDefault( pMaterial, pAttribute, m_pCurrentIShader->GetParamDefault( i ) );
+ pAttribute->Serialize( buf2 );
+
+ if ( ( buf.TellMaxPut() == buf2.TellMaxPut() ) && !memcmp( buf.Base(), buf2.Base(), buf.TellMaxPut() ) )
+ {
+ // Buffers match! Therefore it's still using the default parameter
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ }
+ else
+ {
+ // Restore the actual value
+ pAttribute->Unserialize( buf );
+ }
+ break;
+ }
+ }
+
+ return pMaterial;
+}
+
+
+//-----------------------------------------------------------------------------
+// Saves to disk
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SaveToFile( )
+{
+ if ( m_hRoot.Get() && m_pFileName && m_pFileName[0] )
+ {
+ CDisableUndoScopeGuard guard;
+ CDmElement *pSaveRoot = ExtractDefaultParameters();
+ bool bOk = g_pDataModel->SaveToFile( m_pFileName, NULL, "keyvalues", "vmt", pSaveRoot );
+ DestroyElement( pSaveRoot, TD_DEEP );
+ if ( !bOk )
+ return false;
+ }
+
+ SetDirty( false );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Finds a shader
+//-----------------------------------------------------------------------------
+IShader *CVMTDoc::FindShader( const char *pShaderName )
+{
+ int nCount = g_pMaterialSystem->ShaderCount();
+ IShader **ppShaderList = (IShader**)_alloca( nCount * sizeof(IShader*) );
+ g_pMaterialSystem->GetShaders( 0, nCount, ppShaderList );
+ for ( int i = 0; i < nCount; ++i )
+ {
+ if ( !Q_stricmp( pShaderName, ppShaderList[i]->GetName() ) )
+ return ppShaderList[i];
+ }
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Is this attribute a shader parameter?
+//-----------------------------------------------------------------------------
+bool CVMTDoc::IsShaderParam( CDmAttribute* pAttribute )
+{
+ const char *pName = pAttribute->GetName();
+
+ // Shader params start with a $ or %
+ if ( pName[0] != '$' && pName[0] != '%' )
+ return false;
+
+ // Don't remove name, type, or id
+ if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) )
+ return false;
+
+ // All shader params have USERDEFINED set
+ if ( !pAttribute->IsFlagSet( FATTRIB_USERDEFINED ) )
+ return false;
+
+ // Don't remove arrays... those aren't shader parameters
+ if ( pAttribute->GetType() == AT_ELEMENT_ARRAY )
+ return false;
+
+ // Standard params aren't counted here
+ for ( int i = 0; g_pStandardParams[i].m_pParamName; ++i )
+ {
+ if ( !Q_stricmp( g_pStandardParams[i].m_pParamName, pName ) )
+ return false;
+ }
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Remove all shader parameters
+//-----------------------------------------------------------------------------
+void CVMTDoc::RemoveAllShaderParams( CDmElement *pMaterial )
+{
+ CDmAttribute* pAttribute;
+ CDmAttribute* pNextAttribute = NULL;
+ for ( pAttribute = pMaterial->FirstAttribute(); pAttribute; pAttribute = pNextAttribute )
+ {
+ pNextAttribute = pAttribute->NextAttribute();
+
+ // Only remove shader parameters
+ if ( !IsShaderParam( pAttribute ) )
+ continue;
+
+ m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Remove all shader parameters that don't exist in the new shader
+//-----------------------------------------------------------------------------
+void CVMTDoc::RemoveUnusedShaderParams( CDmElement *pMaterial, IShader *pShader, IShader *pOldShader )
+{
+ CDmAttribute* pAttribute = pMaterial->FirstAttribute();
+ CDmAttribute* pNextAttribute = NULL;
+ for ( ; pAttribute; pAttribute = pNextAttribute )
+ {
+ pNextAttribute = pAttribute->NextAttribute();
+
+ // Only remove shader parameters
+ if ( !IsShaderParam( pAttribute ) )
+ continue;
+
+ // Don't remove flags
+ int nCount = g_pMaterialSystem->ShaderFlagCount();
+ int i;
+ for ( i = 0; i < nCount; ++i )
+ {
+ const char *pFlagName = g_pMaterialSystem->ShaderFlagName( i );
+ if ( !Q_stricmp( pAttribute->GetName(), pFlagName ) )
+ break;
+ }
+
+ if ( i != nCount )
+ continue;
+
+ const char *pShaderParam = pAttribute->GetName();
+
+ // Remove parameters we've currently got but which don't exist in the new shader
+ nCount = pShader->GetNumParams();
+ for ( i = 0; i < nCount; ++i )
+ {
+ // FIXME: Check type matches
+ if ( !Q_stricmp( pShaderParam, pShader->GetParamName( i ) ) )
+ break;
+ }
+
+ // No match? Remove it!
+ if ( i == nCount )
+ {
+ m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ continue;
+ }
+
+ // Remove parameters from the old shader which match the default value
+ // This will make the default values update to the new shader's defaults
+ if ( pOldShader )
+ {
+ nCount = pOldShader->GetNumParams();
+ for ( i = 0; i < nCount; ++i )
+ {
+ // FIXME: Check type matches
+ if ( Q_stricmp( pShaderParam, pOldShader->GetParamName( i ) ) )
+ continue;
+
+ // NOTE: This isn't particularly efficient. Too bad!
+ // It's hard to do efficiently owing to all the import conversion
+ char temp1[512];
+ char temp2[512];
+ CUtlBuffer buf1( temp1, sizeof(temp1), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ CUtlBuffer buf2( temp2, sizeof(temp2), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ pAttribute->Serialize( buf1 );
+ SetAttributeValueFromDefault( pMaterial, pAttribute, pOldShader->GetParamDefault( i ) );
+ pAttribute->Serialize( buf2 );
+
+ if ( ( buf1.TellMaxPut() == buf2.TellMaxPut() ) && !memcmp( buf1.Base(), buf2.Base(), buf1.TellMaxPut() ) )
+ {
+ // Buffers match! Therefore it's still using the default parameter
+ m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
+ pMaterial->RemoveAttributeByPtr( pAttribute );
+ }
+ else
+ {
+ pAttribute->Unserialize( buf1 );
+ }
+ break;
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Add attribute for shader parameter
+//-----------------------------------------------------------------------------
+CDmAttribute* CVMTDoc::AddAttributeForShaderParameter( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType )
+{
+ CDmAttribute *pAttribute = NULL;
+ switch ( paramType )
+ {
+ case SHADER_PARAM_TYPE_INTEGER:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_INT );
+ break;
+
+ case SHADER_PARAM_TYPE_BOOL:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_BOOL );
+ break;
+
+ case SHADER_PARAM_TYPE_FLOAT:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_FLOAT );
+ break;
+
+ case SHADER_PARAM_TYPE_STRING:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
+ break;
+
+ case SHADER_PARAM_TYPE_COLOR:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_COLOR );
+ break;
+
+ case SHADER_PARAM_TYPE_VEC2:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR2 );
+ break;
+
+ case SHADER_PARAM_TYPE_VEC3:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR3 );
+ break;
+
+ case SHADER_PARAM_TYPE_VEC4:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR4 );
+ break;
+
+ case SHADER_PARAM_TYPE_FOURCC:
+ Assert( 0 );
+ break;
+
+ case SHADER_PARAM_TYPE_MATRIX:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_VMATRIX );
+ break;
+
+ case SHADER_PARAM_TYPE_TEXTURE:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
+ m_pCallback->AddShaderParameter( pParamName, "vtfpicker", "vtfName" );
+ break;
+
+ case SHADER_PARAM_TYPE_MATERIAL:
+ pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
+ m_pCallback->AddShaderParameter( pParamName, "vmtpicker", "vmtName" );
+ break;
+
+ default:
+ break;
+ }
+
+ if ( pAttribute )
+ {
+ pAttribute->AddFlag( FATTRIB_USERDEFINED );
+ }
+
+ return pAttribute;
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple methods to set vmatrix param values from strings (OLD METHOD!)
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SetVMatrixParamValue( CDmAttribute *pAttribute, const char *pValue )
+{
+ // FIXME: Change default strings to match DME?
+ // Then we could remove this crap
+ VMatrix mat;
+ int count = sscanf( pValue, " [ %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ]",
+ &mat.m[0][0], &mat.m[0][1], &mat.m[0][2], &mat.m[0][3],
+ &mat.m[1][0], &mat.m[1][1], &mat.m[1][2], &mat.m[1][3],
+ &mat.m[2][0], &mat.m[2][1], &mat.m[2][2], &mat.m[2][3],
+ &mat.m[3][0], &mat.m[3][1], &mat.m[3][2], &mat.m[3][3] );
+ if (count == 16)
+ {
+ pAttribute->SetValue( mat );
+ return true;
+ }
+
+ Vector2D scale, center;
+ float angle;
+ Vector2D translation;
+ count = sscanf( pValue, " center %f %f scale %f %f rotate %f translate %f %f",
+ &center.x, &center.y, &scale.x, &scale.y, &angle, &translation.x, &translation.y );
+ if (count != 7)
+ return false;
+
+ VMatrix temp;
+ MatrixBuildTranslation( mat, -center.x, -center.y, 0.0f );
+ MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
+ MatrixMultiply( temp, mat, mat );
+ MatrixBuildRotateZ( temp, angle );
+ MatrixMultiply( temp, mat, mat );
+ MatrixBuildTranslation( temp, center.x + translation.x, center.y + translation.y, 0.0f );
+ MatrixMultiply( temp, mat, mat );
+ pAttribute->SetValue( mat );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple methods to set vmatrix param values from strings (OLD METHOD!)
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SetVector2DParamValue( CDmAttribute *pAttribute, const char *pValue )
+{
+ Vector2D vec;
+ int count = sscanf( pValue, " [ %f %f ]", &vec[0], &vec[1] );
+ if ( count == 2 )
+ {
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ count = sscanf( pValue, " { %f %f }", &vec[0], &vec[1] );
+ if ( count == 2 )
+ {
+ vec /= 255.0f;
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple methods to set vmatrix param values from strings (OLD METHOD!)
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SetVector3DParamValue( CDmAttribute *pAttribute, const char *pValue )
+{
+ Vector vec;
+ int count = sscanf( pValue, " [ %f %f %f ]", &vec[0], &vec[1], &vec[2] );
+ if ( count == 3 )
+ {
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ count = sscanf( pValue, " { %f %f %f }", &vec[0], &vec[1], &vec[2] );
+ if ( count == 3 )
+ {
+ vec /= 255.0f;
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple methods to set vmatrix param values from strings (OLD METHOD!)
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SetVector4DParamValue( CDmAttribute *pAttribute, const char *pValue )
+{
+ Vector4D vec;
+ int count = sscanf( pValue, " [ %f %f %f %f ]", &vec[0], &vec[1], &vec[2], &vec[3] );
+ if ( count == 4 )
+ {
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ count = sscanf( pValue, " { %f %f %f %f }", &vec[0], &vec[1], &vec[2], &vec[3] );
+ if ( count == 4 )
+ {
+ vec /= 255.0f;
+ pAttribute->SetValue( vec );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// A couple methods to set vmatrix param values from strings (OLD METHOD!)
+//-----------------------------------------------------------------------------
+bool CVMTDoc::SetColorParamValue( CDmAttribute *pAttribute, const char *pValue )
+{
+ Color c;
+ int r, g, b;
+ Vector vec;
+ int count = sscanf( pValue, " [ %f %f %f ]", &vec[0], &vec[1], &vec[2] );
+ if ( count == 3 )
+ {
+ vec *= 255.0f;
+ r = clamp( vec[0], 0, 255 );
+ g = clamp( vec[1], 0, 255 );
+ b = clamp( vec[2], 0, 255 );
+ c.SetColor( r, g, b, 255 );
+ pAttribute->SetValue( c );
+ return true;
+ }
+
+ count = sscanf( pValue, " { %d %d %d }", &r, &g, &b );
+ if ( count == 3 )
+ {
+ c.SetColor( r, g, b, 255 );
+ pAttribute->SetValue( c );
+ return true;
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets an attribute value from the shader param default
+//-----------------------------------------------------------------------------
+void CVMTDoc::SetAttributeValueFromDefault( CDmElement *pMaterial, CDmAttribute *pAttribute, const char *pValue )
+{
+ // FIXME: Change default strings to match DME?
+ // Then we could remove this crap
+ switch ( pAttribute->GetType() )
+ {
+ case AT_VMATRIX:
+ if ( SetVMatrixParamValue( pAttribute, pValue ) )
+ return;
+ break;
+ case AT_COLOR:
+ if ( SetColorParamValue( pAttribute, pValue ) )
+ return;
+ break;
+ case AT_VECTOR2:
+ if ( SetVector2DParamValue( pAttribute, pValue ) )
+ return;
+ break;
+ case AT_VECTOR3:
+ if ( SetVector3DParamValue( pAttribute, pValue ) )
+ return;
+ break;
+ case AT_VECTOR4:
+ if ( SetVector4DParamValue( pAttribute, pValue ) )
+ return;
+ break;
+ }
+
+ pMaterial->SetValueFromString( pAttribute->GetName(), pValue );
+}
+
+
+//-----------------------------------------------------------------------------
+// Add a single shader parameter if it doesn't exist
+//-----------------------------------------------------------------------------
+void CVMTDoc::AddNewShaderParam( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType, const char *pValue )
+{
+ char temp[512];
+ Q_strncpy( temp, pParamName, sizeof(temp) );
+ Q_strlower( temp );
+ pParamName = temp;
+
+ CDmAttribute* pAttribute = NULL;
+ for ( pAttribute = pMaterial->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
+ {
+ // Don't bother testing against name, type, or id
+ if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) )
+ continue;
+
+ const char *pAttributeName = pAttribute->GetName();
+ if ( !Q_stricmp( pAttributeName, pParamName ) )
+ return;
+ }
+
+ // No match? Add it!
+ pAttribute = AddAttributeForShaderParameter( pMaterial, pParamName, paramType );
+ if ( pAttribute )
+ {
+ SetAttributeValueFromDefault( pMaterial, pAttribute, pValue );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Add all shader parameters that don't currently exist
+//-----------------------------------------------------------------------------
+void CVMTDoc::AddNewShaderParams( CDmElement *pMaterial, IShader *pShader )
+{
+ // First add all flags
+ m_pCallback->RemoveAllFlagParameters();
+ int nCount = g_pMaterialSystem->ShaderFlagCount();
+ int i;
+ for ( i = 0; i < nCount; ++i )
+ {
+ const char *pParamName = g_pMaterialSystem->ShaderFlagName( i );
+ AddNewShaderParam( pMaterial, pParamName, SHADER_PARAM_TYPE_BOOL, "0" );
+ m_pCallback->AddFlagParameter( pParamName );
+ }
+
+ // Next add all shader-specific parameters
+ nCount = pShader->GetNumParams();
+ for ( i = 0; i < nCount; ++i )
+ {
+ const char *pParamName = pShader->GetParamName( i );
+
+ // Don't add parameters that don't want to be editable
+ if ( pShader->GetParamFlags( i ) & SHADER_PARAM_NOT_EDITABLE )
+ continue;
+
+ ShaderParamType_t paramType = pShader->GetParamType( i );
+ const char *pDefault = pShader->GetParamDefault( i );
+ AddNewShaderParam( pMaterial, pParamName, paramType, pDefault );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets shader parameters to the default for that shader
+//-----------------------------------------------------------------------------
+void CVMTDoc::SetParamsToDefault()
+{
+ // This is undoable
+ CAppUndoScopeGuard guard( 0, "Set Params to Default", "Set Params to Default" );
+
+ // Next add all shader-specific parameters
+ int nCount = m_pCurrentIShader->GetNumParams();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ const char *pParamName = m_pCurrentIShader->GetParamName( i );
+
+ // Don't set parameters that don't want to be editable
+ if ( m_pCurrentIShader->GetParamFlags( i ) & SHADER_PARAM_NOT_EDITABLE )
+ continue;
+
+ char pAttributeName[512];
+ Q_strncpy( pAttributeName, pParamName, sizeof(pAttributeName) );
+ Q_strlower( pAttributeName );
+
+ if ( !m_hRoot->HasAttribute( pAttributeName ) )
+ continue;
+
+ CDmAttribute *pAttribute = m_hRoot->GetAttribute( pAttributeName );
+ const char *pDefault = m_pCurrentIShader->GetParamDefault( i );
+ SetAttributeValueFromDefault( m_hRoot, pAttribute, pDefault );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets the shader in the material
+//-----------------------------------------------------------------------------
+void CVMTDoc::SetShader( const char *pShaderName )
+{
+ // No change? don't bother
+ if ( !Q_stricmp( m_CurrentShader, pShaderName ) )
+ return;
+
+ m_CurrentShader = pShaderName;
+
+ // This is undoable
+ CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Set Shader", "Set Shader" );
+
+ char pActualShaderName[512];
+ g_pMaterialSystem->GetShaderFallback( pShaderName, pActualShaderName, sizeof(pActualShaderName) );
+
+ m_hRoot->SetValue( "shader", pShaderName );
+
+ // First, find the shader
+ IShader *pShader = FindShader( pActualShaderName );
+
+ // Remove all shader parameters that don't exist in the new shader
+ // And also remove shader parameters that do match the default value
+ RemoveUnusedShaderParams( m_hRoot, pShader, m_pCurrentIShader );
+
+ // Add all shader parameters that don't currently exist
+ AddNewShaderParams( m_hRoot, pShader );
+
+ m_pCurrentIShader = pShader;
+}
+
+
+//-----------------------------------------------------------------------------
+// Gets the preview material
+//-----------------------------------------------------------------------------
+IMaterial *CVMTDoc::GetPreviewMaterial()
+{
+ return m_pPreviewMaterial;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates the preview material
+//-----------------------------------------------------------------------------
+void CVMTDoc::UpdatePreviewMaterial()
+{
+ if ( !m_hRoot.Get() )
+ return;
+
+ // Update all shader parameters
+ SetShader( m_hRoot->GetValueString( "shader" ) );
+
+ // Use the file conversion to write to a text format
+ char buf[1024];
+ CUtlBuffer vmtBuf( buf, sizeof(buf), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
+ g_pDataModel->Serialize( vmtBuf, "vmt", "vmt", m_hRoot );
+
+ // Now use the text format to create a keyvalues
+ KeyValues *pVMTKeyValues = new KeyValues( "ShaderName" );
+ pVMTKeyValues->LoadFromBuffer( "VMT Preview", vmtBuf, g_pFileSystem, "GAME" );
+
+ // Finally, hook the keyvalues into the material.
+ m_pPreviewMaterial->SetShaderAndParams( pVMTKeyValues );
+ pVMTKeyValues->deleteThis();
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the root object
+//-----------------------------------------------------------------------------
+CDmElement *CVMTDoc::GetRootObject()
+{
+ return m_hRoot;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called when data changes
+//-----------------------------------------------------------------------------
+void CVMTDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
+ UpdatePreviewMaterial();
+ m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
+}
diff --git a/tools/vmt/vmtdoc.h b/tools/vmt/vmtdoc.h
new file mode 100644
index 0000000..8b9d876
--- /dev/null
+++ b/tools/vmt/vmtdoc.h
@@ -0,0 +1,133 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+
+#ifndef VMTDOC_H
+#define VMTDOC_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "dme_controls/inotifyui.h"
+#include "datamodel/dmehandle.h"
+#include "materialsystem/MaterialSystemUtil.h"
+#include "tier1/utlstring.h"
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class IVMTDocCallback;
+class IShader;
+enum ShaderParamType_t;
+class IMaterial;
+class IShader;
+
+
+//-----------------------------------------------------------------------------
+// Contains all editable state
+//-----------------------------------------------------------------------------
+class CVMTDoc : public IDmNotify
+{
+public:
+ CVMTDoc( IVMTDocCallback *pCallback );
+ ~CVMTDoc();
+
+ // Inherited from INotifyUI
+ virtual void NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Sets/Gets the file name
+ const char *GetFileName();
+ void SetFileName( const char *pFileName );
+
+ // Dirty bits (has it changed since the last time it was saved?)
+ void SetDirty( bool bDirty );
+ bool IsDirty() const;
+
+ // Creates a new act busy list
+ void CreateNew();
+
+ // Saves/loads from file
+ bool LoadFromFile( const char *pFileName );
+ bool SaveToFile( );
+
+ // Returns the root object
+ CDmElement *GetRootObject();
+
+ // Called when data changes (see INotifyUI for flags)
+ void OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+
+ // Sets the shader in the material
+ void SetShader( const char *pShaderName );
+
+ // Gets the preview material
+ IMaterial *GetPreviewMaterial();
+
+ // Sets shader parameters to the default for that shader
+ void SetParamsToDefault();
+
+private:
+ // Creates the root element
+ bool CreateRootElement();
+
+ // Add attribute for shader parameter
+ CDmAttribute* AddAttributeForShaderParameter( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType );
+
+ // Add a single shader parameter if it doesn't exist
+ void AddNewShaderParam( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType, const char *pValue );
+
+ // Add all shader parameters that don't currently exist
+ void AddNewShaderParams( CDmElement *pMaterial, IShader *pShader );
+
+ // Is this attribute a shader parameter?
+ bool IsShaderParam( CDmAttribute* pAttribute );
+
+ // Remove all shader parameters that don't exist in the new shader
+ void RemoveUnusedShaderParams( CDmElement *pMaterial, IShader *pShader, IShader *pOldShader );
+
+ // Remove all shader parameters
+ void RemoveAllShaderParams( CDmElement *pMaterial );
+
+ // Finds a shader
+ IShader *FindShader( const char *pShaderName );
+
+ // Updates the preview material
+ void UpdatePreviewMaterial();
+
+ // Copies VMT parameters into the root
+ void CopyParamsFromVMT( CDmElement *pVMT );
+
+ // A couple methods to set param values from strings (OLD METHOD!)
+ bool SetVMatrixParamValue( CDmAttribute *pAttribute, const char *pValue );
+ bool SetVector2DParamValue( CDmAttribute *pAttribute, const char *pValue );
+ bool SetVector3DParamValue( CDmAttribute *pAttribute, const char *pValue );
+ bool SetVector4DParamValue( CDmAttribute *pAttribute, const char *pValue );
+ bool SetColorParamValue( CDmAttribute *pAttribute, const char *pValue );
+
+ // Sets an attribute value from the shader param default
+ void SetAttributeValueFromDefault( CDmElement *pMaterial, CDmAttribute *pAttribute, const char *pValue );
+
+ // Hooks the preview to an existing material, if there is one
+ void SetupPreviewMaterial( );
+
+ // Prior to saving to disk, extract all shader parameters which == the default
+ CDmElement* ExtractDefaultParameters( );
+
+ IVMTDocCallback *m_pCallback;
+ CMaterialReference m_pScratchMaterial;
+ CMaterialReference m_pPreviewMaterial;
+ CDmeHandle< CDmElement > m_hRoot;
+ CUtlString m_CurrentShader;
+ IShader *m_pCurrentIShader;
+ char m_pFileName[512];
+ bool m_bDirty;
+};
+
+
+#endif // VMTDOC_H
diff --git a/tools/vmt/vmttool.cpp b/tools/vmt/vmttool.cpp
new file mode 100644
index 0000000..a42f672
--- /dev/null
+++ b/tools/vmt/vmttool.cpp
@@ -0,0 +1,1337 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Act busy tool; main UI smarts class
+//
+//=============================================================================
+
+#include "toolutils/basetoolsystem.h"
+#include "toolutils/toolmenubar.h"
+#include "toolutils/toolswitchmenubutton.h"
+#include "toolutils/toolfilemenubutton.h"
+#include "toolutils/tooleditmenubutton.h"
+#include "toolutils/toolmenubutton.h"
+#include "vgui_controls/Menu.h"
+#include "tier1/KeyValues.h"
+#include "toolutils/enginetools_int.h"
+#include "toolframework/ienginetool.h"
+#include "vgui/IInput.h"
+#include "vgui/KeyCode.h"
+#include "vgui_controls/FileOpenDialog.h"
+#include "filesystem.h"
+#include "vmtdoc.h"
+#include "vgui/ilocalize.h"
+#include "dme_controls/elementpropertiestree.h"
+#include "matsys_controls/vmtpanel.h"
+#include "vmttool.h"
+#include "movieobjects/dmeeditortypedictionary.h"
+#include "dme_controls/attributestringchoicepanel.h"
+#include "matsys_controls/mdlsequencepicker.h"
+#include "istudiorender.h"
+#include "materialsystem/imaterialsystem.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "toolutils/toolwindowfactory.h"
+#include "toolutils/basepropertiescontainer.h"
+#include "toolutils/savewindowpositions.h"
+#include "tier3/tier3.h"
+#include "tier2/fileutils.h"
+#include "vgui/ivgui.h"
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+CDmeEditorTypeDictionary *g_pEditorTypeDict;
+
+
+//-----------------------------------------------------------------------------
+// Methods needed by scenedatabase. They have to live here instead of toolutils
+// because this is a DLL but toolutils is only a static library
+//-----------------------------------------------------------------------------
+char const *GetVGuiControlsModuleName()
+{
+ return "VMTTool";
+}
+
+//-----------------------------------------------------------------------------
+// Connect, disconnect
+//-----------------------------------------------------------------------------
+bool ConnectTools( CreateInterfaceFn factory )
+{
+ return (g_pMDLCache != NULL) && (studiorender != NULL) && (materials != NULL) && (g_pMatSystemSurface != NULL);
+}
+
+void DisconnectTools( )
+{
+}
+
+
+//-----------------------------------------------------------------------------
+// Implementation of the act busy tool
+//-----------------------------------------------------------------------------
+class CVMTTool : public CBaseToolSystem, public IFileMenuCallbacks, public IVMTDocCallback
+{
+ DECLARE_CLASS_SIMPLE( CVMTTool, CBaseToolSystem );
+
+public:
+ CVMTTool();
+
+ // Inherited from IToolSystem
+ virtual char const *GetToolName() { return "Material Editor"; }
+ virtual const char *GetBindingsContextFile() { return "cfg/VMTTool.kb"; }
+ virtual bool Init();
+ virtual void Shutdown();
+ virtual bool CanQuit( );
+ virtual void PostMessage( HTOOLHANDLE hEntity, KeyValues *message );
+
+ // Inherited from IFileMenuCallbacks
+ virtual int GetFileMenuItemsEnabled( );
+ virtual void AddRecentFilesToMenu( vgui::Menu *menu );
+ virtual bool GetPerforceFileName( char *pFileName, int nMaxLen );
+ virtual vgui::Panel* GetRootPanel() { return this; }
+
+ // Inherited from IVMTDocCallback
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags );
+ virtual void AddShaderParameter( const char *pParam, const char *pWidget, const char *pTextType );
+ virtual void RemoveShaderParameter( const char *pParam );
+ virtual void AddFlagParameter( const char *pParam );
+ virtual void AddToolParameter( const char *pParam, const char *pWidget, const char *pTextType );
+ virtual void RemoveAllFlagParameters();
+ virtual void RemoveAllToolParameters();
+
+ // Inherited from CBaseToolSystem
+ virtual vgui::HScheme GetToolScheme();
+ virtual vgui::Menu *CreateActionMenu( vgui::Panel *pParent );
+ virtual void OnCommand( const char *cmd );
+ virtual const char *GetRegistryName() { return "VMT"; }
+ virtual vgui::MenuBar *CreateMenuBar( CBaseToolSystem *pParent );
+ virtual void OnToolActivate();
+ virtual void OnToolDeactivate();
+ virtual CVMTDoc *GetDocument();
+ virtual CBasePropertiesContainer *GetProperties();
+ virtual void SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual bool OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues );
+ virtual void OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues );
+
+public:
+ // Commands related to the file menu
+ MESSAGE_FUNC( OnNew, "OnNew" );
+ MESSAGE_FUNC( OnOpen, "OnOpen" );
+ MESSAGE_FUNC( OnSave, "OnSave" );
+ MESSAGE_FUNC( OnSaveAs, "OnSaveAs" );
+ MESSAGE_FUNC( OnClose, "OnClose" );
+ MESSAGE_FUNC( OnCloseNoSave, "OnCloseNoSave" );
+ MESSAGE_FUNC( OnMarkNotDirty, "OnMarkNotDirty" );
+ MESSAGE_FUNC( OnExit, "OnExit" );
+ void PerformNew();
+ void OpenFileFromHistory( int slot, const char *pCommand );
+ void OpenSpecificFile( const char *pFileName );
+
+ // Commands related to the edit menu
+ KEYBINDING_FUNC( undo, KEY_Z, vgui::MODIFIER_CONTROL, OnUndo, "#undo_help", 0 );
+ KEYBINDING_FUNC( redo, KEY_Z, vgui::MODIFIER_CONTROL | vgui::MODIFIER_SHIFT, OnRedo, "#redo_help", 0 );
+ void OnDescribeUndo();
+
+ // Methods related to the view menu
+ MESSAGE_FUNC( OnToggleProperties, "OnToggleProperties" );
+ MESSAGE_FUNC( OnToggleVMTPreview, "OnToggleVMTPreview" );
+ MESSAGE_FUNC( OnShowFlags, "OnShowFlags" );
+ MESSAGE_FUNC( OnShowToolParams, "OnShowToolParams" );
+ MESSAGE_FUNC( OnDefaultLayout, "OnDefaultLayout" );
+
+ // Methods related to the material menu
+ MESSAGE_FUNC( OnSetParamsToDefault, "OnSetParamsToDefault" );
+
+ // Returns the VMT preview window
+ CVMTPanel *GetVMTPreview();
+
+ // Which parameters are visible?
+ bool IsFlagParamsVisible() const;
+ bool IsToolParamsVisible() const;
+
+private:
+ // Flags for HideStandardFields
+ enum EditorTypeStandardFields_t
+ {
+ EDITOR_FIELD_NAME = 0x1,
+ EDITOR_FIELD_TYPE = 0x2,
+ EDITOR_FIELD_ID = 0x4,
+ EDITOR_FIELD_EDITORTYPE = 0x8,
+ };
+
+ void HideStandardFields( CDmeEditorType *pEditorType, int nFieldFlags );
+
+ // Creates a new document
+ void NewDocument( );
+
+ // Loads up a new document
+ bool LoadDocument( char const *pDocName );
+
+ // Updates the menu bar based on the current file
+ void UpdateMenuBar( );
+
+ // Shows element properties
+ void ShowElementProperties( );
+
+ // Create custom editors
+ void InitEditorDict();
+
+ void CreateTools( CVMTDoc *doc );
+ void InitTools();
+ void DestroyTools();
+
+ void ToggleToolWindow( Panel *tool, char const *toolName );
+ void ShowToolWindow( Panel *tool, char const *toolName, bool visible );
+
+ void DestroyToolContainers();
+
+ virtual char const *GetLogoTextureName();
+
+private:
+ // All editable data
+ CVMTDoc *m_pDoc;
+
+ // The menu bar
+ CToolFileMenuBar *m_pMenuBar;
+
+ // Element properties for editing material
+ vgui::DHANDLE< CBasePropertiesContainer > m_hProperties;
+
+ // The sequence picker!
+ vgui::DHANDLE< CVMTPanel > m_hVMTPreview;
+
+ // The VMT editor type
+ CDmeEditorType *m_pVMTType;
+
+ // Separate undo context for the act busy tool
+ CToolWindowFactory< ToolWindow > m_ToolWindowFactory;
+
+ // List of tool + flag parameters
+ CUtlVector<CUtlString> m_ToolParams;
+ CUtlVector<CUtlString> m_FlagParams;
+
+ bool m_bToolParamsVisible;
+ bool m_bFlagParamsVisible;
+
+ CUtlVector< DmElementHandle_t > m_toolElements;
+};
+
+
+//-----------------------------------------------------------------------------
+// Singleton
+//-----------------------------------------------------------------------------
+CVMTTool *g_pVMTTool = NULL;
+
+void CreateTools()
+{
+ g_pVMTTool = new CVMTTool();
+}
+
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CVMTTool::CVMTTool()
+{
+ m_pVMTType = NULL;
+ m_pMenuBar = NULL;
+ m_pDoc = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CVMTTool::Init()
+{
+ m_bToolParamsVisible = false;
+ m_bFlagParamsVisible = true;
+ m_pDoc = NULL;
+ m_RecentFiles.LoadFromRegistry( GetRegistryName() );
+
+ // NOTE: This has to happen before BaseClass::Init
+ g_pVGuiLocalize->AddFile( "resource/toolvmt_%language%.txt" );
+
+ if ( !BaseClass::Init() )
+ return false;
+
+ InitEditorDict();
+
+ return true;
+}
+
+void CVMTTool::Shutdown()
+{
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+
+ {
+ CDisableUndoScopeGuard sg;
+ int nElements = m_toolElements.Count();
+ for ( int i = 0; i < nElements; ++i )
+ {
+ g_pDataModel->DestroyElement( m_toolElements[ i ] );
+ }
+ }
+
+ BaseClass::Shutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// Tool activation/deactivation
+//-----------------------------------------------------------------------------
+void CVMTTool::OnToolActivate()
+{
+ BaseClass::OnToolActivate();
+}
+
+void CVMTTool::OnToolDeactivate()
+{
+ BaseClass::OnToolDeactivate();
+}
+
+
+//-----------------------------------------------------------------------------
+// Hides standard fields
+//-----------------------------------------------------------------------------
+void CVMTTool::HideStandardFields( CDmeEditorType *pEditorType, int nFieldFlags )
+{
+ CDmeEditorAttributeInfo *pInfo;
+
+ if ( nFieldFlags & EDITOR_FIELD_NAME )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "name info", pEditorType->GetFileId() );
+ pEditorType->AddAttributeInfo( "name", pInfo );
+ pInfo->m_bIsVisible = false;
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+
+ if ( nFieldFlags & EDITOR_FIELD_TYPE )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "type info", pEditorType->GetFileId() );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "type", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+
+ if ( nFieldFlags & EDITOR_FIELD_ID )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "id info", pEditorType->GetFileId() );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "id", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+
+ if ( nFieldFlags & EDITOR_FIELD_EDITORTYPE )
+ {
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "editor type info", pEditorType->GetFileId() );
+ pInfo->m_bIsVisible = false;
+ pEditorType->AddAttributeInfo( "editorType", pInfo );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Update the editor dict based on the current material parameters
+//-----------------------------------------------------------------------------
+void CVMTTool::AddShaderParameter( const char *pParam, const char *pWidget, const char *pTextType )
+{
+ // anims only accept activity names
+ CDmeEditorAttributeInfo *pInfo = CreateElement< CDmeEditorAttributeInfo >( "shader param info", m_pVMTType->GetFileId() );
+ m_pVMTType->AddAttributeInfo( pParam, pInfo );
+ pInfo->m_Widget = pWidget;
+ if ( pTextType )
+ {
+ pInfo->SetValue( "texttype", pTextType );
+ }
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+}
+
+
+//-----------------------------------------------------------------------------
+// Update the editor dict based on the current material parameters
+//-----------------------------------------------------------------------------
+void CVMTTool::RemoveShaderParameter( const char *pParam )
+{
+ m_pVMTType->RemoveAttributeInfo( pParam );
+}
+
+
+//-----------------------------------------------------------------------------
+// Which parameters are visible?
+//-----------------------------------------------------------------------------
+inline bool CVMTTool::IsFlagParamsVisible() const
+{
+ return m_bFlagParamsVisible;
+}
+
+inline bool CVMTTool::IsToolParamsVisible() const
+{
+ return m_bToolParamsVisible;
+}
+
+
+//-----------------------------------------------------------------------------
+// Adds flags, tool parameters
+//-----------------------------------------------------------------------------
+void CVMTTool::AddFlagParameter( const char *pParam )
+{
+ Assert( m_pVMTType->GetAttributeInfo( pParam ) == NULL );
+
+ int i = m_FlagParams.AddToTail( );
+ m_FlagParams[i] = pParam;
+
+ CDmeEditorAttributeInfo *pInfo = CreateElement< CDmeEditorAttributeInfo >( "flag param info", m_pVMTType->GetFileId() );
+ m_pVMTType->AddAttributeInfo( pParam, pInfo );
+ pInfo->m_bIsVisible = m_bFlagParamsVisible;
+ pInfo->m_Widget = NULL;
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+}
+
+void CVMTTool::AddToolParameter( const char *pParam, const char *pWidget, const char *pTextType )
+{
+ Assert( m_pVMTType->GetAttributeInfo( pParam ) == NULL );
+
+ int i = m_ToolParams.AddToTail( );
+ m_ToolParams[i] = pParam;
+
+ CDmeEditorAttributeInfo *pInfo = CreateElement< CDmeEditorAttributeInfo >( "tool param info", m_pVMTType->GetFileId() );
+ m_pVMTType->AddAttributeInfo( pParam, pInfo );
+ pInfo->m_bIsVisible = m_bToolParamsVisible;
+ pInfo->m_Widget = pWidget;
+ if ( pTextType )
+ {
+ pInfo->SetValue( "texttype", pTextType );
+ }
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+}
+
+void CVMTTool::RemoveAllFlagParameters()
+{
+ int nCount = m_FlagParams.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ RemoveShaderParameter( m_FlagParams[i] );
+ }
+ m_FlagParams.RemoveAll();
+}
+
+void CVMTTool::RemoveAllToolParameters()
+{
+ int nCount = m_ToolParams.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ RemoveShaderParameter( m_ToolParams[i] );
+ }
+ m_ToolParams.RemoveAll();
+}
+
+
+//-----------------------------------------------------------------------------
+// Create custom editors
+//-----------------------------------------------------------------------------
+void CVMTTool::InitEditorDict()
+{
+ CDmeEditorAttributeInfo *pInfo;
+
+ // FIXME: This eventually will move to an .fgd-like file.
+ g_pEditorTypeDict = CreateElement< CDmeEditorTypeDictionary >( "DmeEditorTypeDictionary", DMFILEID_INVALID );
+ m_toolElements.AddToTail( g_pEditorTypeDict->GetHandle() );
+
+ m_pVMTType = CreateElement< CDmeEditorType >( "vmt", DMFILEID_INVALID );
+ HideStandardFields( m_pVMTType, EDITOR_FIELD_NAME | EDITOR_FIELD_TYPE | EDITOR_FIELD_ID | EDITOR_FIELD_EDITORTYPE );
+ g_pEditorTypeDict->AddEditorType( m_pVMTType );
+ m_toolElements.AddToTail( m_pVMTType->GetHandle() );
+
+ // Create a picker for the shader name
+ pInfo = CreateElement< CDmeEditorAttributeInfo >( "shader name info", DMFILEID_INVALID );
+ m_pVMTType->AddAttributeInfo( "shader", pInfo );
+ pInfo->m_Widget = "shaderpicker";
+ pInfo->SetValue( "texttype", "shaderName" );
+ m_toolElements.AddToTail( pInfo->GetHandle() );
+}
+
+
+
+//-----------------------------------------------------------------------------
+//
+// The Material menu
+//
+//-----------------------------------------------------------------------------
+class CVMTMaterialMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CVMTMaterialMenuButton, CToolMenuButton );
+public:
+ CVMTMaterialMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+};
+
+CVMTMaterialMenuButton::CVMTMaterialMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ AddMenuItem( "default", "#VMTSetToDefault", new KeyValues( "OnSetParamsToDefault" ), pActionSignalTarget );
+ SetMenu(m_pMenu);
+}
+
+void CVMTMaterialMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CVMTDoc *pDoc = g_pVMTTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "default" );
+ m_pMenu->SetItemEnabled( id, true );
+ }
+ else
+ {
+ id = m_Items.Find( "default" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+//
+// The View menu
+//
+//-----------------------------------------------------------------------------
+class CVMTViewMenuButton : public CToolMenuButton
+{
+ DECLARE_CLASS_SIMPLE( CVMTViewMenuButton, CToolMenuButton );
+public:
+ CVMTViewMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget );
+ virtual void OnShowMenu(vgui::Menu *menu);
+};
+
+CVMTViewMenuButton::CVMTViewMenuButton( vgui::Panel *parent, const char *panelName, const char *text, vgui::Panel *pActionSignalTarget )
+ : BaseClass( parent, panelName, text, pActionSignalTarget )
+{
+ AddCheckableMenuItem( "properties", "#VMTProperties", new KeyValues( "OnToggleProperties" ), pActionSignalTarget );
+ AddCheckableMenuItem( "preview", "#VMTPreview", new KeyValues( "OnToggleVMTPreview" ), pActionSignalTarget );
+
+ AddSeparator();
+
+ AddCheckableMenuItem( "showflagparams", "#VMTShowFlags", new KeyValues( "OnShowFlags" ), pActionSignalTarget );
+ AddCheckableMenuItem( "showtoolparams", "#VMTShowToolParams", new KeyValues( "OnShowToolParams" ), pActionSignalTarget );
+
+ AddSeparator();
+
+ AddMenuItem( "defaultlayout", "#VMTViewDefault", new KeyValues( "OnDefaultLayout" ), pActionSignalTarget );
+
+ SetMenu(m_pMenu);
+}
+
+void CVMTViewMenuButton::OnShowMenu(vgui::Menu *menu)
+{
+ BaseClass::OnShowMenu( menu );
+
+ // Update the menu
+ int id;
+
+ CVMTDoc *pDoc = g_pVMTTool->GetDocument();
+ if ( pDoc )
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ Panel *p;
+ p = g_pVMTTool->GetProperties();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "preview" );
+ m_pMenu->SetItemEnabled( id, true );
+
+ p = g_pVMTTool->GetVMTPreview();
+ Assert( p );
+ m_pMenu->SetMenuItemChecked( id, ( p && p->GetParent() ) ? true : false );
+
+ id = m_Items.Find( "showflagparams" );
+ m_pMenu->SetItemEnabled( id, true );
+ m_pMenu->SetMenuItemChecked( id, g_pVMTTool->IsFlagParamsVisible() );
+
+ id = m_Items.Find( "showtoolparams" );
+ m_pMenu->SetItemEnabled( id, true );
+ m_pMenu->SetMenuItemChecked( id, g_pVMTTool->IsToolParamsVisible() );
+ }
+ else
+ {
+ id = m_Items.Find( "properties" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "preview" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "showflagparams" );
+ m_pMenu->SetItemEnabled( id, false );
+ id = m_Items.Find( "showtoolparams" );
+ m_pMenu->SetItemEnabled( id, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the menu bar
+//-----------------------------------------------------------------------------
+vgui::MenuBar *CVMTTool::CreateMenuBar( CBaseToolSystem *pParent )
+{
+ m_pMenuBar = new CToolFileMenuBar( pParent, "VMTMenuBar" );
+
+ // Sets info in the menu bar
+ char title[ 64 ];
+ ComputeMenuBarTitle( title, sizeof( title ) );
+ m_pMenuBar->SetInfo( title );
+ m_pMenuBar->SetToolName( GetToolName() );
+ UpdateMenuBar();
+
+ // Add menu buttons
+ CToolMenuButton *pFileButton = CreateToolFileMenuButton( m_pMenuBar, "File", "&File", GetActionTarget(), this );
+ CToolMenuButton *pEditButton = CreateToolEditMenuButton( m_pMenuBar, "Edit", "&Edit", GetActionTarget() );
+ CToolMenuButton *pMaterialButton = new CVMTMaterialMenuButton( m_pMenuBar, "Material", "&Material", GetActionTarget() );
+ CToolMenuButton *pSwitchButton = CreateToolSwitchMenuButton( m_pMenuBar, "Switcher", "&Tools", GetActionTarget() );
+ CVMTViewMenuButton *pViewButton = new CVMTViewMenuButton( m_pMenuBar, "View", "&View", GetActionTarget() );
+
+ m_pMenuBar->AddButton( pFileButton );
+ m_pMenuBar->AddButton( pEditButton );
+ m_pMenuBar->AddButton( pMaterialButton );
+ m_pMenuBar->AddButton( pViewButton );
+ m_pMenuBar->AddButton( pSwitchButton );
+
+ return m_pMenuBar;
+}
+
+
+//-----------------------------------------------------------------------------
+// Updates the menu bar based on the current file
+//-----------------------------------------------------------------------------
+void CVMTTool::UpdateMenuBar( )
+{
+ if ( !m_pDoc )
+ {
+ m_pMenuBar->SetFileName( "#VMTNoFile" );
+ return;
+ }
+
+ if ( m_pDoc->IsDirty() )
+ {
+ char sz[ 512 ];
+ Q_snprintf( sz, sizeof( sz ), "* %s", m_pDoc->GetFileName() );
+ m_pMenuBar->SetFileName( sz );
+ }
+ else
+ {
+ m_pMenuBar->SetFileName( m_pDoc->GetFileName() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IFileMenuCallbacks
+//-----------------------------------------------------------------------------
+int CVMTTool::GetFileMenuItemsEnabled( )
+{
+ int nFlags;
+ if ( !m_pDoc )
+ {
+ nFlags = FILE_NEW | FILE_OPEN | FILE_RECENT | FILE_CLEAR_RECENT | FILE_EXIT;
+ }
+ else
+ {
+ nFlags = FILE_ALL;
+ }
+
+ if ( m_RecentFiles.IsEmpty() )
+ {
+ nFlags &= ~(FILE_RECENT | FILE_CLEAR_RECENT);
+ }
+ return nFlags;
+}
+
+void CVMTTool::AddRecentFilesToMenu( vgui::Menu *pMenu )
+{
+ m_RecentFiles.AddToMenu( pMenu, GetActionTarget(), "OnRecent" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Returns the file name for perforce
+//-----------------------------------------------------------------------------
+bool CVMTTool::GetPerforceFileName( char *pFileName, int nMaxLen )
+{
+ if ( !m_pDoc )
+ return false;
+ Q_strncpy( pFileName, m_pDoc->GetFileName(), nMaxLen );
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get a new scheme to be applied to this tool
+//-----------------------------------------------------------------------------
+vgui::HScheme CVMTTool::GetToolScheme()
+{
+ return vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Creates the action menu
+//-----------------------------------------------------------------------------
+vgui::Menu *CVMTTool::CreateActionMenu( vgui::Panel *pParent )
+{
+ vgui::Menu *pActionMenu = new Menu( pParent, "ActionMenu" );
+ pActionMenu->AddMenuItem( "#ToolHide", new KeyValues( "Command", "command", "HideActionMenu" ), GetActionTarget() );
+ return pActionMenu;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+//-----------------------------------------------------------------------------
+void CVMTTool::OnExit()
+{
+ // Throw up a "save" dialog?
+ enginetools->Command( "quit\n" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Handle commands from the action menu and other menus
+//-----------------------------------------------------------------------------
+void CVMTTool::OnCommand( const char *cmd )
+{
+ if ( !V_stricmp( cmd, "HideActionMenu" ) )
+ {
+ if ( GetActionMenu() )
+ {
+ GetActionMenu()->SetVisible( false );
+ }
+ }
+ else if ( !V_stricmp( cmd, "OnUndo" ) )
+ {
+ OnUndo();
+ }
+ else if ( !V_stricmp( cmd, "OnRedo" ) )
+ {
+ OnRedo();
+ }
+ else if ( !V_stricmp( cmd, "OnDescribeUndo" ) )
+ {
+ OnDescribeUndo();
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnRecent" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ g_pVMTTool->OpenFileFromHistory( idx, cmd );
+ }
+ else if ( const char *pSuffix = StringAfterPrefix( cmd, "OnTool" ) )
+ {
+ int idx = Q_atoi( pSuffix );
+ enginetools->SwitchToTool( idx );
+ }
+ else
+ {
+ BaseClass::OnCommand( cmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Messages from the engine
+//-----------------------------------------------------------------------------
+void CVMTTool::PostMessage( HTOOLHANDLE hEntity, KeyValues *message )
+{
+ if ( !Q_stricmp( message->GetName(), "EditMaterial" ) )
+ {
+ const char *pMaterialName = message->GetString( "material", "debug/debugempty" );
+
+ char pLocalPath[ MAX_PATH ];
+ char pAbsPath[ MAX_PATH ];
+ if ( pMaterialName[0] == '/' && pMaterialName[1] == '/' && pMaterialName[2] != '/' )
+ {
+ Q_strncpy( pAbsPath, pMaterialName, sizeof(pAbsPath) );
+ Q_DefaultExtension( pAbsPath, ".vmt", sizeof(pAbsPath) );
+ }
+ else
+ {
+ Q_snprintf( pLocalPath, sizeof(pLocalPath), "materials/%s", pMaterialName );
+ Q_DefaultExtension( pLocalPath, ".vmt", sizeof(pLocalPath) );
+ g_pFileSystem->RelativePathToFullPath( pLocalPath, "GAME", pAbsPath, sizeof(pAbsPath) );
+ }
+
+ Q_FixSlashes( pAbsPath );
+ OpenSpecificFile( pAbsPath );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Derived classes can implement this to get notified when files are saved/loaded
+//-----------------------------------------------------------------------------
+void CVMTTool::OnFileOperationCompleted( const char *pFileType, bool bWroteFile, vgui::FileOpenStateMachine::CompletionState_t state, KeyValues *pContextKeyValues )
+{
+ if ( bWroteFile )
+ {
+ OnMarkNotDirty();
+ }
+
+ if ( !pContextKeyValues )
+ return;
+
+ if ( state != FileOpenStateMachine::SUCCESSFUL )
+ return;
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnNew" ) )
+ {
+ PerformNew();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnClose" ) )
+ {
+ OnCloseNoSave();
+ return;
+ }
+
+ if ( !Q_stricmp( pContextKeyValues->GetName(), "OnQuit" ) )
+ {
+ OnCloseNoSave();
+ vgui::ivgui()->PostMessage( GetVPanel(), new KeyValues( "OnExit" ), 0 );
+ return;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by SaveFile to allow clients to set up the save dialog
+//-----------------------------------------------------------------------------
+void CVMTTool::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog, bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ // Compute starting directory
+ char pStartingDir[ MAX_PATH ];
+ GetModSubdirectory( "materials", pStartingDir, sizeof(pStartingDir) );
+
+ if ( bOpenFile )
+ {
+ pDialog->SetTitle( "Open Material .VMT File", true );
+ }
+ else
+ {
+ pDialog->SetTitle( "Save Material .VMT File As", true );
+ }
+
+ pDialog->SetStartDirectoryContext( "vmt_session", pStartingDir );
+ pDialog->AddFilter( "*.vmt", "VMT (*.vmt)", true );
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by SaveFile to allow clients to actually write the file out
+//-----------------------------------------------------------------------------
+bool CVMTTool::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ OnCloseNoSave();
+ if ( !LoadDocument( pFileName ) )
+ return false;
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Called by SaveFile to allow clients to actually write the file out
+//-----------------------------------------------------------------------------
+bool CVMTTool::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
+{
+ if ( !m_pDoc )
+ return true;
+
+ m_pDoc->SetFileName( pFileName );
+ if ( !m_pDoc->SaveToFile( ) )
+ return false;
+
+ m_RecentFiles.Add( pFileName, pFileFormat );
+ m_RecentFiles.SaveToRegistry( GetRegistryName() );
+ UpdateMenuBar();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Command handlers
+//-----------------------------------------------------------------------------
+void CVMTTool::PerformNew()
+{
+ OnCloseNoSave();
+ NewDocument();
+}
+
+void CVMTTool::OnNew()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetFileName(), "vmt", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnNew" ) );
+ return;
+ }
+ PerformNew();
+}
+
+void CVMTTool::OnOpen( )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetFileName();
+ }
+
+ OpenFile( "vmt", pSaveFileName, "vmt", nFlags );
+}
+
+void CVMTTool::OnSave()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( m_pDoc->GetFileName(), "vmt", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CVMTTool::OnSaveAs()
+{
+ if ( m_pDoc )
+ {
+ SaveFile( NULL, "vmt", FOSM_SHOW_PERFORCE_DIALOGS );
+ }
+}
+
+void CVMTTool::OnClose()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ SaveFile( m_pDoc->GetFileName(), "vmt", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnClose" ) );
+ return;
+ }
+
+ OnCloseNoSave();
+}
+
+void CVMTTool::OnCloseNoSave()
+{
+ DestroyTools();
+
+ if ( m_pDoc )
+ {
+ CAppNotifyScopeGuard sg( "CVMTTool::OnCloseNoSave", NOTIFY_CHANGE_OTHER );
+
+ delete m_pDoc;
+ m_pDoc = NULL;
+
+ if ( m_hProperties )
+ {
+ m_hProperties->SetObject( NULL );
+ }
+ }
+
+ UpdateMenuBar( );
+}
+
+void CVMTTool::OnMarkNotDirty()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->SetDirty( false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Open a specific file
+//-----------------------------------------------------------------------------
+void CVMTTool::OpenSpecificFile( const char *pFileName )
+{
+ int nFlags = 0;
+ const char *pSaveFileName = NULL;
+ if ( m_pDoc )
+ {
+ // File is already open
+ if ( !Q_stricmp( m_pDoc->GetFileName(), pFileName ) )
+ return;
+
+ if ( m_pDoc->IsDirty() )
+ {
+ nFlags = FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY;
+ pSaveFileName = m_pDoc->GetFileName();
+ }
+ }
+
+ OpenFile( pFileName, "vmt", pSaveFileName, "vmt", nFlags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Show the save document query dialog
+//-----------------------------------------------------------------------------
+void CVMTTool::OpenFileFromHistory( int slot, const char *pCommand )
+{
+ const char *pFileName = m_RecentFiles.GetFile( slot );
+ if ( !pFileName )
+ return;
+ OpenSpecificFile( pFileName );
+}
+
+bool CVMTTool::CanQuit()
+{
+ if ( m_pDoc && m_pDoc->IsDirty() )
+ {
+ // Show Save changes Yes/No/Cancel and re-quit if hit yes/no
+ SaveFile( m_pDoc->GetFileName(), "vmt", FOSM_SHOW_PERFORCE_DIALOGS | FOSM_SHOW_SAVE_QUERY,
+ new KeyValues( "OnQuit" ) );
+ return false;
+ }
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Various command handlers related to the Edit menu
+//-----------------------------------------------------------------------------
+void CVMTTool::OnUndo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Undo();
+}
+
+void CVMTTool::OnRedo()
+{
+ CDisableUndoScopeGuard guard;
+ g_pDataModel->Redo();
+}
+
+void CVMTTool::OnDescribeUndo()
+{
+ CUtlVector< UndoInfo_t > list;
+ g_pDataModel->GetUndoInfo( list );
+
+ Msg( "%i operations in stack\n", list.Count() );
+
+ for ( int i = list.Count() - 1; i >= 0; --i )
+ {
+ UndoInfo_t& entry = list[ i ];
+ if ( entry.terminator )
+ {
+ Msg( "[ '%s' ] - %i operations\n", entry.undo, entry.numoperations );
+ }
+
+ Msg( " +%s\n", entry.desc );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Inherited from IVMTDocCallback
+//-----------------------------------------------------------------------------
+void CVMTTool::OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
+{
+ UpdateMenuBar();
+ if ( ( nNotifySource != NOTIFY_SOURCE_PROPERTIES_TREE ) && m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : CVMTDoc
+//-----------------------------------------------------------------------------
+CVMTDoc *CVMTTool::GetDocument()
+{
+ return m_pDoc;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : -
+// Output : virtual CBasePropertiesContainer
+//-----------------------------------------------------------------------------
+CBasePropertiesContainer *CVMTTool::GetProperties()
+{
+ return m_hProperties.Get();
+}
+
+CVMTPanel *CVMTTool::GetVMTPreview()
+{
+ return m_hVMTPreview.Get();
+}
+
+
+//-----------------------------------------------------------------------------
+// Initializes the tools
+//-----------------------------------------------------------------------------
+void CVMTTool::InitTools()
+{
+ ShowElementProperties();
+
+ // FIXME: There are no tool windows here; how should this work?
+ // These panels are saved
+ windowposmgr->RegisterPanel( "properties", m_hProperties, false );
+ windowposmgr->RegisterPanel( "vmtpanel", m_hVMTPreview, false );
+
+ if ( !windowposmgr->LoadPositions( "cfg/vmt.txt", this, &m_ToolWindowFactory, "VMT" ) )
+ {
+ OnDefaultLayout();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+bool CVMTTool::LoadDocument( char const *pDocName )
+{
+ Assert( !m_pDoc );
+
+ DestroyTools();
+
+ m_pDoc = new CVMTDoc( this );
+ if ( !m_pDoc->LoadFromFile( pDocName ) )
+ {
+ delete m_pDoc;
+ m_pDoc = NULL;
+ Warning( "Fatal error loading '%s'\n", pDocName );
+ return false;
+ }
+
+ CreateTools( m_pDoc );
+ InitTools();
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Loads up a new document
+//-----------------------------------------------------------------------------
+void CVMTTool::NewDocument( )
+{
+ Assert( !m_pDoc );
+
+ m_pDoc = new CVMTDoc( this );
+ m_pDoc->CreateNew( );
+
+ CreateTools( m_pDoc );
+ UpdateMenuBar( );
+ InitTools();
+}
+
+
+//-----------------------------------------------------------------------------
+// Shows element properties
+//-----------------------------------------------------------------------------
+void CVMTTool::ShowElementProperties( )
+{
+ if ( !m_pDoc )
+ return;
+
+ if ( !m_pDoc->GetRootObject() )
+ return;
+
+ // It should already exist
+ Assert( m_hProperties.Get() );
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->SetObject( m_pDoc->GetRootObject() );
+ }
+}
+
+void CVMTTool::DestroyTools()
+{
+ windowposmgr->SavePositions( "cfg/vmt.txt", "VMT" );
+
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+
+ UnregisterAllToolWindows();
+ if ( m_hProperties.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hProperties.Get() );
+ delete m_hProperties.Get();
+ m_hProperties = NULL;
+ }
+ if ( m_hVMTPreview.Get() )
+ {
+ windowposmgr->UnregisterPanel( m_hVMTPreview.Get() );
+ delete m_hVMTPreview.Get();
+ m_hVMTPreview = NULL;
+ }
+}
+
+void CVMTTool::CreateTools( CVMTDoc *doc )
+{
+ if ( !m_hProperties.Get() )
+ {
+ m_hProperties = new CBasePropertiesContainer( NULL, m_pDoc, g_pEditorTypeDict );
+ }
+ if ( !m_hVMTPreview.Get() )
+ {
+ m_hVMTPreview = new CVMTPanel( NULL, "VMT Preview" );
+ SETUP_PANEL( m_hVMTPreview.Get() );
+ m_hVMTPreview->SetMaterial( m_pDoc->GetPreviewMaterial() );
+ }
+ RegisterToolWindow( m_hProperties );
+ RegisterToolWindow( m_hVMTPreview );
+}
+
+void CVMTTool::ShowToolWindow( Panel *tool, char const *toolName, bool visible )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL && visible )
+ {
+ m_ToolWindowFactory.InstanceToolWindow( this, false, tool, toolName, false );
+ }
+ else if ( !visible )
+ {
+ ToolWindow *tw = dynamic_cast< ToolWindow * >( tool->GetParent()->GetParent() );
+ Assert( tw );
+ tw->RemovePage( tool );
+ }
+}
+
+void CVMTTool::ToggleToolWindow( Panel *tool, char const *toolName )
+{
+ Assert( tool );
+
+ if ( tool->GetParent() == NULL )
+ {
+ ShowToolWindow( tool, toolName, true );
+ }
+ else
+ {
+ ShowToolWindow( tool, toolName, false );
+ }
+}
+
+void CVMTTool::DestroyToolContainers()
+{
+ int c = ToolWindow::GetToolWindowCount();
+ for ( int i = c - 1; i >= 0 ; --i )
+ {
+ ToolWindow *kill = ToolWindow::GetToolWindow( i );
+ delete kill;
+ }
+}
+
+void CVMTTool::OnDefaultLayout()
+{
+ int y = m_pMenuBar->GetTall();
+
+ int usew, useh;
+ GetSize( usew, useh );
+
+ DestroyToolContainers();
+
+ Assert( ToolWindow::GetToolWindowCount() == 0 );
+
+ CBasePropertiesContainer *properties = GetProperties();
+ CVMTPanel *pVMTPreview = GetVMTPreview();
+
+ // Need three containers
+ ToolWindow *pPropertyWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, properties, "#VMTProperties", false );
+ ToolWindow *pVMTPreviewWindow = m_ToolWindowFactory.InstanceToolWindow( GetClientArea(), false, pVMTPreview, "#VMTPreview", false );
+
+ int halfScreen = usew / 2;
+ int bottom = useh - y;
+ int sy = (bottom - y) / 2;
+
+ SetMiniViewportBounds( halfScreen, y, halfScreen, sy - y );
+ pPropertyWindow->SetBounds( 0, y, halfScreen, bottom );
+ pVMTPreviewWindow->SetBounds( halfScreen, sy, halfScreen, bottom - sy );
+}
+
+void CVMTTool::OnToggleProperties()
+{
+ if ( m_hProperties.Get() )
+ {
+ ToggleToolWindow( m_hProperties.Get(), "#VMTProperties" );
+ }
+}
+
+void CVMTTool::OnToggleVMTPreview()
+{
+ if ( m_hVMTPreview.Get() )
+ {
+ ToggleToolWindow( m_hVMTPreview.Get(), "#VMTPreview" );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Show/hide tool params + flags
+//-----------------------------------------------------------------------------
+void CVMTTool::OnShowFlags()
+{
+ m_bFlagParamsVisible = !m_bFlagParamsVisible;
+
+ int nCount = m_FlagParams.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeEditorAttributeInfo *pInfo = m_pVMTType->GetAttributeInfo( m_FlagParams[i] );
+ Assert( pInfo );
+ pInfo->m_bIsVisible = m_bFlagParamsVisible;
+ }
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+}
+
+void CVMTTool::OnShowToolParams()
+{
+ m_bToolParamsVisible = !m_bToolParamsVisible;
+
+ int nCount = m_ToolParams.Count();
+ for ( int i = 0; i < nCount; ++i )
+ {
+ CDmeEditorAttributeInfo *pInfo = m_pVMTType->GetAttributeInfo( m_ToolParams[i] );
+ Assert( pInfo );
+ pInfo->m_bIsVisible = m_bToolParamsVisible;
+ }
+ if ( m_hProperties.Get() )
+ {
+ m_hProperties->Refresh();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Sets shader parameters to the default for that shader
+//-----------------------------------------------------------------------------
+void CVMTTool::OnSetParamsToDefault()
+{
+ if ( m_pDoc )
+ {
+ m_pDoc->SetParamsToDefault();
+ }
+}
+
+char const *CVMTTool::GetLogoTextureName()
+{
+ return "vgui/tools/vmt/vmt_logo";
+} \ No newline at end of file
diff --git a/tools/vmt/vmttool.h b/tools/vmt/vmttool.h
new file mode 100644
index 0000000..28e5ffe
--- /dev/null
+++ b/tools/vmt/vmttool.h
@@ -0,0 +1,50 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: VMT tool; main UI smarts class
+//
+//=============================================================================
+
+#ifndef VMTTOOL_H
+#define VMTTOOL_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+//-----------------------------------------------------------------------------
+// Forward declarations
+//-----------------------------------------------------------------------------
+class CDmeEditorTypeDictionary;
+
+
+//-----------------------------------------------------------------------------
+// Singleton interfaces
+//-----------------------------------------------------------------------------
+extern CDmeEditorTypeDictionary *g_pEditorTypeDict;
+
+
+//-----------------------------------------------------------------------------
+// Allows the doc to call back into the VMT editor tool
+//-----------------------------------------------------------------------------
+class IVMTDocCallback
+{
+public:
+ // Called by the doc when the data changes
+ virtual void OnDocChanged( const char *pReason, int nNotifySource, int nNotifyFlags ) = 0;
+
+ // Update the editor dict based on the current material parameters
+ virtual void AddShaderParameter( const char *pParam, const char *pWidget, const char *pTextType ) = 0;
+
+ // Update the editor dict based on the current material parameters
+ virtual void RemoveShaderParameter( const char *pParam ) = 0;
+
+ // Adds flags, tool parameters
+ virtual void AddFlagParameter( const char *pParam ) = 0;
+ virtual void AddToolParameter( const char *pParam, const char *pWidget = NULL, const char *pTextType = NULL ) = 0;
+ virtual void RemoveAllFlagParameters() = 0;
+ virtual void RemoveAllToolParameters() = 0;
+};
+
+
+#endif // VMTTOOL_H