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

1084 lines
32 KiB

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