Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1078 lines
32 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "vmtdoc.h"
  9. #include "tier1/KeyValues.h"
  10. #include "tier1/utlbuffer.h"
  11. #include "datamodel/dmelement.h"
  12. #include "vmttool.h"
  13. #include "materialsystem/imaterialsystem.h"
  14. #include "materialsystem/ishader.h"
  15. #include "toolutils/enginetools_int.h"
  16. #include "filesystem.h"
  17. //-----------------------------------------------------------------------------
  18. // Standard properties
  19. //-----------------------------------------------------------------------------
  20. struct StandardParam_t
  21. {
  22. const char *m_pParamName;
  23. ShaderParamType_t m_ParamType;
  24. const char *m_pDefaultValue;
  25. const char *m_pWidgetType;
  26. const char *m_pTextType;
  27. };
  28. // NOTE: All entries in here must have all-lowercase param names!
  29. static StandardParam_t g_pStandardParams[] =
  30. {
  31. { "$surfaceprop", SHADER_PARAM_TYPE_STRING, "default", "surfacepropertypicker", "surfacePropertyName" },
  32. { "%detailtype", SHADER_PARAM_TYPE_STRING, "", "detailtypepicker", "detailTypeName" },
  33. { "%compilesky", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  34. { "%compilehint", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  35. { "%compileskip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  36. { "%compileorigin", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  37. { "%compileclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  38. { "%playerclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  39. { "%compilenpcclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  40. { "%compilenochop", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  41. { "%compiletrigger", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  42. { "%compilenolight", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  43. { "%compileplayercontrolclip", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  44. { "%compileladder", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  45. { "%compilewet", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  46. { "%compilenodraw", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  47. { "%compileinvisible", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  48. { "%compilenonsolid", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  49. { "%compiledetail", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  50. { "%compilewater", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  51. { "%compileslime", SHADER_PARAM_TYPE_BOOL, "0", NULL, NULL },
  52. { NULL, SHADER_PARAM_TYPE_BOOL, NULL, NULL, NULL }
  53. };
  54. //-----------------------------------------------------------------------------
  55. // Constructor
  56. //-----------------------------------------------------------------------------
  57. CVMTDoc::CVMTDoc( IVMTDocCallback *pCallback ) : m_pCallback( pCallback )
  58. {
  59. m_hRoot = NULL;
  60. m_pFileName[0] = 0;
  61. m_bDirty = false;
  62. m_pCurrentIShader = NULL;
  63. KeyValues *pKeyValues = new KeyValues( "Wireframe" );
  64. m_pScratchMaterial.Init( "VMT Preview", pKeyValues );
  65. g_pDataModel->InstallNotificationCallback( this );
  66. }
  67. CVMTDoc::~CVMTDoc()
  68. {
  69. if ( m_hRoot.Get() )
  70. {
  71. RemoveAllShaderParams( m_hRoot );
  72. }
  73. g_pDataModel->RemoveNotificationCallback( this );
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Inherited from INotifyUI
  77. //-----------------------------------------------------------------------------
  78. void CVMTDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
  79. {
  80. OnDataChanged( pReason, nNotifySource, nNotifyFlags );
  81. }
  82. //-----------------------------------------------------------------------------
  83. // Gets the file name
  84. //-----------------------------------------------------------------------------
  85. const char *CVMTDoc::GetFileName()
  86. {
  87. return m_pFileName;
  88. }
  89. void CVMTDoc::SetFileName( const char *pFileName )
  90. {
  91. Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
  92. Q_FixSlashes( m_pFileName );
  93. SetDirty( true );
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Dirty bits
  97. //-----------------------------------------------------------------------------
  98. void CVMTDoc::SetDirty( bool bDirty )
  99. {
  100. m_bDirty = bDirty;
  101. }
  102. bool CVMTDoc::IsDirty() const
  103. {
  104. return m_bDirty;
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Creates the root element
  108. //-----------------------------------------------------------------------------
  109. bool CVMTDoc::CreateRootElement()
  110. {
  111. Assert( !m_hRoot.Get() );
  112. DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( GetFileName() );
  113. // Create the main element
  114. m_hRoot = g_pDataModel->CreateElement( "DmElement", GetFileName(), fileid );
  115. if ( m_hRoot == DMELEMENT_HANDLE_INVALID )
  116. return false;
  117. g_pDataModel->SetFileRoot( fileid, m_hRoot );
  118. // Each VMT list needs to have an editortype associated with it so it displays nicely in editors
  119. m_hRoot->SetValue( "editorType", "vmt" );
  120. m_hRoot->AddAttribute( "proxies", AT_ELEMENT_ARRAY );
  121. m_hRoot->AddAttribute( "fallbacks", AT_ELEMENT_ARRAY );
  122. m_pCallback->RemoveAllToolParameters();
  123. // Add standard parameters
  124. for ( int i = 0; g_pStandardParams[i].m_pParamName; ++i )
  125. {
  126. AddNewShaderParam( m_hRoot, g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_ParamType,
  127. g_pStandardParams[i].m_pDefaultValue );
  128. if ( g_pStandardParams[i].m_pParamName[0] == '%' )
  129. {
  130. m_pCallback->AddToolParameter( g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_pWidgetType, g_pStandardParams[i].m_pTextType );
  131. }
  132. else if ( g_pStandardParams[i].m_pWidgetType || g_pStandardParams[i].m_pTextType )
  133. {
  134. m_pCallback->RemoveShaderParameter( g_pStandardParams[i].m_pParamName );
  135. m_pCallback->AddShaderParameter( g_pStandardParams[i].m_pParamName, g_pStandardParams[i].m_pWidgetType, g_pStandardParams[i].m_pTextType );
  136. }
  137. }
  138. return true;
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Creates a new VMT
  142. //-----------------------------------------------------------------------------
  143. void CVMTDoc::CreateNew()
  144. {
  145. Assert( !m_hRoot.Get() );
  146. // This is not undoable
  147. CAppDisableUndoScopeGuard guard( "CVMTDoc::CreateNew", NOTIFY_CHANGE_OTHER );
  148. Q_strncpy( m_pFileName, "untitled", sizeof( m_pFileName ) );
  149. // Create the main element
  150. if ( !CreateRootElement() )
  151. return;
  152. m_pPreviewMaterial.Init( m_pScratchMaterial );
  153. SetShader( "wireframe" );
  154. SetDirty( false );
  155. }
  156. //-----------------------------------------------------------------------------
  157. // Copies VMT parameters into the root
  158. //-----------------------------------------------------------------------------
  159. void CVMTDoc::CopyParamsFromVMT( CDmElement *pVMT )
  160. {
  161. // First, set the shader parameters
  162. SetShader( pVMT->GetValueString( "shader" ) );
  163. // Now, copy the shader parameters over
  164. CDmAttribute* pSrc;
  165. CDmAttribute* pDst;
  166. for ( pSrc = pVMT->FirstAttribute(); pSrc; pSrc = pSrc->NextAttribute() )
  167. {
  168. // Only copy shader parameters
  169. if ( !IsShaderParam( pSrc ) )
  170. continue;
  171. // Adds the attribute if it doesn't exist
  172. const char *pSrcName = pSrc->GetName();
  173. if ( !m_hRoot->HasAttribute( pSrcName ) )
  174. {
  175. m_hRoot->AddAttribute( pSrcName, pSrc->GetType() );
  176. }
  177. pDst = m_hRoot->GetAttribute( pSrcName );
  178. pDst->AddFlag( FATTRIB_USERDEFINED );
  179. DmAttributeType_t srcType = pSrc->GetType();
  180. DmAttributeType_t dstType = pDst->GetType();
  181. if ( dstType == srcType )
  182. {
  183. pDst->SetValue( pSrc );
  184. continue;
  185. }
  186. // Certain type conversions are allowed
  187. switch( dstType )
  188. {
  189. case AT_BOOL:
  190. if ( srcType == AT_INT )
  191. {
  192. pDst->SetValue( pSrc );
  193. }
  194. break;
  195. case AT_INT:
  196. if ( srcType == AT_BOOL )
  197. {
  198. pDst->SetValue( pSrc );
  199. }
  200. break;
  201. case AT_COLOR:
  202. if ( srcType == AT_VECTOR3 )
  203. {
  204. Color c;
  205. int r, g, b;
  206. Vector v = pSrc->GetValue<Vector>( );
  207. v *= 255.0f;
  208. r = clamp( v[0], 0, 255 );
  209. g = clamp( v[1], 0, 255 );
  210. b = clamp( v[2], 0, 255 );
  211. c.SetColor( r, g, b, 255 );
  212. pDst->SetValue( c );
  213. }
  214. break;
  215. }
  216. }
  217. // Any shader parameter that isn't in the VMT make undefined
  218. for ( pDst = m_hRoot->FirstAttribute(); pDst; pDst = pDst->NextAttribute() )
  219. {
  220. if ( !IsShaderParam( pDst ) )
  221. continue;
  222. if ( !pVMT->HasAttribute( pDst->GetName() ) )
  223. {
  224. // Special hack for alpha + colors
  225. if ( !Q_stricmp( pDst->GetName(), "$alpha" ) )
  226. {
  227. pDst->SetValue( 1.0f );
  228. }
  229. else if ( pDst->GetType() == AT_COLOR )
  230. {
  231. Color c( 255, 255, 255, 255 );
  232. pDst->SetValue( c );
  233. }
  234. else
  235. {
  236. pDst->SetToDefaultValue();
  237. }
  238. }
  239. }
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Hooks the preview to an existing material, if there is one
  243. //-----------------------------------------------------------------------------
  244. void CVMTDoc::SetupPreviewMaterial( )
  245. {
  246. // Extract a material name from the material
  247. char pLocalName[MAX_PATH];
  248. // relative paths can be passed in for in-game material picking
  249. if ( !g_pFileSystem->FullPathToRelativePath( m_pFileName, pLocalName, sizeof(pLocalName) ) )
  250. {
  251. Q_strcpy( pLocalName, m_pFileName );
  252. }
  253. if ( Q_strnicmp( pLocalName, "materials", 9 ) )
  254. goto noMaterialConnection;
  255. // Skip the '/' also
  256. char pMaterialName[MAX_PATH];
  257. Q_StripExtension( pLocalName + 10, pMaterialName, sizeof(pMaterialName) );
  258. IMaterial *pMaterial = g_pMaterialSystem->FindMaterial( pMaterialName, "Editable material", false );
  259. if ( !pMaterial || pMaterial->IsErrorMaterial() )
  260. goto noMaterialConnection;
  261. m_pPreviewMaterial.Init( pMaterial );
  262. return;
  263. noMaterialConnection:
  264. m_pPreviewMaterial.Init( m_pScratchMaterial );
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Saves/loads from file
  268. //-----------------------------------------------------------------------------
  269. bool CVMTDoc::LoadFromFile( const char *pFileName )
  270. {
  271. Assert( !m_hRoot.Get() );
  272. SetDirty( false );
  273. Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
  274. if ( !m_pFileName[0] )
  275. return false;
  276. // This is not undoable
  277. CAppDisableUndoScopeGuard guard( "CVMTDoc::LoadFromFile", NOTIFY_CHANGE_OTHER );
  278. // Create the main element
  279. if ( !CreateRootElement() )
  280. return false;
  281. // change the filename of all the elements under the root, so we can unload the imported elements later
  282. DmFileId_t rootFileId = g_pDataModel->GetFileId( m_pFileName );
  283. g_pDataModel->SetFileName( rootFileId, "<temp>" );
  284. // This will allow us to edit in context!
  285. SetupPreviewMaterial( );
  286. CDmElement *pIVMT = NULL;
  287. g_pDataModel->RestoreFromFile( m_pFileName, NULL, "vmt", &pIVMT );
  288. CDmElement *pVMT = CastElement< CDmElement >( pIVMT );
  289. if ( !pVMT )
  290. return false;
  291. // FIXME: This is necessary so that all shader parameters appear in
  292. // the same order, with the same type, as what you'd get using File->New.
  293. // If we added a dependency to the material system into dmserializers,
  294. // we could avoid this work here (I think!).
  295. CopyParamsFromVMT( pVMT );
  296. // unload the imported elements and change the root's filename back
  297. DmFileId_t vmtFileId = g_pDataModel->GetFileId( m_pFileName );
  298. g_pDataModel->RemoveFileId( vmtFileId );
  299. g_pDataModel->SetFileName( rootFileId, m_pFileName );
  300. SetDirty( false );
  301. return true;
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Prior to saving to disk, extract all shader parameters which == the default
  305. //-----------------------------------------------------------------------------
  306. CDmElement* CVMTDoc::ExtractDefaultParameters( )
  307. {
  308. CDmElement *pMaterial = m_hRoot->Copy( );
  309. CDmAttribute* pAttribute = pMaterial->FirstAttribute();
  310. CDmAttribute* pNextAttribute = NULL;
  311. for ( ; pAttribute; pAttribute = pNextAttribute )
  312. {
  313. pNextAttribute = pAttribute->NextAttribute();
  314. const char *pShaderParam = pAttribute->GetName();
  315. // Check for standard params
  316. int i;
  317. for ( i = 0; g_pStandardParams[i].m_pParamName != NULL; ++i )
  318. {
  319. if ( !Q_stricmp( g_pStandardParams[i].m_pParamName, pShaderParam ) )
  320. {
  321. char temp[512];
  322. CUtlBuffer buf( temp, sizeof(temp), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
  323. pAttribute->Serialize( buf );
  324. if ( !Q_stricmp( (char*)buf.Base(), g_pStandardParams[i].m_pDefaultValue ) )
  325. {
  326. // Buffers match! Therefore it's still using the default parameter
  327. pMaterial->RemoveAttributeByPtr( pAttribute );
  328. }
  329. break;
  330. }
  331. }
  332. // Standard attribute found, continue
  333. if ( g_pStandardParams[i].m_pParamName )
  334. continue;
  335. // Only remove shader parameters
  336. if ( !IsShaderParam( pAttribute ) )
  337. continue;
  338. // Remove flags whose value is 0
  339. int nCount = g_pMaterialSystem->ShaderFlagCount();
  340. for ( i = 0; i < nCount; ++i )
  341. {
  342. const char *pFlagName = g_pMaterialSystem->ShaderFlagName( i );
  343. if ( !Q_stricmp( pShaderParam, pFlagName ) )
  344. break;
  345. }
  346. // It's a flag! Remove the attribute if its value is 0
  347. if ( i != nCount )
  348. {
  349. if ( pAttribute->GetValue<bool>( ) == 0 )
  350. {
  351. pMaterial->RemoveAttributeByPtr( pAttribute );
  352. }
  353. continue;
  354. }
  355. // FIXME: We can't do this.. the defaults in the strings need to be changed to
  356. // make it so they actually match the true defaults
  357. continue;
  358. // Remove parameters which match the default value
  359. nCount = m_pCurrentIShader->GetNumParams();
  360. for ( i = 0; i < nCount; ++i )
  361. {
  362. // FIXME: Check type matches
  363. if ( Q_stricmp( pShaderParam, m_pCurrentIShader->GetParamName( i ) ) )
  364. continue;
  365. // NOTE: This isn't particularly efficient. Too bad!
  366. // It's hard to do efficiently owing to all the import conversion
  367. char temp[512];
  368. char temp2[512];
  369. CUtlBuffer buf( temp, sizeof(temp), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
  370. CUtlBuffer buf2( temp2, sizeof(temp2), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
  371. pAttribute->Serialize( buf );
  372. SetAttributeValueFromDefault( pMaterial, pAttribute, m_pCurrentIShader->GetParamDefault( i ) );
  373. pAttribute->Serialize( buf2 );
  374. if ( ( buf.TellMaxPut() == buf2.TellMaxPut() ) && !memcmp( buf.Base(), buf2.Base(), buf.TellMaxPut() ) )
  375. {
  376. // Buffers match! Therefore it's still using the default parameter
  377. pMaterial->RemoveAttributeByPtr( pAttribute );
  378. }
  379. else
  380. {
  381. // Restore the actual value
  382. pAttribute->Unserialize( buf );
  383. }
  384. break;
  385. }
  386. }
  387. return pMaterial;
  388. }
  389. //-----------------------------------------------------------------------------
  390. // Saves to disk
  391. //-----------------------------------------------------------------------------
  392. bool CVMTDoc::SaveToFile( )
  393. {
  394. if ( m_hRoot.Get() && m_pFileName && m_pFileName[0] )
  395. {
  396. CDisableUndoScopeGuard guard;
  397. CDmElement *pSaveRoot = ExtractDefaultParameters();
  398. bool bOk = g_pDataModel->SaveToFile( m_pFileName, NULL, "keyvalues", "vmt", pSaveRoot );
  399. DestroyElement( pSaveRoot, TD_DEEP );
  400. if ( !bOk )
  401. return false;
  402. }
  403. SetDirty( false );
  404. return true;
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Finds a shader
  408. //-----------------------------------------------------------------------------
  409. IShader *CVMTDoc::FindShader( const char *pShaderName )
  410. {
  411. int nCount = g_pMaterialSystem->ShaderCount();
  412. IShader **ppShaderList = (IShader**)_alloca( nCount * sizeof(IShader*) );
  413. g_pMaterialSystem->GetShaders( 0, nCount, ppShaderList );
  414. for ( int i = 0; i < nCount; ++i )
  415. {
  416. if ( !Q_stricmp( pShaderName, ppShaderList[i]->GetName() ) )
  417. return ppShaderList[i];
  418. }
  419. return NULL;
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Is this attribute a shader parameter?
  423. //-----------------------------------------------------------------------------
  424. bool CVMTDoc::IsShaderParam( CDmAttribute* pAttribute )
  425. {
  426. const char *pName = pAttribute->GetName();
  427. // Shader params start with a $ or %
  428. if ( pName[0] != '$' && pName[0] != '%' )
  429. return false;
  430. // Don't remove name, type, or id
  431. if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) )
  432. return false;
  433. // All shader params have USERDEFINED set
  434. if ( !pAttribute->IsFlagSet( FATTRIB_USERDEFINED ) )
  435. return false;
  436. // Don't remove arrays... those aren't shader parameters
  437. if ( pAttribute->GetType() == AT_ELEMENT_ARRAY )
  438. return false;
  439. // Standard params aren't counted here
  440. for ( int i = 0; g_pStandardParams[i].m_pParamName; ++i )
  441. {
  442. if ( !Q_stricmp( g_pStandardParams[i].m_pParamName, pName ) )
  443. return false;
  444. }
  445. return true;
  446. }
  447. //-----------------------------------------------------------------------------
  448. // Remove all shader parameters
  449. //-----------------------------------------------------------------------------
  450. void CVMTDoc::RemoveAllShaderParams( CDmElement *pMaterial )
  451. {
  452. CDmAttribute* pAttribute;
  453. CDmAttribute* pNextAttribute = NULL;
  454. for ( pAttribute = pMaterial->FirstAttribute(); pAttribute; pAttribute = pNextAttribute )
  455. {
  456. pNextAttribute = pAttribute->NextAttribute();
  457. // Only remove shader parameters
  458. if ( !IsShaderParam( pAttribute ) )
  459. continue;
  460. m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
  461. pMaterial->RemoveAttributeByPtr( pAttribute );
  462. }
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Remove all shader parameters that don't exist in the new shader
  466. //-----------------------------------------------------------------------------
  467. void CVMTDoc::RemoveUnusedShaderParams( CDmElement *pMaterial, IShader *pShader, IShader *pOldShader )
  468. {
  469. CDmAttribute* pAttribute = pMaterial->FirstAttribute();
  470. CDmAttribute* pNextAttribute = NULL;
  471. for ( ; pAttribute; pAttribute = pNextAttribute )
  472. {
  473. pNextAttribute = pAttribute->NextAttribute();
  474. // Only remove shader parameters
  475. if ( !IsShaderParam( pAttribute ) )
  476. continue;
  477. // Don't remove flags
  478. int nCount = g_pMaterialSystem->ShaderFlagCount();
  479. int i;
  480. for ( i = 0; i < nCount; ++i )
  481. {
  482. const char *pFlagName = g_pMaterialSystem->ShaderFlagName( i );
  483. if ( !Q_stricmp( pAttribute->GetName(), pFlagName ) )
  484. break;
  485. }
  486. if ( i != nCount )
  487. continue;
  488. const char *pShaderParam = pAttribute->GetName();
  489. // Remove parameters we've currently got but which don't exist in the new shader
  490. nCount = pShader->GetNumParams();
  491. for ( i = 0; i < nCount; ++i )
  492. {
  493. // FIXME: Check type matches
  494. if ( !Q_stricmp( pShaderParam, pShader->GetParamName( i ) ) )
  495. break;
  496. }
  497. // No match? Remove it!
  498. if ( i == nCount )
  499. {
  500. m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
  501. pMaterial->RemoveAttributeByPtr( pAttribute );
  502. continue;
  503. }
  504. // Remove parameters from the old shader which match the default value
  505. // This will make the default values update to the new shader's defaults
  506. if ( pOldShader )
  507. {
  508. nCount = pOldShader->GetNumParams();
  509. for ( i = 0; i < nCount; ++i )
  510. {
  511. // FIXME: Check type matches
  512. if ( Q_stricmp( pShaderParam, pOldShader->GetParamName( i ) ) )
  513. continue;
  514. // NOTE: This isn't particularly efficient. Too bad!
  515. // It's hard to do efficiently owing to all the import conversion
  516. char temp1[512];
  517. char temp2[512];
  518. CUtlBuffer buf1( temp1, sizeof(temp1), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
  519. CUtlBuffer buf2( temp2, sizeof(temp2), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
  520. pAttribute->Serialize( buf1 );
  521. SetAttributeValueFromDefault( pMaterial, pAttribute, pOldShader->GetParamDefault( i ) );
  522. pAttribute->Serialize( buf2 );
  523. if ( ( buf1.TellMaxPut() == buf2.TellMaxPut() ) && !memcmp( buf1.Base(), buf2.Base(), buf1.TellMaxPut() ) )
  524. {
  525. // Buffers match! Therefore it's still using the default parameter
  526. m_pCallback->RemoveShaderParameter( pAttribute->GetName() );
  527. pMaterial->RemoveAttributeByPtr( pAttribute );
  528. }
  529. else
  530. {
  531. pAttribute->Unserialize( buf1 );
  532. }
  533. break;
  534. }
  535. }
  536. }
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Add attribute for shader parameter
  540. //-----------------------------------------------------------------------------
  541. CDmAttribute* CVMTDoc::AddAttributeForShaderParameter( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType )
  542. {
  543. CDmAttribute *pAttribute = NULL;
  544. switch ( paramType )
  545. {
  546. case SHADER_PARAM_TYPE_INTEGER:
  547. pAttribute = pMaterial->AddAttribute( pParamName, AT_INT );
  548. break;
  549. case SHADER_PARAM_TYPE_BOOL:
  550. pAttribute = pMaterial->AddAttribute( pParamName, AT_BOOL );
  551. break;
  552. case SHADER_PARAM_TYPE_FLOAT:
  553. pAttribute = pMaterial->AddAttribute( pParamName, AT_FLOAT );
  554. break;
  555. case SHADER_PARAM_TYPE_STRING:
  556. pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
  557. break;
  558. case SHADER_PARAM_TYPE_COLOR:
  559. pAttribute = pMaterial->AddAttribute( pParamName, AT_COLOR );
  560. break;
  561. case SHADER_PARAM_TYPE_VEC2:
  562. pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR2 );
  563. break;
  564. case SHADER_PARAM_TYPE_VEC3:
  565. pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR3 );
  566. break;
  567. case SHADER_PARAM_TYPE_VEC4:
  568. pAttribute = pMaterial->AddAttribute( pParamName, AT_VECTOR4 );
  569. break;
  570. case SHADER_PARAM_TYPE_FOURCC:
  571. Assert( 0 );
  572. break;
  573. case SHADER_PARAM_TYPE_MATRIX:
  574. pAttribute = pMaterial->AddAttribute( pParamName, AT_VMATRIX );
  575. break;
  576. case SHADER_PARAM_TYPE_TEXTURE:
  577. pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
  578. m_pCallback->AddShaderParameter( pParamName, "vtfpicker", "vtfName" );
  579. break;
  580. case SHADER_PARAM_TYPE_MATERIAL:
  581. pAttribute = pMaterial->AddAttribute( pParamName, AT_STRING );
  582. m_pCallback->AddShaderParameter( pParamName, "vmtpicker", "vmtName" );
  583. break;
  584. default:
  585. break;
  586. }
  587. if ( pAttribute )
  588. {
  589. pAttribute->AddFlag( FATTRIB_USERDEFINED );
  590. }
  591. return pAttribute;
  592. }
  593. //-----------------------------------------------------------------------------
  594. // A couple methods to set vmatrix param values from strings (OLD METHOD!)
  595. //-----------------------------------------------------------------------------
  596. bool CVMTDoc::SetVMatrixParamValue( CDmAttribute *pAttribute, const char *pValue )
  597. {
  598. // FIXME: Change default strings to match DME?
  599. // Then we could remove this crap
  600. VMatrix mat;
  601. int count = sscanf( pValue, " [ %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ]",
  602. &mat.m[0][0], &mat.m[0][1], &mat.m[0][2], &mat.m[0][3],
  603. &mat.m[1][0], &mat.m[1][1], &mat.m[1][2], &mat.m[1][3],
  604. &mat.m[2][0], &mat.m[2][1], &mat.m[2][2], &mat.m[2][3],
  605. &mat.m[3][0], &mat.m[3][1], &mat.m[3][2], &mat.m[3][3] );
  606. if (count == 16)
  607. {
  608. pAttribute->SetValue( mat );
  609. return true;
  610. }
  611. Vector2D scale, center;
  612. float angle;
  613. Vector2D translation;
  614. count = sscanf( pValue, " center %f %f scale %f %f rotate %f translate %f %f",
  615. &center.x, &center.y, &scale.x, &scale.y, &angle, &translation.x, &translation.y );
  616. if (count != 7)
  617. return false;
  618. VMatrix temp;
  619. MatrixBuildTranslation( mat, -center.x, -center.y, 0.0f );
  620. MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
  621. MatrixMultiply( temp, mat, mat );
  622. MatrixBuildRotateZ( temp, angle );
  623. MatrixMultiply( temp, mat, mat );
  624. MatrixBuildTranslation( temp, center.x + translation.x, center.y + translation.y, 0.0f );
  625. MatrixMultiply( temp, mat, mat );
  626. pAttribute->SetValue( mat );
  627. return true;
  628. }
  629. //-----------------------------------------------------------------------------
  630. // A couple methods to set vmatrix param values from strings (OLD METHOD!)
  631. //-----------------------------------------------------------------------------
  632. bool CVMTDoc::SetVector2DParamValue( CDmAttribute *pAttribute, const char *pValue )
  633. {
  634. Vector2D vec;
  635. int count = sscanf( pValue, " [ %f %f ]", &vec[0], &vec[1] );
  636. if ( count == 2 )
  637. {
  638. pAttribute->SetValue( vec );
  639. return true;
  640. }
  641. count = sscanf( pValue, " { %f %f }", &vec[0], &vec[1] );
  642. if ( count == 2 )
  643. {
  644. vec /= 255.0f;
  645. pAttribute->SetValue( vec );
  646. return true;
  647. }
  648. return false;
  649. }
  650. //-----------------------------------------------------------------------------
  651. // A couple methods to set vmatrix param values from strings (OLD METHOD!)
  652. //-----------------------------------------------------------------------------
  653. bool CVMTDoc::SetVector3DParamValue( CDmAttribute *pAttribute, const char *pValue )
  654. {
  655. Vector vec;
  656. int count = sscanf( pValue, " [ %f %f %f ]", &vec[0], &vec[1], &vec[2] );
  657. if ( count == 3 )
  658. {
  659. pAttribute->SetValue( vec );
  660. return true;
  661. }
  662. count = sscanf( pValue, " { %f %f %f }", &vec[0], &vec[1], &vec[2] );
  663. if ( count == 3 )
  664. {
  665. vec /= 255.0f;
  666. pAttribute->SetValue( vec );
  667. return true;
  668. }
  669. return false;
  670. }
  671. //-----------------------------------------------------------------------------
  672. // A couple methods to set vmatrix param values from strings (OLD METHOD!)
  673. //-----------------------------------------------------------------------------
  674. bool CVMTDoc::SetVector4DParamValue( CDmAttribute *pAttribute, const char *pValue )
  675. {
  676. Vector4D vec;
  677. int count = sscanf( pValue, " [ %f %f %f %f ]", &vec[0], &vec[1], &vec[2], &vec[3] );
  678. if ( count == 4 )
  679. {
  680. pAttribute->SetValue( vec );
  681. return true;
  682. }
  683. count = sscanf( pValue, " { %f %f %f %f }", &vec[0], &vec[1], &vec[2], &vec[3] );
  684. if ( count == 4 )
  685. {
  686. vec /= 255.0f;
  687. pAttribute->SetValue( vec );
  688. return true;
  689. }
  690. return false;
  691. }
  692. //-----------------------------------------------------------------------------
  693. // A couple methods to set vmatrix param values from strings (OLD METHOD!)
  694. //-----------------------------------------------------------------------------
  695. bool CVMTDoc::SetColorParamValue( CDmAttribute *pAttribute, const char *pValue )
  696. {
  697. Color c;
  698. int r, g, b;
  699. Vector vec;
  700. int count = sscanf( pValue, " [ %f %f %f ]", &vec[0], &vec[1], &vec[2] );
  701. if ( count == 3 )
  702. {
  703. vec *= 255.0f;
  704. r = clamp( vec[0], 0, 255 );
  705. g = clamp( vec[1], 0, 255 );
  706. b = clamp( vec[2], 0, 255 );
  707. c.SetColor( r, g, b, 255 );
  708. pAttribute->SetValue( c );
  709. return true;
  710. }
  711. count = sscanf( pValue, " { %d %d %d }", &r, &g, &b );
  712. if ( count == 3 )
  713. {
  714. c.SetColor( r, g, b, 255 );
  715. pAttribute->SetValue( c );
  716. return true;
  717. }
  718. return false;
  719. }
  720. //-----------------------------------------------------------------------------
  721. // Sets an attribute value from the shader param default
  722. //-----------------------------------------------------------------------------
  723. void CVMTDoc::SetAttributeValueFromDefault( CDmElement *pMaterial, CDmAttribute *pAttribute, const char *pValue )
  724. {
  725. // FIXME: Change default strings to match DME?
  726. // Then we could remove this crap
  727. switch ( pAttribute->GetType() )
  728. {
  729. case AT_VMATRIX:
  730. if ( SetVMatrixParamValue( pAttribute, pValue ) )
  731. return;
  732. break;
  733. case AT_COLOR:
  734. if ( SetColorParamValue( pAttribute, pValue ) )
  735. return;
  736. break;
  737. case AT_VECTOR2:
  738. if ( SetVector2DParamValue( pAttribute, pValue ) )
  739. return;
  740. break;
  741. case AT_VECTOR3:
  742. if ( SetVector3DParamValue( pAttribute, pValue ) )
  743. return;
  744. break;
  745. case AT_VECTOR4:
  746. if ( SetVector4DParamValue( pAttribute, pValue ) )
  747. return;
  748. break;
  749. }
  750. pMaterial->SetValueFromString( pAttribute->GetName(), pValue );
  751. }
  752. //-----------------------------------------------------------------------------
  753. // Add a single shader parameter if it doesn't exist
  754. //-----------------------------------------------------------------------------
  755. void CVMTDoc::AddNewShaderParam( CDmElement *pMaterial, const char *pParamName, ShaderParamType_t paramType, const char *pValue )
  756. {
  757. char temp[512];
  758. Q_strncpy( temp, pParamName, sizeof(temp) );
  759. Q_strlower( temp );
  760. pParamName = temp;
  761. CDmAttribute* pAttribute = NULL;
  762. for ( pAttribute = pMaterial->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
  763. {
  764. // Don't bother testing against name, type, or id
  765. if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) )
  766. continue;
  767. const char *pAttributeName = pAttribute->GetName();
  768. if ( !Q_stricmp( pAttributeName, pParamName ) )
  769. return;
  770. }
  771. // No match? Add it!
  772. pAttribute = AddAttributeForShaderParameter( pMaterial, pParamName, paramType );
  773. if ( pAttribute )
  774. {
  775. SetAttributeValueFromDefault( pMaterial, pAttribute, pValue );
  776. }
  777. }
  778. //-----------------------------------------------------------------------------
  779. // Add all shader parameters that don't currently exist
  780. //-----------------------------------------------------------------------------
  781. void CVMTDoc::AddNewShaderParams( CDmElement *pMaterial, IShader *pShader )
  782. {
  783. // First add all flags
  784. m_pCallback->RemoveAllFlagParameters();
  785. int nCount = g_pMaterialSystem->ShaderFlagCount();
  786. int i;
  787. for ( i = 0; i < nCount; ++i )
  788. {
  789. const char *pParamName = g_pMaterialSystem->ShaderFlagName( i );
  790. AddNewShaderParam( pMaterial, pParamName, SHADER_PARAM_TYPE_BOOL, "0" );
  791. m_pCallback->AddFlagParameter( pParamName );
  792. }
  793. // Next add all shader-specific parameters
  794. nCount = pShader->GetNumParams();
  795. for ( i = 0; i < nCount; ++i )
  796. {
  797. const char *pParamName = pShader->GetParamName( i );
  798. // Don't add parameters that don't want to be editable
  799. if ( pShader->GetParamFlags( i ) & SHADER_PARAM_NOT_EDITABLE )
  800. continue;
  801. ShaderParamType_t paramType = pShader->GetParamType( i );
  802. const char *pDefault = pShader->GetParamDefault( i );
  803. AddNewShaderParam( pMaterial, pParamName, paramType, pDefault );
  804. }
  805. }
  806. //-----------------------------------------------------------------------------
  807. // Sets shader parameters to the default for that shader
  808. //-----------------------------------------------------------------------------
  809. void CVMTDoc::SetParamsToDefault()
  810. {
  811. // This is undoable
  812. CAppUndoScopeGuard guard( 0, "Set Params to Default", "Set Params to Default" );
  813. // Next add all shader-specific parameters
  814. int nCount = m_pCurrentIShader->GetNumParams();
  815. for ( int i = 0; i < nCount; ++i )
  816. {
  817. const char *pParamName = m_pCurrentIShader->GetParamName( i );
  818. // Don't set parameters that don't want to be editable
  819. if ( m_pCurrentIShader->GetParamFlags( i ) & SHADER_PARAM_NOT_EDITABLE )
  820. continue;
  821. char pAttributeName[512];
  822. Q_strncpy( pAttributeName, pParamName, sizeof(pAttributeName) );
  823. Q_strlower( pAttributeName );
  824. if ( !m_hRoot->HasAttribute( pAttributeName ) )
  825. continue;
  826. CDmAttribute *pAttribute = m_hRoot->GetAttribute( pAttributeName );
  827. const char *pDefault = m_pCurrentIShader->GetParamDefault( i );
  828. SetAttributeValueFromDefault( m_hRoot, pAttribute, pDefault );
  829. }
  830. }
  831. //-----------------------------------------------------------------------------
  832. // Sets the shader in the material
  833. //-----------------------------------------------------------------------------
  834. void CVMTDoc::SetShader( const char *pShaderName )
  835. {
  836. // No change? don't bother
  837. if ( !Q_stricmp( m_CurrentShader, pShaderName ) )
  838. return;
  839. m_CurrentShader = pShaderName;
  840. // This is undoable
  841. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Set Shader", "Set Shader" );
  842. char pActualShaderName[512];
  843. g_pMaterialSystem->GetShaderFallback( pShaderName, pActualShaderName, sizeof(pActualShaderName) );
  844. m_hRoot->SetValue( "shader", pShaderName );
  845. // First, find the shader
  846. IShader *pShader = FindShader( pActualShaderName );
  847. // Remove all shader parameters that don't exist in the new shader
  848. // And also remove shader parameters that do match the default value
  849. RemoveUnusedShaderParams( m_hRoot, pShader, m_pCurrentIShader );
  850. // Add all shader parameters that don't currently exist
  851. AddNewShaderParams( m_hRoot, pShader );
  852. m_pCurrentIShader = pShader;
  853. }
  854. //-----------------------------------------------------------------------------
  855. // Gets the preview material
  856. //-----------------------------------------------------------------------------
  857. IMaterial *CVMTDoc::GetPreviewMaterial()
  858. {
  859. return m_pPreviewMaterial;
  860. }
  861. //-----------------------------------------------------------------------------
  862. // Updates the preview material
  863. //-----------------------------------------------------------------------------
  864. void CVMTDoc::UpdatePreviewMaterial()
  865. {
  866. if ( !m_hRoot.Get() )
  867. return;
  868. // Update all shader parameters
  869. SetShader( m_hRoot->GetValueString( "shader" ) );
  870. // Use the file conversion to write to a text format
  871. char buf[1024];
  872. CUtlBuffer vmtBuf( buf, sizeof(buf), CUtlBuffer::TEXT_BUFFER | CUtlBuffer::EXTERNAL_GROWABLE );
  873. g_pDataModel->Serialize( vmtBuf, "vmt", "vmt", m_hRoot );
  874. // Now use the text format to create a keyvalues
  875. KeyValues *pVMTKeyValues = new KeyValues( "ShaderName" );
  876. pVMTKeyValues->LoadFromBuffer( "VMT Preview", vmtBuf, g_pFileSystem, "GAME" );
  877. // Finally, hook the keyvalues into the material.
  878. m_pPreviewMaterial->SetShaderAndParams( pVMTKeyValues );
  879. pVMTKeyValues->deleteThis();
  880. }
  881. //-----------------------------------------------------------------------------
  882. // Returns the root object
  883. //-----------------------------------------------------------------------------
  884. CDmElement *CVMTDoc::GetRootObject()
  885. {
  886. return m_hRoot;
  887. }
  888. //-----------------------------------------------------------------------------
  889. // Called when data changes
  890. //-----------------------------------------------------------------------------
  891. void CVMTDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
  892. {
  893. SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
  894. UpdatePreviewMaterial();
  895. m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
  896. }