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.

6226 lines
168 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //=============================================================================
  4. // Standard includes
  5. #define WIN32_LEAN_AND_MEAN
  6. #include <windows.h>
  7. #include <io.h>
  8. // Valve includes
  9. #include "itemtest/itemtest.h"
  10. #include "bitmap/bitmap.h"
  11. #include "bitmap/imageformat.h"
  12. #include "bitmap/psd.h"
  13. #include "bitmap/tgaloader.h"
  14. #include "bitmap/tgawriter.h"
  15. #include "vtf/vtf.h"
  16. #include "datamodel/dmattribute.h"
  17. #include "datamodel/dmelement.h"
  18. #include "datamodel/idatamodel.h"
  19. #include "fbxutils/dmfbxserializer.h"
  20. #include "filesystem.h"
  21. #include "movieobjects/dmefaceset.h"
  22. #include "movieobjects/dmematerial.h"
  23. #include "movieobjects/dmemesh.h"
  24. #include "movieobjects/dmemodel.h"
  25. #include "movieobjects/dmobjserializer.h"
  26. #include "movieobjects/dmsmdserializer.h"
  27. #include "movieobjects/dmeanimationlist.h"
  28. #include "movieobjects/dmeclip.h"
  29. #include "movieobjects/dmechannel.h"
  30. #include "movieobjects/dmelog.h"
  31. #include "steam/steam_api.h"
  32. #include "tier1/fmtstr.h"
  33. #include "tier1/utlsymbol.h"
  34. #include "tier2/fileutils.h"
  35. #include "tier2/p4helpers.h"
  36. #include "../public/zip_utils.h"
  37. // Last include
  38. #include "tier0/memdbgon.h"
  39. #ifdef BEGIN_DEFINE_LOGGING_CHANNEL
  40. BEGIN_DEFINE_LOGGING_CHANNEL( LOG_ITEMTEST, "ItemTest", LCF_CONSOLE_ONLY, LS_MESSAGE );
  41. ADD_LOGGING_CHANNEL_TAG( "ItemTest" );
  42. END_DEFINE_LOGGING_CHANNEL();
  43. #endif
  44. // This isn't available in the TF runtime (yet?)
  45. #ifndef FUNCTION_LINE_STRING
  46. #define FUNCTION_LINE_STRINGIFY(x) #x
  47. #define FUNCTION_LINE_TOSTRING(x) FUNCTION_LINE_STRINGIFY(x)
  48. #define FUNCTION_LINE_STRING __FUNCTION__ "(" FUNCTION_LINE_TOSTRING(__LINE__) "): "
  49. #endif
  50. //-----------------------------------------------------------------------------
  51. //
  52. //-----------------------------------------------------------------------------
  53. enum
  54. {
  55. k64KB = 65536
  56. };
  57. //-----------------------------------------------------------------------------
  58. //
  59. //-----------------------------------------------------------------------------
  60. static CSteamAPIContext g_SteamAPIContext;
  61. bool CItemUpload::m_bDev = false;
  62. bool CItemUpload::m_bIgnoreEnvVars = false;
  63. bool CItemUpload::m_bP4 = false;
  64. CUtlString CItemUpload::m_szForcedSteamID = "";
  65. CItemTestManifest *CItemUpload::m_pItemTestManifest = NULL;
  66. static bool g_bCompilePreview = false;
  67. static const char* kVMT = "VMT%d";
  68. //-----------------------------------------------------------------------------
  69. //
  70. //-----------------------------------------------------------------------------
  71. inline bool UtlStringLessThan( const CUtlString &sLhs, const CUtlString &sRhs )
  72. {
  73. return CaselessStringLessThanIgnoreSlashes( sLhs.String(), sRhs.String() );
  74. }
  75. //-----------------------------------------------------------------------------
  76. //
  77. //-----------------------------------------------------------------------------
  78. void CItemLog::Msg( const char *pszFormat, ... ) const
  79. {
  80. va_list args;
  81. va_start( args, pszFormat );
  82. CFmtStrMax str;
  83. str.AppendFormatV( pszFormat, args );
  84. Log( kItemtest_Log_Info, str );
  85. va_end( args );
  86. }
  87. //-----------------------------------------------------------------------------
  88. //
  89. //-----------------------------------------------------------------------------
  90. void CItemLog::Warning( const char *pszFormat, ... ) const
  91. {
  92. va_list args;
  93. va_start( args, pszFormat );
  94. CFmtStrMax str;
  95. str.AppendFormatV( pszFormat, args );
  96. Log( kItemtest_Log_Warning, str );
  97. va_end( args );
  98. }
  99. //-----------------------------------------------------------------------------
  100. //
  101. //-----------------------------------------------------------------------------
  102. void CItemLog::Error( const char *pszFormat, ... ) const
  103. {
  104. va_list args;
  105. va_start( args, pszFormat );
  106. CFmtStrMax str;
  107. str.AppendFormatV( pszFormat, args );
  108. Log( kItemtest_Log_Error, str );
  109. va_end( args );
  110. }
  111. //-----------------------------------------------------------------------------
  112. //
  113. //-----------------------------------------------------------------------------
  114. void CItemLog::Log( ItemtestLogLevel_t nLogLevel, const char *pszMessage ) const
  115. {
  116. if ( m_pItemLog && m_pItemLog != this )
  117. {
  118. m_pItemLog->Log( nLogLevel, pszMessage );
  119. return;
  120. }
  121. switch ( nLogLevel )
  122. {
  123. case kItemtest_Log_Info:
  124. Log_Msg( LOG_ITEMTEST, "%s", pszMessage );
  125. break;
  126. case kItemtest_Log_Warning:
  127. Log_Warning( LOG_ITEMTEST, "%s", pszMessage );
  128. break;
  129. case kItemtest_Log_Error:
  130. Log_Error( LOG_ITEMTEST, "%s", pszMessage );
  131. break;
  132. }
  133. }
  134. //-----------------------------------------------------------------------------
  135. //
  136. //-----------------------------------------------------------------------------
  137. bool CItemUpload::InitManifest( void )
  138. {
  139. if ( m_pItemTestManifest )
  140. return true;
  141. m_pItemTestManifest = new CItemTestManifest( "scripts/itemtest_manifest.txt", new CItemLog() );
  142. return m_pItemTestManifest->IsValid();
  143. }
  144. //-----------------------------------------------------------------------------
  145. //
  146. //-----------------------------------------------------------------------------
  147. bool CItemUpload::SanitizeName( const char *pszName, CUtlString &sCleanName )
  148. {
  149. char pszTemp[MAX_PATH];
  150. V_strcpy_safe( pszTemp, pszName );
  151. // Convert to lowercase, strip punctuation and turn spaces into underscores
  152. char *pszSrc = pszTemp;
  153. char *pszDst = pszTemp;
  154. while ( *pszSrc )
  155. {
  156. char c = *pszSrc++;
  157. if ( c >= 'a' && c <= 'z' )
  158. {
  159. *pszDst++ = c;
  160. }
  161. else if ( c >= 'A' && c <= 'Z' )
  162. {
  163. *pszDst++ = c - 'A' + 'a';
  164. }
  165. else if ( c >= '0' && c <= '9' )
  166. {
  167. *pszDst++ = c;
  168. }
  169. else if ( V_isspace(c) || c == '_' )
  170. {
  171. *pszDst++ = '_';
  172. }
  173. else
  174. {
  175. // Punctuation or non-ASCII characters, skip 'em!
  176. }
  177. }
  178. *pszDst = '\0';
  179. sCleanName = pszTemp;
  180. return !sCleanName.IsEmpty();
  181. }
  182. //-----------------------------------------------------------------------------
  183. //
  184. //-----------------------------------------------------------------------------
  185. CItemTestManifest::CItemTestManifest( const char *pszManifestFile, CItemLog *pItemLog ) :
  186. m_pItemLog( pItemLog ),
  187. m_vecVMTTextureRemaps( UtlStringLessThan )
  188. {
  189. m_pManifestKV = NULL;
  190. m_pItemDirectory = "";
  191. m_pAnimationDirectory = "";
  192. m_pIconDirectory = "";
  193. m_pZipSourceDirectory = "";
  194. m_pZipOutputDirectory = "";
  195. m_pQCTemplate = "";
  196. m_pQCITemplate = "";
  197. m_bTerseMessages = false;
  198. m_bItemPathUsesSteamId = true;
  199. m_pManifestKV = new KeyValues( pszManifestFile );
  200. if ( !m_pManifestKV->LoadFromFile(g_pFullFileSystem, pszManifestFile, "MOD") )
  201. {
  202. m_pManifestKV->deleteThis();
  203. m_pManifestKV = NULL;
  204. m_pItemLog->Warning( "ERROR: Failed to load manifest file: %s\n", pszManifestFile );
  205. return;
  206. }
  207. // Class list
  208. if ( !ParseStringsFromManifest( m_pManifestKV, "classes", m_vecClasses ) )
  209. return;
  210. // MDL Extensions
  211. if ( !ParseStringsFromManifest( m_pManifestKV, "mdl_files", m_vecMDLExtensions ) )
  212. return;
  213. // Animation MDL Extensions
  214. if ( !ParseStringsFromManifest( m_pManifestKV, "animation_mdl_files", m_vecAnimationMDLExtensions ) )
  215. return;
  216. // Material types
  217. KeyValues *pKVMaterialTypes = m_pManifestKV->FindKey("material_types");
  218. if ( !pKVMaterialTypes )
  219. {
  220. m_pItemLog->Warning( "ERROR: Failed to find a 'material_types' section in manifest file: %s\n", pszManifestFile );
  221. return;
  222. }
  223. FOR_EACH_SUBKEY( pKVMaterialTypes, pKVMaterialType )
  224. {
  225. const char *pszString = pKVMaterialType->GetName();
  226. int nIdx = m_vecMaterialTypes.AddToTail();
  227. m_vecMaterialTypes[nIdx].pszMaterialType = pszString;
  228. }
  229. const char *pszDefaultMatTypeString = m_pManifestKV->GetString("default_material_type");
  230. if ( !pszDefaultMatTypeString || !pszDefaultMatTypeString[0] )
  231. {
  232. m_pItemLog->Warning( "ERROR: Failed to find a 'default_material_type' string in manifest file: %s\n", pszManifestFile );
  233. return;
  234. }
  235. m_nDefaultMaterialType = GetMaterialType( pszDefaultMatTypeString );
  236. if ( m_nDefaultMaterialType == kInvalidMaterialType )
  237. {
  238. m_pItemLog->Warning( "ERROR: Default material type '%s' wasn't found in the material type list in manifest file: %s\n", m_nDefaultMaterialType, pszManifestFile );
  239. return;
  240. }
  241. // Material skins
  242. KeyValues *pKVMaterialSkins = m_pManifestKV->FindKey("material_skins");
  243. if ( pKVMaterialSkins )
  244. {
  245. FOR_EACH_SUBKEY( pKVMaterialSkins, pKVMaterialSkin )
  246. {
  247. const char *pszString = pKVMaterialSkin->GetName();
  248. int nIdx = m_vecMaterialSkins.AddToTail();
  249. m_vecMaterialSkins[nIdx].pszMaterialSkin = pszString;
  250. m_vecMaterialSkins[nIdx].pszFilenameAppend = pKVMaterialSkin->GetString("file_append");
  251. }
  252. const char *pszDefaultMatSkinString = m_pManifestKV->GetString("default_material_skin");
  253. if ( !pszDefaultMatSkinString || !pszDefaultMatSkinString[0] )
  254. {
  255. m_pItemLog->Warning( "ERROR: Failed to find a 'default_material_skin' string in manifest file: %s\n", pszManifestFile );
  256. return;
  257. }
  258. m_nDefaultMaterialSkin = GetMaterialSkin( pszDefaultMatSkinString );
  259. if ( m_nDefaultMaterialSkin == kInvalidMaterialSkin )
  260. {
  261. m_pItemLog->Warning( "ERROR: Default material skin '%s' wasn't found in the material skin list in manifest file: %s\n", pszDefaultMatSkinString, pszManifestFile );
  262. m_nDefaultMaterialSkin = 0;
  263. return;
  264. }
  265. }
  266. else
  267. {
  268. m_nDefaultMaterialSkin = 0;
  269. }
  270. // Texture types
  271. KeyValues *pKVTextureTypes = m_pManifestKV->FindKey("texture_types");
  272. if ( !pKVTextureTypes )
  273. {
  274. m_pItemLog->Warning( "ERROR: Failed to find a 'texture_types' section in manifest file: %s\n", pszManifestFile );
  275. return;
  276. }
  277. FOR_EACH_SUBKEY( pKVTextureTypes, pKVTexture )
  278. {
  279. const char *pszString = pKVTexture->GetName();
  280. int nIdx = m_vecTextureTypes.AddToTail();
  281. m_vecTextureTypes[nIdx].pszTextureType = pszString;
  282. m_vecTextureTypes[nIdx].bOptional = pKVTexture->GetBool( "optional" );
  283. m_vecTextureTypes[nIdx].pkvAddToVTEXConfig = pKVTexture->FindKey("add_to_vtex_config");
  284. }
  285. // VMT templates
  286. KeyValues *pKVTemplates = m_pManifestKV->FindKey("vmt_templates");
  287. if ( !pKVTemplates )
  288. {
  289. m_pItemLog->Warning( "ERROR: Failed to find a 'vmt_templates' section in manifest file: %s\n", pszManifestFile );
  290. return;
  291. }
  292. KeyValues *pKVClassTemplates = pKVTemplates->FindKey("classes");
  293. if ( pKVClassTemplates )
  294. {
  295. m_vecClassTemplates.SetCount( m_vecClasses.Count() );
  296. for ( int i = 0; i < m_vecClassTemplates.Count(); ++i )
  297. {
  298. m_vecClassTemplates[ i ] = NULL;
  299. }
  300. FOR_EACH_SUBKEY( pKVClassTemplates, pKVClassTemplate )
  301. {
  302. const char *pszHero = pKVClassTemplate->GetName();
  303. const char *pszTemplate = pKVClassTemplate->GetString();
  304. int iClass = m_vecClasses.Find( pszHero );
  305. if ( iClass == m_vecClasses.InvalidIndex() )
  306. {
  307. m_pItemLog->Warning( "ERROR: Found an invalid class '%s' in the vmt_templates entries in manifest file: %s\n", pszHero, pszManifestFile );
  308. return;
  309. }
  310. m_vecClassTemplates[iClass] = pszTemplate;
  311. }
  312. }
  313. KeyValues *pKVVMTRemaps = pKVTemplates->FindKey("vmt_texture_settings");
  314. if ( pKVVMTRemaps )
  315. {
  316. FOR_EACH_SUBKEY( pKVVMTRemaps, pKVRemap )
  317. {
  318. const char *pszVMTVar = pKVRemap->GetName();
  319. const char *pszTexture = pKVRemap->GetString();
  320. m_vecVMTTextureRemaps.Insert( pszTexture, pszVMTVar );
  321. }
  322. }
  323. // Icon types
  324. KeyValues *pKVIconTypes = m_pManifestKV->FindKey("icon_types");
  325. if ( pKVIconTypes )
  326. {
  327. FOR_EACH_SUBKEY( pKVIconTypes, pKVIcon )
  328. {
  329. const char *pszString = pKVIcon->GetName();
  330. int nIdx = m_vecIconTypes.AddToTail();
  331. m_vecIconTypes[nIdx].pszIconType = pszString;
  332. m_vecIconTypes[nIdx].nWidth = pKVIcon->GetInt( "width" );
  333. m_vecIconTypes[nIdx].nHeight = pKVIcon->GetInt( "height" );
  334. m_vecIconTypes[nIdx].pszFilenameAppend = pKVIcon->GetString("file_append");
  335. m_vecIconTypes[nIdx].pkvAddToVTEXConfig = pKVIcon->FindKey("add_to_vtex_config");
  336. KeyValues *pKVVMT = pKVIcon->FindKey("vmt_template");
  337. if ( pKVVMT )
  338. {
  339. m_vecIconTypes[nIdx].pkvVMTTemplate = pKVVMT->GetFirstSubKey();
  340. }
  341. else
  342. {
  343. m_vecIconTypes[nIdx].pkvVMTTemplate = NULL;
  344. }
  345. }
  346. }
  347. m_pItemDirectory = m_pManifestKV->GetString("item_directory");
  348. m_pAnimationDirectory = m_pManifestKV->GetString("animation_directory");
  349. m_pIconDirectory = m_pManifestKV->GetString("icon_directory");
  350. m_pZipSourceDirectory = m_pManifestKV->GetString("archive_source_path");
  351. m_pZipOutputDirectory = m_pManifestKV->GetString("archive_output_path");
  352. m_pQCTemplate = m_pManifestKV->GetString("qc_template");
  353. if ( V_strlen( m_pQCTemplate ) == 0 )
  354. {
  355. m_pItemLog->Warning( "ERROR: qc_template not defined in manifest file: %s\n", pszManifestFile );
  356. return;
  357. }
  358. m_pQCITemplate = m_pManifestKV->GetString( "qci_template" );
  359. if ( V_strlen( m_pQCITemplate ) == 0 )
  360. {
  361. m_pItemLog->Warning( "ERROR: qci_template not defined in manifest file: %s\n", pszManifestFile );
  362. return;
  363. }
  364. const char *pszQCLODDistances = m_pManifestKV->GetString("qc_lod_distances");
  365. CUtlVector<char*> vecQCLODDistances;
  366. V_SplitString( pszQCLODDistances, ",", vecQCLODDistances );
  367. m_vecQCLODDistances.SetCount( vecQCLODDistances.Count() );
  368. for ( int i = 0; i < vecQCLODDistances.Count(); ++i )
  369. {
  370. m_vecQCLODDistances[i] = V_atoi( vecQCLODDistances[i] );
  371. }
  372. m_bTerseMessages = m_pManifestKV->GetBool( "terse_messages", false );
  373. m_bItemPathUsesSteamId = m_pManifestKV->GetBool( "item_path_has_steamid", true );
  374. }
  375. //-----------------------------------------------------------------------------
  376. //
  377. //-----------------------------------------------------------------------------
  378. bool CItemTestManifest::ParseStringsFromManifest( KeyValues *pKV, const char *pszKeyName, CUtlVector< CUtlString > &vecList )
  379. {
  380. KeyValues *pKVSub = pKV->FindKey(pszKeyName);
  381. if ( !pKVSub )
  382. {
  383. m_pItemLog->Warning( "ERROR: Failed to find a '%s' section in manifest file.\n", pszKeyName );
  384. return false;
  385. }
  386. FOR_EACH_SUBKEY( pKVSub, pKVSubKey )
  387. {
  388. const char *pszString = pKVSubKey->GetName();
  389. vecList.AddToTail( pszString );
  390. }
  391. return true;
  392. }
  393. //-----------------------------------------------------------------------------
  394. //
  395. //-----------------------------------------------------------------------------
  396. int CItemTestManifest::GetMaterialType( const char *pszMaterialType )
  397. {
  398. FOR_EACH_VEC( m_vecMaterialTypes, i )
  399. {
  400. if ( V_stricmp(m_vecMaterialTypes[i].pszMaterialType, pszMaterialType) == 0 )
  401. return i;
  402. }
  403. return kInvalidMaterialType;
  404. }
  405. //-----------------------------------------------------------------------------
  406. //
  407. //-----------------------------------------------------------------------------
  408. int CItemTestManifest::GetMaterialSkin( const char *pszMaterialSkin )
  409. {
  410. FOR_EACH_VEC( m_vecMaterialSkins, i )
  411. {
  412. if ( V_stricmp(m_vecMaterialSkins[i].pszMaterialSkin, pszMaterialSkin) == 0 )
  413. return i;
  414. }
  415. return kInvalidMaterialSkin;
  416. }
  417. //-----------------------------------------------------------------------------
  418. //
  419. //-----------------------------------------------------------------------------
  420. int CItemTestManifest::GetTextureType( const char *pszTextureType )
  421. {
  422. FOR_EACH_VEC( m_vecTextureTypes, i )
  423. {
  424. if ( V_stricmp(m_vecTextureTypes[i].pszTextureType, pszTextureType) == 0 )
  425. return i;
  426. }
  427. return -1;
  428. }
  429. //-----------------------------------------------------------------------------
  430. //
  431. //-----------------------------------------------------------------------------
  432. KeyValues *CItemTestManifest::GetTextureAddToVTEXConfig( const char *pszTextureType )
  433. {
  434. int nIdx = GetTextureType(pszTextureType);
  435. if ( nIdx == -1 )
  436. return NULL;
  437. return m_vecTextureTypes[nIdx].pkvAddToVTEXConfig;
  438. }
  439. //-----------------------------------------------------------------------------
  440. //
  441. //-----------------------------------------------------------------------------
  442. int CItemTestManifest::GetIconType( const char *pszIconType )
  443. {
  444. FOR_EACH_VEC( m_vecIconTypes, i )
  445. {
  446. if ( V_stricmp(m_vecIconTypes[i].pszIconType, pszIconType) == 0 )
  447. return i;
  448. }
  449. return -1;
  450. }
  451. //-----------------------------------------------------------------------------
  452. //
  453. //-----------------------------------------------------------------------------
  454. bool CItemTestManifest::GetIconDimensions( int nIcon, int &nWidth, int &nHeight )
  455. {
  456. if ( nIcon >= 0 && nIcon < m_vecIconTypes.Count() )
  457. {
  458. nWidth = m_vecIconTypes[nIcon].nWidth;
  459. nHeight = m_vecIconTypes[nIcon].nHeight;
  460. return true;
  461. }
  462. else
  463. {
  464. nWidth = 0;
  465. nHeight = 0;
  466. return false;
  467. }
  468. }
  469. //-----------------------------------------------------------------------------
  470. //
  471. //-----------------------------------------------------------------------------
  472. const char *CItemTestManifest::GetVMTVarForTextureType( const char *pszTexture )
  473. {
  474. int nIndex = m_vecVMTTextureRemaps.Find(pszTexture);
  475. if ( nIndex == m_vecVMTTextureRemaps.InvalidIndex() )
  476. return NULL;
  477. return m_vecVMTTextureRemaps[nIndex];
  478. }
  479. //-----------------------------------------------------------------------------
  480. //
  481. //-----------------------------------------------------------------------------
  482. int GetClassCount()
  483. {
  484. return CItemUpload::Manifest()->GetNumClasses();
  485. }
  486. //-----------------------------------------------------------------------------
  487. //
  488. //-----------------------------------------------------------------------------
  489. const char *GetClassString( int i )
  490. {
  491. return ( i < 0 || i >= GetClassCount() ) ? NULL : CItemUpload::Manifest()->GetClass(i);
  492. }
  493. //-----------------------------------------------------------------------------
  494. //
  495. //-----------------------------------------------------------------------------
  496. const char *GetClassString( const char *pszClassString )
  497. {
  498. if ( !pszClassString || V_strlen( pszClassString ) <= 0 )
  499. return NULL;
  500. // Make sure it exists in our manifest file
  501. for ( int i = 0; i < CItemUpload::Manifest()->GetNumClasses(); i++ )
  502. {
  503. const char *pszHero = CItemUpload::Manifest()->GetClass(i);
  504. if ( V_stricmp(pszHero, pszClassString) == 0 )
  505. return pszHero;
  506. }
  507. //Log_Warning( LOG_ITEMTEST, "Invalid class specified: %s\n", pszClassString );
  508. return NULL;
  509. }
  510. //-----------------------------------------------------------------------------
  511. //
  512. //-----------------------------------------------------------------------------
  513. int GetClassIndex( const char *pszClassString )
  514. {
  515. const char *pszCleanClassString = GetClassString( pszClassString );
  516. if ( !pszCleanClassString )
  517. return -1;
  518. for ( int i = 0; i < GetClassCount(); ++i )
  519. {
  520. if ( !V_stricmp( pszCleanClassString, GetClassString( i ) ) )
  521. {
  522. return i;
  523. }
  524. }
  525. return -1;
  526. }
  527. //-----------------------------------------------------------------------------
  528. //
  529. //-----------------------------------------------------------------------------
  530. template < class T >
  531. const Vector &CItemUploadGame< T >::GetBipHead( int i )
  532. {
  533. static const Vector vOrigin( 0, 0, 0 );
  534. return ( i < 0 || i >= GetClassCount() ) ? vOrigin : CItemUploadGame< T >::s_vBipHead[i];
  535. }
  536. //-----------------------------------------------------------------------------
  537. //
  538. //-----------------------------------------------------------------------------
  539. template < class T >
  540. const RadianEuler &CItemUploadGame< T >::GetBipHeadRotation( int i )
  541. {
  542. static const RadianEuler eOrigin( 0, 0, 0 );
  543. return ( i < 0 || i >= GetClassCount() ) ? eOrigin : CItemUploadGame< T >::s_eBipHead[i];
  544. }
  545. //-----------------------------------------------------------------------------
  546. //
  547. //-----------------------------------------------------------------------------
  548. const Vector CItemUploadGame< CItemUploadTF >::s_vBipHead[] =
  549. {
  550. Vector( 0, 76.142968, -0.39608 ), // demo
  551. Vector( 0, 69.030248, -1.264691 ), // engineer
  552. Vector( -0.000138993, 79.541796, -3.352982 ), // heavy
  553. Vector( -0.000111273, 76.504372, -0.565035 ), // medic
  554. Vector( -0.000102534, 71.788881, 2.145585 ), // pyro
  555. Vector( 0, 73.501752, -1.429994 ), // scout
  556. Vector( 0, 75.982279, -3.858408 ), // sniper
  557. Vector( 0, 75.194376, -1.120618 ), // soldier
  558. Vector( 0, 75.679732, -2.87915 ) // spy
  559. };
  560. COMPILE_TIME_ASSERT( ARRAYSIZE( CItemUploadGame< CItemUploadTF >::s_vBipHead ) == CItemUploadTF::kClassCount );
  561. //-----------------------------------------------------------------------------
  562. //
  563. //-----------------------------------------------------------------------------
  564. const RadianEuler CItemUploadGame< CItemUploadTF >::s_eBipHead[] =
  565. {
  566. RadianEuler( DEG2RAD( -180.0 ), 0, 0 ), // demo
  567. RadianEuler( DEG2RAD( -170.459 ), 0, 0 ), // engineer
  568. RadianEuler( DEG2RAD( -180.0 ), 0, 0 ), // heavy
  569. RadianEuler( DEG2RAD( -180.0 ), 0, 0 ), // medic
  570. RadianEuler( DEG2RAD( -154.175 ), 0, 0 ), // pyro
  571. RadianEuler( DEG2RAD( -173.451 ), 0, 0 ), // scout
  572. RadianEuler( DEG2RAD( -172.722 ), 0, 0 ), // sniper
  573. RadianEuler( DEG2RAD( -179.729 ), 0, 0 ), // soldier
  574. RadianEuler( DEG2RAD( -180.0 ), 0, 0 ) // spy
  575. };
  576. COMPILE_TIME_ASSERT( ARRAYSIZE( CItemUploadGame< CItemUploadTF >::s_eBipHead ) == CItemUploadTF::kClassCount );
  577. //-----------------------------------------------------------------------------
  578. //
  579. //-----------------------------------------------------------------------------
  580. template class CItemUploadGame< CItemUploadTF >;
  581. //-----------------------------------------------------------------------------
  582. //
  583. // Try and get the Steam Account ID and return it as a 10 character hex
  584. // string prefixed with 0x.
  585. //
  586. //-----------------------------------------------------------------------------
  587. bool CItemUpload::GetSteamId( CUtlString &sSteamId )
  588. {
  589. if ( GetDevMode() )
  590. {
  591. sSteamId = "";
  592. return true;
  593. }
  594. const char *pszForcedSteamID = GetForcedSteamID();
  595. if ( pszForcedSteamID && pszForcedSteamID[0] )
  596. {
  597. sSteamId = pszForcedSteamID;
  598. return true;
  599. }
  600. bool bRetVal = false;
  601. char szBuf[ BUFSIZ ];
  602. szBuf[0] = '\0';
  603. // Try to query steam directly, this will fail if steam isn't running or the
  604. // process calling this function wasn't launched through steam (or through a
  605. // process launched through steam) or there isn't a steam_appid.txt in
  606. // the same directory as the executable running this (use 440 for TF).
  607. bool shutdownSteam = false;
  608. if ( !SteamClient() )
  609. {
  610. SteamAPI_InitSafe();
  611. SteamAPI_SetTryCatchCallbacks( false ); // We don't use exceptions, so tell steam not to use try/catch in callback handlers
  612. shutdownSteam = true;
  613. }
  614. if ( SteamAPI_IsSteamRunning() )
  615. {
  616. g_SteamAPIContext.Init();
  617. ISteamUser *pSteamUser = g_SteamAPIContext.SteamUser();
  618. if ( pSteamUser )
  619. {
  620. CSteamID cSteamID = pSteamUser->GetSteamID();
  621. const uint32 nAccountID = cSteamID.GetAccountID();
  622. V_snprintf( szBuf, ARRAYSIZE( szBuf ), "0x%08x", nAccountID );
  623. bRetVal = true;
  624. }
  625. }
  626. if ( shutdownSteam )
  627. {
  628. SteamAPI_Shutdown();
  629. }
  630. sSteamId = szBuf;
  631. return bRetVal;
  632. }
  633. //-----------------------------------------------------------------------------
  634. //
  635. //-----------------------------------------------------------------------------
  636. bool CItemUpload::GetVProjectDir( CUtlString &sVProjectDir )
  637. {
  638. char szVProject[ BUFSIZ ] = "";
  639. GetModSubdirectory( "", szVProject, ARRAYSIZE( szVProject ) );
  640. V_StripTrailingSlash( szVProject );
  641. sVProjectDir = szVProject;
  642. return true;
  643. }
  644. //-----------------------------------------------------------------------------
  645. //
  646. //-----------------------------------------------------------------------------
  647. bool CItemUpload::GetVMod( CUtlString &sVMod )
  648. {
  649. sVMod = "";
  650. CUtlString sVProjectDir;
  651. if ( !GetVProjectDir( sVProjectDir ) )
  652. return false;
  653. char szBuf[ k64KB ];
  654. V_FileBase( sVProjectDir.String(), szBuf, ARRAYSIZE( szBuf ) );
  655. sVMod = szBuf;
  656. return true;
  657. }
  658. //-----------------------------------------------------------------------------
  659. // Guess where the SourceSDK root is based on executable directory...
  660. // If there's a /bin/orangebox/bin/ in the executable path we know
  661. // the SourceSDK is above it, otherwise we don't know anything and false is
  662. // returned
  663. //
  664. // If DevMode (-dev) then always returns false
  665. //
  666. // TODO: This is for TF & SourceSDK only and likely this is the only
  667. // weird configuration this hack needs to be done with. If it's
  668. // a normal game/content tree then none of this hacky stuff
  669. // should be needed
  670. //-----------------------------------------------------------------------------
  671. bool CItemUpload::GetSourceSDKFromExe( CUtlString &sSourceSDK, CUtlString &sSourceSDKBin )
  672. {
  673. if ( GetDevMode() )
  674. return false;
  675. CUtlString sCurrentExecutableFileName;
  676. GetCurrentExecutableFileName( sCurrentExecutableFileName );
  677. // Special hack for executables running out of the orange box SDK
  678. sCurrentExecutableFileName.FixSlashes( '/' );
  679. const char *pszBinOrangeBoxBin = V_strstr( sCurrentExecutableFileName.String(), "/bin/orangebox/bin/" );
  680. if ( pszBinOrangeBoxBin )
  681. {
  682. sSourceSDK.SetDirect( sCurrentExecutableFileName.String(), pszBinOrangeBoxBin - sCurrentExecutableFileName.String() );
  683. char szBinDir[ MAX_PATH ];
  684. V_ExtractFilePath( sCurrentExecutableFileName.String(), szBinDir, ARRAYSIZE( szBinDir ) );
  685. sSourceSDKBin = szBinDir;
  686. return true;
  687. }
  688. // Get Source SDK path
  689. HKEY hKey;
  690. char szSDKPath[ k64KB ];
  691. char szEngineVersion[ k64KB ];
  692. szSDKPath[0] = szEngineVersion[0] = '\0';
  693. GetEnvironmentVariable( "SOURCESDK", szSDKPath, sizeof( szSDKPath ) );
  694. if ( ERROR_SUCCESS == RegOpenKey( HKEY_CURRENT_USER, "Software\\Valve\\Source SDK", &hKey ) )
  695. {
  696. DWORD dwSize = sizeof( szEngineVersion );
  697. RegQueryValueEx( hKey, "EngineVer", NULL, NULL, (LPBYTE)szEngineVersion, &dwSize );
  698. RegCloseKey( hKey );
  699. }
  700. else
  701. {
  702. // Let's assume orange box for now
  703. V_strcpy_safe( szEngineVersion, "orangebox" );
  704. }
  705. if ( *szSDKPath )
  706. {
  707. // Normalize slashes to be consistent with the orange box SDK code above
  708. V_FixSlashes( szSDKPath, '/' );
  709. sSourceSDK = szSDKPath;
  710. sSourceSDKBin.Format( "%s/bin/%s/bin", szSDKPath, szEngineVersion );
  711. return true;
  712. }
  713. return false;
  714. }
  715. //-----------------------------------------------------------------------------
  716. // Returns $SOURCESDK_content/FileName( $VPROJECT ) if it SOURCESDK is set
  717. // otherwise returns VCONTENT if it is set, otherwise returns
  718. // $VPROJECT/../
  719. //-----------------------------------------------------------------------------
  720. static bool CheckContentPath( CUtlString &sContentDir )
  721. {
  722. char szContentDir[ MAX_PATH ];
  723. V_FixupPathName( szContentDir, ARRAYSIZE( szContentDir ), sContentDir );
  724. V_StripTrailingSlash( szContentDir );
  725. sContentDir = szContentDir;
  726. return g_pFullFileSystem->IsDirectory( sContentDir );
  727. }
  728. bool CItemUpload::GetContentDir( CUtlString &sContentDir )
  729. {
  730. // Without VPROJECT set, can't figure anything out
  731. CUtlString sVMod;
  732. if ( !GetVMod( sVMod ) )
  733. return false;
  734. char szBuf[ k64KB ];
  735. // The game includes its own content directory?
  736. if ( IgnoreEnvironmentVariables() )
  737. {
  738. CUtlString sVProject;
  739. if ( !GetVProjectDir( sVProject ) )
  740. return false;
  741. sVProject.FixSlashes( '/' );
  742. // When we run in Steam, we get something like this back:
  743. // "u:/steambeta/steamapps/common/[staging] dota 2/dota"
  744. // We need to trim off the game name, and append content.
  745. V_strcpy_safe( szBuf, sVProject );
  746. if ( !V_StripLastDir( szBuf, ARRAYSIZE( szBuf ) ) )
  747. return false;
  748. sContentDir = szBuf;
  749. sContentDir += "content/";
  750. sContentDir += sVMod;
  751. return true;
  752. }
  753. CUtlString sSourceSDK, sSourceSDKBin;
  754. // Check for the game/content layout in dev builds
  755. CUtlString sVProject;
  756. if ( GetVProjectDir( sVProject ) )
  757. {
  758. sVProject.FixSlashes( '/' );
  759. const char *pszGame = V_stristr( sVProject.String(), "/game/" );
  760. if ( pszGame )
  761. {
  762. sContentDir = sVProject;
  763. sContentDir.SetLength( pszGame - sVProject.String() );
  764. sContentDir += "/content/";
  765. sContentDir += sVMod;
  766. V_FixupPathName( szBuf, ARRAYSIZE( szBuf ), sContentDir.String() );
  767. sContentDir = szBuf;
  768. if ( CheckContentPath( sContentDir ) )
  769. {
  770. return true;
  771. }
  772. }
  773. else
  774. {
  775. // try to look for workshop/content in the mod dir
  776. sContentDir = sVProject;
  777. sContentDir += "/workshop/content";
  778. V_FixupPathName( szBuf, ARRAYSIZE( szBuf ), sContentDir.String() );
  779. sContentDir = szBuf;
  780. if ( CheckContentPath( sContentDir ) )
  781. {
  782. return true;
  783. }
  784. }
  785. }
  786. // Check for the VCONTENT environment variable
  787. if ( GetEnvironmentVariable( "VCONTENT", szBuf, ARRAYSIZE( szBuf ) ) != 0 )
  788. {
  789. sContentDir = szBuf;
  790. sContentDir += "/";
  791. sContentDir += sVMod;
  792. V_FixupPathName( szBuf, ARRAYSIZE( szBuf ), sContentDir.String() );
  793. sContentDir = szBuf;
  794. if ( CheckContentPath( sContentDir ) )
  795. {
  796. return true;
  797. }
  798. }
  799. // Check for the Source SDK in steam builds
  800. if ( GetSourceSDKFromExe( sSourceSDK, sSourceSDKBin ) )
  801. {
  802. sContentDir = sSourceSDK;
  803. sContentDir += "_content\\";
  804. sContentDir += sVMod;
  805. V_FixupPathName( szBuf, ARRAYSIZE( szBuf ), sContentDir.String() );
  806. sContentDir = szBuf;
  807. if ( CheckContentPath( sContentDir ) )
  808. {
  809. return true;
  810. }
  811. }
  812. return false;
  813. }
  814. //-----------------------------------------------------------------------------
  815. //
  816. // Find the directory for the binaries
  817. //
  818. //-----------------------------------------------------------------------------
  819. static bool CheckToolPath( CUtlString &sBinDir )
  820. {
  821. char szBinDir[ MAX_PATH ];
  822. V_FixupPathName( szBinDir, ARRAYSIZE( szBinDir ), sBinDir );
  823. V_StripTrailingSlash( szBinDir );
  824. sBinDir = szBinDir;
  825. char szVtexFileName[ MAX_PATH ];
  826. V_ComposeFileName( sBinDir, "vtex.exe", szVtexFileName, ARRAYSIZE( szVtexFileName ) );
  827. char szStudiomdlFileName[ MAX_PATH ];
  828. V_ComposeFileName( sBinDir, "studiomdl.exe", szStudiomdlFileName, ARRAYSIZE( szStudiomdlFileName ) );
  829. return g_pFullFileSystem->FileExists( szVtexFileName ) && g_pFullFileSystem->FileExists( szStudiomdlFileName );
  830. }
  831. bool CItemUpload::GetBinDirectory( CUtlString &sBinDir )
  832. {
  833. // Get the full path to the executable this code is running in
  834. // this should be the 'bin' directory we want... just to be sure
  835. // make sure vtex.exe and studiomdl.exe exist in that directory
  836. CUtlString sCurrentExecutableFileName;
  837. GetCurrentExecutableFileName( sCurrentExecutableFileName );
  838. char szBinDir[ MAX_PATH ];
  839. V_ExtractFilePath( sCurrentExecutableFileName.String(), szBinDir, ARRAYSIZE( szBinDir ) );
  840. sBinDir = szBinDir;
  841. if ( CheckToolPath( sBinDir ) )
  842. {
  843. return true;
  844. }
  845. // Check for the game/bin directory
  846. CUtlString sVProject;
  847. if ( GetVProjectDir( sVProject ) && !sVProject.IsEmpty() )
  848. {
  849. sVProject.FixSlashes( '/' );
  850. const char *pszGame = V_stristr( sVProject.String(), "/game/" );
  851. if ( pszGame )
  852. {
  853. sBinDir = sVProject;
  854. sBinDir.SetLength( pszGame - sVProject.String() );
  855. sBinDir += "/game/bin";
  856. if ( CheckToolPath( sBinDir ) )
  857. {
  858. return true;
  859. }
  860. }
  861. // When we run in Steam, we get something like this back:
  862. // "u:/steambeta/steamapps/common/[staging] dota 2/dota"
  863. // We need to trim off the game name, and append bin.
  864. V_strcpy_safe( szBinDir, sVProject );
  865. if ( !V_StripLastDir( szBinDir, ARRAYSIZE( szBinDir ) ) )
  866. return false;
  867. sBinDir = szBinDir;
  868. sBinDir += "/bin";
  869. if ( CheckToolPath( sBinDir ) )
  870. {
  871. return true;
  872. }
  873. }
  874. // Check for the Source SDK in steam builds
  875. CUtlString sSourceSDK;
  876. if ( !GetDevMode() && GetSourceSDKFromExe( sSourceSDK, sBinDir ) )
  877. {
  878. if ( CheckToolPath( sBinDir ) )
  879. {
  880. return true;
  881. }
  882. }
  883. return false;
  884. }
  885. //-----------------------------------------------------------------------------
  886. //
  887. //-----------------------------------------------------------------------------
  888. bool CItemUpload::FileExists( const char *pszFilename )
  889. {
  890. DWORD attribs = ::GetFileAttributesA( pszFilename );
  891. if ( attribs == INVALID_FILE_ATTRIBUTES )
  892. return false;
  893. return ( ( attribs & FILE_ATTRIBUTE_DIRECTORY ) == 0 );
  894. }
  895. //-----------------------------------------------------------------------------
  896. //
  897. //-----------------------------------------------------------------------------
  898. bool CItemUpload::CopyFiles( const char *pszSourceDir, const char *pszPattern, const char *pszDestDir )
  899. {
  900. char szFindPattern[ k64KB ];
  901. bool bAllSucceeded = true;
  902. V_snprintf( szFindPattern, sizeof( szFindPattern ), "%s%s", pszSourceDir, pszPattern );
  903. WIN32_FIND_DATA findData;
  904. HANDLE hFind = FindFirstFile( szFindPattern, &findData );
  905. if ( hFind == INVALID_HANDLE_VALUE )
  906. {
  907. return false;
  908. }
  909. else
  910. {
  911. do
  912. {
  913. char szSrcPath[ k64KB ];
  914. char szDestPath[ k64KB ];
  915. V_snprintf( szSrcPath, sizeof( szSrcPath ), "%s%s", pszSourceDir, findData.cFileName );
  916. V_snprintf( szDestPath, sizeof( szDestPath ), "%s\\%s", pszDestDir, findData.cFileName );
  917. DeleteFile( szDestPath );
  918. ::CopyFile( szSrcPath, szDestPath, false );
  919. bAllSucceeded &= FileExists( szDestPath );
  920. } while ( FindNextFile( hFind, &findData ) );
  921. FindClose( hFind );
  922. return bAllSucceeded;
  923. }
  924. }
  925. static bool DoFileCopy( const char *pszSourceFile, const char *pszDestFile )
  926. {
  927. int remaining, count;
  928. char buf[4096];
  929. FileHandle_t in, out;
  930. in = g_pFullFileSystem->Open( pszSourceFile, "rb" );
  931. AssertMsg( in, "DoFileCopy: Input file failed to open" );
  932. if ( in == FILESYSTEM_INVALID_HANDLE )
  933. return false;
  934. // create directories up to the cache file
  935. char szDestPath[MAX_PATH];
  936. V_ExtractFilePath( pszDestFile, szDestPath, sizeof( szDestPath ) );
  937. g_pFullFileSystem->CreateDirHierarchy( szDestPath );
  938. out = g_pFullFileSystem->Open( pszDestFile, "wb" );
  939. AssertMsg( out, "DoFileCopy: Output file failed to open" );
  940. if ( out == FILESYSTEM_INVALID_HANDLE )
  941. {
  942. g_pFullFileSystem->Close( in );
  943. return false;
  944. }
  945. remaining = g_pFullFileSystem->Size( in );
  946. while ( remaining > 0 )
  947. {
  948. if (remaining < sizeof(buf))
  949. {
  950. count = remaining;
  951. }
  952. else
  953. {
  954. count = sizeof(buf);
  955. }
  956. g_pFullFileSystem->Read( buf, count, in );
  957. g_pFullFileSystem->Write( buf, count, out );
  958. remaining -= count;
  959. }
  960. g_pFullFileSystem->Close( in );
  961. g_pFullFileSystem->Close( out );
  962. return true;
  963. }
  964. //-----------------------------------------------------------------------------
  965. //
  966. //-----------------------------------------------------------------------------
  967. bool CItemUpload::CopyFile( const char *pszSourceFile, const char *pszDestFile )
  968. {
  969. if ( ::CopyFile( pszSourceFile, pszDestFile, false ) == 0 )
  970. return false;
  971. DWORD nFileAttr = GetFileAttributes( pszDestFile );
  972. if ( nFileAttr == INVALID_FILE_ATTRIBUTES )
  973. return false;
  974. nFileAttr &= ~FILE_ATTRIBUTE_READONLY;
  975. SetFileAttributes( pszDestFile, nFileAttr );
  976. return true;
  977. }
  978. //=============================================================================
  979. //
  980. //=============================================================================
  981. static bool RemoveTextBlock( const char *str, char const *search, char *pszOutBuf, int nSizeofOutBuf )
  982. {
  983. if ( str != pszOutBuf )
  984. {
  985. V_strncpy( pszOutBuf, str, nSizeofOutBuf );
  986. }
  987. bool changed = false;
  988. if ( !V_strstr( str, search ) )
  989. {
  990. return false;
  991. }
  992. int offset = 0;
  993. while ( true )
  994. {
  995. char* pos = V_strstr( str + offset, search );
  996. if ( !pos )
  997. {
  998. break;
  999. }
  1000. CUtlString temp = str;
  1001. // Found an instance
  1002. int left = pos - str;
  1003. CUtlString strLeft = temp.Slice( 0, left );
  1004. pos = V_strstr( str + left, "}" );
  1005. if ( !pos )
  1006. {
  1007. AssertMsg( pos, "cannot find end of text block\n" );
  1008. return false;
  1009. }
  1010. int right = pos - str + 1;
  1011. CUtlString strRight = temp.Slice( right );
  1012. temp = strLeft;
  1013. temp += strRight;
  1014. // Replace entire string
  1015. V_strncpy( pszOutBuf, temp.String(), nSizeofOutBuf );
  1016. offset = right;
  1017. changed = true;
  1018. }
  1019. return changed;
  1020. }
  1021. //=============================================================================
  1022. //
  1023. //=============================================================================
  1024. CTargetBase::CTargetBase( CAsset *pAsset, const CTargetBase *pTargetParent )
  1025. : CItemLog( pAsset )
  1026. , m_pAsset( pAsset )
  1027. , m_nRefCount( 0 )
  1028. , m_pTargetParent( pTargetParent )
  1029. , m_bIgnoreP4( false )
  1030. , m_kvCustomKeys( new KeyValues( "custom keys" ) )
  1031. {
  1032. }
  1033. //-----------------------------------------------------------------------------
  1034. //
  1035. //-----------------------------------------------------------------------------
  1036. bool CTargetBase::Compile()
  1037. {
  1038. CUtlString sName;
  1039. if ( !GetOutputPath( sName, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  1040. {
  1041. Warning( "CTarget%s::Compile - GetOutputPath failed\n", GetTypeString() );
  1042. return false;
  1043. }
  1044. CUtlString sTmp;
  1045. if ( !IsOk( sTmp ) )
  1046. {
  1047. Warning( "CTarget%s::Compile( %s ) - Not Valid: %s\n", GetTypeString(), sName.String(), sTmp.String() );
  1048. return false;
  1049. }
  1050. // Compile all inputs first
  1051. if ( !CreateOutputDirectory() )
  1052. {
  1053. Warning( "CTarget%s::Compile - CreateOutputDirectory failed\n", GetTypeString() );
  1054. return false;
  1055. }
  1056. CUtlVector< CTargetBase * > inputs;
  1057. bool bRet = GetInputs( inputs );
  1058. if ( !bRet )
  1059. {
  1060. Warning( "CTarget%s::Compile - GetInputs failed\n", GetTypeString() );
  1061. return bRet;
  1062. }
  1063. for ( int i = 0; i < inputs.Count(); ++i )
  1064. {
  1065. CTargetBase *pTargetBase = inputs.Element( i );
  1066. if ( !pTargetBase )
  1067. {
  1068. Warning( "WARNING: CTarget%s::Compile - Target %d NULL\n", GetTypeString(), i );
  1069. continue;
  1070. }
  1071. if ( !pTargetBase->Compile() )
  1072. {
  1073. Warning( "WARNING: CTarget%s::Compile - Target %d Compile Failed\n", GetTypeString(), i );
  1074. bRet = false;
  1075. break;
  1076. }
  1077. }
  1078. return bRet;
  1079. }
  1080. //-----------------------------------------------------------------------------
  1081. //
  1082. //-----------------------------------------------------------------------------
  1083. const char *CTargetBase::GetItemDirectory() const
  1084. {
  1085. if ( m_pTargetParent )
  1086. {
  1087. return m_pTargetParent->GetItemDirectory();
  1088. }
  1089. else
  1090. {
  1091. return CItemUpload::Manifest()->GetItemDirectory();
  1092. }
  1093. }
  1094. //-----------------------------------------------------------------------------
  1095. // Return the number of files that are output from this CTarget
  1096. //-----------------------------------------------------------------------------
  1097. int CTargetBase::GetOutputCount() const
  1098. {
  1099. const ExtensionList *pList = GetExtensionsAndCount();
  1100. return (pList ? pList->Count() : 0);
  1101. }
  1102. //-----------------------------------------------------------------------------
  1103. //
  1104. //-----------------------------------------------------------------------------
  1105. bool CTargetBase::GetOutputPath(
  1106. CUtlString &sOutputPath,
  1107. int nIndex /* = 0 */,
  1108. uint nPathFlags /* = PATH_FLAG_ALL */ ) const
  1109. {
  1110. sOutputPath.Clear();
  1111. if ( nIndex < 0 )
  1112. return false;
  1113. CUtlVector< CUtlString > sOutputPaths;
  1114. if ( !GetOutputPaths( sOutputPaths, nPathFlags ) )
  1115. return false;
  1116. if ( nIndex >= sOutputPaths.Count() )
  1117. return false;
  1118. sOutputPath = sOutputPaths.Element( nIndex );
  1119. return ( sOutputPath.Length() > 0 );
  1120. }
  1121. //-----------------------------------------------------------------------------
  1122. //
  1123. //-----------------------------------------------------------------------------
  1124. bool CTargetBase::GetOutputPaths(
  1125. CUtlVector< CUtlString > &sOutputPaths,
  1126. uint nPathFlags /* = PATH_FLAG_ALL */,
  1127. bool bRecurse /* = false */ ) const
  1128. {
  1129. CUtlString sTmp;
  1130. if ( !IsOk( sTmp ) )
  1131. {
  1132. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  1133. return false;
  1134. }
  1135. CUtlString sDirName;
  1136. if ( nPathFlags & PATH_FLAG_PATH )
  1137. {
  1138. if ( !GetDirName( sDirName, nPathFlags ) )
  1139. return false;
  1140. }
  1141. const ExtensionList *pvecExtensions = GetExtensionsAndCount();
  1142. int nExtCount = pvecExtensions ? pvecExtensions->Count() : 0;
  1143. for ( int i = 0; i < nExtCount; ++i )
  1144. {
  1145. CUtlString &sOutputPath = sOutputPaths.Element( sOutputPaths.AddToTail() );
  1146. if ( nPathFlags & PATH_FLAG_PATH )
  1147. {
  1148. sOutputPath = sDirName;
  1149. }
  1150. if ( nPathFlags & PATH_FLAG_FILE )
  1151. {
  1152. if ( sOutputPath.Length() > 0 )
  1153. {
  1154. sOutputPath += "/";
  1155. }
  1156. CUtlString sName;
  1157. GetName( sName );
  1158. sOutputPath += sName;
  1159. if ( nPathFlags & PATH_FLAG_EXTENSION )
  1160. {
  1161. sOutputPath += pvecExtensions->Element(i);
  1162. }
  1163. }
  1164. sOutputPath.FixSlashes();
  1165. }
  1166. bool bRet = sOutputPaths.Count() > 0;
  1167. if ( bRecurse )
  1168. {
  1169. CUtlVector< CTargetBase * > inputs;
  1170. if ( GetInputs( inputs ) )
  1171. {
  1172. for ( int i = 0; i < inputs.Count(); ++i )
  1173. {
  1174. CTargetBase *pTargetBase = inputs.Element( i );
  1175. if ( !pTargetBase )
  1176. continue;
  1177. bRet = pTargetBase->GetOutputPaths( sOutputPaths, nPathFlags, bRecurse );
  1178. }
  1179. }
  1180. else
  1181. {
  1182. bRet = false;
  1183. }
  1184. }
  1185. return bRet;
  1186. }
  1187. //-----------------------------------------------------------------------------
  1188. //
  1189. //-----------------------------------------------------------------------------
  1190. bool CTargetBase::GetOutputPaths(
  1191. CUtlVector< CUtlString > &sOutputPaths,
  1192. bool bRelative /* = true */,
  1193. bool bRecurse /* = true */,
  1194. bool bExtension /* = true */,
  1195. bool bPrefix /* = true */ ) const
  1196. {
  1197. CUtlString sTmp;
  1198. if ( !IsOk( sTmp ) )
  1199. {
  1200. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  1201. return false;
  1202. }
  1203. CUtlString sDirA;
  1204. if ( bRelative )
  1205. {
  1206. if ( !Asset()->GetRelativeDir( sDirA, bPrefix ? GetPrefix() : NULL, this ) )
  1207. return false;
  1208. }
  1209. else
  1210. {
  1211. if ( !Asset()->GetAbsoluteDir( sDirA, bPrefix ? GetPrefix() : NULL, this ) )
  1212. return false;
  1213. }
  1214. const ExtensionList *pvecExtensions = GetExtensionsAndCount();
  1215. int nExtCount = pvecExtensions ? pvecExtensions->Count() : 0;
  1216. for ( int i = 0; i < nExtCount; ++i )
  1217. {
  1218. CUtlString &sRelativePath = sOutputPaths.Element( sOutputPaths.AddToTail() );
  1219. CUtlString sName;
  1220. GetName( sName );
  1221. sRelativePath = sDirA;
  1222. sRelativePath += "/";
  1223. sRelativePath += sName;
  1224. if ( bExtension )
  1225. {
  1226. sRelativePath += pvecExtensions->Element(i);
  1227. }
  1228. sRelativePath.FixSlashes();
  1229. }
  1230. bool bRet = sOutputPaths.Count() > 0;
  1231. if ( bRecurse )
  1232. {
  1233. CUtlVector< CTargetBase * > inputs;
  1234. if ( GetInputs( inputs ) )
  1235. {
  1236. for ( int i = 0; i < inputs.Count(); ++i )
  1237. {
  1238. CTargetBase *pTargetBase = inputs.Element( i );
  1239. if ( !pTargetBase )
  1240. continue;
  1241. bRet = pTargetBase->GetOutputPaths( sOutputPaths, bRelative, bRecurse, bExtension ) && bRet;
  1242. }
  1243. }
  1244. else
  1245. {
  1246. bRet = false;
  1247. }
  1248. }
  1249. return bRet;
  1250. }
  1251. //-----------------------------------------------------------------------------
  1252. //
  1253. //-----------------------------------------------------------------------------
  1254. bool CTargetBase::GetInputPaths(
  1255. CUtlVector< CUtlString > &sInputPaths,
  1256. bool bRelative /* = true */,
  1257. bool bRecurse /* = true */,
  1258. bool bExtension /* = true */ )
  1259. {
  1260. CUtlString sTmp;
  1261. if ( !IsOk( sTmp ) )
  1262. {
  1263. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  1264. return false;
  1265. }
  1266. CUtlVector< CTargetBase * > inputs;
  1267. if ( !GetInputs( inputs ) )
  1268. return false;
  1269. bool bRet = true;
  1270. for ( int i = 0; bRet && i < inputs.Count(); ++i )
  1271. {
  1272. CTargetBase *pTargetBase = inputs.Element( i );
  1273. if ( !pTargetBase )
  1274. continue;
  1275. bRet = pTargetBase->GetOutputPaths( sInputPaths, bRelative, false, bExtension ) && bRet;
  1276. if ( bRecurse )
  1277. {
  1278. bRet = pTargetBase->GetInputPaths( sInputPaths, bRelative, bRecurse, bExtension ) && bRet;
  1279. }
  1280. }
  1281. return bRet;
  1282. }
  1283. //-----------------------------------------------------------------------------
  1284. //
  1285. //-----------------------------------------------------------------------------
  1286. void CTargetBase::GetName( CUtlString &sName ) const
  1287. {
  1288. if ( !GetCustomOutputName().IsEmpty() )
  1289. {
  1290. sName = GetCustomOutputName();
  1291. sName += GetNameSuffix();
  1292. return;
  1293. }
  1294. // don't take parent's custom output name
  1295. if ( m_pTargetParent && m_pTargetParent->GetCustomOutputName().IsEmpty() )
  1296. {
  1297. m_pTargetParent->GetName( sName );
  1298. }
  1299. else
  1300. {
  1301. sName = GetAssetName();
  1302. }
  1303. sName += GetNameSuffix();
  1304. }
  1305. //-----------------------------------------------------------------------------
  1306. //
  1307. //-----------------------------------------------------------------------------
  1308. const CUtlString &CTargetBase::GetAssetName() const
  1309. {
  1310. return Asset()->GetAssetName();
  1311. }
  1312. //-----------------------------------------------------------------------------
  1313. //
  1314. //-----------------------------------------------------------------------------
  1315. CAsset *CTargetBase::Asset() const
  1316. {
  1317. return m_pAsset;
  1318. }
  1319. //-----------------------------------------------------------------------------
  1320. //
  1321. //-----------------------------------------------------------------------------
  1322. bool CTargetBase::CheckFile( const char *pszFilename ) const
  1323. {
  1324. if ( _access( pszFilename, 06 ) == 0 )
  1325. return true;
  1326. Warning( "CTarget%s::Compile NO FILE! - %s\n", GetTypeString(), pszFilename );
  1327. return false;
  1328. }
  1329. //-----------------------------------------------------------------------------
  1330. //
  1331. //-----------------------------------------------------------------------------
  1332. bool CTargetBase::GetDirName(
  1333. CUtlString &sDirName,
  1334. uint nPathFlags /* = PATH_FLAG_ALL */ ) const
  1335. {
  1336. sDirName.Clear();
  1337. CAsset *pAsset = Asset();
  1338. if ( !pAsset )
  1339. {
  1340. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - NULL Asset\n", GetTypeString() );
  1341. return false;
  1342. }
  1343. CUtlString sTmp;
  1344. if ( !pAsset->IsOk( sTmp ) )
  1345. {
  1346. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  1347. return false;
  1348. }
  1349. if ( nPathFlags & PATH_FLAG_ABSOLUTE )
  1350. {
  1351. if ( IsContent() )
  1352. {
  1353. if ( !CItemUpload::GetContentDir( sDirName ) )
  1354. return false;
  1355. }
  1356. else
  1357. {
  1358. if ( !CItemUpload::GetVProjectDir( sDirName ) )
  1359. return false;
  1360. }
  1361. sDirName += "/";
  1362. // ABSOLUTE implies PREFIX & MODELS
  1363. nPathFlags |= PATH_FLAG_PREFIX;
  1364. nPathFlags |= PATH_FLAG_MODELS;
  1365. }
  1366. if ( nPathFlags & PATH_FLAG_ZIP )
  1367. {
  1368. const char *pszZipPrefix;
  1369. if ( IsContent() )
  1370. {
  1371. pszZipPrefix = CItemUpload::Manifest()->GetZipSourceDirectory();
  1372. }
  1373. else
  1374. {
  1375. pszZipPrefix = CItemUpload::Manifest()->GetZipOutputDirectory();
  1376. }
  1377. if ( *pszZipPrefix )
  1378. {
  1379. sDirName += pszZipPrefix;
  1380. sDirName += "/";
  1381. }
  1382. }
  1383. if ( ( nPathFlags & PATH_FLAG_PREFIX ) && ( nPathFlags & PATH_FLAG_MODELS ) )
  1384. {
  1385. const char *pszPrefix = GetPrefix();
  1386. if ( pszPrefix )
  1387. {
  1388. sDirName += pszPrefix;
  1389. sDirName += "/";
  1390. }
  1391. // PREFIX implies MODELS
  1392. nPathFlags |= PATH_FLAG_MODELS;
  1393. }
  1394. if ( nPathFlags & PATH_FLAG_MODELS && IsModelPath() )
  1395. {
  1396. // If not starting with prefix, then optionally start with models
  1397. sDirName += "models/";
  1398. }
  1399. if ( GetCustomRelativeDir() )
  1400. {
  1401. sDirName += GetCustomRelativeDir();
  1402. }
  1403. else
  1404. {
  1405. sDirName += GetItemDirectory();
  1406. sDirName += pAsset->GetClass();
  1407. sDirName += "/";
  1408. if ( CItemUpload::Manifest()->GetItemPathUsesSteamId() )
  1409. {
  1410. const char *pszSteamId = pAsset->GetSteamId();
  1411. if ( pszSteamId )
  1412. {
  1413. sDirName += pszSteamId;
  1414. sDirName += "/";
  1415. }
  1416. }
  1417. sDirName += pAsset->GetAssetName();
  1418. }
  1419. char szBuf[ k64KB ];
  1420. V_FixupPathName( szBuf, ARRAYSIZE( szBuf ), sDirName.String() );
  1421. sDirName = szBuf;
  1422. return true;
  1423. }
  1424. //-----------------------------------------------------------------------------
  1425. //
  1426. //-----------------------------------------------------------------------------
  1427. bool CTargetBase::CreateOutputDirectory() const
  1428. {
  1429. CUtlString sDir;
  1430. if ( !GetOutputPath( sDir, 0, PATH_FLAG_PATH | PATH_FLAG_ABSOLUTE ) )
  1431. return false;
  1432. if ( !CItemUpload::CreateDirectory( sDir.String() ) )
  1433. {
  1434. Warning( "CTarget%s::CreateDirectory( %s ) - Failed\n", GetTypeString(), sDir.String() );
  1435. return false;
  1436. }
  1437. return true;
  1438. }
  1439. //-----------------------------------------------------------------------------
  1440. //
  1441. //-----------------------------------------------------------------------------
  1442. void CTargetBase::AddOrEditP4File( const char *pszFilePath )
  1443. {
  1444. if ( m_bIgnoreP4 )
  1445. return;
  1446. if ( CItemUpload::GetP4() )
  1447. {
  1448. char szCorrectCaseFilePath[MAX_PATH];
  1449. g_pFullFileSystem->GetCaseCorrectFullPath( pszFilePath, szCorrectCaseFilePath );
  1450. CP4AutoEditAddFile a( szCorrectCaseFilePath );
  1451. }
  1452. }
  1453. //=============================================================================
  1454. //
  1455. //=============================================================================
  1456. bool VTFGetInfo( const char *fileName, int *width, int *height, ImageFormat *imageFormat, float *sourceGamma )
  1457. {
  1458. // Just load the whole file into a memory buffer
  1459. CUtlBuffer bufFileContents;
  1460. if ( !g_pFullFileSystem->ReadFile( fileName, NULL, bufFileContents ) )
  1461. {
  1462. return false;
  1463. }
  1464. IVTFTexture *pVTFTexture = CreateVTFTexture();
  1465. if ( !pVTFTexture->Unserialize( bufFileContents, true ) )
  1466. {
  1467. return false;
  1468. }
  1469. *width = pVTFTexture->Width();
  1470. *height = pVTFTexture->Height();
  1471. // It's not actually RGBA, but it will be when we decompress and load it...
  1472. *imageFormat = IMAGE_FORMAT_RGBA8888;
  1473. *sourceGamma = 0.0f;
  1474. DestroyVTFTexture( pVTFTexture );
  1475. return true;
  1476. }
  1477. //=============================================================================
  1478. //
  1479. //=============================================================================
  1480. CTargetTGA::CTargetTGA( CAsset *pAsset, const CTargetVMT *pTargetVMT )
  1481. : CTargetBase( pAsset, pTargetVMT )
  1482. , m_pTargetVMT( pTargetVMT )
  1483. , m_nSrcImageType( IMAGE_FILE_UNKNOWN )
  1484. , m_nWidth( 0 )
  1485. , m_nHeight( 0 )
  1486. , m_nChannelCount( 0 )
  1487. , m_bNoNiceFiltering( false )
  1488. , m_bAlpha( false )
  1489. , m_bPowerOfTwo( false )
  1490. {
  1491. }
  1492. //-----------------------------------------------------------------------------
  1493. //
  1494. //-----------------------------------------------------------------------------
  1495. CTargetTGA::~CTargetTGA()
  1496. {
  1497. }
  1498. //-----------------------------------------------------------------------------
  1499. //
  1500. //-----------------------------------------------------------------------------
  1501. bool CTargetTGA::IsOk( CUtlString &sMsg ) const
  1502. {
  1503. // No input file specified
  1504. if ( m_sInputFile.Length() <= 0 )
  1505. {
  1506. sMsg = "No input file specified";
  1507. return false;
  1508. }
  1509. // Input file invalid size
  1510. if ( m_nWidth <= 0 )
  1511. {
  1512. sMsg = "Invalid image width (";
  1513. sMsg += m_nWidth;
  1514. sMsg += ")";
  1515. return false;
  1516. }
  1517. if ( m_nHeight <= 0 )
  1518. {
  1519. sMsg = "Invalid image height (";
  1520. sMsg += m_nHeight;
  1521. sMsg += ")";
  1522. return false;
  1523. }
  1524. // TODO: Maximum size?
  1525. // Only 3 or 4 channel images ok
  1526. if ( m_nChannelCount != 3 && m_nChannelCount != 4 )
  1527. {
  1528. sMsg = "Invalid number of channels (";
  1529. sMsg += m_nChannelCount;
  1530. sMsg = ") only 3 (RGB) and 4 (RGBA) channel images allowed";
  1531. return false;
  1532. }
  1533. // Has to be a power of two
  1534. if ( !m_bPowerOfTwo )
  1535. {
  1536. sMsg = "Image dimensions are not a power of two";
  1537. return false;
  1538. }
  1539. return true;
  1540. }
  1541. //-----------------------------------------------------------------------------
  1542. //
  1543. //-----------------------------------------------------------------------------
  1544. bool CTargetTGA::IsModelPath() const
  1545. {
  1546. return m_pTargetVMT->IsModelPath();
  1547. }
  1548. //-----------------------------------------------------------------------------
  1549. //
  1550. //-----------------------------------------------------------------------------
  1551. bool CTargetTGA::GetInputPaths(
  1552. CUtlVector< CUtlString > &sInputPaths,
  1553. bool bRelative /* = true */,
  1554. bool bRecurse /* = true */,
  1555. bool bExtension /* = true */ )
  1556. {
  1557. sInputPaths.AddToTail( m_sInputFile );
  1558. return CTargetBase::GetInputPaths( sInputPaths, bRelative, bRecurse, bExtension );
  1559. }
  1560. //-----------------------------------------------------------------------------
  1561. //
  1562. //-----------------------------------------------------------------------------
  1563. const ExtensionList *CTargetTGA::GetExtensionsAndCount( void ) const
  1564. {
  1565. static ExtensionList vecExtensions;
  1566. if ( !vecExtensions.Count() )
  1567. {
  1568. vecExtensions.AddToTail( ".tga" );
  1569. vecExtensions.AddToTail( ".txt" );
  1570. }
  1571. return &vecExtensions;
  1572. }
  1573. //-----------------------------------------------------------------------------
  1574. //
  1575. //-----------------------------------------------------------------------------
  1576. const char *CTargetTGA::GetPrefix() const
  1577. {
  1578. if ( m_sPrefix.IsEmpty() ) {
  1579. CUtlString strParentPrefix = m_pTargetVMT->GetPrefix();
  1580. m_sPrefix = strParentPrefix.Replace( "materials", "materialsrc" );
  1581. }
  1582. return m_sPrefix.String();
  1583. }
  1584. //-----------------------------------------------------------------------------
  1585. //
  1586. //-----------------------------------------------------------------------------
  1587. void CTargetTGA::GetName( CUtlString &sName ) const
  1588. {
  1589. if ( GetCustomOutputName().IsEmpty() )
  1590. {
  1591. CTargetBase::GetName( sName );
  1592. }
  1593. else
  1594. {
  1595. sName = GetCustomOutputName();
  1596. }
  1597. }
  1598. //-----------------------------------------------------------------------------
  1599. //
  1600. //-----------------------------------------------------------------------------
  1601. bool CTargetTGA::Compile()
  1602. {
  1603. // 'reset' the input file from the current value to force a reload on compile, make a temp copy as it's going to be overwritten
  1604. if ( !SetInputFile( CUtlString( GetInputFile() ).String() ) )
  1605. return false;
  1606. if ( !CTargetBase::Compile() )
  1607. return false;
  1608. CUtlString sName;
  1609. if ( !GetOutputPath( sName, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  1610. {
  1611. Warning( "CTarget%s::Compile - GetOutputPath Failed\n", GetTypeString() );
  1612. return false;
  1613. }
  1614. CUtlString sTmp;
  1615. if ( !IsOk( sTmp ) )
  1616. {
  1617. Warning( "CTarget%s::Compile( %s ) - Not Valid: %s\n", GetTypeString(), sName.String(), sTmp.String() );
  1618. return false;
  1619. }
  1620. CUtlString sAbsPath;
  1621. GetOutputPath( sAbsPath, 0 );
  1622. CUtlString sRelPath;
  1623. GetOutputPath( sRelPath, 0, PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE );
  1624. if ( sAbsPath.IsEmpty() || sRelPath.IsEmpty() )
  1625. {
  1626. Warning( "CTarget%s::Compile( %s ) - GetOutputPath failed\n", GetTypeString(), sName.String() );
  1627. return false;
  1628. }
  1629. Msg( "Compiling %s: %s\n", GetTypeString(), sRelPath.String() );
  1630. if ( CItemUpload::IsSameFile( m_sInputFile.String(), sAbsPath.String() ) )
  1631. {
  1632. Warning( "CTarget%s::Compile( %s ) - Same File, No Work To Do!\n", GetTypeString(), sName.String() );
  1633. return true;
  1634. }
  1635. Bitmap_t bitmap;
  1636. CUtlMemory< unsigned char > tgaBits;
  1637. switch ( m_nSrcImageType )
  1638. {
  1639. case IMAGE_FILE_TGA:
  1640. {
  1641. int nWidth = 0, nHeight = 0;
  1642. if ( !TGALoader::LoadRGBA8888( m_sInputFile.String(), tgaBits, nWidth, nHeight ) )
  1643. {
  1644. Warning( "CTarget%s::Compile( %s ) - Couldn't Load TGA\n", GetTypeString(), sName.String() );
  1645. return false;
  1646. }
  1647. bitmap.SetBuffer( nWidth, nHeight, IMAGE_FORMAT_RGBA8888, tgaBits.Base(), false, nWidth*4 );
  1648. }
  1649. break;
  1650. case IMAGE_FILE_PSD:
  1651. {
  1652. if ( !PSDReadFileRGBA8888( m_sInputFile.String(), NULL, bitmap ) )
  1653. {
  1654. Warning( "CTarget%s::Compile( %s ) - Couldn't Load PSD\n", GetTypeString(), sName.String() );
  1655. return false;
  1656. }
  1657. }
  1658. break;
  1659. case IMAGE_FILE_VTF:
  1660. {
  1661. // Just load the whole file into a memory buffer
  1662. CUtlBuffer bufFileContents;
  1663. if ( !g_pFullFileSystem->ReadFile( m_sInputFile.String(), NULL, bufFileContents ) )
  1664. {
  1665. Warning( "CTarget%s::Compile( %s ) - Couldn't Load VTF\n", GetTypeString(), sName.String() );
  1666. return false;
  1667. }
  1668. IVTFTexture *pVTFTexture = CreateVTFTexture();
  1669. if ( !pVTFTexture->Unserialize( bufFileContents ) )
  1670. {
  1671. Warning( "CTarget%s::Compile( %s ) - Couldn't Load VTF\n", GetTypeString(), sName.String() );
  1672. return false;
  1673. }
  1674. int nWidth = pVTFTexture->Width();
  1675. int nHeight = pVTFTexture->Height();
  1676. pVTFTexture->ConvertImageFormat( IMAGE_FORMAT_RGBA8888, false );
  1677. int nMemSize = ImageLoader::GetMemRequired( nWidth, nHeight, 1, IMAGE_FORMAT_RGBA8888, false );
  1678. tgaBits.EnsureCapacity( nMemSize );
  1679. Q_memcpy( tgaBits.Base(), pVTFTexture->ImageData(), nMemSize );
  1680. DestroyVTFTexture( pVTFTexture );
  1681. bitmap.SetBuffer( nWidth, nHeight, IMAGE_FORMAT_RGBA8888, tgaBits.Base(), false, nWidth*4 );
  1682. }
  1683. break;
  1684. }
  1685. if ( bitmap.Format() != IMAGE_FORMAT_RGBA8888 || bitmap.Width() != m_nWidth || bitmap.Height() != m_nHeight )
  1686. {
  1687. Warning( "CTarget%s::Compile( %s ) - Invalid Bitmap Size, Expected %d x %d x %d (%d)\n",
  1688. GetTypeString(), sName.String(), m_nWidth, m_nHeight, 4, m_nWidth * m_nHeight * 4 );
  1689. return false;
  1690. }
  1691. CUtlBuffer bufVTEXConfig( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1692. // If we're supposed to resize these to another resolution, setup the VTEX config file to do so.
  1693. int nTargetWidth = m_pTargetVMT->GetTargetWidth();
  1694. int nTargetHeight = m_pTargetVMT->GetTargetHeight();
  1695. if ( nTargetWidth && nTargetHeight )
  1696. {
  1697. // We want to use "reduce", not "maxwidth" & "maxheight", so we throw away the higher resolution mips.
  1698. // Determine the right amount of reduction based on the texture's width & height (and fail if it's the wrong aspect ratio)
  1699. int nFactor = (m_nWidth / nTargetWidth);
  1700. if ( nFactor <= 0 )
  1701. {
  1702. Warning( "CTarget%s::Compile( %s ) - Failed to determine reduction factor (target width is %d, texture is %d)\n", GetTypeString(), sName.String(), nTargetWidth, m_nWidth );
  1703. return false;
  1704. }
  1705. int nHeightFactor = (m_nHeight / nTargetHeight);
  1706. if ( nFactor != nHeightFactor )
  1707. {
  1708. Warning( "CTarget%s::Compile( %s ) - Failed to determine reduction factor (target size aspect ratio (%dx%d) doesn't match texture's aspect ratio (%dx%d))\n", GetTypeString(), sName.String(), nTargetWidth, nTargetHeight, m_nWidth, m_nHeight );
  1709. return false;
  1710. }
  1711. if ( nFactor > 1 )
  1712. {
  1713. bufVTEXConfig.PutString( CFmtStr("reduce %d\n", nFactor) );
  1714. }
  1715. }
  1716. KeyValues *pKV = m_pTargetVMT->GetTextureAddToVTEXConfigForTGA( this );
  1717. if ( pKV )
  1718. {
  1719. FOR_EACH_SUBKEY( pKV, pKVEntry )
  1720. {
  1721. bufVTEXConfig.Printf( "%s %s\n", pKVEntry->GetName(), pKVEntry->GetString() );
  1722. }
  1723. }
  1724. // check if we should modify abspath
  1725. CUtlString sTGAOutput = Asset()->CheckRedundantOutputFilePath( GetInputFile().String(), bufVTEXConfig.String(), sAbsPath.String() );
  1726. AddOrEditP4File( sTGAOutput.String() );
  1727. char szVTEXConfigFilename[MAX_PATH];
  1728. V_strcpy_safe( szVTEXConfigFilename, sTGAOutput.String() );
  1729. V_SetExtension( szVTEXConfigFilename, ".txt", sizeof(szVTEXConfigFilename) );
  1730. AddOrEditP4File( szVTEXConfigFilename );
  1731. g_pFullFileSystem->WriteFile( szVTEXConfigFilename, NULL, bufVTEXConfig );
  1732. // TODO: Don't write alpha if VMT using this doesn't specify the alpha is used for anything
  1733. CUtlBuffer outBuf;
  1734. const bool bWriteTGA = TGAWriter::WriteToBuffer( bitmap.GetBits(), outBuf, bitmap.Width(), bitmap.Height(), bitmap.Format(), m_bAlpha ? IMAGE_FORMAT_BGRA8888 : IMAGE_FORMAT_BGR888 );
  1735. if ( !bWriteTGA )
  1736. {
  1737. Warning( "CTarget%s::Compile( %s ) - Couldn't write TGA to buffer\n", GetTypeString(), sName.String() );
  1738. return false;
  1739. }
  1740. if ( !g_pFullFileSystem->WriteFile( sTGAOutput.String(), NULL, outBuf ) )
  1741. {
  1742. Warning( "CTarget%s::Compile( %s ) - Couldn't write TGA to file \"%s\"\n", GetTypeString(), sName.String(), sTGAOutput.String() );
  1743. return false;
  1744. }
  1745. if ( !CheckFile( sTGAOutput.String() ) )
  1746. {
  1747. Warning( "CTarget%s::Compile( %s ) - File Check Failed - \"%s\"\n", GetTypeString(), sName.String(), sTGAOutput.String() );
  1748. return false;
  1749. }
  1750. if ( CItemUpload::Manifest()->UseTerseMessages() )
  1751. {
  1752. Msg( " - Compilation successful.\n" );
  1753. }
  1754. else
  1755. {
  1756. Msg( "CTarget%s::Compile OK! - %s\n", GetTypeString(), sRelPath.String() );
  1757. }
  1758. // store the output name to use it to output VTF file
  1759. char szFileName[FILENAME_MAX];
  1760. V_StripExtension( V_GetFileName( szVTEXConfigFilename ), szFileName, ARRAYSIZE( szFileName ) );
  1761. SetCustomOutputName( szFileName );
  1762. return true;
  1763. }
  1764. //-----------------------------------------------------------------------------
  1765. //
  1766. //-----------------------------------------------------------------------------
  1767. void CTargetTGA::Clear()
  1768. {
  1769. m_sInputFile = "";
  1770. m_sFileBase = "";
  1771. m_sExtension = "";
  1772. m_nWidth = 0;
  1773. m_nHeight = 0;
  1774. m_nChannelCount = 0;
  1775. m_bNoNiceFiltering = false;
  1776. m_bAlpha = false;
  1777. m_bPowerOfTwo = false;
  1778. }
  1779. //-----------------------------------------------------------------------------
  1780. //
  1781. //-----------------------------------------------------------------------------
  1782. bool CTargetTGA::SetInputFile( const char *pszFilename )
  1783. {
  1784. Clear();
  1785. if ( !pszFilename || V_strlen( pszFilename ) <= 0 )
  1786. {
  1787. Warning( "ERROR: Empty filename specified for TGA file\n" );
  1788. return false;
  1789. }
  1790. char szBuf[ k64KB ];
  1791. m_sInputFile = pszFilename;
  1792. V_FileBase( pszFilename, szBuf, ARRAYSIZE( szBuf ) );
  1793. m_sFileBase = szBuf;
  1794. // Try to automatically handle the suffixes for properly named assets
  1795. static const char *szSuffixes[] =
  1796. {
  1797. //"_color",
  1798. "_normal",
  1799. "_height",
  1800. "_specmask"
  1801. "_specexp",
  1802. "_trans",
  1803. "_illum",
  1804. "_color_red",
  1805. "_color_blue"
  1806. };
  1807. CUtlString sTmp;
  1808. for ( int i = 0; i < ARRAYSIZE( szSuffixes ); ++i )
  1809. {
  1810. const char *pszSuffix = szSuffixes[i];
  1811. sTmp = GetAssetName();
  1812. sTmp += pszSuffix;
  1813. if ( m_sFileBase == sTmp )
  1814. {
  1815. SetNameSuffix( pszSuffix );
  1816. }
  1817. }
  1818. V_ExtractFileExtension( pszFilename, szBuf, ARRAYSIZE( szBuf ) );
  1819. m_sExtension = szBuf;
  1820. ImageFormat imageFormat;
  1821. float flSourceGamma = 0;
  1822. if ( TGALoader::GetInfo( pszFilename, &m_nWidth, &m_nHeight, &imageFormat, &flSourceGamma ) )
  1823. {
  1824. m_nSrcImageType = IMAGE_FILE_TGA;
  1825. }
  1826. else if ( PSDGetInfo( pszFilename, NULL, &m_nWidth, &m_nHeight, &imageFormat, &flSourceGamma ) )
  1827. {
  1828. m_nSrcImageType = IMAGE_FILE_PSD;
  1829. }
  1830. else if ( VTFGetInfo( pszFilename, &m_nWidth, &m_nHeight, &imageFormat, &flSourceGamma ) )
  1831. {
  1832. m_nSrcImageType = IMAGE_FILE_VTF;
  1833. }
  1834. else
  1835. {
  1836. Warning( "ERROR: Specified file is not a TGA (Targa) or PSD File: \"%s\"\n", szBuf );
  1837. Clear();
  1838. return false;
  1839. }
  1840. // ImageFormat can only be one of:
  1841. switch ( imageFormat )
  1842. {
  1843. case IMAGE_FORMAT_I8:
  1844. m_nChannelCount = 1;
  1845. m_bAlpha = false;
  1846. break;
  1847. case IMAGE_FORMAT_ABGR8888:
  1848. case IMAGE_FORMAT_BGRA8888:
  1849. m_nChannelCount = 4;
  1850. m_bAlpha = true;
  1851. break;
  1852. case IMAGE_FORMAT_BGR888:
  1853. m_nChannelCount = 3;
  1854. m_bAlpha = false;
  1855. break;
  1856. case IMAGE_FORMAT_RGBA8888:
  1857. m_nChannelCount = 4;
  1858. m_bAlpha = true;
  1859. break;
  1860. case IMAGE_FORMAT_RGB888:
  1861. m_nChannelCount = 3;
  1862. m_bAlpha = false;
  1863. break;
  1864. default:
  1865. break;
  1866. }
  1867. const int nWidthPow = NearestPowerOfTwo( m_nWidth );
  1868. const int nHeightPow = NearestPowerOfTwo( m_nHeight );
  1869. if ( nWidthPow == m_nWidth && nHeightPow == m_nHeight )
  1870. {
  1871. m_bPowerOfTwo = true;
  1872. }
  1873. else
  1874. {
  1875. Warning( "ERROR: Specified texture file (%s) Size %dx%d dimensions not powers of two, perhaps resize to %dx%d\n",
  1876. m_sInputFile.String(),
  1877. m_nWidth, m_nHeight,
  1878. nWidthPow, nHeightPow );
  1879. return false;
  1880. }
  1881. return true;
  1882. }
  1883. //-----------------------------------------------------------------------------
  1884. //
  1885. //-----------------------------------------------------------------------------
  1886. const CUtlString &CTargetTGA::GetInputFile() const
  1887. {
  1888. return m_sInputFile;
  1889. }
  1890. //-----------------------------------------------------------------------------
  1891. //
  1892. //-----------------------------------------------------------------------------
  1893. template < class T >
  1894. T CTargetTGA::NearestPowerOfTwo( T v )
  1895. {
  1896. if (v == 0)
  1897. return static_cast< T >( 1 );
  1898. T k;
  1899. for ( k = sizeof( T ) * 8 - 1; ( ( static_cast< T >( 1U ) << k) & v ) == 0; --k);
  1900. if ( ( ( static_cast< T >( 1U ) << ( k - 1 ) ) & v ) == 0 )
  1901. return static_cast< T >( 1U ) << k;
  1902. return static_cast< T >( 1U ) << ( k + 1 );
  1903. }
  1904. //-----------------------------------------------------------------------------
  1905. //
  1906. //-----------------------------------------------------------------------------
  1907. void CTargetTGA::UpdateManifest( KeyValues *pKv )
  1908. {
  1909. pKv->SetString( "filename", m_sInputFile.String() );
  1910. CUtlString sOutName;
  1911. if ( GetOutputPath( sOutName, 0, PATH_FLAG_PATH | PATH_FLAG_FILE | PATH_FLAG_PREFIX | PATH_FLAG_MODELS | PATH_FLAG_EXTENSION ) )
  1912. {
  1913. pKv->SetString( "out_filename", sOutName );
  1914. }
  1915. pKv->SetInt( "width", m_nWidth );
  1916. pKv->SetInt( "height", m_nHeight );
  1917. pKv->SetInt( "channels", m_nChannelCount );
  1918. pKv->SetInt( "nonice", m_bNoNiceFiltering );
  1919. pKv->SetBool( "alpha", m_bAlpha );
  1920. const char *pszTextureType = m_pTargetVMT->GetTextureTypeForTGA( this );
  1921. if ( pszTextureType )
  1922. {
  1923. KeyValues *pVTEXKV = CItemUpload::Manifest()->GetTextureAddToVTEXConfig( pszTextureType );
  1924. if ( pVTEXKV )
  1925. {
  1926. KeyValues *pTmpKey = new KeyValues( pVTEXKV->GetName() );
  1927. pKv->AddSubKey( pTmpKey );
  1928. pVTEXKV->CopySubkeys( pTmpKey );
  1929. }
  1930. }
  1931. }
  1932. //=============================================================================
  1933. //
  1934. //=============================================================================
  1935. CTargetVTF::CTargetVTF( CAsset *pAsset, const CTargetVMT *pTargetVMT )
  1936. : CTargetBase( pAsset, pTargetVMT )
  1937. , m_pTargetVMT( pTargetVMT )
  1938. {
  1939. m_pTargetTGA = Asset()->NewTarget< CTargetTGA >( m_pTargetVMT );
  1940. }
  1941. //-----------------------------------------------------------------------------
  1942. //
  1943. //-----------------------------------------------------------------------------
  1944. CTargetVTF::~CTargetVTF()
  1945. {
  1946. }
  1947. //-----------------------------------------------------------------------------
  1948. //
  1949. //-----------------------------------------------------------------------------
  1950. bool CTargetVTF::IsModelPath() const
  1951. {
  1952. return m_pTargetVMT->IsModelPath();
  1953. }
  1954. //-----------------------------------------------------------------------------
  1955. //
  1956. //-----------------------------------------------------------------------------
  1957. bool CTargetVTF::Compile()
  1958. {
  1959. if ( !CTargetBase::Compile() )
  1960. return false;
  1961. CUtlString sName;
  1962. if ( !GetOutputPath( sName, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  1963. return false;
  1964. CUtlString sTmp;
  1965. if ( !IsOk( sTmp ) )
  1966. {
  1967. Warning( "CTarget%s::Compile( %s ) - Not Valid: %s\n", GetTypeString(), sName.String(), sTmp.String() );
  1968. return false;
  1969. }
  1970. CUtlString sBinDir;
  1971. if ( !CItemUpload::GetBinDirectory( sBinDir ) )
  1972. {
  1973. Warning( "CTarget%s::Compile( %s ) - GetBinDirectory Failed\n", GetTypeString(), sName.String() );
  1974. return false;
  1975. }
  1976. CUtlString sAbsPath;
  1977. GetOutputPath( sAbsPath, 0 );
  1978. CUtlString sRelPath;
  1979. GetOutputPath( sRelPath, 0, PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE );
  1980. if ( sAbsPath.IsEmpty() || sRelPath.IsEmpty() )
  1981. {
  1982. Warning( "CTarget%s::Compile( %s ) - GetOutputPath failed\n", GetTypeString(), sName.String() );
  1983. return false;
  1984. }
  1985. Msg( "Compiling %s: %s\n", GetTypeString(), sRelPath.String() );
  1986. AddOrEditP4File( sAbsPath.String() );
  1987. CUtlVector< CUtlString > sAbsInputPaths;
  1988. if ( !GetInputPaths( sAbsInputPaths, false, false ) )
  1989. {
  1990. Warning( "CTarget%s::Compile( %s ) - GetInputPaths failed\n", GetTypeString(), sName.String() );
  1991. return false;
  1992. }
  1993. if ( sAbsInputPaths.Count() != 2 )
  1994. {
  1995. Warning( "CTarget%s::Compile( %s ) - GetPaths returned %d paths, expected 2\n", GetTypeString(), sName.String(), sAbsInputPaths.Count() );
  1996. return false;
  1997. }
  1998. CFmtStrN< k64KB > sCmd;
  1999. if ( CItemUpload::IgnoreEnvironmentVariables() )
  2000. {
  2001. // We can't rely on environment variables in VTEX. So tell it to just built it on the spot, and we'll move it afterwards.
  2002. sCmd.sprintf( "\"%s\\vtex.exe\" -nop4 -nopause -dontusegamedir \"%s\"", sBinDir.String(), sAbsInputPaths.Element( 0 ).String() );
  2003. }
  2004. else
  2005. {
  2006. CUtlString sVProject;
  2007. CItemUpload::GetVProjectDir( sVProject );
  2008. sCmd.sprintf( "\"%s\\vtex.exe\" -nop4 -nopause -vproject \"%s\" \"%s\"", sBinDir.String(), sVProject.String(), sAbsInputPaths.Element( 0 ).String() );
  2009. }
  2010. if ( !CItemUpload::RunCommandLine( sCmd.Access(), sBinDir.String(), this ) )
  2011. {
  2012. Warning( "CTarget%s::Compile( %s ) - RunCommandLine Failed - \"%s\"\n", GetTypeString(), sName.String(), sCmd.Access() );
  2013. return false;
  2014. }
  2015. if ( CItemUpload::IgnoreEnvironmentVariables() )
  2016. {
  2017. char sVTFName[MAX_PATH];
  2018. V_strcpy_safe( sVTFName, sAbsInputPaths.Element( 0 ).String() );
  2019. V_SetExtension( sVTFName, ".vtf", sizeof(sVTFName) );
  2020. // We built the VTF in the directory with the content. Now move it to the out dir.
  2021. if ( ::MoveFileEx( sVTFName, sAbsPath.String(), MOVEFILE_REPLACE_EXISTING ) == 0 )
  2022. {
  2023. Warning( "CTarget%s::Compile( %s ) - Failed to move \"%s\" to \"%s\"\n", GetTypeString(), sName.String(), sVTFName, sAbsPath.String() );
  2024. return false;
  2025. }
  2026. }
  2027. if ( !CheckFile( sAbsPath.String() ) )
  2028. {
  2029. Warning( "CTarget%s::Compile( %s ) - File Check Failed - \"%s\"\n", GetTypeString(), sName.String(), sAbsPath.String() );
  2030. return false;
  2031. }
  2032. if ( CItemUpload::Manifest()->UseTerseMessages() )
  2033. {
  2034. Msg( " - Compilation successful.\n" );
  2035. }
  2036. else
  2037. {
  2038. Msg( "CTarget%s::Compile OK! - %s\n", GetTypeString(), sRelPath.String() );
  2039. }
  2040. return true;
  2041. }
  2042. //-----------------------------------------------------------------------------
  2043. //
  2044. //-----------------------------------------------------------------------------
  2045. bool CTargetVTF::GetInputs( CUtlVector< CTargetBase * > &inputs ) const
  2046. {
  2047. Assert( m_pTargetTGA.IsValid() );
  2048. inputs.AddToTail( m_pTargetTGA.GetObject() );
  2049. return inputs.Count() > 0;
  2050. }
  2051. //-----------------------------------------------------------------------------
  2052. //
  2053. //-----------------------------------------------------------------------------
  2054. const ExtensionList *CTargetVTF::GetExtensionsAndCount( void ) const
  2055. {
  2056. static ExtensionList vecExtensions;
  2057. if ( !vecExtensions.Count() )
  2058. {
  2059. vecExtensions.AddToTail( ".vtf" );
  2060. }
  2061. return &vecExtensions;
  2062. }
  2063. //-----------------------------------------------------------------------------
  2064. //
  2065. //-----------------------------------------------------------------------------
  2066. const char *CTargetVTF::GetPrefix() const
  2067. {
  2068. return m_pTargetVMT->GetPrefix();
  2069. }
  2070. //-----------------------------------------------------------------------------
  2071. //
  2072. //-----------------------------------------------------------------------------
  2073. void CTargetVTF::GetName( CUtlString &sName ) const
  2074. {
  2075. Assert( m_pTargetTGA.IsValid() );
  2076. m_pTargetTGA->GetName( sName );
  2077. }
  2078. //=============================================================================
  2079. //
  2080. //=============================================================================
  2081. CTargetVMT::CTargetVMT( CAsset *pAsset, const CTargetBase *pTargetParent )
  2082. : CTargetBase( pAsset, pTargetParent )
  2083. , m_pVMTKV( NULL )
  2084. , m_nColorAlphaType( kNoColorAlpha )
  2085. , m_nNormalAlphaType( kNoNormalAlpha )
  2086. , m_nMaterialType( kInvalidMaterialType )
  2087. , m_bDuplicate( false )
  2088. , m_nTargetWidth( 0 )
  2089. , m_nTargetHeight( 0 )
  2090. {
  2091. m_vecTargetVTFs.SetCount( CItemUpload::Manifest()->GetNumMaterialSkins() );
  2092. FOR_EACH_VEC( m_vecTargetVTFs, i )
  2093. {
  2094. m_vecTargetVTFs[i].SetCount( CItemUpload::Manifest()->GetNumTextureTypes() );
  2095. }
  2096. }
  2097. //-----------------------------------------------------------------------------
  2098. //
  2099. //-----------------------------------------------------------------------------
  2100. CTargetVMT::~CTargetVMT()
  2101. {
  2102. if ( m_pVMTKV )
  2103. {
  2104. m_pVMTKV->deleteThis();
  2105. }
  2106. CUtlString sMaterialId;
  2107. GetMaterialId( sMaterialId );
  2108. Asset()->RemoveMaterial( sMaterialId );
  2109. }
  2110. //-----------------------------------------------------------------------------
  2111. //
  2112. //-----------------------------------------------------------------------------
  2113. bool CTargetVMT::Compile()
  2114. {
  2115. if ( GetDuplicate() )
  2116. return true;
  2117. if ( !CTargetBase::Compile() )
  2118. return g_bCompilePreview ? true : false;
  2119. CAsset *pAsset = Asset();
  2120. if ( !pAsset )
  2121. return false;
  2122. CUtlString sName;
  2123. if ( !GetOutputPath( sName, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  2124. return false;
  2125. CUtlString sTmp;
  2126. if ( !IsOk( sTmp ) )
  2127. {
  2128. Warning( "CTarget%s::Compile( %s ) - Not Valid: %s\n", GetTypeString(), sName.String(), sTmp.String() );
  2129. return false;
  2130. }
  2131. int nVmtCount = GetOutputCount();
  2132. CUtlVector< CUtlString > sAbsOutputPaths;
  2133. CUtlVector< CUtlString > sRelOutputPaths;
  2134. if ( !GetOutputPaths( sAbsOutputPaths, false, false, true ) || !GetOutputPaths( sRelOutputPaths, true, false, true ) )
  2135. {
  2136. Warning( "CTarget%s::Compile( %s ) - GetOutputPaths failed\n", GetTypeString(), sName.String() );
  2137. return false;
  2138. }
  2139. if ( sAbsOutputPaths.Count() != nVmtCount || sAbsOutputPaths.Count() != sRelOutputPaths.Count() )
  2140. {
  2141. Warning( "CTarget%s::Compile( %s ) - GetOutputPaths returned %d paths, expected %d\n", GetTypeString(), sName.String(), sAbsOutputPaths.Count(), 1 );
  2142. return false;
  2143. }
  2144. Assert( nVmtCount == sAbsOutputPaths.Count() );
  2145. Assert( nVmtCount == sRelOutputPaths.Count() );
  2146. char szBuf[ k64KB ];
  2147. for ( int i = 0; i < nVmtCount; ++i )
  2148. {
  2149. CUtlVector< CUtlString > sChildRelOutputPaths;
  2150. if ( !GetOutputPath( sName, i, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  2151. {
  2152. Warning( "CTarget%s::Compile( %s ) - Can't GetOutputPath %d\n", GetTypeString(), sName.String(), i );
  2153. return false;
  2154. }
  2155. Msg( "Compiling %s: %s\n", GetTypeString(), sRelOutputPaths.Element( i ).String() );
  2156. AddOrEditP4File( sAbsOutputPaths.Element( i ).String() );
  2157. // Load the template in.
  2158. KeyValues *pVMTKV = GetVMTKV( i );
  2159. if ( !pVMTKV )
  2160. {
  2161. // We've already printed a warning, so we're done
  2162. return false;
  2163. }
  2164. // Set any remapped VMT vars.
  2165. FOR_EACH_VEC( m_vecTargetVTFs[i], iVTF )
  2166. {
  2167. if ( m_vecTargetVTFs[i][iVTF].IsValid() )
  2168. {
  2169. const char *pszVMTVar = CItemUpload::Manifest()->GetVMTVarForTextureType( CItemUpload::Manifest()->GetTextureType(iVTF) );
  2170. if ( pszVMTVar && pszVMTVar[0] )
  2171. {
  2172. sChildRelOutputPaths.RemoveAll();
  2173. m_vecTargetVTFs[i][iVTF]->GetOutputPaths( sChildRelOutputPaths, true, false, false, false );
  2174. if ( sChildRelOutputPaths.Count() > 0 )
  2175. {
  2176. V_strncpy( szBuf, sChildRelOutputPaths.Element( 0 ).String(), ARRAYSIZE( szBuf ) );
  2177. V_FixSlashes( szBuf, '/' );
  2178. if ( pVMTKV->FindKey( pszVMTVar ) )
  2179. {
  2180. pVMTKV->SetString( pszVMTVar, szBuf );
  2181. }
  2182. }
  2183. }
  2184. }
  2185. }
  2186. CUtlBuffer fileBuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  2187. pVMTKV->RecursiveSaveToFile( fileBuf, 0 );
  2188. g_pFullFileSystem->WriteFile( sAbsOutputPaths.Element( i ).String(), "MOD", fileBuf );
  2189. Msg( "CTarget%s::Compile OK! - %s\n", GetTypeString(), sRelOutputPaths.Element( i ).String() );
  2190. }
  2191. return true;
  2192. }
  2193. //-----------------------------------------------------------------------------
  2194. //
  2195. //-----------------------------------------------------------------------------
  2196. const char *CTargetVMT::MaterialTypeToString( int nMaterialType )
  2197. {
  2198. if ( nMaterialType == kInvalidMaterialType )
  2199. return "InvalidMaterialType";
  2200. const char *pszMaterialName = CItemUpload::Manifest()->GetMaterialType( nMaterialType );
  2201. if ( pszMaterialName )
  2202. return pszMaterialName;
  2203. return "Unknown";
  2204. }
  2205. //-----------------------------------------------------------------------------
  2206. //
  2207. //-----------------------------------------------------------------------------
  2208. int CTargetVMT::StringToMaterialType( const char *pszUserData )
  2209. {
  2210. return CItemUpload::Manifest()->GetMaterialType( pszUserData );
  2211. }
  2212. //-----------------------------------------------------------------------------
  2213. //
  2214. //-----------------------------------------------------------------------------
  2215. bool CTargetVMT::IsOk( CUtlString &sMsg ) const
  2216. {
  2217. if ( GetMaterialType() == kInvalidMaterialType )
  2218. {
  2219. sMsg += "\"";
  2220. sMsg += m_sMaterialId;
  2221. sMsg += "\": ";
  2222. sMsg += "Invalid material type, must be one of Primary or Secondary";
  2223. return false;
  2224. }
  2225. if ( GetDuplicate() )
  2226. return true;
  2227. if ( !g_bCompilePreview )
  2228. {
  2229. // Make sure we have all the required textures.
  2230. int nSkinIndex = CItemUpload::Manifest()->GetDefaultMaterialSkin();
  2231. FOR_EACH_VEC( m_vecTargetVTFs[ nSkinIndex ], i )
  2232. {
  2233. if ( !m_vecTargetVTFs[nSkinIndex][i].IsValid() && CItemUpload::Manifest()->IsTextureTypeRequired( i ) )
  2234. {
  2235. sMsg += "\"";
  2236. sMsg += m_sMaterialId;
  2237. sMsg += "\": ";
  2238. sMsg += "Missing required texture type";
  2239. Warning( "Missing texture of type '%s'\n", CItemUpload::Manifest()->GetTextureType( i ) );
  2240. return false;
  2241. }
  2242. }
  2243. }
  2244. return true;
  2245. }
  2246. //-----------------------------------------------------------------------------
  2247. //
  2248. //-----------------------------------------------------------------------------
  2249. const ExtensionList *CTargetVMT::GetExtensionsAndCount( void ) const
  2250. {
  2251. if ( GetDuplicate() )
  2252. return NULL;
  2253. m_vecExtensions.SetCount( 0 );
  2254. FOR_EACH_VEC( m_vecTargetVTFs, i )
  2255. {
  2256. FOR_EACH_VEC( m_vecTargetVTFs[i], j )
  2257. {
  2258. if ( m_vecTargetVTFs[i][j].IsValid() )
  2259. {
  2260. CUtlString sExtension = CItemUpload::Manifest()->GetMaterialSkinFilenameAppend( i );
  2261. sExtension += ".vmt";
  2262. m_vecExtensions.AddToTail( sExtension );
  2263. break;
  2264. }
  2265. }
  2266. }
  2267. return &m_vecExtensions;
  2268. }
  2269. //-----------------------------------------------------------------------------
  2270. //
  2271. //-----------------------------------------------------------------------------
  2272. bool CTargetVMT::GetInputs( CUtlVector< CTargetBase * > &inputs ) const
  2273. {
  2274. CUtlString sTmp;
  2275. if ( !IsOk( sTmp ) )
  2276. {
  2277. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  2278. return false;
  2279. }
  2280. FOR_EACH_VEC( m_vecTargetVTFs, i )
  2281. {
  2282. FOR_EACH_VEC( m_vecTargetVTFs[i], j )
  2283. {
  2284. if ( m_vecTargetVTFs[i][j].IsValid() )
  2285. {
  2286. inputs.AddToTail( m_vecTargetVTFs[i][j].GetObject() );
  2287. }
  2288. }
  2289. }
  2290. return inputs.Count() > 0;
  2291. }
  2292. //-----------------------------------------------------------------------------
  2293. //
  2294. //-----------------------------------------------------------------------------
  2295. void CTargetVMT::GetName( CUtlString &sName ) const
  2296. {
  2297. sName.Clear();
  2298. if ( GetDuplicate() )
  2299. {
  2300. }
  2301. else
  2302. {
  2303. CTargetBase::GetName( sName );
  2304. if ( m_nMaterialType == kInvalidMaterialType )
  2305. {
  2306. sName += "_INVALID";
  2307. }
  2308. else
  2309. {
  2310. if ( m_nMaterialType > 0 )
  2311. {
  2312. sName += "_";
  2313. sName += m_nMaterialType;
  2314. }
  2315. }
  2316. }
  2317. }
  2318. //-----------------------------------------------------------------------------
  2319. //
  2320. //-----------------------------------------------------------------------------
  2321. void CTargetVMT::SetMaterialId( const char *pszMaterialId )
  2322. {
  2323. m_sMaterialId = pszMaterialId;
  2324. }
  2325. //-----------------------------------------------------------------------------
  2326. //
  2327. //-----------------------------------------------------------------------------
  2328. bool CTargetVMT::SetMaterialType( int nMaterialType )
  2329. {
  2330. CAsset *pAsset = Asset();
  2331. if ( !pAsset )
  2332. return false;
  2333. if ( nMaterialType < 0 || nMaterialType >= CItemUpload::Manifest()->GetNumMaterialTypes() )
  2334. return false;
  2335. m_bDuplicate = false;
  2336. m_nMaterialType = kInvalidMaterialType;
  2337. if ( nMaterialType == kInvalidMaterialType )
  2338. return true;
  2339. // Recursively increment other non-duplicate materials which match this material
  2340. // and so on...
  2341. for ( int i = 0; i < pAsset->GetTargetVMTCount(); ++i )
  2342. {
  2343. CTargetVMT *pTargetVMT = pAsset->GetTargetVMT( i );
  2344. if ( !pTargetVMT )
  2345. continue;
  2346. if ( !pTargetVMT->GetDuplicate() && pTargetVMT->GetMaterialType() == nMaterialType )
  2347. {
  2348. pTargetVMT->SetMaterialType( ( ( nMaterialType + 1 ) % CItemUpload::Manifest()->GetNumMaterialTypes() ) );
  2349. }
  2350. }
  2351. m_nMaterialType = nMaterialType;
  2352. return true;
  2353. }
  2354. //-----------------------------------------------------------------------------
  2355. //
  2356. //-----------------------------------------------------------------------------
  2357. int CTargetVMT::GetMaterialType() const
  2358. {
  2359. return m_nMaterialType;
  2360. }
  2361. //-----------------------------------------------------------------------------
  2362. //
  2363. //-----------------------------------------------------------------------------
  2364. void CTargetVMT::SetDuplicate( int nMaterialType )
  2365. {
  2366. if ( nMaterialType < 0 || nMaterialType >= CItemUpload::Manifest()->GetNumMaterialTypes() )
  2367. return;
  2368. m_bDuplicate = true;
  2369. m_nMaterialType = nMaterialType;
  2370. }
  2371. //-----------------------------------------------------------------------------
  2372. //
  2373. //-----------------------------------------------------------------------------
  2374. bool CTargetVMT::SetTargetVTF( const char *pszTextureType, const char *pszFilename, int nSkinIndex )
  2375. {
  2376. // Make sure it's a valid texture type
  2377. int nTextureType = CItemUpload::Manifest()->GetTextureType( pszTextureType );
  2378. if ( nTextureType == -1 )
  2379. {
  2380. Warning( "Invalid texture type specified: '%s'\n", pszTextureType );
  2381. return false;
  2382. }
  2383. if ( nSkinIndex == kInvalidMaterialSkin )
  2384. {
  2385. Warning( "Invalid skin type specified: '%d'\n", nSkinIndex );
  2386. return false;
  2387. }
  2388. CUtlString sSuffix;
  2389. sSuffix += CItemUpload::Manifest()->GetMaterialSkinFilenameAppend( nSkinIndex );
  2390. sSuffix += pszTextureType;
  2391. return SetTargetVTF( m_vecTargetVTFs[nSkinIndex][nTextureType], pszFilename, sSuffix.String() );
  2392. }
  2393. //-----------------------------------------------------------------------------
  2394. //
  2395. //-----------------------------------------------------------------------------
  2396. bool CTargetVMT::SetTargetVTF(
  2397. CSmartPtr< CTargetVTF > &pTargetVTF,
  2398. const char *pszFilename,
  2399. const char *pszSuffix ) const
  2400. {
  2401. if ( !pTargetVTF )
  2402. {
  2403. pTargetVTF = Asset()->NewTarget< CTargetVTF >( this );
  2404. }
  2405. if ( !pTargetVTF )
  2406. return false;
  2407. pTargetVTF->SetNameSuffix( pszSuffix );
  2408. bool bResult = pTargetVTF->SetInputFile( pszFilename );
  2409. return bResult;
  2410. }
  2411. //-----------------------------------------------------------------------------
  2412. //
  2413. //-----------------------------------------------------------------------------
  2414. void CTargetVMT::SetVMTKV( const KeyValues *pKV, int nSkinIndex /*= 0*/ )
  2415. {
  2416. if ( !m_pVMTKV )
  2417. {
  2418. m_pVMTKV = new KeyValues( "data" );
  2419. }
  2420. const char* pszKeyName = CFmtStr( kVMT, nSkinIndex );
  2421. if ( KeyValues *pPreviousKey = m_pVMTKV->FindKey( pszKeyName ) )
  2422. {
  2423. m_pVMTKV->RemoveSubKey( pPreviousKey );
  2424. }
  2425. KeyValues *pNewKey = new KeyValues( pszKeyName );
  2426. pNewKey->AddSubKey( pKV->MakeCopy() );
  2427. m_pVMTKV->AddSubKey( pNewKey );
  2428. }
  2429. //-----------------------------------------------------------------------------
  2430. //
  2431. //-----------------------------------------------------------------------------
  2432. KeyValues *CTargetVMT::GetVMTKV( int nSkinIndex )
  2433. {
  2434. if ( !m_pVMTKV )
  2435. {
  2436. m_pVMTKV = new KeyValues( "data" );
  2437. }
  2438. const char* pszKeyName = CFmtStr( kVMT, nSkinIndex );
  2439. KeyValues* pKey = m_pVMTKV->FindKey( pszKeyName );
  2440. if ( pKey )
  2441. {
  2442. return pKey->GetFirstSubKey();
  2443. }
  2444. KeyValues *pVMTKV = new KeyValues("VMTTemplate");
  2445. if ( CItemUpload::Manifest()->HasClassVMTTemplates() )
  2446. {
  2447. const int nClassIndex = GetClassIndex( Asset()->GetClass() );
  2448. const char *pszVMTTemplate = CItemUpload::Manifest()->GetClassVMTTemplate( nClassIndex );
  2449. if ( !pszVMTTemplate )
  2450. {
  2451. Warning( "Could not find a VMT template for class '%s'\n", Asset()->GetClass() );
  2452. pVMTKV->deleteThis();
  2453. return NULL;
  2454. }
  2455. if ( !pVMTKV->LoadFromFile( g_pFullFileSystem, pszVMTTemplate, "MOD" ) )
  2456. {
  2457. Warning( "Failed to load specified VMT template '%s' for class '%s'.\n", pszVMTTemplate, Asset()->GetClass() );
  2458. pVMTKV->deleteThis();
  2459. return NULL;
  2460. }
  2461. }
  2462. else
  2463. {
  2464. CreateLegacyTemplate( pVMTKV );
  2465. }
  2466. KeyValues *pNewKey = new KeyValues( pszKeyName );
  2467. pNewKey->AddSubKey( pVMTKV );
  2468. m_pVMTKV->AddSubKey( pNewKey );
  2469. return pVMTKV;
  2470. }
  2471. //-----------------------------------------------------------------------------
  2472. //
  2473. //-----------------------------------------------------------------------------
  2474. void CTargetVMT::CreateLegacyTemplate( KeyValues *pVMTKV )
  2475. {
  2476. pVMTKV->SetName( "VertexlitGeneric" );
  2477. for ( int iVTF = 0; iVTF < CItemUpload::Manifest()->GetNumTextureTypes(); ++iVTF )
  2478. {
  2479. const char *pszVMTVar = CItemUpload::Manifest()->GetVMTVarForTextureType( CItemUpload::Manifest()->GetTextureType( iVTF ) );
  2480. if ( pszVMTVar && *pszVMTVar )
  2481. {
  2482. pVMTKV->SetString( pszVMTVar, "" );
  2483. }
  2484. }
  2485. // Wearables usually use this lightwarp: "models/player/pyro/pyro_lightwarp"
  2486. // Weapons usually use this lightwarp: "models/lightwarps/weapon_lightwarp"
  2487. // Weapons are the more custom case, so we'll default to a good wearable lightwarp
  2488. pVMTKV->SetString( "$lightwarptexture", "models/player/pyro/pyro_lightwarp" );
  2489. pVMTKV->SetString( "$phong", "1" );
  2490. pVMTKV->SetString( "$phongexponent", "25" );
  2491. pVMTKV->SetString( "$phongboost", "0.1" );
  2492. pVMTKV->SetString( "$phongfresnelranges", "[.25 .5 1]" );
  2493. pVMTKV->SetString( "$rimlight", "1" ); // To enable rim lighting (requires phong)
  2494. pVMTKV->SetString( "$rimlightexponent", "4" ); // Exponent for phong component of rim
  2495. pVMTKV->SetString( "$rimlightboost", "2" ); // Boost for ambient cube component of rim lighting
  2496. switch ( m_nColorAlphaType )
  2497. {
  2498. case kNoColorAlpha:
  2499. break;
  2500. case kTransparency:
  2501. pVMTKV->SetString( "$translucent", "1" );
  2502. break;
  2503. case kPaintable:
  2504. pVMTKV->SetString( "$blendtintbybasealpha", "1" );
  2505. pVMTKV->SetString( "$blendtintcoloroverbase", "0" ); // between 0-1 determines how much blended by tinting vs. replacing the color
  2506. pVMTKV->SetString( "$colortint_base", "{ 255 255 255 }" ); // put the RGB value of whats being colored when no paint is present, if $blendtintcoloroverbase is 0 then put [255 255 255] here.
  2507. pVMTKV->SetString( "$color2", "{ 255 255 255 }" );
  2508. pVMTKV->SetString( "$colortint_tmp", "[0 0 0]" );
  2509. break;
  2510. case kColorSpecPhong:
  2511. pVMTKV->SetString( "$basemapalphaphongmask", "1" );
  2512. break;
  2513. }
  2514. switch ( m_nNormalAlphaType )
  2515. {
  2516. case kNoNormalAlpha:
  2517. break;
  2518. case kNormalSpecPhong:
  2519. pVMTKV->SetString( "$bumpmapalphaphongmask", "1" );
  2520. break;
  2521. }
  2522. // Variables for the cloak effect
  2523. pVMTKV->SetString( "$cloakPassEnabled", "1" );
  2524. // Variables for the burning effect
  2525. pVMTKV->SetString( "$detail", "effects/tiledfire/fireLayeredSlowTiled512" );
  2526. pVMTKV->SetString( "$detailscale", "5" );
  2527. pVMTKV->SetString( "$detailblendfactor", "0" );
  2528. pVMTKV->SetString( "$detailblendmode", "6" );
  2529. // Variables for the jarate effect
  2530. pVMTKV->SetString( "$yellow", "0" );
  2531. // The order of the proxies is important!
  2532. KeyValues *pProxies = pVMTKV->FindKey( "Proxies", true );
  2533. // Proxies for the cloak effect
  2534. KeyValues *pProxiesWeaponInvis = pProxies->FindKey( "invis", true );
  2535. pProxiesWeaponInvis->FindKey( "temp_key_wont_print_dont_worry", true );
  2536. // Proxies for the burning effect
  2537. KeyValues *pProxiesAnimatedTexture = pProxies->FindKey( "AnimatedTexture", true );
  2538. pProxiesAnimatedTexture->SetString( "animatedtexturevar", "$detail" );
  2539. pProxiesAnimatedTexture->SetString( "animatedtextureframenumvar", "$detailframe" );
  2540. pProxiesAnimatedTexture->SetString( "animatedtextureframerate", "30" );
  2541. KeyValues *pProxiesBurnLevel = pProxies->FindKey( "BurnLevel", true );
  2542. pProxiesBurnLevel->SetString( "resultVar", "$detailblendfactor" );
  2543. // Proxies for paintable items
  2544. if ( m_nColorAlphaType == kPaintable )
  2545. {
  2546. KeyValues *pProxiesItemTintColor = pProxies->FindKey( "ItemTintColor", true );
  2547. pProxiesItemTintColor->SetString( "resultVar", "$colortint_tmp" );
  2548. KeyValues *pProxiesSelectFirstIfNonZero = pProxies->FindKey( "SelectFirstIfNonZero", true );
  2549. pProxiesSelectFirstIfNonZero->SetString( "srcVar1", "$colortint_tmp" );
  2550. pProxiesSelectFirstIfNonZero->SetString( "srcVar2", "$colortint_base" );
  2551. pProxiesSelectFirstIfNonZero->SetString( "resultVar", "$color2" );
  2552. // Proxies for the jarate effect
  2553. KeyValues *pProxiesYellowLevel = pProxies->FindKey( "YellowLevel", true );
  2554. pProxiesYellowLevel->SetString( "resultVar", "$yellow" );
  2555. KeyValues *pProxiesMultiply = pProxies->FindKey( "Multiply", true );
  2556. pProxiesMultiply->SetString( "srcVar1", "$color2" );
  2557. pProxiesMultiply->SetString( "srcVar2", "$yellow" );
  2558. pProxiesMultiply->SetString( "resultVar", "$color2" );
  2559. }
  2560. else
  2561. {
  2562. // Proxies for the jarate effect
  2563. KeyValues *pProxiesYellowLevel = pProxies->FindKey( "YellowLevel", true );
  2564. pProxiesYellowLevel->SetString( "resultVar", "$yellow" );
  2565. KeyValues *pProxiesEquals = pProxies->FindKey( "Equals", true );
  2566. pProxiesEquals->SetString( "srcVar1", "$yellow" );
  2567. pProxiesEquals->SetString( "resultVar", "$color2" );
  2568. }
  2569. }
  2570. //-----------------------------------------------------------------------------
  2571. //
  2572. //-----------------------------------------------------------------------------
  2573. void CTargetVMT::UpdateManifest( KeyValues *pKV )
  2574. {
  2575. pKV->SetString( "materialId", m_sMaterialId.String() );
  2576. pKV->SetString( "materialType", MaterialTypeToString( GetMaterialType() ) );
  2577. pKV->SetInt( "duplicate", GetDuplicate() );
  2578. pKV->SetInt( "target_width", m_nTargetWidth );
  2579. pKV->SetInt( "target_height", m_nTargetHeight );
  2580. if ( !GetDuplicate() )
  2581. {
  2582. KeyValues *pColorSubKey = new KeyValues( "color" );
  2583. pKV->AddSubKey( pColorSubKey );
  2584. pColorSubKey->SetString( "alphaType", ColorAlphaTypeToString( GetColorAlphaType() ) );
  2585. FOR_EACH_VEC( m_vecTargetVTFs, i )
  2586. {
  2587. KeyValues *pSkinSubKey;
  2588. const char *pszSkinType = CItemUpload::Manifest()->GetMaterialSkin(i);
  2589. if ( pszSkinType )
  2590. pSkinSubKey = new KeyValues( pszSkinType );
  2591. else
  2592. pSkinSubKey = pColorSubKey;
  2593. FOR_EACH_VEC( m_vecTargetVTFs[i], j )
  2594. {
  2595. if ( m_vecTargetVTFs[i][j].IsValid() )
  2596. {
  2597. const char *pszTextureType = CItemUpload::Manifest()->GetTextureType(j);
  2598. KeyValues *pSubKey = new KeyValues( pszTextureType );
  2599. pSkinSubKey->AddSubKey( pSubKey );
  2600. m_vecTargetVTFs[i][j]->UpdateManifest( pSubKey );
  2601. }
  2602. }
  2603. }
  2604. }
  2605. }
  2606. //=============================================================================
  2607. //
  2608. //=============================================================================
  2609. CTargetIcon::CTargetIcon( CAsset *pAsset, int nIconType )
  2610. : CTargetVMT( pAsset, pAsset )
  2611. , m_nIconType( nIconType )
  2612. {
  2613. int nWidth, nHeight;
  2614. CItemUpload::Manifest()->GetIconDimensions( m_nIconType, nWidth, nHeight );
  2615. SetTargetResolution( nWidth, nHeight );
  2616. const char *pszSuffix = CItemUpload::Manifest()->GetIconFilenameAppend( m_nIconType );
  2617. SetNameSuffix( pszSuffix );
  2618. KeyValues *pVMTKV = CItemUpload::Manifest()->GetIconVMTTemplate( m_nIconType );
  2619. if ( pVMTKV )
  2620. {
  2621. SetVMTKV( pVMTKV );
  2622. }
  2623. SetMaterialType( CItemUpload::Manifest()->GetDefaultMaterialType() );
  2624. }
  2625. //-----------------------------------------------------------------------------
  2626. //
  2627. //-----------------------------------------------------------------------------
  2628. bool CTargetIcon::SetTargetVTF( const char *pszFilename )
  2629. {
  2630. return CTargetVMT::SetTargetVTF( m_vecTargetVTFs[0][0], pszFilename, "" );
  2631. }
  2632. //=============================================================================
  2633. //
  2634. //=============================================================================
  2635. CTargetDMX::CTargetDMX( CAsset *pAsset, const CTargetQC *pTargetQC )
  2636. : CTargetBase( pAsset, pTargetQC )
  2637. , m_pDmRoot( NULL )
  2638. , m_nLod( -1 )
  2639. , m_flAnimationLoopStartTime( -1.f )
  2640. {
  2641. }
  2642. //-----------------------------------------------------------------------------
  2643. //
  2644. //-----------------------------------------------------------------------------
  2645. CTargetDMX::~CTargetDMX()
  2646. {
  2647. Clear();
  2648. }
  2649. //-----------------------------------------------------------------------------
  2650. //
  2651. //-----------------------------------------------------------------------------
  2652. bool CTargetDMX::IsOk( CUtlString &sMsg ) const
  2653. {
  2654. if ( m_nLod < 0 )
  2655. {
  2656. sMsg = "Invalid LOD (";
  2657. sMsg += m_nLod;
  2658. sMsg += ")";
  2659. return false;
  2660. }
  2661. if ( m_sInputFile.IsEmpty() || m_sExtension.IsEmpty() )
  2662. {
  2663. sMsg = "No input file specified";
  2664. return false;
  2665. }
  2666. if ( !CItemUpload::FileExists( m_sInputFile.String() ) )
  2667. {
  2668. sMsg = "Input file: \"";
  2669. sMsg += m_sInputFile;
  2670. sMsg += "\" doesn't exist";
  2671. return false;
  2672. }
  2673. if ( !( IsInputSmd() || IsInputObj() || IsInputDmx() || IsInputFbx() ) )
  2674. {
  2675. sMsg = "Input file: \"";
  2676. sMsg += m_sInputFile;
  2677. sMsg += "\" is not a DMX, OBJ or SMD file";
  2678. return false;
  2679. }
  2680. if ( !m_pDmRoot )
  2681. {
  2682. sMsg = "Input file: \"";
  2683. sMsg += m_sInputFile;
  2684. sMsg += "\" couldn't be read";
  2685. return false;
  2686. }
  2687. const int nPolyCount = GetPolyCount();
  2688. if ( nPolyCount <= 0 && m_strQCITemplate.IsEmpty() )
  2689. {
  2690. sMsg = "Invalid polygon count (";
  2691. sMsg += nPolyCount;
  2692. sMsg += ")";
  2693. return false;
  2694. }
  2695. return true;
  2696. }
  2697. //-----------------------------------------------------------------------------
  2698. //
  2699. //-----------------------------------------------------------------------------
  2700. bool CTargetDMX::Compile()
  2701. {
  2702. if ( !ReloadFile() )
  2703. return false;
  2704. if ( !CTargetBase::Compile() )
  2705. return false;
  2706. CUtlString sName;
  2707. if ( !GetOutputPath( sName, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  2708. return false;
  2709. CUtlString sTmp;
  2710. if ( !IsOk( sTmp ) )
  2711. {
  2712. Warning( "CTarget%s::Compile( %s ) - Not Valid: %s\n", GetTypeString(), sName.String(), sTmp.String() );
  2713. return false;
  2714. }
  2715. CUtlString sAbsPath;
  2716. GetOutputPath( sAbsPath, 0 );
  2717. CUtlString sRelPath;
  2718. GetOutputPath( sRelPath, 0, PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE );
  2719. if ( sAbsPath.IsEmpty() || sRelPath.IsEmpty() )
  2720. {
  2721. Warning( "CTarget%s::Compile( %s ) - GetOutputPath failed\n", GetTypeString(), sName.String() );
  2722. return false;
  2723. }
  2724. Msg( "Compiling %s: %s\n", GetTypeString(), sRelPath.String() );
  2725. AddOrEditP4File( sAbsPath.String() );
  2726. CUndoScopeGuard undo( "replaceMaterial" );
  2727. ReplaceMaterials();
  2728. SkinToBipHead();
  2729. #ifdef _DEBUG
  2730. const bool bRet = g_pDataModel->SaveToFile( sAbsPath.String(), NULL, "keyvalues2", "model", m_pDmRoot );
  2731. #else // ifdef _DEBUG
  2732. const bool bRet = g_pDataModel->SaveToFile( sAbsPath.String(), NULL, "binary", "model", m_pDmRoot );
  2733. #endif // _DEBUG
  2734. undo.Abort();
  2735. if ( !bRet )
  2736. {
  2737. Msg( "CTarget%s::Compile( %s ) - SaveToFile failed - \"%s\"\n", GetTypeString(), sName.String(), sAbsPath.String() );
  2738. return false;
  2739. }
  2740. if ( !CheckFile( sAbsPath.String() ) )
  2741. {
  2742. Warning( "CTarget%s::Compile( %s ) - File Check Failed - \"%s\"\n", GetTypeString(), sName.String(), sAbsPath.String() );
  2743. return false;
  2744. }
  2745. if ( !OutputQCIFile() )
  2746. {
  2747. return false;
  2748. }
  2749. if ( CItemUpload::Manifest()->UseTerseMessages() )
  2750. {
  2751. Msg( " - Compilation successful.\n" );
  2752. }
  2753. else
  2754. {
  2755. Msg( "CTarget%s::Compile OK! - %s\n", GetTypeString(), sRelPath.String() );
  2756. }
  2757. return true;
  2758. }
  2759. //-----------------------------------------------------------------------------
  2760. //
  2761. //-----------------------------------------------------------------------------
  2762. bool CTargetDMX::GetInputPaths(
  2763. CUtlVector< CUtlString > &sInputPaths,
  2764. bool bRelative /* = true */,
  2765. bool bRecurse /* = true */,
  2766. bool bExtension /* = true */ )
  2767. {
  2768. sInputPaths.AddToTail( m_sInputFile );
  2769. return CTargetBase::GetInputPaths( sInputPaths, bRelative, bRecurse, bExtension );
  2770. }
  2771. //-----------------------------------------------------------------------------
  2772. //
  2773. //-----------------------------------------------------------------------------
  2774. const ExtensionList *CTargetDMX::GetExtensionsAndCount( void ) const
  2775. {
  2776. static ExtensionList vecExtensions;
  2777. vecExtensions.RemoveAll();
  2778. vecExtensions.AddToTail( ".dmx" );
  2779. if ( !m_strQCITemplate.IsEmpty() )
  2780. {
  2781. vecExtensions.AddToTail( ".qci" );
  2782. }
  2783. return &vecExtensions;
  2784. }
  2785. //-----------------------------------------------------------------------------
  2786. //
  2787. //-----------------------------------------------------------------------------
  2788. void CTargetDMX::GetName( CUtlString &sName ) const
  2789. {
  2790. CTargetBase::GetName( sName );
  2791. if ( GetLod() > 0 )
  2792. {
  2793. sName += "_lod";
  2794. sName += GetLod();
  2795. }
  2796. }
  2797. //-----------------------------------------------------------------------------
  2798. //
  2799. //-----------------------------------------------------------------------------
  2800. int CTargetDMX::GetPolyCount() const
  2801. {
  2802. if ( !m_pDmRoot )
  2803. return 0;
  2804. int nPolyCount = 0;
  2805. const DmFileId_t hRootFileId = m_pDmRoot->GetFileId();
  2806. for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement(); hElement != DMELEMENT_HANDLE_INVALID; hElement = g_pDataModel->NextAllocatedElement( hElement ) )
  2807. {
  2808. if ( hElement == DMELEMENT_HANDLE_INVALID )
  2809. continue;
  2810. CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( g_pDataModel->GetElement( hElement ) );
  2811. if ( !pDmeMesh || pDmeMesh->GetFileId() != hRootFileId )
  2812. continue;
  2813. for ( int i = 0; i < pDmeMesh->FaceSetCount(); ++i )
  2814. {
  2815. CDmeFaceSet *pDmeFaceSet = pDmeMesh->GetFaceSet( i );
  2816. if ( !pDmeFaceSet )
  2817. continue;
  2818. nPolyCount += pDmeFaceSet->GetFaceCount();
  2819. }
  2820. }
  2821. return nPolyCount;
  2822. }
  2823. //-----------------------------------------------------------------------------
  2824. //
  2825. //-----------------------------------------------------------------------------
  2826. int CTargetDMX::GetTriangleCount() const
  2827. {
  2828. if ( !m_pDmRoot )
  2829. return 0;
  2830. int nTriangleCount = 0;
  2831. const DmFileId_t hRootFileId = m_pDmRoot->GetFileId();
  2832. for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement(); hElement != DMELEMENT_HANDLE_INVALID; hElement = g_pDataModel->NextAllocatedElement( hElement ) )
  2833. {
  2834. if ( hElement == DMELEMENT_HANDLE_INVALID )
  2835. continue;
  2836. CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( g_pDataModel->GetElement( hElement ) );
  2837. if ( !pDmeMesh || pDmeMesh->GetFileId() != hRootFileId )
  2838. continue;
  2839. for ( int i = 0; i < pDmeMesh->FaceSetCount(); ++i )
  2840. {
  2841. CDmeFaceSet *pDmeFaceSet = pDmeMesh->GetFaceSet( i );
  2842. if ( !pDmeFaceSet )
  2843. continue;
  2844. nTriangleCount += pDmeFaceSet->GetTriangulatedIndexCount() / 3;
  2845. }
  2846. }
  2847. return nTriangleCount;
  2848. }
  2849. //-----------------------------------------------------------------------------
  2850. //
  2851. //-----------------------------------------------------------------------------
  2852. int CTargetDMX::GetVertexCount() const
  2853. {
  2854. if ( !m_pDmRoot )
  2855. return 0;
  2856. int nVertexCount = 0;
  2857. const DmFileId_t hRootFileId = m_pDmRoot->GetFileId();
  2858. for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement(); hElement != DMELEMENT_HANDLE_INVALID; hElement = g_pDataModel->NextAllocatedElement( hElement ) )
  2859. {
  2860. if ( hElement == DMELEMENT_HANDLE_INVALID )
  2861. continue;
  2862. CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( g_pDataModel->GetElement( hElement ) );
  2863. if ( !pDmeMesh || pDmeMesh->GetFileId() != hRootFileId )
  2864. continue;
  2865. CDmeVertexData *pVertexData = pDmeMesh->GetBindBaseState();
  2866. if ( !pVertexData )
  2867. continue;
  2868. nVertexCount += pVertexData->VertexCount();
  2869. }
  2870. return nVertexCount;
  2871. }
  2872. bool CTargetDMX::GetAnimationFrameInfo( float& flFrameRate, int& nFrameCount ) const
  2873. {
  2874. if ( !m_pDmRoot )
  2875. return false;
  2876. CDmeAnimationList *pDmeAnimationList = m_pDmRoot->GetValueElement< CDmeAnimationList >( "animationList" );
  2877. CDmeChannelsClip *pDmeChannelsClip = NULL;
  2878. if ( pDmeAnimationList )
  2879. {
  2880. if ( pDmeAnimationList->GetAnimationCount() < 0 )
  2881. {
  2882. Warning( "No DmeChannelsClips found in root.animationList of DMX file: \"%s\"\n", m_sInputFile.String() );
  2883. return false;
  2884. }
  2885. pDmeChannelsClip = pDmeAnimationList->GetAnimation( 0 );
  2886. if ( !pDmeChannelsClip )
  2887. {
  2888. Warning( "No DmeChannelsClip found in root.animationList[0] of DMX file: \"%s\"\n", m_sInputFile.String() );
  2889. return false;
  2890. }
  2891. flFrameRate = pDmeChannelsClip->GetValue< int >( "frameRate", 30 );
  2892. nFrameCount = (int)( ( pDmeChannelsClip->GetDuration().GetSeconds() * flFrameRate ) + 0.5f ) + 1;
  2893. return true;
  2894. }
  2895. return false;
  2896. }
  2897. //-----------------------------------------------------------------------------
  2898. // Returns true if all meshes in the DMX data have skinning information
  2899. // false if any mesh doesn't have skinning data
  2900. //-----------------------------------------------------------------------------
  2901. bool CTargetDMX::AreAllMeshesSkinned() const
  2902. {
  2903. if ( !m_pDmRoot )
  2904. return false; // No DMX data
  2905. const DmFileId_t hRootFileId = m_pDmRoot->GetFileId();
  2906. int nMeshCount = 0;
  2907. for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement(); hElement != DMELEMENT_HANDLE_INVALID; hElement = g_pDataModel->NextAllocatedElement( hElement ) )
  2908. {
  2909. if ( hElement == DMELEMENT_HANDLE_INVALID )
  2910. continue;
  2911. CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( g_pDataModel->GetElement( hElement ) );
  2912. if ( !pDmeMesh || pDmeMesh->GetFileId() != hRootFileId )
  2913. continue;
  2914. CDmeVertexData *pDmeVertexData = pDmeMesh->GetBindBaseState();
  2915. if ( !pDmeVertexData )
  2916. continue;
  2917. // If even one mesh doesn't have skinning data, abort
  2918. if ( !pDmeVertexData->HasSkinningData() )
  2919. return false;
  2920. }
  2921. // Make sure we saw at least one mesh
  2922. return ( nMeshCount > 0 );
  2923. }
  2924. //-----------------------------------------------------------------------------
  2925. //
  2926. //-----------------------------------------------------------------------------
  2927. const CUtlString &CTargetDMX::GetInputFile() const
  2928. {
  2929. return m_sInputFile;
  2930. }
  2931. //-----------------------------------------------------------------------------
  2932. //
  2933. //-----------------------------------------------------------------------------
  2934. void CTargetDMX::Clear()
  2935. {
  2936. if ( m_pDmRoot )
  2937. {
  2938. CDisableUndoScopeGuard noUndo;
  2939. m_targetVmtList.RemoveAll();
  2940. g_pDataModel->UnloadFile( m_pDmRoot->GetFileId() );
  2941. m_pDmRoot = NULL;
  2942. }
  2943. }
  2944. //-----------------------------------------------------------------------------
  2945. //
  2946. //-----------------------------------------------------------------------------
  2947. bool CTargetDMX::SetInputFile( const char *pszFilename )
  2948. {
  2949. // Because of the way datamodel works, bad things will happen if the same file is loaded twice
  2950. Clear();
  2951. m_sInputFile = pszFilename;
  2952. char szBuf[ k64KB ];
  2953. V_ExtractFileExtension( pszFilename, szBuf, ARRAYSIZE( szBuf ) );
  2954. m_sExtension = szBuf;
  2955. DmFileId_t hRootFileId = g_pDataModel->GetFileId( pszFilename );
  2956. DmElementHandle_t hRootElement = g_pDataModel->GetFileRoot( hRootFileId );
  2957. CDmElement *pDmRoot = g_pDataModel->GetElement( hRootElement );
  2958. if ( !pDmRoot )
  2959. {
  2960. pDmRoot = LoadDmx();
  2961. }
  2962. if ( !pDmRoot )
  2963. {
  2964. pDmRoot = LoadFbx();
  2965. }
  2966. if ( !pDmRoot )
  2967. {
  2968. pDmRoot = LoadSmd();
  2969. }
  2970. if ( !pDmRoot )
  2971. {
  2972. pDmRoot = LoadObj();
  2973. }
  2974. if ( !pDmRoot )
  2975. {
  2976. Warning( "ERROR: Don't Know What Type Of Input File Is\n" );
  2977. return false;
  2978. }
  2979. m_pDmRoot = pDmRoot;
  2980. // TODO: Change to walking from root?
  2981. hRootFileId = m_pDmRoot->GetFileId();
  2982. // we must store the root handle so we don't reload the same file multiple time
  2983. g_pDataModel->SetFileRoot( hRootFileId, m_pDmRoot->GetHandle() );
  2984. int nMaterialType = 0;
  2985. for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement(); hElement != DMELEMENT_HANDLE_INVALID; hElement = g_pDataModel->NextAllocatedElement( hElement ) )
  2986. {
  2987. if ( hElement == DMELEMENT_HANDLE_INVALID )
  2988. continue;
  2989. CDmeMaterial *pDmeMaterial = CastElement< CDmeMaterial >( g_pDataModel->GetElement( hElement ) );
  2990. if ( !pDmeMaterial || pDmeMaterial->GetFileId() != hRootFileId )
  2991. continue;
  2992. CSmartPtr< CTargetVMT > pTargetVMT = Asset()->FindOrAddMaterial( pDmeMaterial->GetMaterialName(), nMaterialType );
  2993. if ( pTargetVMT.IsValid() )
  2994. {
  2995. m_targetVmtList.AddToTail( pTargetVMT );
  2996. ++nMaterialType;
  2997. }
  2998. }
  2999. CUtlString sTmp;
  3000. if ( IsOk( sTmp ) )
  3001. return true;
  3002. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  3003. return false;
  3004. }
  3005. //-----------------------------------------------------------------------------
  3006. //
  3007. //-----------------------------------------------------------------------------
  3008. bool CTargetDMX::ReloadFile()
  3009. {
  3010. // Keep references to all target VMT's to prevent them from being destroyed by a reload of the same file
  3011. CUtlVector< CSmartPtr< CTargetVMT > > tmpVmtCopy;
  3012. tmpVmtCopy = m_targetVmtList;
  3013. // 'reset' the input file from the current value to force a reload on compile, make a temp copy as it's going to be overwritten
  3014. if ( !SetInputFile( CUtlString( GetInputFile() ).String() ) )
  3015. return false;
  3016. return true;
  3017. }
  3018. //-----------------------------------------------------------------------------
  3019. //
  3020. //-----------------------------------------------------------------------------
  3021. bool CTargetDMX::IsInputObj() const
  3022. {
  3023. // TODO: Perhaps look at magic in the start of the file
  3024. return !V_stricmp( "obj", m_sExtension.String() );
  3025. }
  3026. //-----------------------------------------------------------------------------
  3027. //
  3028. //-----------------------------------------------------------------------------
  3029. bool CTargetDMX::IsInputSmd() const
  3030. {
  3031. // TODO: Perhaps look at magic in the start of the file
  3032. return !V_stricmp( "smd", m_sExtension.String() );
  3033. }
  3034. //-----------------------------------------------------------------------------
  3035. //
  3036. //-----------------------------------------------------------------------------
  3037. bool CTargetDMX::IsInputDmx() const
  3038. {
  3039. // TODO: Perhaps look at magic in the start of the file
  3040. return !V_stricmp( "dmx", m_sExtension.String() );
  3041. }
  3042. //-----------------------------------------------------------------------------
  3043. //
  3044. //-----------------------------------------------------------------------------
  3045. bool CTargetDMX::IsInputFbx() const
  3046. {
  3047. // TODO: Perhaps look at magic in the start of the file
  3048. return !V_stricmp( "fbx", m_sExtension.String() );
  3049. }
  3050. //-----------------------------------------------------------------------------
  3051. //
  3052. //-----------------------------------------------------------------------------
  3053. CDmElement *CTargetDMX::LoadObj()
  3054. {
  3055. if ( !IsInputObj() )
  3056. return NULL;
  3057. CDisableUndoScopeGuard noUndo;
  3058. CDmObjSerializer dmObjSerializer;
  3059. return dmObjSerializer.ReadOBJ( m_sInputFile.String() );
  3060. }
  3061. //-----------------------------------------------------------------------------
  3062. //
  3063. //-----------------------------------------------------------------------------
  3064. CDmElement *CTargetDMX::LoadSmd()
  3065. {
  3066. if ( !IsInputSmd() )
  3067. return NULL;
  3068. CDisableUndoScopeGuard noUndo;
  3069. CDmSmdSerializer dmSmdSerializer;
  3070. dmSmdSerializer.SetIsAnimation( !m_strQCITemplate.IsEmpty() );
  3071. return dmSmdSerializer.ReadSMD( m_sInputFile.String() );
  3072. }
  3073. //-----------------------------------------------------------------------------
  3074. //
  3075. //-----------------------------------------------------------------------------
  3076. CDmElement *CTargetDMX::LoadDmx()
  3077. {
  3078. if ( !IsInputDmx() )
  3079. return NULL;
  3080. CDisableUndoScopeGuard noUndo;
  3081. CDmElement *pDmRoot = NULL;
  3082. g_pDataModel->RestoreFromFile( m_sInputFile.String(), NULL, NULL, &pDmRoot );
  3083. return pDmRoot;
  3084. }
  3085. //-----------------------------------------------------------------------------
  3086. //
  3087. //-----------------------------------------------------------------------------
  3088. CDmElement *CTargetDMX::LoadFbx()
  3089. {
  3090. if ( !IsInputFbx() )
  3091. return NULL;
  3092. CDisableUndoScopeGuard noUndo;
  3093. CDmFbxSerializer dmFbxSerializer;
  3094. return dmFbxSerializer.ReadFBX( m_sInputFile.String() );
  3095. }
  3096. //-----------------------------------------------------------------------------
  3097. //
  3098. //-----------------------------------------------------------------------------
  3099. void CTargetDMX::ReplaceMaterials() const
  3100. {
  3101. CUtlString sTmp;
  3102. if ( !IsOk( sTmp ) )
  3103. {
  3104. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  3105. return;
  3106. }
  3107. DmFileId_t hRootFileId = m_pDmRoot->GetFileId();
  3108. if ( hRootFileId == DMFILEID_INVALID )
  3109. return;
  3110. CAsset *pAsset = Asset();
  3111. if ( !pAsset )
  3112. return;
  3113. CUtlMap< CUtlString, CUtlString > materialMap( UtlStringLessThan );
  3114. CUtlString sRelativeDir;
  3115. pAsset->GetRelativeDir( sRelativeDir, NULL, this );
  3116. char szBuf[ k64KB ];
  3117. for ( int i = 0; i < pAsset->GetTargetVMTCount(); ++i )
  3118. {
  3119. CTargetVMT *pTargetVMT = pAsset->GetTargetVMT( i );
  3120. if ( !pTargetVMT )
  3121. continue;
  3122. CUtlString sMaterialId;
  3123. pTargetVMT->GetMaterialId( sMaterialId );
  3124. if ( sMaterialId.IsEmpty() || materialMap.IsValidIndex( materialMap.Find( sMaterialId ) ) )
  3125. continue;
  3126. CTargetVMT *pSrcTargetVMT = pTargetVMT;
  3127. if ( pTargetVMT->GetDuplicate() )
  3128. {
  3129. const int nMaterialType = pTargetVMT->GetMaterialType();
  3130. if ( nMaterialType < 0 || nMaterialType >= CItemUpload::Manifest()->GetNumMaterialTypes() )
  3131. {
  3132. Warning( "CTarget%s::ReplaceMaterials - Duplicate VMT (%s) with bad material type (%d)\n", GetTypeString(), sMaterialId.String(), nMaterialType );
  3133. continue;
  3134. }
  3135. for ( int j = 0; j < pAsset->GetTargetVMTCount(); ++j )
  3136. {
  3137. CTargetVMT *pTmpTargetVMT = pAsset->GetTargetVMT( j );
  3138. if ( !pTmpTargetVMT || pTmpTargetVMT->GetDuplicate() )
  3139. continue;
  3140. if ( pTmpTargetVMT->GetMaterialType() == nMaterialType )
  3141. {
  3142. pSrcTargetVMT = pTmpTargetVMT;
  3143. break;
  3144. }
  3145. }
  3146. if ( pTargetVMT == pSrcTargetVMT )
  3147. {
  3148. Warning( "CTarget%s::ReplaceMaterials - Duplicate VMT (%s) Cannot Find Source Material Type (%d)\n", GetTypeString(), sMaterialId.String(), nMaterialType );
  3149. continue;
  3150. }
  3151. }
  3152. sMaterialId.FixSlashes( '/' );
  3153. // The full extension can be _red.vmt or _blue.vmt so we need to keep the _red but not the .vmt
  3154. CUtlString sMaterialPath;
  3155. pSrcTargetVMT->GetOutputPath( sMaterialPath, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION | PATH_FLAG_PATH | PATH_FLAG_MODELS );
  3156. V_StripExtension( sMaterialPath, szBuf, ARRAYSIZE( szBuf ) );
  3157. sMaterialPath.FixSlashes( '/' );
  3158. sMaterialPath = szBuf;
  3159. materialMap.InsertOrReplace( sMaterialId, sMaterialPath.String() );
  3160. }
  3161. for ( DmElementHandle_t hElement = g_pDataModel->FirstAllocatedElement(); hElement != DMELEMENT_HANDLE_INVALID; hElement = g_pDataModel->NextAllocatedElement( hElement ) )
  3162. {
  3163. if ( hElement == DMELEMENT_HANDLE_INVALID )
  3164. continue;
  3165. CDmeMesh *pDmeMesh = CastElement< CDmeMesh >( g_pDataModel->GetElement( hElement ) );
  3166. if ( !pDmeMesh || pDmeMesh->GetFileId() != hRootFileId )
  3167. continue;
  3168. FOR_EACH_MAP_FAST( materialMap, mmi )
  3169. {
  3170. pDmeMesh->ReplaceMaterial( materialMap.Key( mmi ), materialMap.Element( mmi ) );
  3171. }
  3172. }
  3173. }
  3174. //-----------------------------------------------------------------------------
  3175. //
  3176. //-----------------------------------------------------------------------------
  3177. void CTargetDMX::SkinToBipHead()
  3178. {
  3179. CAssetTF *pAssetTF = dynamic_cast< CAssetTF * >( Asset() );
  3180. if ( !pAssetTF )
  3181. return;
  3182. if ( !pAssetTF->SkinToBipHead() )
  3183. return;
  3184. CDisableUndoScopeGuard undoGuard;
  3185. CDmeModel *pSrcModel = m_pDmRoot->GetValueElement< CDmeModel >( "model" );
  3186. if ( !pSrcModel )
  3187. return;
  3188. const DmFileId_t nFileId = m_pDmRoot->GetFileId();
  3189. CDmElement *pDstRoot = CreateElement< CDmElement >( m_pDmRoot->GetName(), nFileId );
  3190. CDmeModel *pDstModel = CreateElement< CDmeModel >( pSrcModel->GetName(), nFileId );
  3191. pDstModel->GetTransform()->SetName( pDstModel->GetName() );
  3192. pDstRoot->SetValue( "model", pDstModel );
  3193. pDstRoot->SetValue( "skeleton", pDstModel );
  3194. CDmeJoint *pBipHead = CreateElement< CDmeJoint >( "bip_head", nFileId );
  3195. pBipHead->GetTransform()->SetName( "bip_head" );
  3196. pDstModel->AddChild( pBipHead );
  3197. pDstModel->AddJoint( pBipHead );
  3198. const Vector &vBipHead = pAssetTF->GetBipHead();
  3199. const RadianEuler &eBipHead = pAssetTF->GetBipHeadRotation();
  3200. const Quaternion qBipHead = eBipHead;
  3201. pBipHead->GetTransform()->SetOrientation( qBipHead );
  3202. CUtlStack< CDmeDag * > depthFirstStack;
  3203. depthFirstStack.Push( pSrcModel );
  3204. while ( depthFirstStack.Count() )
  3205. {
  3206. CDmeDag *pDmeDag = NULL;
  3207. depthFirstStack.Pop( pDmeDag );
  3208. if ( !pDmeDag )
  3209. continue;
  3210. SkinToBipHead_R( pDstModel, pDmeDag, vBipHead );
  3211. for ( int i = pDmeDag->GetChildCount() - 1; i >= 0; --i )
  3212. {
  3213. depthFirstStack.Push( pDmeDag->GetChild( i ) );
  3214. }
  3215. }
  3216. pDstModel->CaptureJointsToBaseState( "bind" );
  3217. DestroyElement( m_pDmRoot, TD_ALL );
  3218. m_pDmRoot = pDstRoot;
  3219. }
  3220. //-----------------------------------------------------------------------------
  3221. //
  3222. //-----------------------------------------------------------------------------
  3223. void CTargetDMX::SkinToBipHead_R( CDmeModel *pDstModel, CDmeDag *pSrcDag, const Vector &vBipHead )
  3224. {
  3225. if ( !pDstModel || !pSrcDag )
  3226. return;
  3227. CDmeMesh *pSrcMesh = CastElement< CDmeMesh >( pSrcDag->GetShape() );
  3228. if ( !pSrcMesh )
  3229. return;
  3230. CDmeVertexData *pSrcBind = pSrcMesh->GetBindBaseState();
  3231. if ( !pSrcBind )
  3232. return;
  3233. CDmeDag *pDstDag = CreateElement< CDmeDag >( pSrcDag->GetName(), pDstModel->GetFileId() );
  3234. if ( !pDstDag )
  3235. return;
  3236. pDstDag->GetTransform()->SetName( pDstDag->GetName() );
  3237. CDmeMesh *pDstMesh = pSrcMesh->Copy();
  3238. if ( !pDstMesh )
  3239. return;
  3240. // Current state is left empty, not sure why
  3241. pDstMesh->SetBindBaseState( pDstMesh->GetCurrentBaseState() );
  3242. pDstMesh->Resolve();
  3243. pDstDag->SetShape( pDstMesh );
  3244. pDstModel->AddChild( pDstDag );
  3245. matrix3x4_t mIdentity; // TODO: Is there a static identity matrix like quat_identity?
  3246. SetIdentityMatrix( mIdentity );
  3247. matrix3x4_t mSrcAbs;
  3248. // pSrcDag->GetAbsTransform( mSrcAbs );
  3249. {
  3250. matrix3x4_t parentToWorld;
  3251. pSrcDag->GetParentWorldMatrix( parentToWorld );
  3252. matrix3x4_t localMatrix;
  3253. pSrcDag->GetLocalMatrix( localMatrix );
  3254. ConcatTransforms( parentToWorld, localMatrix, mSrcAbs );
  3255. }
  3256. matrix3x4_t mNormal;
  3257. MatrixInverseTranspose( mSrcAbs, mNormal );
  3258. bool bConvertToWorldSpace = !MatricesAreEqual( mIdentity, mSrcAbs );
  3259. for ( int i = 0; i < pDstMesh->BaseStateCount(); ++i )
  3260. {
  3261. CDmeVertexData *pDstVertexData = pDstMesh->GetBaseState( i );
  3262. if ( !pDstVertexData )
  3263. continue;
  3264. pDstVertexData->Resolve();
  3265. // Remove all skinning information
  3266. // This seems a little odd, creating data to remove it but if it already exists this is
  3267. // the only way of setting the joint count to 0 without cheating (i.e. referring to the field by name)
  3268. FieldIndex_t nJointWeightField;
  3269. FieldIndex_t nJointIndexField;
  3270. pDstVertexData->CreateJointWeightsAndIndices( 0, &nJointWeightField, &nJointIndexField );
  3271. pDstVertexData->RemoveAttribute( pDstVertexData->FieldName( nJointWeightField ) );
  3272. pDstVertexData->RemoveAttribute( pDstVertexData->FieldName( nJointIndexField ) );
  3273. // Convert data to world space if required
  3274. {
  3275. Vector vTmp;
  3276. static const int nZero = 0;
  3277. static const float flOne = 1;
  3278. FieldIndex_t nPositionField = pDstVertexData->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  3279. if ( nPositionField >= 0 )
  3280. {
  3281. CDmAttribute *pPosAttr = pDstVertexData->GetVertexData( nPositionField );
  3282. if ( pPosAttr )
  3283. {
  3284. CDmrArray< Vector > posData = pPosAttr;
  3285. // Set everything up to be skinned to joint 0
  3286. pDstVertexData->CreateJointWeightsAndIndices( 1, &nJointWeightField, &nJointIndexField );
  3287. pDstVertexData->AddVertexData( nJointIndexField, posData.Count() );
  3288. pDstVertexData->AddVertexData( nJointWeightField, posData.Count() );
  3289. if ( bConvertToWorldSpace )
  3290. {
  3291. for ( int iPos = 0; iPos < posData.Count(); ++iPos )
  3292. {
  3293. pDstVertexData->SetVertexData( nJointIndexField, iPos, 1, AT_INT, &nZero );
  3294. pDstVertexData->SetVertexData( nJointWeightField, iPos, 1, AT_FLOAT, &flOne );
  3295. }
  3296. }
  3297. else
  3298. {
  3299. for ( int iPos = 0; iPos < posData.Count(); ++iPos )
  3300. {
  3301. VectorTransform( posData[iPos], mSrcAbs, vTmp );
  3302. posData.Set( iPos, vTmp );
  3303. pDstVertexData->SetVertexData( nJointIndexField, i, 1, AT_INT, &nZero );
  3304. pDstVertexData->SetVertexData( nJointWeightField, i, 1, AT_FLOAT, &flOne );
  3305. }
  3306. }
  3307. }
  3308. }
  3309. FieldIndex_t nNormalField = pDstVertexData->FindFieldIndex( CDmeVertexData::FIELD_NORMAL );
  3310. if ( nNormalField >= 0 )
  3311. {
  3312. CDmAttribute *pNormalAttr = pDstVertexData->GetVertexData( nNormalField );
  3313. if ( pNormalAttr )
  3314. {
  3315. CDmrArray< Vector > normalData = pNormalAttr;
  3316. for ( int iData = 0; iData < normalData.Count(); ++iData )
  3317. {
  3318. VectorRotate( normalData[iData], mNormal, vTmp );
  3319. vTmp.NormalizeInPlace();
  3320. normalData.Set( iData, vTmp );
  3321. }
  3322. }
  3323. }
  3324. }
  3325. pDstVertexData->Resolve();
  3326. }
  3327. Vector vMin;
  3328. Vector vMax;
  3329. pDstMesh->GetBoundingBox( vMin, vMax );
  3330. const Vector vCenter = ( vMax - vMin ) / 2.0 + vMin;
  3331. const float flSqDistOrigin = vCenter.DistToSqr( Vector( 0, 0, 0 ) );
  3332. const float flSqDistBipHead = vCenter.DistToSqr( vBipHead );
  3333. // See where the model was modelled... around the bip_head bone or at the origin?
  3334. // There are probably other problems which aren't accounted for this is a really naive
  3335. // algorithm
  3336. if ( flSqDistBipHead < flSqDistOrigin )
  3337. {
  3338. // Model centered around bip head, subtract vBipHead from position data
  3339. Vector vTmp;
  3340. for ( int i = 0; i < pDstMesh->BaseStateCount(); ++i )
  3341. {
  3342. CDmeVertexData *pDstVertexData = pDstMesh->GetBaseState( i );
  3343. if ( !pDstVertexData )
  3344. continue;
  3345. pDstVertexData->Resolve();
  3346. FieldIndex_t nPositionField = pDstVertexData->FindFieldIndex( CDmeVertexData::FIELD_POSITION );
  3347. if ( nPositionField >= 0 )
  3348. {
  3349. CDmAttribute *pPosAttr = pDstVertexData->GetVertexData( nPositionField );
  3350. if ( pPosAttr )
  3351. {
  3352. CDmrArray< Vector > posData = pPosAttr;
  3353. for ( int iPos = 0; iPos < posData.Count(); ++iPos )
  3354. {
  3355. VectorSubtract( posData[iPos], vBipHead, vTmp );
  3356. posData.Set( iPos, vTmp );
  3357. }
  3358. }
  3359. }
  3360. pDstVertexData->Resolve();
  3361. }
  3362. }
  3363. }
  3364. //=============================================================================
  3365. //
  3366. //=============================================================================
  3367. bool CTargetDMX::OutputQCIFile()
  3368. {
  3369. // Should we output QCI?
  3370. if ( !m_strQCITemplate.IsEmpty() )
  3371. {
  3372. CUtlString sDMXName;
  3373. if ( !GetOutputPath( sDMXName, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  3374. return false;
  3375. CUtlString sName;
  3376. if ( !GetOutputPath( sName, 1, PATH_FLAG_FILE ) )
  3377. return false;
  3378. CUtlString sAbsPath;
  3379. if ( !GetOutputPath( sAbsPath, 1 ) )
  3380. return false;
  3381. float flFrameRate;
  3382. int nFrameCount;
  3383. if ( !GetAnimationFrameInfo( flFrameRate, nFrameCount ) )
  3384. {
  3385. Warning( "Failed to get animation's frame info for %s\n", sAbsPath.String() );
  3386. return false;
  3387. }
  3388. const int nBlendFrameOffset = 5;
  3389. const int nLastFrameIndex = nFrameCount - 1;
  3390. CUtlString strLayerName = "layer_";
  3391. strLayerName += sName;
  3392. CUtlString strBuf = m_strQCITemplate.Replace( "<ITEMTEST_SEQUENCE_LAYER_NAME>", strLayerName.String() );
  3393. strBuf = strBuf.Replace( "<ITEMTEST_SEQUENCE_NAME>", sName.String() );
  3394. strBuf = strBuf.Replace( "<ITEMTEST_DMX_FILE>", sName.String() );
  3395. strBuf = strBuf.Replace( "<FPS>", CFmtStr( "fps %d", (int)flFrameRate ) );
  3396. strBuf = strBuf.Replace( "<BLEND_LAYER_RANGE>", CFmtStr( "0 %d %d <LAST_FRAME_INDEX>", nBlendFrameOffset, nLastFrameIndex - nBlendFrameOffset ) );
  3397. strBuf = strBuf.Replace( "<FRAME_COUNT>", CFmtStr( "%d", nFrameCount ) );
  3398. strBuf = strBuf.Replace( "<LAST_FRAME_INDEX>", CFmtStr( "%d", nLastFrameIndex ) );
  3399. CUtlBuffer bufQCFile( 0, 0, CUtlBuffer::TEXT_BUFFER );
  3400. bufQCFile.PutString( strBuf.String() );
  3401. AddOrEditP4File( sAbsPath.String() );
  3402. g_pFullFileSystem->WriteFile( sAbsPath.String(), "MOD", bufQCFile );
  3403. }
  3404. return true;
  3405. }
  3406. void LeftRightToValueBalance( float flLeft, float flRight, float &flOutValue, float &flOutBalance )
  3407. {
  3408. if ( flLeft > flRight )
  3409. {
  3410. flOutValue = flLeft;
  3411. flOutBalance = 0.5f * flRight / flLeft;
  3412. }
  3413. else
  3414. {
  3415. flOutValue = flRight;
  3416. flOutBalance = 1.0f - 0.5f * flRight / flLeft;
  3417. }
  3418. }
  3419. void BufPrintf( CUtlBuffer& buf, int nLevel, const char *fmt, ... )
  3420. {
  3421. va_list argptr;
  3422. va_start( argptr, fmt );
  3423. while ( nLevel-- > 0 )
  3424. {
  3425. buf.Printf( " " );
  3426. }
  3427. buf.VaPrintf( fmt, argptr );
  3428. va_end( argptr );
  3429. }
  3430. void BufBeginBlock( CUtlBuffer& buf, int &nLevel )
  3431. {
  3432. BufPrintf( buf, nLevel, "{\n" );
  3433. ++nLevel;
  3434. }
  3435. void BufEndBlock( CUtlBuffer& buf, int &nLevel )
  3436. {
  3437. --nLevel;
  3438. BufPrintf( buf, nLevel, "}\n" );
  3439. }
  3440. template< class T >
  3441. CDmeTypedLogLayer< T > *GetTopmostLogLayer( CDmeChannel *pChannel )
  3442. {
  3443. if ( !pChannel )
  3444. return NULL;
  3445. CDmeTypedLog< T > *pLog = CastElement< CDmeTypedLog< T > >( pChannel->GetLog() );
  3446. if ( !pLog )
  3447. return NULL;
  3448. return pLog->GetLayer( pLog->GetTopmostLayer() );
  3449. }
  3450. void CTargetDMX::OutputSounds( CUtlBuffer &buf, int nIndentLevel, CDmElement *pExportedSounds )
  3451. {
  3452. if ( !pExportedSounds )
  3453. return;
  3454. CDmrElementArray< CDmElement > soundsArray( pExportedSounds, "sounds" );
  3455. if ( !soundsArray.IsValid() )
  3456. return;
  3457. int nSounds = soundsArray.Count();
  3458. if ( nSounds == 0 )
  3459. return;
  3460. CUtlBuffer soundScriptBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
  3461. if ( !m_strSoundScriptFile.IsEmpty() )
  3462. {
  3463. if ( !g_pFullFileSystem->ReadFile( m_strSoundScriptFile.String(), "MOD", soundScriptBuffer ) )
  3464. {
  3465. Warning( "Failed to load sound script file\n" );
  3466. return;
  3467. }
  3468. }
  3469. else
  3470. {
  3471. Warning( "Sound script file not specified\n" );
  3472. return;
  3473. }
  3474. BufPrintf( buf, nIndentLevel, "channel \"sounds\"\n" );
  3475. BufBeginBlock( buf, nIndentLevel );
  3476. {
  3477. for ( int i = 0; i < nSounds; ++i )
  3478. {
  3479. CDmElement *pSound = soundsArray[ i ];
  3480. if ( !pSound )
  3481. continue;
  3482. float flStartTime = pSound->GetValue< float >( "startTime" );
  3483. CUtlString strWaveName = pSound->GetValueString( "fileName" );
  3484. V_FixSlashes( strWaveName.GetForModify(), '/' );
  3485. if ( !g_pFullFileSystem->FileExists( CFmtStr( "sound/%s", strWaveName.String() ), "GAME" ) )
  3486. {
  3487. CUtlString strSoundName = strWaveName.StripExtension();
  3488. if ( !g_pFullFileSystem->FileExists( CFmtStr( "sound/%s.mp3", strSoundName.String() ), "GAME" ) )
  3489. {
  3490. Warning( "OutputSounds to VCD missing sound file: %s.wav/mp3\n", strSoundName.String() );
  3491. continue;
  3492. }
  3493. }
  3494. bool bIsVO = V_strstr( strWaveName.String(), "vo/" ) != NULL;
  3495. const char *pszSoundScriptName = CFmtStr( "<CLASS_NAME>_<ITEMTEST_SEQUENCE_NAME>_%s", pSound->GetName() );
  3496. // write sound script entry to sound script file
  3497. int nSoundIndentLevel = 0;
  3498. BufPrintf( soundScriptBuffer, nSoundIndentLevel, "\"%s\"\n", pszSoundScriptName );
  3499. BufBeginBlock( soundScriptBuffer, nSoundIndentLevel );
  3500. {
  3501. BufPrintf( soundScriptBuffer, nSoundIndentLevel, "\"channel\" \"%s\"\n", bIsVO ? "CHAN_VOICE" : "CHAN_STATIC" );
  3502. BufPrintf( soundScriptBuffer, nSoundIndentLevel, "\"volume\" \"VOL_NORM\"\n" );
  3503. BufPrintf( soundScriptBuffer, nSoundIndentLevel, "\"pitch\" \"PITCH_NORM\"\n" );
  3504. BufPrintf( soundScriptBuffer, nSoundIndentLevel, "\"soundlevel\" \"SNDLVL_95dB\"\n" );
  3505. BufPrintf( soundScriptBuffer, nSoundIndentLevel, "\"wave\" \"%s\"\n", strWaveName.String() );
  3506. }
  3507. BufEndBlock( soundScriptBuffer, nSoundIndentLevel );
  3508. // write vcd speak event
  3509. BufPrintf( buf, nIndentLevel, "event speak \"%s\"\n", pszSoundScriptName );
  3510. BufBeginBlock( buf, nIndentLevel );
  3511. {
  3512. BufPrintf( buf, nIndentLevel, "time %f <MAX_SEQUENCE_LENGTH>\n", flStartTime );
  3513. BufPrintf( buf, nIndentLevel, "param \"%s\"", pszSoundScriptName );
  3514. BufPrintf( buf, nIndentLevel, "fixedlength\n" );
  3515. BufPrintf( buf, nIndentLevel, "cctpe \"cc_master\"\n" );
  3516. BufPrintf( buf, nIndentLevel, "cctoken \"\"\n" );
  3517. }
  3518. BufEndBlock( buf, nIndentLevel );
  3519. }
  3520. }
  3521. BufEndBlock( buf, nIndentLevel );
  3522. CUtlString strBuf = soundScriptBuffer.String();
  3523. FOR_EACH_SUBKEY( GetCustomKeyValues(), pSubKey )
  3524. {
  3525. strBuf = strBuf.Replace( pSubKey->GetName(), pSubKey->GetString() );
  3526. }
  3527. soundScriptBuffer.Clear();
  3528. soundScriptBuffer.PutString( strBuf.String() );
  3529. // write to sound script file
  3530. CUtlString sWorkingDir;
  3531. CItemUpload::GetVProjectDir( sWorkingDir );
  3532. char szSoundScriptFullPath[MAX_PATH];
  3533. V_MakeAbsolutePath( szSoundScriptFullPath, sizeof( szSoundScriptFullPath ), m_strSoundScriptFile.String(), sWorkingDir.String() );
  3534. if ( !g_pFullFileSystem->WriteFile( szSoundScriptFullPath, NULL, soundScriptBuffer ) )
  3535. {
  3536. Warning( "Failed to output soundscript: %s\n", szSoundScriptFullPath );
  3537. }
  3538. if ( GetCustomModPath() )
  3539. {
  3540. char szCustomPath[MAX_PATH];
  3541. V_MakeAbsolutePath( szCustomPath, sizeof( szCustomPath ), CFmtStr( "%s/%s", GetCustomModPath(), m_strSoundScriptFile.String() ), sWorkingDir.String() );
  3542. V_FixSlashes( szCustomPath );
  3543. if ( DoFileCopy( szSoundScriptFullPath, szCustomPath ) )
  3544. {
  3545. Asset()->AddModOutput( szCustomPath );
  3546. }
  3547. }
  3548. }
  3549. // pChannelsClip is assumed to be an exported channelsclip (vs a live channelsclip)
  3550. bool CTargetDMX::WriteVCD( CUtlBuffer &vcdBuf )
  3551. {
  3552. CDmeAnimationList *pDmeAnimationList = m_pDmRoot->GetValueElement< CDmeAnimationList >( "animationList" );
  3553. CDmeChannelsClip *pDmeChannelsClip = NULL;
  3554. if ( pDmeAnimationList )
  3555. {
  3556. if ( pDmeAnimationList->GetAnimationCount() < 0 )
  3557. {
  3558. Warning( "No DmeChannelsClips found in root.animationList of DMX file: \"%s\"\n", m_sInputFile.String() );
  3559. return false;
  3560. }
  3561. pDmeChannelsClip = pDmeAnimationList->GetAnimation( 0 );
  3562. if ( !pDmeChannelsClip )
  3563. {
  3564. Warning( "No DmeChannelsClip found in root.animationList[0] of DMX file: \"%s\"\n", m_sInputFile.String() );
  3565. return false;
  3566. }
  3567. }
  3568. DmeFramerate_t framerate( pDmeChannelsClip->GetValue< int >( "frameRate", 30 ) );
  3569. int nLevel = 0;
  3570. BufPrintf( vcdBuf, nLevel, "// Choreo version 1\n" );
  3571. // loop animation?
  3572. if ( m_flAnimationLoopStartTime >= 0.f )
  3573. {
  3574. BufPrintf( vcdBuf, nLevel, "event loop \"<ITEMTEST_SEQUENCE_NAME>_loop\"\n" );
  3575. BufBeginBlock( vcdBuf, nLevel );
  3576. {
  3577. BufPrintf( vcdBuf, nLevel, "time <MAX_SEQUENCE_LENGTH> -1.000000\n" );
  3578. BufPrintf( vcdBuf, nLevel, "param \"%f\"\n", m_flAnimationLoopStartTime );
  3579. BufPrintf( vcdBuf, nLevel, "loopcount \"-1\"\n" );
  3580. }
  3581. BufEndBlock( vcdBuf, nLevel );
  3582. }
  3583. BufPrintf( vcdBuf, nLevel, "actor \"<CLASS_NAME>\"\n" );
  3584. BufBeginBlock( vcdBuf, nLevel );
  3585. {
  3586. // sequence channel
  3587. BufPrintf( vcdBuf, nLevel, "channel \"<CLASS_NAME>\"\n" );
  3588. BufBeginBlock( vcdBuf, nLevel );
  3589. {
  3590. BufPrintf( vcdBuf, nLevel, "event sequence <ITEMTEST_SEQUENCE_NAME>\n" );
  3591. BufBeginBlock( vcdBuf, nLevel );
  3592. {
  3593. BufPrintf( vcdBuf, nLevel, "time 0.000000 <MAX_SEQUENCE_LENGTH>\n" );
  3594. BufPrintf( vcdBuf, nLevel, "param <ITEMTEST_SEQUENCE_NAME>\n" );
  3595. }
  3596. BufEndBlock( vcdBuf, nLevel );
  3597. }
  3598. BufEndBlock( vcdBuf, nLevel );
  3599. // Flex Anim channel
  3600. BufPrintf( vcdBuf, nLevel, "channel \"Face\"\n" );
  3601. BufBeginBlock( vcdBuf, nLevel );
  3602. {
  3603. int nChannelCount = pDmeChannelsClip->m_Channels.Count();
  3604. for ( int ci = 0; ci < nChannelCount; ++ci )
  3605. {
  3606. CDmeChannel *pChannel = pDmeChannelsClip->m_Channels[ ci ];
  3607. // skip all transform
  3608. if ( !pChannel || !pChannel->GetToAttribute() || pChannel->GetToAttribute()->GetType() != AT_FLOAT )
  3609. continue;
  3610. CDmElement *pToElement = pChannel->GetToElement();
  3611. const char *pszToElementName = pToElement->GetName();
  3612. // figure out IsStereoControl by checking if prefix is left_ and right_
  3613. // in pDmeChannelsClip->m_Channels
  3614. CDmeChannel *pLeftChannel = NULL; //pChannel->GetValueElement< CDmeChannel >( "leftvaluechannel" );
  3615. CDmeChannel *pRightChannel = NULL; //pChannel->GetValueElement< CDmeChannel >( "rightvaluechannel" );
  3616. for ( int iSearch = 0; iSearch < nChannelCount; ++iSearch )
  3617. {
  3618. CDmeChannel *pSearchChannel = pDmeChannelsClip->m_Channels[ iSearch ];
  3619. if ( !pSearchChannel )
  3620. continue;
  3621. // search for left and right channels
  3622. const char *pszSearchChannelName = pSearchChannel->GetName();
  3623. if ( V_strstr( pszSearchChannelName, pszToElementName ) )
  3624. {
  3625. if ( V_strstr( pszSearchChannelName, "left_" ) )
  3626. {
  3627. Assert( pLeftChannel == NULL );
  3628. pLeftChannel = pSearchChannel;
  3629. }
  3630. else if ( V_strstr( pszSearchChannelName, "right_" ) )
  3631. {
  3632. Assert( pRightChannel == NULL );
  3633. pRightChannel = pSearchChannel;
  3634. }
  3635. }
  3636. }
  3637. bool bIsStereo = pLeftChannel && pRightChannel;
  3638. if ( bIsStereo )
  3639. {
  3640. // should we do anything for stereo (eye animation)?
  3641. AssertMsg( 0, "Stereo channel is not supported." );
  3642. continue;
  3643. CDmeFloatLogLayer *pLeftLogLayer = GetTopmostLogLayer< float >( pLeftChannel );
  3644. CDmeFloatLogLayer *pRightLogLayer = GetTopmostLogLayer< float >( pRightChannel );
  3645. if ( !pLeftLogLayer || !pRightLogLayer )
  3646. continue;
  3647. CUtlVectorFixedGrowable< DmeTime_t, 1024 > times;
  3648. CUtlVectorFixedGrowable< float, 1024 > values;
  3649. CUtlVectorFixedGrowable< float, 1024 > balances;
  3650. // we should have some key count on both left and right key
  3651. if ( pLeftLogLayer->GetKeyCount() == 0 || pRightLogLayer->GetKeyCount() == 0 )
  3652. {
  3653. // something is wrong here.
  3654. Assert( 0 );
  3655. continue;
  3656. }
  3657. DmeTime_t tStartOnFrame = MIN( pLeftLogLayer ->GetKeyTime( 0 ), pRightLogLayer->GetKeyTime( 0 ) );
  3658. DmeTime_t tEndOnFrame = MAX( pLeftLogLayer ->GetKeyTime( pLeftLogLayer->GetKeyCount() - 1 ), pRightLogLayer->GetKeyTime( pRightLogLayer->GetKeyCount() - 1 ) );
  3659. #if 1 // resample time
  3660. for ( DmeTime_t tCurr = tStartOnFrame; tCurr <= tEndOnFrame; tCurr = tCurr.TimeAtNextFrame( framerate ) )
  3661. {
  3662. float flLeftValue = pLeftLogLayer->GetValue( pDmeChannelsClip->FromChildMediaTime( tCurr ) );
  3663. float flRightValue = pLeftLogLayer->GetValue( pDmeChannelsClip->FromChildMediaTime( tCurr ) );
  3664. float flValue, flBalance;
  3665. LeftRightToValueBalance( flLeftValue, flRightValue, flValue, flBalance );
  3666. times.AddToTail( tCurr );
  3667. values.AddToTail( flValue );
  3668. balances.AddToTail( flBalance );
  3669. }
  3670. #else // merge time list from left and right channels
  3671. int nLeft = pLeftLogLayer->GetKeyCount();
  3672. int nRight = pRightLogLayer->GetKeyCount();
  3673. int iLeft = pLeftLogLayer->FindKey( pDmeChannelsClip->ToChildMediaTime( tStart ) );
  3674. int iRight = pLeftLogLayer->FindKey( pDmeChannelsClip->ToChildMediaTime( tStart ) );
  3675. while ( iLeft < nLeft || iRight < nRight )
  3676. {
  3677. DmeTime_t tLeft = iLeft < nLeft ? pDmeChannelsClip->FromChildMediaTime( pLeftLogLayer ->GetKeyTime( iLeft ) ) : DMETIME_MAXTIME;
  3678. DmeTime_t tRight = iRight < nRight ? pDmeChannelsClip->FromChildMediaTime( pRightLogLayer->GetKeyTime( iRight ) ) : DMETIME_MAXTIME;
  3679. DmeTime_t t;
  3680. float flLeftVal, flRightVal;
  3681. if ( tLeft == tRight )
  3682. {
  3683. t = tLeft;
  3684. flLeftVal = pLeftLogLayer->GetKeyValue( iLeft );
  3685. flRightVal = pRightLogLayer->GetKeyValue( iRight );
  3686. iLeft++;
  3687. iRight++;
  3688. }
  3689. else if ( tLeft < tRight )
  3690. {
  3691. t = tLeft;
  3692. flLeftVal = pLeftLogLayer->GetKeyValue( iLeft );
  3693. flRightVal = pRightLogLayer->GetValue( t );
  3694. iLeft++;
  3695. }
  3696. else
  3697. {
  3698. t = tRight;
  3699. flLeftVal = pLeftLogLayer->GetValue( t );
  3700. flRightVal = pRightLogLayer->GetKeyValue( iRight );
  3701. iRight++;
  3702. }
  3703. float flValue, flBalance;
  3704. LeftRightToValueBalance( flLeftVal, flRightVal, flValue, flBalance );
  3705. times.AddToTail( t );
  3706. values.AddToTail( flValue );
  3707. balances.AddToTail( flBalance );
  3708. }
  3709. #endif
  3710. BufPrintf( vcdBuf, nLevel, "\"%s\" combo\n", pChannel->GetName() );
  3711. BufBeginBlock( vcdBuf, nLevel );
  3712. int nSamples = times.Count();
  3713. for ( int si = 0; si < nSamples; ++si )
  3714. {
  3715. BufPrintf( vcdBuf, nLevel, "%.4f %.4f\n", times[ si ].GetSeconds(), values[ si ] );
  3716. }
  3717. BufEndBlock( vcdBuf, nLevel );
  3718. BufBeginBlock( vcdBuf, nLevel );
  3719. for ( int si = 0; si < nSamples; ++si )
  3720. {
  3721. BufPrintf( vcdBuf, nLevel, "%.4f %.4f\n", times[ si ].GetSeconds(), balances[ si ] );
  3722. }
  3723. BufEndBlock( vcdBuf, nLevel );
  3724. }
  3725. else
  3726. {
  3727. CDmeFloatLogLayer *pLogLayer = GetTopmostLogLayer< float >( pChannel );
  3728. if ( !pLogLayer || pLogLayer->GetKeyCount() == 0 )
  3729. continue;
  3730. BufPrintf( vcdBuf, nLevel, "event expression \"%s\"\n", pToElement->GetName() );
  3731. BufBeginBlock( vcdBuf, nLevel );
  3732. {
  3733. BufPrintf( vcdBuf, nLevel, "time %.4f %.4f\n", pDmeChannelsClip->GetStartTime().GetSeconds(), pDmeChannelsClip->GetEndTime().GetSeconds() );
  3734. BufPrintf( vcdBuf, nLevel, "param \"player\\<CLASS_NAME>\\emotion\\emotion\"\n" );
  3735. BufPrintf( vcdBuf, nLevel, "param2 \"%s\"\n", pToElement->GetName() );
  3736. BufPrintf( vcdBuf, nLevel, "event_ramp\n" );
  3737. BufBeginBlock( vcdBuf, nLevel );
  3738. {
  3739. #if 0 // resampling
  3740. if ( tStart < tStartOnFrame )
  3741. {
  3742. float flValue = pLogLayer->GetValue( pDmeChannelsClip->FromChildMediaTime( tStart ) );
  3743. BufPrintf( vcdBuf, nLevel, "%.4f %.4f\n", tStart.GetSeconds(), flValue );
  3744. }
  3745. for ( DmeTime_t tCurr = tStartOnFrame; tCurr <= tEndOnFrame; tCurr = tCurr.TimeAtNextFrame( framerate ) )
  3746. {
  3747. float flValue = pLogLayer->GetValue( pDmeChannelsClip->FromChildMediaTime( tCurr ) );
  3748. BufPrintf( vcdBuf, nLevel, "%.4f %.4f\n", tCurr.GetSeconds(), flValue );
  3749. }
  3750. if ( tEnd > tEndOnFrame )
  3751. {
  3752. float flValue = pLogLayer->GetValue( pDmeChannelsClip->FromChildMediaTime( tEnd ) );
  3753. BufPrintf( vcdBuf, nLevel, "%.4f %.4f\n", tEnd.GetSeconds(), flValue );
  3754. }
  3755. #else // use sample time that's already in the animation
  3756. int nKeys = pLogLayer->GetKeyCount();
  3757. for ( int k = 0; k < nKeys; ++k )
  3758. {
  3759. DmeTime_t t = pDmeChannelsClip->FromChildMediaTime( pLogLayer->GetKeyTime( k ) );
  3760. float flValue = pLogLayer->GetKeyValue( k );
  3761. BufPrintf( vcdBuf, nLevel, "%.4f %.4f\n", t.GetSeconds(), flValue );
  3762. }
  3763. #endif
  3764. }
  3765. BufEndBlock( vcdBuf, nLevel );
  3766. }
  3767. BufEndBlock( vcdBuf, nLevel );
  3768. }
  3769. }
  3770. // channel sounds
  3771. OutputSounds( vcdBuf, nLevel, m_pDmRoot->GetValueElement< CDmElement >( "exportedSounds" ) );
  3772. }
  3773. BufEndBlock( vcdBuf, nLevel );
  3774. }
  3775. BufEndBlock( vcdBuf, nLevel );
  3776. BufPrintf( vcdBuf, nLevel, "fps %d\n", RoundFloatToInt( framerate.GetFramesPerSecond() ) );
  3777. BufPrintf( vcdBuf, nLevel, "snap off\n" );
  3778. CUtlString strBuf = vcdBuf.String();
  3779. FOR_EACH_SUBKEY( GetCustomKeyValues(), pSubKey )
  3780. {
  3781. strBuf = strBuf.Replace( pSubKey->GetName(), pSubKey->GetString() );
  3782. }
  3783. vcdBuf.Clear();
  3784. vcdBuf.PutString( strBuf );
  3785. return true;
  3786. }
  3787. //=============================================================================
  3788. //
  3789. //=============================================================================
  3790. CTargetVCD::CTargetVCD( CAsset *pAsset, const CTargetQC *pTargetQC )
  3791. : CTargetBase( pAsset, pTargetQC ), m_pTargetQC( pTargetQC )
  3792. {
  3793. }
  3794. //-----------------------------------------------------------------------------
  3795. //
  3796. //-----------------------------------------------------------------------------
  3797. bool CTargetVCD::Compile()
  3798. {
  3799. if ( !CTargetBase::Compile() )
  3800. return false;
  3801. CUtlString sName;
  3802. if ( !GetOutputPath( sName, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  3803. return false;
  3804. CUtlString sTmp;
  3805. if ( !IsOk( sTmp ) )
  3806. {
  3807. Warning( "CTarget%s::Compile( %s ) - Not Valid: %s\n", GetTypeString(), sName.String(), sTmp.String() );
  3808. return false;
  3809. }
  3810. CUtlString sBinDir;
  3811. if ( !CItemUpload::GetBinDirectory( sBinDir ) )
  3812. {
  3813. Warning( "CTarget%s::Compile( %s ) - GetBinDirectory Failed\n", GetTypeString(), sName.String() );
  3814. return false;
  3815. }
  3816. CUtlString sAbsPath;
  3817. GetOutputPath( sAbsPath, 0 );
  3818. CUtlString sRelPath;
  3819. GetOutputPath( sRelPath, 0, PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE );
  3820. if ( sAbsPath.IsEmpty() || sRelPath.IsEmpty() )
  3821. {
  3822. Warning( "CTarget%s::Compile( %s ) - GetOutputPath failed\n", GetTypeString(), sName.String() );
  3823. return false;
  3824. }
  3825. Msg( "Compiling %s: %s\n", GetTypeString(), sRelPath.String() );
  3826. CUtlBuffer bufVCDFile( 0, 0, CUtlBuffer::TEXT_BUFFER );
  3827. if ( m_strVCDPath.IsEmpty() )
  3828. {
  3829. if ( !m_pTargetQC->GetTargetDMX( 0 )->WriteVCD( bufVCDFile ) )
  3830. {
  3831. Warning( "CTarget%s::Compile( %s ) - failed to create VCD buffer\n", GetTypeString(), m_strVCDPath.String() );
  3832. return false;
  3833. }
  3834. }
  3835. else if ( !g_pFullFileSystem->ReadFile( m_strVCDPath, NULL, bufVCDFile ) )
  3836. {
  3837. Warning( "CTarget%s::Compile( %s ) - failed to read input file\n", GetTypeString(), m_strVCDPath.String() );
  3838. return false;
  3839. }
  3840. // output to the correct file path
  3841. AddOrEditP4File( sAbsPath.String() );
  3842. g_pFullFileSystem->WriteFile( sAbsPath.String(), "MOD", bufVCDFile );
  3843. Msg( "CTarget%s::Compile OK! - %s\n", GetTypeString(), sRelPath );
  3844. if ( GetCustomModPath() )
  3845. {
  3846. CUtlString sWorkingDir;
  3847. if ( CItemUpload::IgnoreEnvironmentVariables() )
  3848. {
  3849. sWorkingDir = sAbsPath;
  3850. sWorkingDir.SetLength( sWorkingDir.Length() - sRelPath.Length() );
  3851. V_StripTrailingSlash( sWorkingDir.GetForModify() );
  3852. }
  3853. else
  3854. {
  3855. CItemUpload::GetVProjectDir( sWorkingDir );
  3856. }
  3857. char szCustomPath[MAX_PATH];
  3858. V_MakeAbsolutePath( szCustomPath, sizeof( szCustomPath ), CFmtStr( "%s/%s", GetCustomModPath(), sRelPath.String() ), sWorkingDir.String() );
  3859. V_FixSlashes( szCustomPath );
  3860. if ( DoFileCopy( sAbsPath.String(), szCustomPath ) )
  3861. {
  3862. Asset()->AddModOutput( szCustomPath );
  3863. }
  3864. }
  3865. return true;
  3866. }
  3867. //-----------------------------------------------------------------------------
  3868. //
  3869. //-----------------------------------------------------------------------------
  3870. const ExtensionList *CTargetVCD::GetExtensionsAndCount( void ) const
  3871. {
  3872. static ExtensionList vecExtensions;
  3873. if ( !vecExtensions.Count() )
  3874. {
  3875. vecExtensions.AddToTail( ".vcd" );
  3876. }
  3877. return &vecExtensions;
  3878. }
  3879. //=============================================================================
  3880. //
  3881. //=============================================================================
  3882. CTargetQC::CTargetQC( CAsset *pAsset, const CTargetMDL *pTargetMDL )
  3883. : CTargetBase( pAsset, pTargetMDL )
  3884. , m_QCTemplate( 0, 0, CUtlBuffer::TEXT_BUFFER )
  3885. , m_TargetVCD( NULL )
  3886. {
  3887. }
  3888. //-----------------------------------------------------------------------------
  3889. //
  3890. //-----------------------------------------------------------------------------
  3891. bool CTargetQC::IsOk( CUtlString &sMsg ) const
  3892. {
  3893. if ( m_TargetDMXs.Count() <= 0 )
  3894. {
  3895. sMsg = "No DMX input files specified";
  3896. return false;
  3897. }
  3898. return true;
  3899. }
  3900. //-----------------------------------------------------------------------------
  3901. //
  3902. //-----------------------------------------------------------------------------
  3903. bool CTargetQC::Compile()
  3904. {
  3905. if ( !CTargetBase::Compile() )
  3906. return false;
  3907. CUtlString sName;
  3908. if ( !GetOutputPath( sName, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  3909. return false;
  3910. CUtlString sAbsPath;
  3911. GetOutputPath( sAbsPath, 0 );
  3912. CUtlString sRelPath;
  3913. GetOutputPath( sRelPath, 0, PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE );
  3914. if ( sAbsPath.IsEmpty() || sRelPath.IsEmpty() )
  3915. {
  3916. Warning( "CTarget%s::Compile( %s ) - GetOutputPath failed\n", GetTypeString(), sName.String() );
  3917. return false;
  3918. }
  3919. CUtlString sLOD0;
  3920. GetOutputPath( sLOD0, 0, PATH_FLAG_PATH | PATH_FLAG_FILE | PATH_FLAG_PREFIX | PATH_FLAG_MODELS );
  3921. sLOD0.FixSlashes( '/' );
  3922. const char *pszPostModel = V_strstr( sLOD0.String(), "models/" );
  3923. CUtlString sModelName = pszPostModel ? pszPostModel + 7 : sLOD0;
  3924. sModelName += ".mdl";
  3925. Msg( "Compiling %s: %s\n", GetTypeString(), sRelPath.String() );
  3926. AddOrEditP4File( sAbsPath.String() );
  3927. CUtlString strBuf = GetQCTemplate();
  3928. if ( strBuf.IsEmpty() )
  3929. {
  3930. return false;
  3931. }
  3932. strBuf = strBuf.Replace( "<ITEMTEST_REPLACE_MDLABSPATH>", sModelName.String() );
  3933. for ( int nLOD = 1; nLOD < m_TargetDMXs.Count(); ++nLOD )
  3934. {
  3935. strBuf = strBuf.Replace( CFmtStr( "<ITEMTEST_REPLACE_LOD%d_HEADER>", nLOD ), CFmtStr( "$lod %d", CItemUpload::Manifest()->GetQCLODDistance( nLOD ) ) );
  3936. }
  3937. // Remove REPLACE_LOD block if it's not necessary
  3938. RemoveTextBlock( strBuf.String(), "<ITEMTEST_REPLACE_LOD1_HEADER>", strBuf.GetForModify(), strBuf.Length() );
  3939. RemoveTextBlock( strBuf.String(), "<ITEMTEST_REPLACE_LOD2_HEADER>", strBuf.GetForModify(), strBuf.Length() );
  3940. CUtlString sSearch = "<ITEMTEST_REPLACE_SKIN_OPTIONALBLOCK>";
  3941. CUtlString sReplace = "$cdmaterials \"<ITEMTEST_REPLACE_MATERIALS_PATH>\"\n$texturegroup skinfamilies\n{\n";
  3942. CUtlString sMaterialPath;
  3943. for ( int nSkin = 0; nSkin < CItemUpload::Manifest()->GetNumMaterialSkins(); ++nSkin )
  3944. {
  3945. int nVMTCount = 0;
  3946. CUtlString sSkinMaterials = " { ";
  3947. for ( int nVMT = 0; nVMT < Asset()->GetTargetVMTCount(); ++nVMT )
  3948. {
  3949. CTargetVMT *pTargetVMT = Asset()->GetTargetVMT( nVMT );
  3950. if ( nSkin >= pTargetVMT->GetOutputCount() )
  3951. continue;
  3952. // We grab the extension which includes the skin variant, and then trim the actual file extension
  3953. CUtlString sVMTName;
  3954. if ( !pTargetVMT->GetOutputPath( sVMTName, nSkin, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  3955. {
  3956. Warning( "CTarget%s::Compile( %s ) - VMT %d skin %d GetOutputPath failed\n", GetTypeString(), sName.String(), nVMT, nSkin );
  3957. continue;
  3958. }
  3959. V_StripExtension( sVMTName.String(), sVMTName.GetForModify(), sVMTName.Length() );
  3960. if ( sMaterialPath.IsEmpty() )
  3961. {
  3962. pTargetVMT->GetOutputPath( sMaterialPath, 0, PATH_FLAG_PATH | PATH_FLAG_MODELS );
  3963. }
  3964. sSkinMaterials += CFmtStr( "\"%s\" ", sVMTName.String() );
  3965. ++nVMTCount;
  3966. }
  3967. sSkinMaterials += "}\n";
  3968. if ( nVMTCount > 0 )
  3969. {
  3970. sReplace += sSkinMaterials;
  3971. }
  3972. }
  3973. sReplace += "}\n";
  3974. strBuf = strBuf.Replace( sSearch.String(), sReplace.String() );
  3975. strBuf = strBuf.Replace( "<ITEMTEST_REPLACE_MATERIALS_PATH>", sMaterialPath.String() );
  3976. for ( int nLOD = 0; nLOD < m_TargetDMXs.Count(); ++nLOD )
  3977. {
  3978. CUtlString sLOD;
  3979. m_TargetDMXs[ nLOD ]->GetOutputPath( sLOD, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION );
  3980. strBuf = strBuf.Replace( CFmtStr( "<ITEMTEST_REPLACE_LOD%d>", nLOD ), sLOD.String() );
  3981. }
  3982. // Should we include QCI?
  3983. if ( !m_strQCITemplate.IsEmpty() )
  3984. {
  3985. CUtlString strQCIDir;
  3986. m_TargetDMXs[ 0 ]->GetOutputPath( strQCIDir, 1, PATH_FLAG_PATH & ~PATH_FLAG_ABSOLUTE );
  3987. strQCIDir = strQCIDir.Replace( '\\', '/' );
  3988. strBuf = strBuf.Replace( "<QCI_RELATIVE_DIR>", strQCIDir.String() );
  3989. CUtlString strQCIRel;
  3990. m_TargetDMXs[ 0 ]->GetOutputPath( strQCIRel, 1, PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE & ~PATH_FLAG_MODELS );
  3991. strQCIRel = strQCIRel.Replace( '\\', '/' );
  3992. strBuf = strBuf.Replace( "<QCI_RELATIVE_PATH>", strQCIRel.String() );
  3993. }
  3994. FOR_EACH_SUBKEY( GetCustomKeyValues(), pSubKey )
  3995. {
  3996. strBuf = strBuf.Replace( pSubKey->GetName(), pSubKey->GetString() );
  3997. }
  3998. CUtlBuffer bufQCFile( 0, 0, CUtlBuffer::TEXT_BUFFER );
  3999. bufQCFile.PutString( strBuf.String() );
  4000. g_pFullFileSystem->WriteFile( sAbsPath.String(), "MOD", bufQCFile );
  4001. if ( !CheckFile( sAbsPath.String() ) )
  4002. {
  4003. Warning( "CTarget%s::Compile( %s ) - File Check Failed - \"%s\"\n", GetTypeString(), sName.String(), sAbsPath.String() );
  4004. return false;
  4005. }
  4006. if ( CItemUpload::Manifest()->UseTerseMessages() )
  4007. {
  4008. Msg( " - Compilation successful.\n" );
  4009. }
  4010. else
  4011. {
  4012. Msg( "CTarget%s::Compile OK! - %s\n", GetTypeString(), sRelPath.String() );
  4013. }
  4014. return true;
  4015. }
  4016. //-----------------------------------------------------------------------------
  4017. //
  4018. //-----------------------------------------------------------------------------
  4019. const ExtensionList *CTargetQC::GetExtensionsAndCount( void ) const
  4020. {
  4021. static ExtensionList vecExtensions;
  4022. if ( !vecExtensions.Count() )
  4023. {
  4024. vecExtensions.AddToTail( ".qc" );
  4025. }
  4026. return &vecExtensions;
  4027. }
  4028. //-----------------------------------------------------------------------------
  4029. //
  4030. //-----------------------------------------------------------------------------
  4031. bool CTargetQC::GetInputs( CUtlVector< CTargetBase * > &sInputs ) const
  4032. {
  4033. CUtlString sTmp;
  4034. if ( !IsOk( sTmp ) )
  4035. {
  4036. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  4037. return false;
  4038. }
  4039. int nOkCount = 0;
  4040. for ( int i = 0; i < m_TargetDMXs.Count(); ++i )
  4041. {
  4042. CTargetBase *pTargetBase = m_TargetDMXs.Element( i ).GetObject();
  4043. if ( !pTargetBase )
  4044. continue;
  4045. nOkCount += ( sInputs.AddToTail( pTargetBase ) >= 0 ? 1 : 0 );
  4046. }
  4047. if ( m_TargetVCD.IsValid() )
  4048. {
  4049. CTargetBase *pTargetBase = m_TargetVCD.GetObject();
  4050. if ( pTargetBase )
  4051. {
  4052. nOkCount += ( sInputs.AddToTail( pTargetBase ) >= 0 ? 1 : 0 );
  4053. }
  4054. }
  4055. return nOkCount > 0;
  4056. }
  4057. //-----------------------------------------------------------------------------
  4058. //
  4059. //-----------------------------------------------------------------------------
  4060. int CTargetQC::TargetDMXCount() const
  4061. {
  4062. return m_TargetDMXs.Count();
  4063. }
  4064. //-----------------------------------------------------------------------------
  4065. //
  4066. //-----------------------------------------------------------------------------
  4067. void CTargetQC::SetQCTemplate( const char *pszQCTemplate )
  4068. {
  4069. m_QCTemplate.Clear();
  4070. m_QCTemplate.PutString( pszQCTemplate );
  4071. }
  4072. //-----------------------------------------------------------------------------
  4073. //
  4074. //-----------------------------------------------------------------------------
  4075. const char *CTargetQC::GetQCTemplate()
  4076. {
  4077. if ( m_QCTemplate.TellMaxPut() == 0 )
  4078. {
  4079. const char *pszQCTemplate = CItemUpload::Manifest()->GetQCTemplate();
  4080. if ( pszQCTemplate )
  4081. {
  4082. if ( !g_pFullFileSystem->ReadFile( pszQCTemplate, "MOD", m_QCTemplate ) )
  4083. {
  4084. Warning( "Failed to load specified QC template '%s'.\n", pszQCTemplate );
  4085. }
  4086. }
  4087. }
  4088. return (char*)m_QCTemplate.Base();
  4089. }
  4090. //-----------------------------------------------------------------------------
  4091. //
  4092. //-----------------------------------------------------------------------------
  4093. int CTargetQC::AddTargetDMX( const char *pszGeometryFile )
  4094. {
  4095. CSmartPtr< CTargetDMX > pTargetDMX = Asset()->NewTarget< CTargetDMX >( this );
  4096. if ( !pTargetDMX )
  4097. return -1;
  4098. const int nIndex = m_TargetDMXs.AddToTail( pTargetDMX );
  4099. if ( nIndex < 0 )
  4100. {
  4101. // Failed to add
  4102. return -1;
  4103. }
  4104. if ( !SetTargetDMX( nIndex, pszGeometryFile ) )
  4105. {
  4106. m_TargetDMXs.RemoveMultipleFromTail( 1 );
  4107. return -1;
  4108. }
  4109. return nIndex;
  4110. }
  4111. //-----------------------------------------------------------------------------
  4112. //
  4113. //-----------------------------------------------------------------------------
  4114. bool CTargetQC::SetTargetDMX( int nLOD, const char *pszGeometryFile )
  4115. {
  4116. if ( nLOD >= TargetDMXCount() )
  4117. return false;
  4118. CSmartPtr< CTargetDMX > pTargetDMX = m_TargetDMXs.Element( nLOD );
  4119. if ( !pTargetDMX )
  4120. return false;
  4121. pTargetDMX->SetNameSuffix( GetNameSuffix() );
  4122. pTargetDMX->SetLod( nLOD );
  4123. pTargetDMX->SetQCITemplate( m_strQCITemplate.String() );
  4124. return pTargetDMX->SetInputFile( pszGeometryFile );
  4125. }
  4126. //-----------------------------------------------------------------------------
  4127. //
  4128. //-----------------------------------------------------------------------------
  4129. bool CTargetQC::RemoveTargetDMX( int nLOD )
  4130. {
  4131. if ( nLOD != m_TargetDMXs.Count() - 1 )
  4132. return false;
  4133. m_TargetDMXs.RemoveMultipleFromTail( 1 );
  4134. return false;
  4135. }
  4136. //-----------------------------------------------------------------------------
  4137. //
  4138. //-----------------------------------------------------------------------------
  4139. CSmartPtr< CTargetDMX > CTargetQC::GetTargetDMX( int nLOD ) const
  4140. {
  4141. if ( nLOD >= TargetDMXCount() )
  4142. return NULL;
  4143. return m_TargetDMXs.Element( nLOD );
  4144. }
  4145. //-----------------------------------------------------------------------------
  4146. //
  4147. //-----------------------------------------------------------------------------
  4148. CSmartPtr< CTargetVCD > CTargetQC::GetTargetVCD()
  4149. {
  4150. if ( m_TargetVCD == NULL )
  4151. {
  4152. m_TargetVCD = Asset()->NewTarget< CTargetVCD >( this );
  4153. }
  4154. return m_TargetVCD;
  4155. }
  4156. //=============================================================================
  4157. //
  4158. //=============================================================================
  4159. CTargetMDL::CTargetMDL( CAsset *pAsset, const CTargetBase *pTargetParent )
  4160. : CTargetBase( pAsset, pTargetParent )
  4161. , m_pTargetQC( NULL )
  4162. {
  4163. m_pTargetQC = Asset()->NewTarget< CTargetQC >( this );
  4164. }
  4165. //-----------------------------------------------------------------------------
  4166. //
  4167. //-----------------------------------------------------------------------------
  4168. bool CTargetMDL::IsOk( CUtlString &sMsg ) const
  4169. {
  4170. CUtlString sTmp;
  4171. if ( !m_pTargetQC || !m_pTargetQC->IsOk( sTmp ) )
  4172. {
  4173. sMsg = "Invalid QC: ";
  4174. sMsg += sTmp;
  4175. return false;
  4176. }
  4177. return true;
  4178. }
  4179. //-----------------------------------------------------------------------------
  4180. //
  4181. //-----------------------------------------------------------------------------
  4182. bool CTargetMDL::Compile()
  4183. {
  4184. if ( !CTargetBase::Compile() )
  4185. return false;
  4186. CUtlString sName;
  4187. if ( !GetOutputPath( sName, 0, PATH_FLAG_FILE | PATH_FLAG_EXTENSION ) )
  4188. return false;
  4189. CUtlString sBinDir;
  4190. if ( !CItemUpload::GetBinDirectory( sBinDir ) )
  4191. {
  4192. Warning( "CTarget%s::Compile( %s ) - GetBinDirectory Failed\n", GetTypeString(), sName.String() );
  4193. return false;
  4194. }
  4195. CUtlVector< CUtlString > sAbsPaths;
  4196. GetOutputPaths( sAbsPaths );
  4197. if ( sAbsPaths.Count() <= 0 )
  4198. {
  4199. Warning( "CTarget%s::Compile( %s ) - GetOutputPaths failed\n", GetTypeString(), sName.String() );
  4200. return false;
  4201. }
  4202. CUtlString sAbsPath = sAbsPaths.Element( 0 );
  4203. CUtlString sRelPath;
  4204. GetOutputPath( sRelPath, 0, PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE );
  4205. if ( sAbsPath.IsEmpty() || sRelPath.IsEmpty() )
  4206. {
  4207. Warning( "CTarget%s::Compile( %s ) - GetOutputPath failed\n", GetTypeString(), sName.String() );
  4208. return false;
  4209. }
  4210. CUtlVector< CUtlString > sAbsInputPaths;
  4211. if ( !GetInputPaths( sAbsInputPaths, false, false ) )
  4212. {
  4213. Warning( "CTarget%s::Compile( %s ) - GetInputPaths failed\n", GetTypeString(), sName.String() );
  4214. return false;
  4215. }
  4216. if ( sAbsInputPaths.Count() != 1 )
  4217. {
  4218. Warning( "CTarget%s::Compile( %s ) - GetPaths returned %d paths, expected 1\n", GetTypeString(), sName.String(), sAbsInputPaths.Count() );
  4219. return false;
  4220. }
  4221. if ( !Asset()->Mkdir( NULL, this ) )
  4222. {
  4223. Warning( "CTarget%s::Compile - Mkdir failed\n", GetTypeString() );
  4224. return false;
  4225. }
  4226. Msg( "Compiling %s: %s\n", GetTypeString(), sRelPath.String() );
  4227. if ( CItemUpload::GetP4() )
  4228. {
  4229. for ( int i = 0; i < sAbsPaths.Count(); ++i )
  4230. {
  4231. AddOrEditP4File( sAbsPaths.Element( i ).String() );
  4232. }
  4233. }
  4234. CUtlString sWorkingDir;
  4235. CFmtStrN< k64KB > sCmd;
  4236. if ( CItemUpload::IgnoreEnvironmentVariables() )
  4237. {
  4238. sWorkingDir = sAbsPath;
  4239. sWorkingDir.SetLength( sWorkingDir.Length() - sRelPath.Length() );
  4240. V_StripTrailingSlash( sWorkingDir.GetForModify() );
  4241. sCmd.sprintf( "\"%s\\studiomdl.exe\" -nop4 -game \"%s\" \"%s\"", sBinDir.String(), sWorkingDir.String(), sAbsInputPaths.Element( 0 ).String() );
  4242. }
  4243. else
  4244. {
  4245. CItemUpload::GetVProjectDir( sWorkingDir );
  4246. sCmd.sprintf( "\"%s\\studiomdl.exe\" -nop4 -vproject \"%s\" \"%s\"", sBinDir.String(), sWorkingDir.String(), sAbsInputPaths.Element( 0 ).String() );
  4247. }
  4248. bool bOk = true;
  4249. if ( CItemUpload::RunCommandLine( sCmd.Access(), sBinDir.String(), this ) )
  4250. {
  4251. for ( int i = 0; i < sAbsPaths.Count(); ++i )
  4252. {
  4253. if ( !CheckFile( sAbsPaths.Element( i ).String() ) )
  4254. {
  4255. Warning( "CTarget%s::Compile( %s ) - CheckFile failed - \"%s\"\n", GetTypeString(), sName.String(), sAbsPaths.Element( i ).String() );
  4256. bOk = false;
  4257. break;
  4258. }
  4259. }
  4260. }
  4261. else
  4262. {
  4263. bOk = false;
  4264. }
  4265. if ( bOk )
  4266. {
  4267. if ( CItemUpload::Manifest()->UseTerseMessages() )
  4268. {
  4269. Msg( " - Compilation successful.\n" );
  4270. }
  4271. else
  4272. {
  4273. Msg( "CTarget%s::Compile OK! - %s\n", GetTypeString(), sRelPath.String() );
  4274. }
  4275. }
  4276. else
  4277. {
  4278. Warning( "CTarget%s::Compile Failed - %s\n", GetTypeString(), sAbsPath.String() );
  4279. return false;
  4280. }
  4281. if ( GetCustomModPath() )
  4282. {
  4283. char szCustomPath[MAX_PATH];
  4284. V_MakeAbsolutePath( szCustomPath, sizeof( szCustomPath ), CFmtStr( "%s/%s", GetCustomModPath(), sRelPath.String() ), sWorkingDir.String() );
  4285. V_FixSlashes( szCustomPath );
  4286. DoFileCopy( sAbsPath.String(), szCustomPath );
  4287. Asset()->AddModOutput( szCustomPath );
  4288. }
  4289. return true;
  4290. }
  4291. //-----------------------------------------------------------------------------
  4292. //
  4293. //-----------------------------------------------------------------------------
  4294. const ExtensionList *CTargetMDL::GetExtensionsAndCount( void ) const
  4295. {
  4296. // Only output .mdl for animation
  4297. CSmartPtr< CTargetQC > pTargetQC = GetTargetQC();
  4298. if ( pTargetQC.IsValid() && pTargetQC->GetQCITemplate() )
  4299. {
  4300. return CItemUpload::Manifest()->GetAnimationMDLExtentions();
  4301. }
  4302. return CItemUpload::Manifest()->GetMDLExtensions();
  4303. /*
  4304. static const char *s_szExtensionsDX8[] = {
  4305. ".mdl",
  4306. ".dx80.vtx",
  4307. ".dx90.vtx",
  4308. ".sw.vtx",
  4309. ".phy",
  4310. ".vvd"
  4311. };
  4312. static const char *s_szExtensions[] = {
  4313. ".mdl",
  4314. ".dx90.vtx",
  4315. ".phy",
  4316. ".vvd"
  4317. };
  4318. static const char **s_ppszExtensions = s_szExtensionsDX8;
  4319. static bool s_bGameInfoParsed = false;
  4320. if ( !s_bGameInfoParsed )
  4321. {
  4322. KeyValues *pKeyValues = new KeyValues( "gameinfo.txt" );
  4323. if ( pKeyValues != NULL )
  4324. {
  4325. if ( g_pFullFileSystem && pKeyValues->LoadFromFile( g_pFullFileSystem, "gameinfo.txt" ) )
  4326. {
  4327. if ( pKeyValues->GetInt( "SupportsDX8" ) != 0 )
  4328. {
  4329. s_ppszExtensions = s_szExtensionsDX8;
  4330. }
  4331. else
  4332. {
  4333. s_ppszExtensions = s_szExtensions;
  4334. }
  4335. s_bGameInfoParsed = true;
  4336. }
  4337. pKeyValues->deleteThis();
  4338. }
  4339. }
  4340. if ( s_ppszExtensions == s_szExtensions )
  4341. {
  4342. nExtensionCount = ARRAYSIZE( s_szExtensions );
  4343. }
  4344. else
  4345. {
  4346. nExtensionCount = ARRAYSIZE( s_szExtensionsDX8 );
  4347. }
  4348. return s_ppszExtensions;
  4349. */
  4350. }
  4351. //-----------------------------------------------------------------------------
  4352. //
  4353. //-----------------------------------------------------------------------------
  4354. bool CTargetMDL::GetInputs( CUtlVector< CTargetBase * > &inputs ) const
  4355. {
  4356. CUtlString sTmp;
  4357. if ( !IsOk( sTmp ) )
  4358. {
  4359. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  4360. return false;
  4361. }
  4362. inputs.RemoveAll();
  4363. inputs.AddToTail( m_pTargetQC.GetObject() );
  4364. return true;
  4365. }
  4366. //=============================================================================
  4367. //
  4368. //=============================================================================
  4369. CAsset::CAsset()
  4370. : CTargetBase( NULL, NULL )
  4371. , m_bSkinToBipHead( false )
  4372. , m_nCurrentModel( -1 )
  4373. , m_vmtMap( UtlStringLessThan )
  4374. , m_bShouldBuildScenesImage( false )
  4375. {
  4376. m_pAsset = this;
  4377. CItemUpload::GetSteamId( m_sSteamId );
  4378. AddModel();
  4379. m_vecTargetIcons.SetCount( CItemUpload::Manifest()->GetNumIconTypes() );
  4380. m_sExcludeFileExtensions.AddToTail( "zip" );
  4381. }
  4382. //-----------------------------------------------------------------------------
  4383. //
  4384. //-----------------------------------------------------------------------------
  4385. CAsset::CAsset( const char *pszName, bool *pbOk /* = NULL */ )
  4386. : CTargetBase( NULL, NULL )
  4387. , m_nCurrentModel( -1 )
  4388. , m_bShouldBuildScenesImage( false )
  4389. {
  4390. m_pAsset = this;
  4391. CItemUpload::GetSteamId( m_sSteamId );
  4392. m_sName = pszName;
  4393. AddModel();
  4394. m_vecTargetIcons.SetCount( CItemUpload::Manifest()->GetNumIconTypes() );
  4395. if ( pbOk )
  4396. {
  4397. CUtlString sTmp;
  4398. *pbOk = IsOk( sTmp );
  4399. if ( !( *pbOk ) )
  4400. {
  4401. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  4402. }
  4403. }
  4404. m_sExcludeFileExtensions.AddToTail( "zip" );
  4405. }
  4406. //-----------------------------------------------------------------------------
  4407. //
  4408. //-----------------------------------------------------------------------------
  4409. CAsset::~CAsset()
  4410. {
  4411. }
  4412. //-----------------------------------------------------------------------------
  4413. //
  4414. //-----------------------------------------------------------------------------
  4415. bool CAsset::IsOk( CUtlString &sMsg ) const
  4416. {
  4417. if ( !IsNameValid() )
  4418. {
  4419. sMsg = "Invalid asset name";
  4420. return false;
  4421. }
  4422. if ( !IsSteamIdValid() )
  4423. {
  4424. sMsg = "Invalid steam id";
  4425. return false;
  4426. }
  4427. if ( !GetTargetMDL().IsValid() )
  4428. {
  4429. sMsg = "No target MDL";
  4430. return false;
  4431. }
  4432. CUtlString sTmp;
  4433. if ( !CItemUpload::GetContentDir( sTmp ) || sTmp.IsEmpty() )
  4434. {
  4435. sMsg = "Cannot figure out content directory, have you installed the Source SDK and restarted Steam?";
  4436. return false;
  4437. }
  4438. return true;
  4439. }
  4440. bool CAsset::BuildScenesImage()
  4441. {
  4442. CUtlString sBinDir;
  4443. if ( !CItemUpload::GetBinDirectory( sBinDir ) )
  4444. {
  4445. Warning( "CTarget%s::Compile( %s ) - GetBinDirectory Failed\n", GetTypeString(), GetAssetName() );
  4446. return false;
  4447. }
  4448. CUtlString sAbsPath;
  4449. GetOutputPath( sAbsPath );
  4450. CUtlString sRelPath;
  4451. GetOutputPath( sRelPath, 0, PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE );
  4452. CUtlString sWorkingDir;
  4453. if ( CItemUpload::IgnoreEnvironmentVariables() )
  4454. {
  4455. sWorkingDir = sAbsPath;
  4456. sWorkingDir.SetLength( sWorkingDir.Length() - sRelPath.Length() );
  4457. V_StripTrailingSlash( sWorkingDir.GetForModify() );
  4458. }
  4459. else
  4460. {
  4461. CItemUpload::GetVProjectDir( sWorkingDir );
  4462. }
  4463. char szScenesImage[MAX_PATH];
  4464. V_MakeAbsolutePath( szScenesImage, sizeof( szScenesImage ), "scenes\\scenes.image", sWorkingDir.String() );
  4465. AddOrEditP4File( szScenesImage );
  4466. CFmtStrN< k64KB > sCmd;
  4467. sCmd.sprintf( "%s\\makescenesimage.exe", sBinDir.String() );
  4468. if ( !CItemUpload::RunCommandLine( sCmd.Access(), sWorkingDir.String(), this ) )
  4469. {
  4470. Warning( "Failed to build %s\n", szScenesImage );
  4471. return false;
  4472. }
  4473. Msg( "Build scenes.image OK!\n" );
  4474. if ( GetCustomModPath() )
  4475. {
  4476. char szCustomPath[MAX_PATH];
  4477. V_MakeAbsolutePath( szCustomPath, sizeof( szCustomPath ), CFmtStr( "%s/%s", GetCustomModPath(), "scenes/scenes.image" ), sWorkingDir.String() );
  4478. V_FixSlashes( szCustomPath );
  4479. DoFileCopy( szScenesImage, szCustomPath );
  4480. Asset()->AddModOutput( szCustomPath );
  4481. }
  4482. return true;
  4483. }
  4484. //-----------------------------------------------------------------------------
  4485. //
  4486. //-----------------------------------------------------------------------------
  4487. bool CAsset::CompilePreview()
  4488. {
  4489. bool bOldP4State = CItemUpload::GetP4();
  4490. CItemUpload::SetP4( false );
  4491. m_CompileOutputFiles.RemoveAll();
  4492. g_bCompilePreview = true;
  4493. // Record the files that are created so they can be removed after preview
  4494. m_sAbsPaths.RemoveAll();
  4495. m_sRelPaths.RemoveAll();
  4496. m_sModOutputs.RemoveAll();
  4497. CUtlVector< CTargetBase * > inputs;
  4498. if ( GetInputs( inputs ) )
  4499. {
  4500. for ( int i = 0; i < inputs.Count(); ++i )
  4501. {
  4502. CTargetBase *pTargetBase = inputs.Element( i );
  4503. if ( !pTargetBase )
  4504. continue;
  4505. pTargetBase->GetOutputPaths( m_sAbsPaths, PATH_FLAG_ALL, true );
  4506. pTargetBase->GetOutputPaths( m_sRelPaths, (PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE) | PATH_FLAG_ZIP, true );
  4507. }
  4508. }
  4509. bool bResult = CTargetBase::Compile();
  4510. g_bCompilePreview = false;
  4511. CItemUpload::SetP4( bOldP4State );
  4512. if ( bResult )
  4513. {
  4514. PostCompilePreview();
  4515. }
  4516. return bResult;
  4517. }
  4518. //-----------------------------------------------------------------------------
  4519. //
  4520. //-----------------------------------------------------------------------------
  4521. bool CAsset::PostCompilePreview()
  4522. {
  4523. Msg( "CAsset::PostCompilePreview Start:\n");
  4524. bool bResult = true;
  4525. if ( m_bShouldBuildScenesImage )
  4526. {
  4527. bResult = BuildScenesImage();
  4528. }
  4529. if ( bResult )
  4530. {
  4531. Msg( "CAsset::PostCompilePreview OK!\n" );
  4532. }
  4533. else
  4534. {
  4535. Msg( "CAsset::PostCompilePreview FAILED!\n" );
  4536. }
  4537. return bResult;
  4538. }
  4539. //-----------------------------------------------------------------------------
  4540. //
  4541. //-----------------------------------------------------------------------------
  4542. bool CAsset::Compile()
  4543. {
  4544. m_CompileOutputFiles.RemoveAll();
  4545. if ( m_sArchivePath.IsEmpty() )
  4546. {
  4547. GetOutputPath( m_sArchivePath, 0 );
  4548. }
  4549. CUtlString sRelPath;
  4550. GetOutputPath( sRelPath, 0, PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE );
  4551. if ( m_sArchivePath.IsEmpty() || sRelPath.IsEmpty() )
  4552. {
  4553. Warning( "CTarget%s::Compile - GetOutputPath failed\n", GetTypeString() );
  4554. return false;
  4555. }
  4556. // this gets filled by Compile()
  4557. m_sModOutputs.RemoveAll();
  4558. if ( !CTargetBase::Compile() )
  4559. return false;
  4560. m_sAbsPaths.RemoveAll();
  4561. GetOutputPaths( m_sAbsPaths, PATH_FLAG_ALL, true );
  4562. m_sRelPaths.RemoveAll();
  4563. GetOutputPaths( m_sRelPaths, (PATH_FLAG_ALL & ~PATH_FLAG_ABSOLUTE) | PATH_FLAG_ZIP, true );
  4564. Assert( m_sAbsPaths.Count() == m_sRelPaths.Count() );
  4565. if ( m_sAbsPaths.Count() <= 0 || m_sAbsPaths.Count() != m_sRelPaths.Count() )
  4566. {
  4567. Warning( "CTarget%s::Compile - GetOutputPaths failed\n", GetTypeString() );
  4568. return false;
  4569. }
  4570. Msg( "Compiling %s: %s\n", GetTypeString(), sRelPath.String() );
  4571. AddOrEditP4File( m_sArchivePath.String() );
  4572. if ( CItemUpload::FileExists( m_sArchivePath.String() ) )
  4573. {
  4574. _unlink( m_sArchivePath.String() );
  4575. }
  4576. HANDLE m_hOutputZipFile = CreateFile( m_sArchivePath.String(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  4577. if ( m_hOutputZipFile == INVALID_HANDLE_VALUE )
  4578. {
  4579. Warning( "CTarget%s::Compile CreateZip Failed - Unable to create ZIP file %s.\n", GetTypeString(), m_sArchivePath.String() );
  4580. return false;
  4581. }
  4582. IZip *pZip = IZip::CreateZip();
  4583. if ( pZip == NULL )
  4584. {
  4585. Warning( "CTarget%s::Compile CreateZip Failed - %s\n", GetTypeString(), sRelPath.String() );
  4586. CloseHandle( m_hOutputZipFile );
  4587. return false;
  4588. }
  4589. CUtlBuffer kvBuf( 0, 0, CUtlBuffer::TEXT_BUFFER );
  4590. CreateManifest( kvBuf );
  4591. pZip->AddBufferToZip( "manifest.txt", kvBuf.Base(), kvBuf.TellPut(), true );
  4592. for ( int i = 0; i < m_sAbsPaths.Count(); ++i )
  4593. {
  4594. const char *pszFileExtension = V_GetFileExtension( m_sAbsPaths.Element( i ).String() );
  4595. bool bExcluded = false;
  4596. FOR_EACH_VEC( m_sExcludeFileExtensions, e )
  4597. {
  4598. if ( m_sExcludeFileExtensions[e] == pszFileExtension )
  4599. {
  4600. bExcluded = true;
  4601. break;
  4602. }
  4603. }
  4604. if ( bExcluded )
  4605. continue;
  4606. if ( CItemUpload::Manifest()->UseTerseMessages() )
  4607. {
  4608. Msg( " - added %s\n", m_sRelPaths.Element( i ).String() );
  4609. }
  4610. else
  4611. {
  4612. Msg( " + Zip Add: %s\n", m_sRelPaths.Element( i ).String() );
  4613. }
  4614. pZip->AddFileToZip( m_sRelPaths.Element( i ).String(), m_sAbsPaths.Element( i ).String() );
  4615. }
  4616. pZip->SaveToDisk( m_hOutputZipFile );
  4617. IZip::ReleaseZip( pZip );
  4618. CloseHandle( m_hOutputZipFile );
  4619. if ( !CheckFile( m_sArchivePath.String() ) )
  4620. {
  4621. if ( CItemUpload::Manifest()->UseTerseMessages() )
  4622. {
  4623. Warning( "Failed to write .zip file: \"%s\"\n", m_sArchivePath.String() );
  4624. }
  4625. else
  4626. {
  4627. Warning( "CTarget%s::Compile - File Check Failed - \"%s\"\n", GetTypeString(), m_sArchivePath.String() );
  4628. }
  4629. return false;
  4630. }
  4631. if ( CItemUpload::Manifest()->UseTerseMessages() )
  4632. {
  4633. Msg( " - Compilation successful.\n" );
  4634. }
  4635. else
  4636. {
  4637. Msg( "CTarget%s::Compile OK! - %s\n", GetTypeString(), sRelPath.String() );
  4638. }
  4639. return PostCompile();
  4640. }
  4641. //-----------------------------------------------------------------------------
  4642. //
  4643. //-----------------------------------------------------------------------------
  4644. bool CAsset::PostCompile()
  4645. {
  4646. Msg( "CAsset::PostCompile Start:\n");
  4647. bool bResult = true;
  4648. if ( m_bShouldBuildScenesImage )
  4649. {
  4650. bResult = BuildScenesImage();
  4651. }
  4652. if ( bResult )
  4653. {
  4654. Msg( "CAsset::PostCompile OK!\n" );
  4655. }
  4656. else
  4657. {
  4658. Msg( "CAsset::PostCompile FAILED!\n" );
  4659. }
  4660. return bResult;
  4661. }
  4662. //-----------------------------------------------------------------------------
  4663. //
  4664. //-----------------------------------------------------------------------------
  4665. bool CAsset::GetInputs( CUtlVector< CTargetBase * > &inputs ) const
  4666. {
  4667. CUtlString sTmp;
  4668. if ( !IsOk( sTmp ) )
  4669. {
  4670. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  4671. return false;
  4672. }
  4673. for ( int nIcon = 0; nIcon < m_vecTargetIcons.Count(); ++nIcon )
  4674. {
  4675. if ( m_vecTargetIcons[ nIcon ].IsValid() )
  4676. {
  4677. inputs.AddToTail( m_vecTargetIcons[ nIcon ].GetObject() );
  4678. }
  4679. }
  4680. for ( int i = 0; i < GetTargetVMTCount(); ++i )
  4681. {
  4682. inputs.AddToTail( GetTargetVMT( i ) );
  4683. }
  4684. FOR_EACH_VEC( m_vecModels, nModelIndex )
  4685. {
  4686. if ( m_vecModels[ nModelIndex ].IsValid() )
  4687. {
  4688. inputs.AddToTail( m_vecModels[ nModelIndex ].GetObject() );
  4689. }
  4690. }
  4691. return inputs.Count() > 0;
  4692. }
  4693. //-----------------------------------------------------------------------------
  4694. //
  4695. //-----------------------------------------------------------------------------
  4696. const ExtensionList *CAsset::GetExtensionsAndCount( void ) const
  4697. {
  4698. static ExtensionList vecExtensions;
  4699. if ( !vecExtensions.Count() )
  4700. {
  4701. vecExtensions.AddToTail( ".zip" );
  4702. }
  4703. return &vecExtensions;
  4704. }
  4705. //-----------------------------------------------------------------------------
  4706. // Returns items/<steamid>/<name>, false if there's something wrong
  4707. //-----------------------------------------------------------------------------
  4708. bool CAsset::GetRelativeDir( CUtlString &sRelativeDir, const char *pszPrefix, const CTargetBase *pTarget ) const
  4709. {
  4710. CUtlString sTmp;
  4711. if ( !IsOk( sTmp ) )
  4712. {
  4713. Warning( FUNCTION_LINE_STRING "Error! CTarget%s - Not Valid: %s\n", GetTypeString(), sTmp.String() );
  4714. return false;
  4715. }
  4716. if ( pszPrefix )
  4717. {
  4718. sRelativeDir = pszPrefix;
  4719. sRelativeDir += "/";
  4720. }
  4721. else
  4722. {
  4723. sRelativeDir = "";
  4724. }
  4725. if ( pTarget->IsModelPath() )
  4726. sRelativeDir += "models/";
  4727. if ( pTarget->GetCustomRelativeDir() )
  4728. {
  4729. sRelativeDir += pTarget->GetCustomRelativeDir();
  4730. }
  4731. else
  4732. {
  4733. sRelativeDir += pTarget->GetItemDirectory();
  4734. const char *pszClass = GetClass();
  4735. if ( pszClass )
  4736. {
  4737. sRelativeDir += pszClass;
  4738. sRelativeDir += "/";
  4739. }
  4740. if ( CItemUpload::Manifest()->GetItemPathUsesSteamId() )
  4741. {
  4742. if ( !m_sSteamId.IsEmpty() )
  4743. {
  4744. sRelativeDir += m_sSteamId;
  4745. sRelativeDir += "/";
  4746. }
  4747. }
  4748. sRelativeDir += m_sName;
  4749. }
  4750. sRelativeDir.FixSlashes();
  4751. return true;
  4752. }
  4753. //-----------------------------------------------------------------------------
  4754. // Returns GetAbsoluteContentDir()/GetRelativeDir() or GetAbsoluteGameDir()/GetRelativeDir()
  4755. //-----------------------------------------------------------------------------
  4756. bool CAsset::GetAbsoluteDir( CUtlString &sAbsoluteDir, const char *pszPrefix /* = NULL */, const CTargetBase *pTarget ) const
  4757. {
  4758. CUtlString sDirA;
  4759. if ( pTarget->IsContent() )
  4760. {
  4761. if ( !CItemUpload::GetContentDir( sDirA ) )
  4762. return false;
  4763. }
  4764. else
  4765. {
  4766. if ( !CItemUpload::GetVProjectDir( sDirA ) )
  4767. return false;
  4768. }
  4769. CUtlString sDirB;
  4770. if ( !GetRelativeDir( sDirB, pszPrefix, pTarget ) )
  4771. return false;
  4772. sAbsoluteDir = sDirA;
  4773. sAbsoluteDir += "/";
  4774. sAbsoluteDir += sDirB;
  4775. sAbsoluteDir.FixSlashes();
  4776. return true;
  4777. }
  4778. //-----------------------------------------------------------------------------
  4779. //
  4780. //-----------------------------------------------------------------------------
  4781. bool CAsset::SetName( const char *pszName )
  4782. {
  4783. if ( !CItemUpload::SanitizeName( pszName, m_sName ) )
  4784. return false;
  4785. return IsNameValid();
  4786. }
  4787. //-----------------------------------------------------------------------------
  4788. //
  4789. //-----------------------------------------------------------------------------
  4790. bool CAsset::IsNameValid() const
  4791. {
  4792. return m_sName.Length() > 0;
  4793. }
  4794. //-----------------------------------------------------------------------------
  4795. //
  4796. //-----------------------------------------------------------------------------
  4797. const char *CAsset::GetSteamId() const
  4798. {
  4799. return m_sSteamId.String();
  4800. }
  4801. //-----------------------------------------------------------------------------
  4802. //
  4803. //-----------------------------------------------------------------------------
  4804. bool CAsset::IsSteamIdValid() const
  4805. {
  4806. return CItemUpload::GetDevMode() || m_sSteamId.Length() > 0;
  4807. }
  4808. //-----------------------------------------------------------------------------
  4809. //
  4810. //-----------------------------------------------------------------------------
  4811. bool CAsset::SetTargetIcon( int nIcon, const char *pszIconFile )
  4812. {
  4813. if ( !m_vecTargetIcons[ nIcon ].IsValid() )
  4814. {
  4815. m_vecTargetIcons[ nIcon ] = new CTargetIcon( this, nIcon );
  4816. }
  4817. return m_vecTargetIcons[ nIcon ]->SetTargetVTF( pszIconFile );
  4818. }
  4819. //-----------------------------------------------------------------------------
  4820. // Add a new model to the output and make it current
  4821. //-----------------------------------------------------------------------------
  4822. int CAsset::AddModel()
  4823. {
  4824. CSmartPtr< CTargetMDL > pModel = NewTarget< CTargetMDL >( this );
  4825. m_nCurrentModel = m_vecModels.AddToTail( pModel );
  4826. return m_nCurrentModel;
  4827. }
  4828. //-----------------------------------------------------------------------------
  4829. //
  4830. //-----------------------------------------------------------------------------
  4831. bool CAsset::SetCurrentModel( int nModel )
  4832. {
  4833. if ( nModel >= 0 && nModel < GetNumModels() )
  4834. {
  4835. m_nCurrentModel = nModel;
  4836. return true;
  4837. }
  4838. return false;
  4839. }
  4840. //-----------------------------------------------------------------------------
  4841. //
  4842. //-----------------------------------------------------------------------------
  4843. void CAsset::RemoveModels()
  4844. {
  4845. m_vecModels.RemoveAll();
  4846. m_nCurrentModel = -1;
  4847. }
  4848. //-----------------------------------------------------------------------------
  4849. //
  4850. //-----------------------------------------------------------------------------
  4851. int CAsset::TargetDMXCount() const
  4852. {
  4853. CSmartPtr< CTargetQC > pTargetQC = GetTargetQC();
  4854. if ( !pTargetQC )
  4855. return false;
  4856. return pTargetQC->TargetDMXCount();
  4857. }
  4858. //-----------------------------------------------------------------------------
  4859. //
  4860. //-----------------------------------------------------------------------------
  4861. int CAsset::AddTargetDMX( const char *pszGeometryFile )
  4862. {
  4863. CSmartPtr< CTargetQC > pTargetQC = GetTargetQC();
  4864. if ( !pTargetQC )
  4865. return -1;
  4866. return pTargetQC->AddTargetDMX( pszGeometryFile );
  4867. }
  4868. //-----------------------------------------------------------------------------
  4869. //
  4870. //-----------------------------------------------------------------------------
  4871. bool CAsset::SetTargetDMX( int nLOD, const char *pszGeometryFile )
  4872. {
  4873. CSmartPtr< CTargetQC > pTargetQC = GetTargetQC();
  4874. if ( !pTargetQC )
  4875. return false;
  4876. return pTargetQC->SetTargetDMX( nLOD, pszGeometryFile );
  4877. }
  4878. //-----------------------------------------------------------------------------
  4879. //
  4880. //-----------------------------------------------------------------------------
  4881. bool CAsset::RemoveTargetDMX( int nLOD )
  4882. {
  4883. CSmartPtr< CTargetQC > pTargetQC = GetTargetQC();
  4884. if ( !pTargetQC )
  4885. return false;
  4886. return pTargetQC->RemoveTargetDMX( nLOD );
  4887. }
  4888. //-----------------------------------------------------------------------------
  4889. //
  4890. //----------------------------------------------------------------------------
  4891. CSmartPtr< CTargetDMX > CAsset::GetTargetDMX( int nLOD )
  4892. {
  4893. CSmartPtr< CTargetQC > pTargetQC = GetTargetQC();
  4894. if ( !pTargetQC )
  4895. return false;
  4896. return pTargetQC->GetTargetDMX( nLOD );
  4897. }
  4898. //-----------------------------------------------------------------------------
  4899. //
  4900. //-----------------------------------------------------------------------------
  4901. CSmartPtr< CTargetMDL > CAsset::GetTargetMDL() const
  4902. {
  4903. if ( m_nCurrentModel >= 0 )
  4904. {
  4905. return m_vecModels[ m_nCurrentModel ];
  4906. }
  4907. return CSmartPtr< CTargetMDL >();
  4908. }
  4909. //-----------------------------------------------------------------------------
  4910. //
  4911. //-----------------------------------------------------------------------------
  4912. CSmartPtr< CTargetQC > CAsset::GetTargetQC() const
  4913. {
  4914. CSmartPtr< CTargetMDL > pTargetMDL = GetTargetMDL();
  4915. if ( !pTargetMDL )
  4916. return NULL;
  4917. return pTargetMDL->GetTargetQC();
  4918. }
  4919. //-----------------------------------------------------------------------------
  4920. //
  4921. //-----------------------------------------------------------------------------
  4922. int CAsset::GetTargetVMTCount() const
  4923. {
  4924. return m_vmtMap.Count();
  4925. }
  4926. //-----------------------------------------------------------------------------
  4927. //
  4928. //-----------------------------------------------------------------------------
  4929. CTargetVMT *CAsset::GetTargetVMT( int nIndex ) const
  4930. {
  4931. if ( nIndex < 0 || nIndex >= GetTargetVMTCount() )
  4932. return NULL;
  4933. int nMapIndex = 0;
  4934. FOR_EACH_MAP( m_vmtMap, nMapIt )
  4935. {
  4936. if ( nIndex == nMapIndex )
  4937. return m_vmtMap.Element( nMapIt );
  4938. ++nMapIndex;
  4939. }
  4940. return NULL;
  4941. }
  4942. //-----------------------------------------------------------------------------
  4943. //
  4944. //-----------------------------------------------------------------------------
  4945. CSmartPtr< CTargetVMT > CAsset::FindOrAddMaterial( const char *pszMaterial, int nMaterialType )
  4946. {
  4947. const CUtlString sMaterial( pszMaterial );
  4948. CUtlMap< CUtlString, CTargetVMT * >::IndexType_t nIndex = m_vmtMap.Find( sMaterial );
  4949. if ( !m_vmtMap.IsValidIndex( nIndex ) )
  4950. {
  4951. CSmartPtr< CTargetVMT > pTargetVMT = NewTarget< CTargetVMT >( this );
  4952. if ( !pTargetVMT )
  4953. return NULL;
  4954. pTargetVMT->SetMaterialId( pszMaterial );
  4955. m_vmtMap.Insert( sMaterial, pTargetVMT.GetObject() );
  4956. // See if this is a duplicate of an existing material
  4957. for ( int i = 0; i < GetTargetVMTCount(); ++i )
  4958. {
  4959. CTargetVMT *pTmpTargetVMT = GetTargetVMT( i );
  4960. if ( !pTmpTargetVMT )
  4961. continue;
  4962. if ( pTmpTargetVMT->GetMaterialType() == nMaterialType )
  4963. {
  4964. pTargetVMT->SetDuplicate( nMaterialType );
  4965. break;
  4966. }
  4967. }
  4968. if ( !pTargetVMT->GetDuplicate() )
  4969. {
  4970. pTargetVMT->SetMaterialType( nMaterialType );
  4971. }
  4972. return pTargetVMT;
  4973. }
  4974. else
  4975. {
  4976. return m_vmtMap.Element( nIndex );
  4977. }
  4978. return NULL;
  4979. }
  4980. //-----------------------------------------------------------------------------
  4981. //
  4982. //-----------------------------------------------------------------------------
  4983. CSmartPtr< CTargetVMT > CAsset::FindMaterial( const char *pszMaterial )
  4984. {
  4985. const CUtlString sMaterial( pszMaterial );
  4986. CUtlMap< CUtlString, CTargetVMT * >::IndexType_t nIndex = m_vmtMap.Find( sMaterial );
  4987. if ( m_vmtMap.IsValidIndex( nIndex ) )
  4988. return m_vmtMap.Element( nIndex );
  4989. return NULL;
  4990. }
  4991. //-----------------------------------------------------------------------------
  4992. //
  4993. //-----------------------------------------------------------------------------
  4994. bool CAsset::Mkdir( const char *pszPrefix, const CTargetBase *pTarget )
  4995. {
  4996. CUtlString sAbsolute;
  4997. if ( !GetAbsoluteDir( sAbsolute, pszPrefix, pTarget ) )
  4998. return false;
  4999. char szBuf[ k64KB ];
  5000. if ( _fullpath( szBuf, sAbsolute.String(), ARRAYSIZE( szBuf ) ) == NULL )
  5001. return false;
  5002. return CItemUpload::CreateDirectory( szBuf );
  5003. }
  5004. //-----------------------------------------------------------------------------
  5005. //
  5006. //-----------------------------------------------------------------------------
  5007. void CAsset::CreateManifest( CUtlBuffer &manifestBuf )
  5008. {
  5009. KeyValues *pAssetKV = new KeyValues( "asset" );
  5010. UpdateManifest( pAssetKV );
  5011. manifestBuf.Clear();
  5012. manifestBuf.SetBufferType( true, true );
  5013. pAssetKV->RecursiveSaveToFile( manifestBuf, 0 );
  5014. pAssetKV->deleteThis();
  5015. }
  5016. const char* CAsset::CheckRedundantOutputFilePath( const char* pszInputFilePath, const char* pszVTEXConfig, const char* pszOutputFilePath )
  5017. {
  5018. const char* pszLocalVTEXConfig = pszVTEXConfig ? pszVTEXConfig : "";
  5019. // we don't want to output multiple of the same texture file with the same vtex config
  5020. for ( int i=0; i<m_CompileOutputFiles.Count(); ++i )
  5021. {
  5022. const CompileOutputFile_t& tga = m_CompileOutputFiles[i];
  5023. if ( !V_stricmp( tga.m_strInputFilePath.String(), pszInputFilePath ) )
  5024. {
  5025. if ( !V_stricmp( tga.m_strVTEXConfig.String(), pszLocalVTEXConfig ) )
  5026. {
  5027. return tga.m_strOutputFilePath.String();
  5028. }
  5029. }
  5030. }
  5031. int index = m_CompileOutputFiles.AddToTail();
  5032. CompileOutputFile_t& newTGA = m_CompileOutputFiles[index];
  5033. newTGA.m_strInputFilePath = pszInputFilePath;
  5034. newTGA.m_strVTEXConfig = pszLocalVTEXConfig;
  5035. newTGA.m_strOutputFilePath = pszOutputFilePath;
  5036. return newTGA.m_strOutputFilePath.String();
  5037. }
  5038. //-----------------------------------------------------------------------------
  5039. //
  5040. //-----------------------------------------------------------------------------
  5041. bool CAsset::RemoveMaterial( const char *pszMaterial )
  5042. {
  5043. const CUtlString sMaterial( pszMaterial );
  5044. return m_vmtMap.Remove( sMaterial );
  5045. }
  5046. //-----------------------------------------------------------------------------
  5047. //
  5048. //-----------------------------------------------------------------------------
  5049. const CUtlString &CAsset::GetAssetName() const
  5050. {
  5051. return m_sName;
  5052. }