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.

738 lines
21 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "importkeyvaluebase.h"
  7. #include "dmserializers.h"
  8. #include "datamodel/idatamodel.h"
  9. #include "datamodel/dmelement.h"
  10. #include "tier1/KeyValues.h"
  11. #include "tier1/utlbuffer.h"
  12. #include "datamodel/dmattribute.h"
  13. #include "filesystem.h"
  14. #include "tier2/tier2.h"
  15. //-----------------------------------------------------------------------------
  16. // Serialization class for Key Values
  17. //-----------------------------------------------------------------------------
  18. class CImportVMT : public CImportKeyValueBase
  19. {
  20. public:
  21. virtual const char *GetName() const { return "vmt"; }
  22. virtual const char *GetDescription() const { return "Valve Material File"; }
  23. virtual int GetCurrentVersion() const { return 0; } // doesn't store a version
  24. bool Serialize( CUtlBuffer &outBuf, CDmElement *pRoot );
  25. CDmElement* UnserializeFromKeyValues( KeyValues *pKeyValues );
  26. private:
  27. // Unserialize fallbacks
  28. bool UnserializeFallbacks( CDmElement *pRoot, KeyValues *pFallbackKeyValues );
  29. // Unserialize proxies
  30. bool UnserializeProxies( CDmElement *pRoot, KeyValues *pKeyValues );
  31. // Creates a shader parameter from a key value
  32. bool UnserializeShaderParam( CDmElement *pRoot, KeyValues* pKeyValue );
  33. // Creates a matrix material var
  34. bool CreateMatrixMaterialVarFromKeyValue( CDmElement *pRoot, const char *pParamName, const char *pString );
  35. // Creates a vector shader parameter
  36. bool CreateVectorMaterialVarFromKeyValue( CDmElement *pRoot, const char *pParamName, const char *pString );
  37. // Writes out a single shader parameter
  38. bool SerializeShaderParameter( CUtlBuffer &buf, CDmAttribute *pAttribute );
  39. // Writes out all shader parameters
  40. bool SerializeShaderParameters( CUtlBuffer &buf, CDmElement *pRoot );
  41. // Writes out all shader fallbacks
  42. bool SerializeFallbacks( CUtlBuffer &buf, CDmElement *pRoot );
  43. // Writes out all material proxies
  44. bool SerializeProxies( CUtlBuffer &buf, CDmElement *pRoot );
  45. // Handle patch files
  46. void ExpandPatchFile( KeyValues *pKeyValues );
  47. };
  48. //-----------------------------------------------------------------------------
  49. // Singleton instance
  50. //-----------------------------------------------------------------------------
  51. static CImportVMT s_ImportVMT;
  52. void InstallVMTImporter( IDataModel *pFactory )
  53. {
  54. pFactory->AddSerializer( &s_ImportVMT );
  55. }
  56. //-----------------------------------------------------------------------------
  57. // Writes out a single shader parameter
  58. //-----------------------------------------------------------------------------
  59. bool CImportVMT::SerializeShaderParameter( CUtlBuffer &buf, CDmAttribute *pAttribute )
  60. {
  61. // We have a shader parameter at this point.
  62. switch ( pAttribute->GetType() )
  63. {
  64. case AT_INT:
  65. buf.Printf( "\"%s\" \"%d\"\n", pAttribute->GetName(), pAttribute->GetValue<int>( ) );
  66. break;
  67. case AT_BOOL:
  68. buf.Printf( "\"%s\" \"%d\"\n", pAttribute->GetName(), pAttribute->GetValue<bool>( ) );
  69. break;
  70. case AT_FLOAT:
  71. buf.Printf( "\"%s\" \"%f\"\n", pAttribute->GetName(), pAttribute->GetValue<float>( ) );
  72. break;
  73. case AT_STRING:
  74. buf.Printf( "\"%s\" \"%s\"\n", pAttribute->GetName(), pAttribute->GetValue<CUtlString>( ).Get() );
  75. break;
  76. case AT_VECTOR2:
  77. {
  78. const Vector2D &vec = pAttribute->GetValue<Vector2D>( );
  79. buf.Printf( "\"%s\" \"[ %f %f ]\"\n", pAttribute->GetName(), vec.x, vec.y );
  80. }
  81. break;
  82. case AT_VECTOR3:
  83. {
  84. const Vector &vec = pAttribute->GetValue<Vector>( );
  85. buf.Printf( "\"%s\" \"[ %f %f %f ]\"\n", pAttribute->GetName(), vec.x, vec.y, vec.z );
  86. }
  87. break;
  88. case AT_VECTOR4:
  89. {
  90. const Vector4D &vec = pAttribute->GetValue<Vector4D>( );
  91. buf.Printf( "\"%s\" \"[ %f %f %f %f ]\"\n", pAttribute->GetName(), vec.x, vec.y, vec.z, vec.w );
  92. }
  93. break;
  94. case AT_COLOR:
  95. {
  96. // NOTE: VMTs only support 3 component color (no alpha)
  97. const Color &color = pAttribute->GetValue<Color>( );
  98. buf.Printf( "\"%s\" \"{ %d %d %d }\"\n", pAttribute->GetName(), color.r(), color.g(), color.b() );
  99. }
  100. break;
  101. case AT_VMATRIX:
  102. {
  103. const VMatrix &mat = pAttribute->GetValue<VMatrix>( );
  104. buf.Printf( "\"%s\" \"[ %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ]\"\n", pAttribute->GetName(),
  105. mat[0][0], mat[0][1], mat[0][2], mat[0][3],
  106. mat[1][0], mat[1][1], mat[1][2], mat[1][3],
  107. mat[2][0], mat[2][1], mat[2][2], mat[2][3],
  108. mat[3][0], mat[3][1], mat[3][2], mat[3][3] );
  109. }
  110. break;
  111. default:
  112. Warning( "Attempted to serialize an unsupported shader parameter type %s (%s)\n",
  113. pAttribute->GetName(), g_pDataModel->GetAttributeNameForType( pAttribute->GetType() ) );
  114. return false;
  115. }
  116. return true;
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Writes out all shader parameters
  120. //-----------------------------------------------------------------------------
  121. bool CImportVMT::SerializeShaderParameters( CUtlBuffer &buf, CDmElement *pRoot )
  122. {
  123. for ( CDmAttribute *pAttribute = pRoot->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() )
  124. {
  125. // Skip the standard attributes
  126. if ( pAttribute->IsFlagSet( FATTRIB_STANDARD ) )
  127. continue;
  128. // Skip the shader name
  129. const char *pName = pAttribute->GetName();
  130. if ( !Q_stricmp( pAttribute->GetName(), "shader" ) )
  131. continue;
  132. // Names that don't start with a $ or a % are not shader parameters
  133. if ( pName[0] != '$' && pName[0] != '%' )
  134. continue;
  135. // Skip element array children; we'll handle them separately.
  136. if ( pAttribute->GetType() == AT_ELEMENT_ARRAY )
  137. continue;
  138. // Write out the shader parameter
  139. if ( !SerializeShaderParameter( buf, pAttribute ) )
  140. return false;
  141. }
  142. return true;
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Writes out all shader fallbacks
  146. //-----------------------------------------------------------------------------
  147. bool CImportVMT::SerializeFallbacks( CUtlBuffer &buf, CDmElement *pRoot )
  148. {
  149. if ( !pRoot->HasAttribute( "fallbacks" ) )
  150. return true;
  151. CDmAttribute *pFallbacks = pRoot->GetAttribute( "fallbacks" );
  152. if ( pFallbacks->GetType() != AT_ELEMENT_ARRAY )
  153. return false;
  154. CDmrElementArray<> array( pFallbacks );
  155. int nCount = array.Count();
  156. for ( int i = 0; i < nCount; ++i )
  157. {
  158. CDmElement *pFallback = array[i];
  159. Assert( pFallback );
  160. PrintStringAttribute( pFallback, buf, "shader", false, true );
  161. buf.Printf( "{\n" );
  162. buf.PushTab();
  163. if ( !SerializeShaderParameters( buf, pFallback ) )
  164. return false;
  165. buf.PopTab();
  166. buf.Printf( "}\n" );
  167. }
  168. return true;
  169. }
  170. //-----------------------------------------------------------------------------
  171. // Writes out all material proxies
  172. //-----------------------------------------------------------------------------
  173. bool CImportVMT::SerializeProxies( CUtlBuffer &buf, CDmElement *pRoot )
  174. {
  175. if ( !pRoot->HasAttribute( "proxies" ) )
  176. return true;
  177. CDmAttribute *pProxies = pRoot->GetAttribute( "proxies" );
  178. if ( pProxies->GetType() != AT_ELEMENT_ARRAY )
  179. return false;
  180. CDmrElementArray<> array( pProxies );
  181. int nCount = array.Count();
  182. if ( nCount == 0 )
  183. return true;
  184. buf.Printf( "\"Proxies\"\n" );
  185. buf.Printf( "{\n" );
  186. buf.PushTab();
  187. for ( int i = 0; i < nCount; ++i )
  188. {
  189. CDmElement *pProxy = array[i];
  190. Assert( pProxy );
  191. PrintStringAttribute( pProxy, buf, "proxyType", false, true );
  192. buf.Printf( "{\n" );
  193. buf.PushTab();
  194. if ( !SerializeShaderParameters( buf, pProxy ) )
  195. return false;
  196. buf.PopTab();
  197. buf.Printf( "}\n" );
  198. }
  199. buf.PopTab();
  200. buf.Printf( "}\n" );
  201. return true;
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Writes out a new vmt file
  205. //-----------------------------------------------------------------------------
  206. bool CImportVMT::Serialize( CUtlBuffer &buf, CDmElement *pRoot )
  207. {
  208. PrintStringAttribute( pRoot, buf, "shader", false, true );
  209. buf.Printf( "{\n" );
  210. buf.PushTab();
  211. if ( !SerializeShaderParameters( buf, pRoot ) )
  212. return false;
  213. if ( !SerializeFallbacks( buf, pRoot ) )
  214. return false;
  215. if ( !SerializeProxies( buf, pRoot ) )
  216. return false;
  217. buf.PopTab();
  218. buf.Printf( "}\n" );
  219. return true;
  220. }
  221. //-----------------------------------------------------------------------------
  222. // Parser utilities
  223. //-----------------------------------------------------------------------------
  224. static inline bool IsWhitespace( char c )
  225. {
  226. return c == ' ' || c == '\t';
  227. }
  228. static inline bool IsEndline( char c )
  229. {
  230. return c == '\n' || c == '\0';
  231. }
  232. static inline bool IsVector( char const* v )
  233. {
  234. while (IsWhitespace(*v))
  235. {
  236. ++v;
  237. if (IsEndline(*v))
  238. return false;
  239. }
  240. return *v == '[' || *v == '{';
  241. }
  242. //-----------------------------------------------------------------------------
  243. // Creates a vector material var
  244. //-----------------------------------------------------------------------------
  245. int ParseVectorFromKeyValueString( const char *pParamName, const char* pScan, const char *pMaterialName, float vecVal[4] )
  246. {
  247. bool divideBy255 = false;
  248. // skip whitespace
  249. while( IsWhitespace(*pScan) )
  250. {
  251. ++pScan;
  252. }
  253. if( *pScan == '{' )
  254. {
  255. divideBy255 = true;
  256. }
  257. else
  258. {
  259. Assert( *pScan == '[' );
  260. }
  261. // skip the '['
  262. ++pScan;
  263. int i;
  264. for( i = 0; i < 4; i++ )
  265. {
  266. // skip whitespace
  267. while( IsWhitespace(*pScan) )
  268. {
  269. ++pScan;
  270. }
  271. if( IsEndline(*pScan) || *pScan == ']' || *pScan == '}' )
  272. {
  273. if (*pScan != ']' && *pScan != '}')
  274. {
  275. Warning( "Warning in .VMT file (%s): no ']' or '}' found in vector key \"%s\".\n"
  276. "Did you forget to surround the vector with \"s?\n", pMaterialName, pParamName );
  277. }
  278. // allow for vec2's, etc.
  279. vecVal[i] = 0.0f;
  280. break;
  281. }
  282. char* pEnd;
  283. vecVal[i] = strtod( pScan, &pEnd );
  284. if (pScan == pEnd)
  285. {
  286. Warning( "Error in .VMT file: error parsing vector element \"%s\" in \"%s\"\n", pParamName, pMaterialName );
  287. return 0;
  288. }
  289. pScan = pEnd;
  290. }
  291. if( divideBy255 )
  292. {
  293. vecVal[0] *= ( 1.0f / 255.0f );
  294. vecVal[1] *= ( 1.0f / 255.0f );
  295. vecVal[2] *= ( 1.0f / 255.0f );
  296. vecVal[3] *= ( 1.0f / 255.0f );
  297. }
  298. return i;
  299. }
  300. //-----------------------------------------------------------------------------
  301. // Sets shader parameter attributes
  302. //-----------------------------------------------------------------------------
  303. template< class T >
  304. inline bool SetShaderParamAttribute( CDmElement *pElement, const char *pAttributeName, const T &value )
  305. {
  306. if ( !pElement )
  307. return false;
  308. if ( !pElement->SetValue( pAttributeName, value ) )
  309. return false;
  310. CDmAttribute *pAttribute = pElement->GetAttribute( pAttributeName );
  311. pAttribute->AddFlag( FATTRIB_USERDEFINED );
  312. return true;
  313. }
  314. inline bool SetShaderParamAttribute( CDmElement *pElement, const char *pAttributeName, const char *value )
  315. {
  316. if ( !pElement )
  317. return false;
  318. if ( !pElement->SetValue( pAttributeName, value ) )
  319. return false;
  320. CDmAttribute *pAttribute = pElement->GetAttribute( pAttributeName );
  321. pAttribute->AddFlag( FATTRIB_USERDEFINED );
  322. return true;
  323. }
  324. //-----------------------------------------------------------------------------
  325. // Creates a vector shader parameter
  326. //-----------------------------------------------------------------------------
  327. bool CImportVMT::CreateVectorMaterialVarFromKeyValue( CDmElement *pElement, const char *pParamName, const char *pString )
  328. {
  329. Vector4D vecVal;
  330. int nDim = ParseVectorFromKeyValueString( pParamName, pString, FileName(), vecVal.Base() );
  331. if ( nDim == 0 )
  332. return false;
  333. // Create the variable!
  334. switch ( nDim )
  335. {
  336. case 1:
  337. return SetShaderParamAttribute( pElement, pParamName, vecVal[0] );
  338. case 2:
  339. return SetShaderParamAttribute( pElement, pParamName, vecVal.AsVector2D() );
  340. case 3:
  341. return SetShaderParamAttribute( pElement, pParamName, vecVal.AsVector3D() );
  342. case 4:
  343. return SetShaderParamAttribute( pElement, pParamName, vecVal );
  344. }
  345. return false;
  346. }
  347. //-----------------------------------------------------------------------------
  348. // Creates a matrix shader parameter
  349. //-----------------------------------------------------------------------------
  350. bool CImportVMT::CreateMatrixMaterialVarFromKeyValue( CDmElement *pElement, const char *pParamName, const char *pScan )
  351. {
  352. // Matrices can be specified one of two ways:
  353. // [ # # # # # # # # # # # # # # # # ]
  354. // or
  355. // center # # scale # # rotate # translate # #
  356. VMatrix mat;
  357. int count = sscanf( pScan, " [ %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f ]",
  358. &mat.m[0][0], &mat.m[0][1], &mat.m[0][2], &mat.m[0][3],
  359. &mat.m[1][0], &mat.m[1][1], &mat.m[1][2], &mat.m[1][3],
  360. &mat.m[2][0], &mat.m[2][1], &mat.m[2][2], &mat.m[2][3],
  361. &mat.m[3][0], &mat.m[3][1], &mat.m[3][2], &mat.m[3][3] );
  362. if (count == 16)
  363. {
  364. return SetShaderParamAttribute( pElement, pParamName, mat );
  365. }
  366. Vector2D scale, center;
  367. float angle;
  368. Vector2D translation;
  369. count = sscanf( pScan, " center %f %f scale %f %f rotate %f translate %f %f",
  370. &center.x, &center.y, &scale.x, &scale.y, &angle, &translation.x, &translation.y );
  371. if (count != 7)
  372. return false;
  373. VMatrix temp;
  374. MatrixBuildTranslation( mat, -center.x, -center.y, 0.0f );
  375. MatrixBuildScale( temp, scale.x, scale.y, 1.0f );
  376. MatrixMultiply( temp, mat, mat );
  377. MatrixBuildRotateZ( temp, angle );
  378. MatrixMultiply( temp, mat, mat );
  379. MatrixBuildTranslation( temp, center.x + translation.x, center.y + translation.y, 0.0f );
  380. MatrixMultiply( temp, mat, mat );
  381. // Create the variable!
  382. return SetShaderParamAttribute( pElement, pParamName, mat );
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Creates a shader parameter from a key value
  386. //-----------------------------------------------------------------------------
  387. bool CImportVMT::UnserializeShaderParam( CDmElement *pRoot, KeyValues* pKeyValues )
  388. {
  389. char pParamName[512];
  390. Q_strncpy( pParamName, pKeyValues->GetName(), sizeof(pParamName) );
  391. Q_strlower( pParamName );
  392. switch( pKeyValues->GetDataType() )
  393. {
  394. case KeyValues::TYPE_INT:
  395. return SetShaderParamAttribute( pRoot, pParamName, pKeyValues->GetInt() );
  396. case KeyValues::TYPE_FLOAT:
  397. return SetShaderParamAttribute( pRoot, pParamName, pKeyValues->GetFloat() );
  398. case KeyValues::TYPE_STRING:
  399. {
  400. char const* pString = pKeyValues->GetString();
  401. // Only valid if it's a texture attribute
  402. if ( !pString || !pString[0] )
  403. return SetShaderParamAttribute( pRoot, pParamName, pString );
  404. // Look for matrices
  405. if ( CreateMatrixMaterialVarFromKeyValue( pRoot, pParamName, pString ) )
  406. return true;
  407. // Look for vectors
  408. if ( !IsVector( pString ) )
  409. return SetShaderParamAttribute( pRoot, pParamName, pString );
  410. // Parse the string as a vector...
  411. return CreateVectorMaterialVarFromKeyValue( pRoot, pParamName, pString );
  412. }
  413. }
  414. return false;
  415. }
  416. //-----------------------------------------------------------------------------
  417. // Unserialize proxies
  418. //-----------------------------------------------------------------------------
  419. bool CImportVMT::UnserializeProxies( CDmElement *pElement, KeyValues *pKeyValues )
  420. {
  421. // Create a child element array to contain all material proxies
  422. CDmAttribute *pProxies = pElement->AddAttribute( "proxies", AT_ELEMENT_ARRAY );
  423. if ( !pProxies )
  424. return false;
  425. CDmrElementArray<> array( pProxies );
  426. // Proxies are a list of sub-keys, the name is the proxy name, subkeys are values
  427. for ( KeyValues *pProxy = pKeyValues->GetFirstTrueSubKey(); pProxy != NULL; pProxy = pProxy->GetNextTrueSubKey() )
  428. {
  429. CDmElement *pProxyElement = CreateDmElement( "DmElement", pProxy->GetName(), NULL );
  430. array.AddToTail( pProxyElement );
  431. pProxyElement->SetValue( "proxyType", pKeyValues->GetName() );
  432. pProxyElement->SetValue( "editorType", "vmtProxy" );
  433. // Normal keys are proxy parameters
  434. for ( KeyValues *pProxyParam = pProxy->GetFirstValue(); pProxyParam != NULL; pProxyParam = pProxyParam->GetNextValue() )
  435. {
  436. switch( pProxyParam->GetDataType() )
  437. {
  438. case KeyValues::TYPE_INT:
  439. pProxyElement->SetValue( pProxyParam->GetName(), pProxyParam->GetInt() );
  440. return true;
  441. case KeyValues::TYPE_FLOAT:
  442. pProxyElement->SetValue( pProxyParam->GetName(), pProxyParam->GetFloat() );
  443. return true;
  444. case KeyValues::TYPE_STRING:
  445. pProxyElement->SetValue( pProxyParam->GetName(), pProxyParam->GetString() );
  446. return true;
  447. default:
  448. Warning( "Unhandled proxy keyvalues type (proxy %s var %s)\n", pProxy->GetName(), pProxyParam->GetName() );
  449. return false;
  450. }
  451. }
  452. }
  453. return true;
  454. }
  455. //-----------------------------------------------------------------------------
  456. // Unserialize fallbacks
  457. //-----------------------------------------------------------------------------
  458. bool CImportVMT::UnserializeFallbacks( CDmElement *pElement, KeyValues *pFallbackKeyValues )
  459. {
  460. // Create a child element array to contain all material proxies
  461. CDmAttribute *pFallbacks = pElement->AddAttribute( "fallbacks", AT_ELEMENT_ARRAY );
  462. if ( !pFallbacks )
  463. return false;
  464. CDmrElementArray<> array( pFallbacks );
  465. CDmElement *pFallback = CreateDmElement( "DmElement", pFallbackKeyValues->GetName(), NULL );
  466. array.AddToTail( pFallback );
  467. pFallback->SetValue( "editorType", "vmtFallback" );
  468. // Normal keys are shader parameters
  469. for ( KeyValues *pShaderParam = pFallbackKeyValues->GetFirstValue(); pShaderParam != NULL; pShaderParam = pShaderParam->GetNextValue() )
  470. {
  471. if ( !UnserializeShaderParam( pFallback, pShaderParam ) )
  472. {
  473. Warning( "Error importing vmt shader parameter %s\n", pShaderParam->GetName() );
  474. return NULL;
  475. }
  476. }
  477. return true;
  478. }
  479. //-----------------------------------------------------------------------------
  480. // VMT parser
  481. //-----------------------------------------------------------------------------
  482. void InsertKeyValues( KeyValues& dst, KeyValues& src, bool bCheckForExistence )
  483. {
  484. KeyValues *pSrcVar = src.GetFirstSubKey();
  485. while( pSrcVar )
  486. {
  487. if ( !bCheckForExistence || dst.FindKey( pSrcVar->GetName() ) )
  488. {
  489. switch( pSrcVar->GetDataType() )
  490. {
  491. case KeyValues::TYPE_STRING:
  492. dst.SetString( pSrcVar->GetName(), pSrcVar->GetString() );
  493. break;
  494. case KeyValues::TYPE_INT:
  495. dst.SetInt( pSrcVar->GetName(), pSrcVar->GetInt() );
  496. break;
  497. case KeyValues::TYPE_FLOAT:
  498. dst.SetFloat( pSrcVar->GetName(), pSrcVar->GetFloat() );
  499. break;
  500. case KeyValues::TYPE_PTR:
  501. dst.SetPtr( pSrcVar->GetName(), pSrcVar->GetPtr() );
  502. break;
  503. }
  504. }
  505. pSrcVar = pSrcVar->GetNextKey();
  506. }
  507. if( bCheckForExistence )
  508. {
  509. for( KeyValues *pScan = dst.GetFirstTrueSubKey(); pScan; pScan = pScan->GetNextTrueSubKey() )
  510. {
  511. KeyValues *pTmp = src.FindKey( pScan->GetName() );
  512. if( !pTmp )
  513. continue;
  514. // make sure that this is a subkey.
  515. if( pTmp->GetDataType() != KeyValues::TYPE_NONE )
  516. continue;
  517. InsertKeyValues( *pScan, *pTmp, bCheckForExistence );
  518. }
  519. }
  520. }
  521. //-----------------------------------------------------------------------------
  522. // Handle patch files
  523. //-----------------------------------------------------------------------------
  524. void CImportVMT::ExpandPatchFile( KeyValues *pKeyValues )
  525. {
  526. int count = 0;
  527. while( count < 10 && stricmp( pKeyValues->GetName(), "patch" ) == 0 )
  528. {
  529. // WriteKeyValuesToFile( "patch.txt", keyValues );
  530. const char *pIncludeFileName = pKeyValues->GetString( "include" );
  531. if( pIncludeFileName )
  532. {
  533. KeyValues * includeKeyValues = new KeyValues( "vmt" );
  534. bool success = includeKeyValues->LoadFromFile( g_pFullFileSystem, pIncludeFileName, IsX360() ? "GAME" : NULL );
  535. if( success )
  536. {
  537. KeyValues *pInsertSection = pKeyValues->FindKey( "insert" );
  538. if( pInsertSection )
  539. {
  540. InsertKeyValues( *includeKeyValues, *pInsertSection, false );
  541. }
  542. KeyValues *pReplaceSection = pKeyValues->FindKey( "replace" );
  543. if( pReplaceSection )
  544. {
  545. InsertKeyValues( *includeKeyValues, *pReplaceSection, true );
  546. }
  547. *pKeyValues = *includeKeyValues;
  548. includeKeyValues->deleteThis();
  549. // Could add other commands here, like "delete", "rename", etc.
  550. }
  551. else
  552. {
  553. includeKeyValues->deleteThis();
  554. return;
  555. }
  556. }
  557. else
  558. {
  559. return;
  560. }
  561. count++;
  562. }
  563. if( count >= 10 )
  564. {
  565. Warning( "Infinite recursion in patch file?\n" );
  566. }
  567. }
  568. //-----------------------------------------------------------------------------
  569. // Main entry point for the unserialization
  570. //-----------------------------------------------------------------------------
  571. CDmElement* CImportVMT::UnserializeFromKeyValues( KeyValues *pKeyValues )
  572. {
  573. ExpandPatchFile( pKeyValues );
  574. // Create the main element
  575. CDmElement *pRoot = CreateDmElement( "DmElement", "VMT", NULL );
  576. if ( !pRoot )
  577. return NULL;
  578. // Each material needs to have an editortype associated with it so it displays nicely in editors
  579. pRoot->SetValue( "editorType", "vmt" );
  580. // Each material needs a proxy list and a fallback list
  581. if ( !pRoot->AddAttribute( "proxies", AT_ELEMENT_ARRAY ) )
  582. return NULL;
  583. if ( !pRoot->AddAttribute( "fallbacks", AT_ELEMENT_ARRAY ) )
  584. return NULL;
  585. // The keyvalues name is the shader name
  586. pRoot->SetValue( "shader", pKeyValues->GetName() );
  587. // Normal keys are shader parameters
  588. for ( KeyValues *pShaderParam = pKeyValues->GetFirstValue(); pShaderParam != NULL; pShaderParam = pShaderParam->GetNextValue() )
  589. {
  590. if ( !UnserializeShaderParam( pRoot, pShaderParam ) )
  591. {
  592. Warning( "Error importing vmt shader parameter %s\n", pShaderParam->GetName() );
  593. return NULL;
  594. }
  595. }
  596. // Subkeys are either proxies or fallbacks
  597. for ( KeyValues *pSubKey = pKeyValues->GetFirstTrueSubKey(); pSubKey != NULL; pSubKey = pSubKey->GetNextTrueSubKey() )
  598. {
  599. if ( !Q_stricmp( pSubKey->GetName(), "Proxies" ) )
  600. {
  601. UnserializeProxies( pRoot, pSubKey );
  602. }
  603. else
  604. {
  605. UnserializeFallbacks( pRoot, pSubKey );
  606. }
  607. }
  608. // Resolve all element references recursively
  609. RecursivelyResolveElement( pRoot );
  610. return pRoot;
  611. }