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.

745 lines
22 KiB

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