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.

598 lines
20 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "movieobjects/dmeparticlesystemdefinition.h"
  7. #include "datamodel/dmelementfactoryhelper.h"
  8. #include "movieobjects/dmeeditortypedictionary.h"
  9. #include "toolutils/enginetools_int.h"
  10. #include "tier1/KeyValues.h"
  11. #include "tier1/utlbuffer.h"
  12. #include "tier1/convar.h"
  13. #include "particles/particles.h"
  14. #include "dme_controls/attributeintchoicepanel.h"
  15. #include "dme_controls/attributeboolchoicepanel.h"
  16. #include "dme_controls/attributestringchoicepanel.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. //-----------------------------------------------------------------------------
  20. // Human readable string for the particle functions
  21. //-----------------------------------------------------------------------------
  22. static const char *s_pParticleFuncTypeName[PARTICLE_FUNCTION_COUNT] =
  23. {
  24. "Renderer", // FUNCTION_RENDERER = 0,
  25. "Operator", // FUNCTION_OPERATOR,
  26. "Initializer", // FUNCTION_INITIALIZER,
  27. "Emitter", // FUNCTION_EMITTER,
  28. "Children", // FUNCTION_CHILDREN,
  29. "ForceGenerator", // FUNCTION_FORCEGENERATOR
  30. "Constraint", // FUNCTION_CONSTRAINT
  31. };
  32. const char *GetParticleFunctionTypeName( ParticleFunctionType_t type )
  33. {
  34. return s_pParticleFuncTypeName[type];
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Expose this class to the scene database
  38. //-----------------------------------------------------------------------------
  39. IMPLEMENT_ELEMENT_FACTORY_INSTALL_EXPLICITLY( DmeParticleFunction, CDmeParticleFunction );
  40. //-----------------------------------------------------------------------------
  41. // Purpose:
  42. //-----------------------------------------------------------------------------
  43. void CDmeParticleFunction::OnConstruction()
  44. {
  45. m_bSkipNextResolve = false;
  46. }
  47. void CDmeParticleFunction::OnDestruction()
  48. {
  49. DestroyElement( m_hTypeDictionary, TD_DEEP );
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Construct an appropriate editor attribute info
  53. //-----------------------------------------------------------------------------
  54. static void CreateEditorAttributeInfo( CDmeEditorType *pEditorType, const char *pAttributeName, const char *pWidgetInfo )
  55. {
  56. if ( !pWidgetInfo )
  57. return;
  58. CCommand parse;
  59. parse.Tokenize( pWidgetInfo );
  60. if ( parse.ArgC() == 1 )
  61. {
  62. CDmeEditorAttributeInfo *pInfo = CreateElement< CDmeEditorAttributeInfo >( "field info" );
  63. pEditorType->AddAttributeInfo( pAttributeName, pInfo );
  64. pInfo->m_Widget = parse[0];
  65. return;
  66. }
  67. if ( parse.ArgC() == 2 )
  68. {
  69. CDmeEditorChoicesInfo *pInfo = NULL;
  70. if ( !Q_stricmp( parse[0], "intchoice" ) )
  71. {
  72. pInfo = CreateElement< CDmeEditorIntChoicesInfo >( "field info" );
  73. }
  74. if ( !Q_stricmp( parse[0], "boolchoice" ) )
  75. {
  76. pInfo = CreateElement< CDmeEditorBoolChoicesInfo >( "field info" );
  77. }
  78. if ( !Q_stricmp( parse[0], "stringchoice" ) )
  79. {
  80. pInfo = CreateElement< CDmeEditorStringChoicesInfo >( "field info" );
  81. }
  82. if ( !Q_stricmp( parse[0], "elementchoice" ) )
  83. {
  84. pInfo = CreateElement< CDmeEditorChoicesInfo >( "field info" );
  85. }
  86. if ( pInfo )
  87. {
  88. pInfo->SetChoiceType( parse[1] );
  89. pEditorType->AddAttributeInfo( pAttributeName, pInfo );
  90. pInfo->m_Widget = parse[0];
  91. return;
  92. }
  93. }
  94. }
  95. //-----------------------------------------------------------------------------
  96. // Used for backward compat
  97. //-----------------------------------------------------------------------------
  98. void CDmeParticleFunction::AddMissingFields( const DmxElementUnpackStructure_t *pUnpack )
  99. {
  100. DestroyElement( m_hTypeDictionary, TD_DEEP );
  101. m_hTypeDictionary = CreateElement< CDmeEditorTypeDictionary >( "particleFunctionDict" );
  102. CDmeEditorType *pEditorType = CreateElement< CDmeEditorType >( GetTypeString() );
  103. for ( ; pUnpack->m_pAttributeName; ++pUnpack )
  104. {
  105. CreateEditorAttributeInfo( pEditorType, pUnpack->m_pAttributeName, (const char *)pUnpack->m_pUserData );
  106. // Can happen if 'name' or 'functionName' is used
  107. if ( HasAttribute( pUnpack->m_pAttributeName ) )
  108. continue;
  109. CDmAttribute *pAttribute = AddAttribute( pUnpack->m_pAttributeName, pUnpack->m_AttributeType );
  110. if ( pUnpack->m_pDefaultString )
  111. {
  112. int nLen = Q_strlen( pUnpack->m_pDefaultString );
  113. CUtlBuffer bufParse( pUnpack->m_pDefaultString, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
  114. pAttribute->Unserialize( bufParse );
  115. }
  116. }
  117. m_hTypeDictionary->AddEditorType( pEditorType );
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Sets the particle operator
  121. //-----------------------------------------------------------------------------
  122. void CDmeParticleFunction::UpdateAttributes( const DmxElementUnpackStructure_t *pUnpack )
  123. {
  124. // Delete all old attributes
  125. CDmAttribute *pNext;
  126. for( CDmAttribute *pAttr = FirstAttribute(); pAttr; pAttr = pNext )
  127. {
  128. pNext = pAttr->NextAttribute();
  129. if ( pAttr->IsFlagSet( FATTRIB_EXTERNAL | FATTRIB_STANDARD ) )
  130. continue;
  131. RemoveAttributeByPtr( pAttr );
  132. }
  133. AddMissingFields( pUnpack );
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Marks a particle system as a new instance
  137. // This is basically a workaround to prevent newly-copied particle functions
  138. // from recompiling themselves a zillion times
  139. //-----------------------------------------------------------------------------
  140. void CDmeParticleFunction::MarkNewInstance()
  141. {
  142. m_bSkipNextResolve = true;
  143. }
  144. //-----------------------------------------------------------------------------
  145. // Don't bother resolving during unserialization, the owning def will handle it
  146. //-----------------------------------------------------------------------------
  147. void CDmeParticleFunction::OnElementUnserialized()
  148. {
  149. BaseClass::OnElementUnserialized();
  150. MarkNewInstance();
  151. }
  152. //-----------------------------------------------------------------------------
  153. // Recompiles the particle system when a change occurs
  154. //-----------------------------------------------------------------------------
  155. void CDmeParticleFunction::Resolve()
  156. {
  157. BaseClass::Resolve();
  158. if ( m_bSkipNextResolve )
  159. {
  160. m_bSkipNextResolve = false;
  161. return;
  162. }
  163. for( CDmAttribute* pAttr = FirstAttribute(); pAttr; pAttr = pAttr->NextAttribute() )
  164. {
  165. if ( !pAttr->IsFlagSet( FATTRIB_DIRTY ) )
  166. continue;
  167. // Find all CDmeParticleSystemDefinitions referring to this function
  168. DmAttributeReferenceIterator_t i = g_pDataModel->FirstAttributeReferencingElement( GetHandle() );
  169. while ( i != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID )
  170. {
  171. CDmAttribute *pAttribute = g_pDataModel->GetAttribute( i );
  172. // NOTE: This could cause the same particle system definition to recompile
  173. // multiple times if it refers to the same function multiple times,
  174. // but we don't expect that to happen, so we won't bother checking for it
  175. CDmeParticleSystemDefinition *pDef = CastElement<CDmeParticleSystemDefinition>( pAttribute->GetOwner() );
  176. if ( pDef && pDef->GetFileId() == GetFileId() )
  177. {
  178. pDef->RecompileParticleSystem();
  179. }
  180. i = g_pDataModel->NextAttributeReferencingElement( i );
  181. }
  182. break;
  183. }
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Returns the editor type dictionary
  187. //-----------------------------------------------------------------------------
  188. CDmeEditorTypeDictionary* CDmeParticleFunction::GetEditorTypeDictionary()
  189. {
  190. return m_hTypeDictionary;
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Expose this class to the scene database
  194. //-----------------------------------------------------------------------------
  195. IMPLEMENT_ELEMENT_FACTORY_INSTALL_EXPLICITLY( DmeParticleOperator, CDmeParticleOperator );
  196. //-----------------------------------------------------------------------------
  197. // Constructor, destructor
  198. //-----------------------------------------------------------------------------
  199. void CDmeParticleOperator::OnConstruction()
  200. {
  201. m_FunctionName.Init( this, "functionName" );
  202. }
  203. void CDmeParticleOperator::OnDestruction()
  204. {
  205. }
  206. //-----------------------------------------------------------------------------
  207. // Sets the particle operator
  208. //-----------------------------------------------------------------------------
  209. void CDmeParticleOperator::SetFunction( IParticleOperatorDefinition *pDefinition )
  210. {
  211. m_FunctionName = pDefinition->GetName();
  212. const DmxElementUnpackStructure_t *pUnpack = pDefinition->GetUnpackStructure();
  213. UpdateAttributes( pUnpack );
  214. }
  215. const char *CDmeParticleOperator::GetFunctionType() const
  216. {
  217. return m_FunctionName;
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Expose this class to the scene database
  221. //-----------------------------------------------------------------------------
  222. IMPLEMENT_ELEMENT_FACTORY_INSTALL_EXPLICITLY( DmeParticleChild, CDmeParticleChild );
  223. //-----------------------------------------------------------------------------
  224. // Constructor, destructor
  225. //-----------------------------------------------------------------------------
  226. void CDmeParticleChild::OnConstruction()
  227. {
  228. m_Child.Init( this, "child", FATTRIB_NEVERCOPY );
  229. }
  230. void CDmeParticleChild::OnDestruction()
  231. {
  232. }
  233. //-----------------------------------------------------------------------------
  234. // Sets the particle system child
  235. //-----------------------------------------------------------------------------
  236. void CDmeParticleChild::SetChildParticleSystem( CDmeParticleSystemDefinition *pDef, IParticleOperatorDefinition *pDefinition )
  237. {
  238. // FIXME: Convert system name into a
  239. m_Child = pDef;
  240. const DmxElementUnpackStructure_t *pUnpack = pDefinition->GetUnpackStructure();
  241. UpdateAttributes( pUnpack );
  242. }
  243. const char *CDmeParticleChild::GetFunctionType() const
  244. {
  245. const CDmeParticleSystemDefinition *pChild = m_Child;
  246. return pChild ? pChild->GetName() : "";
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Expose this class to the scene database
  250. //-----------------------------------------------------------------------------
  251. IMPLEMENT_ELEMENT_FACTORY_INSTALL_EXPLICITLY( DmeParticleSystemDefinition, CDmeParticleSystemDefinition );
  252. //-----------------------------------------------------------------------------
  253. // Purpose:
  254. //-----------------------------------------------------------------------------
  255. void CDmeParticleSystemDefinition::OnConstruction()
  256. {
  257. m_ParticleFunction[FUNCTION_RENDERER].Init( this, "renderers" );
  258. m_ParticleFunction[FUNCTION_OPERATOR].Init( this, "operators" );
  259. m_ParticleFunction[FUNCTION_INITIALIZER].Init( this, "initializers" );
  260. m_ParticleFunction[FUNCTION_EMITTER].Init( this, "emitters" );
  261. m_ParticleFunction[FUNCTION_CHILDREN].Init( this, "children" );
  262. m_ParticleFunction[FUNCTION_FORCEGENERATOR].Init( this, "forces" );
  263. m_ParticleFunction[FUNCTION_CONSTRAINT].Init( this, "constraints" );
  264. m_bPreventNameBasedLookup.Init( this, "preventNameBasedLookup" );
  265. m_hTypeDictionary = CreateElement< CDmeEditorTypeDictionary >( "particleSystemDefinitionDict" );
  266. CDmeEditorType *pEditorType = CreateElement< CDmeEditorType >( "DmeParticleSystemDefinition" );
  267. const DmxElementUnpackStructure_t *pUnpack = g_pParticleSystemMgr->GetParticleSystemDefinitionUnpackStructure();
  268. for ( ; pUnpack->m_pAttributeName; ++pUnpack )
  269. {
  270. CreateEditorAttributeInfo( pEditorType, pUnpack->m_pAttributeName, (const char *)pUnpack->m_pUserData );
  271. CDmAttribute *pAttribute = AddAttribute( pUnpack->m_pAttributeName, pUnpack->m_AttributeType );
  272. if ( pUnpack->m_pDefaultString )
  273. {
  274. int nLen = Q_strlen( pUnpack->m_pDefaultString );
  275. CUtlBuffer bufParse( pUnpack->m_pDefaultString, nLen, CUtlBuffer::TEXT_BUFFER | CUtlBuffer::READ_ONLY );
  276. pAttribute->Unserialize( bufParse );
  277. }
  278. }
  279. m_hTypeDictionary->AddEditorType( pEditorType );
  280. }
  281. void CDmeParticleSystemDefinition::OnDestruction()
  282. {
  283. DestroyElement( m_hTypeDictionary, TD_DEEP );
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Returns the editor type dictionary
  287. //-----------------------------------------------------------------------------
  288. CDmeEditorTypeDictionary* CDmeParticleSystemDefinition::GetEditorTypeDictionary()
  289. {
  290. return m_hTypeDictionary;
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Remove obsolete attributes
  294. //-----------------------------------------------------------------------------
  295. static void RemoveObsoleteAttributes( CDmElement *pElement, const DmxElementUnpackStructure_t *pUnpack )
  296. {
  297. // Delete all obsolete attributes
  298. CDmAttribute *pNext;
  299. for( CDmAttribute *pAttr = pElement->FirstAttribute(); pAttr; pAttr = pNext )
  300. {
  301. pNext = pAttr->NextAttribute();
  302. if ( pAttr->IsFlagSet( FATTRIB_EXTERNAL | FATTRIB_STANDARD ) )
  303. continue;
  304. bool bFound = false;
  305. for ( const DmxElementUnpackStructure_t *pTrav = pUnpack; pTrav->m_pAttributeName; ++pTrav )
  306. {
  307. if ( !Q_stricmp( pTrav->m_pAttributeName, pAttr->GetName() ) )
  308. {
  309. bFound = true;
  310. break;
  311. }
  312. }
  313. if ( !bFound )
  314. {
  315. pElement->RemoveAttributeByPtr( pAttr );
  316. }
  317. }
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Used for automatic handling of backward compatability
  321. //-----------------------------------------------------------------------------
  322. void CDmeParticleSystemDefinition::OnElementUnserialized()
  323. {
  324. BaseClass::OnElementUnserialized();
  325. RemoveObsoleteAttributes( this, g_pParticleSystemMgr->GetParticleSystemDefinitionUnpackStructure() );
  326. // Add missing fields that are new
  327. for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i )
  328. {
  329. ParticleFunctionType_t type = (ParticleFunctionType_t)i;
  330. CUtlVector< IParticleOperatorDefinition *> &list = g_pParticleSystemMgr->GetAvailableParticleOperatorList( type );
  331. int nAvailType = list.Count();
  332. int nCount = GetParticleFunctionCount( type );
  333. for ( int j = 0; j < nCount; ++j )
  334. {
  335. CDmeParticleFunction *pFunction = GetParticleFunction( type, j );
  336. if ( i == FUNCTION_CHILDREN )
  337. {
  338. RemoveObsoleteAttributes( pFunction, list[0]->GetUnpackStructure() );
  339. pFunction->AddMissingFields( list[0]->GetUnpackStructure() );
  340. continue;
  341. }
  342. for ( int k = 0; k < nAvailType; ++k )
  343. {
  344. if ( Q_stricmp( pFunction->GetName(), list[k]->GetName() ) )
  345. continue;
  346. RemoveObsoleteAttributes( pFunction, list[k]->GetUnpackStructure() );
  347. pFunction->AddMissingFields( list[k]->GetUnpackStructure() );
  348. break;
  349. }
  350. }
  351. }
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Check to see if any attributes changed
  355. //-----------------------------------------------------------------------------
  356. void CDmeParticleSystemDefinition::Resolve()
  357. {
  358. BaseClass::Resolve();
  359. for( CDmAttribute* pAttr = FirstAttribute(); pAttr; pAttr = pAttr->NextAttribute() )
  360. {
  361. if ( pAttr->IsFlagSet( FATTRIB_DIRTY ) )
  362. {
  363. RecompileParticleSystem();
  364. break;
  365. }
  366. }
  367. }
  368. //-----------------------------------------------------------------------------
  369. // Add, remove
  370. //-----------------------------------------------------------------------------
  371. CDmeParticleFunction* CDmeParticleSystemDefinition::AddOperator( ParticleFunctionType_t type, const char *pFunctionName )
  372. {
  373. CUtlVector< IParticleOperatorDefinition *> &list = g_pParticleSystemMgr->GetAvailableParticleOperatorList( type );
  374. int nCount = list.Count();
  375. for ( int i = 0; i < nCount; ++i )
  376. {
  377. if ( Q_stricmp( pFunctionName, list[i]->GetName() ) )
  378. continue;
  379. CDmeParticleOperator *pFunction = CreateElement< CDmeParticleOperator >( pFunctionName, GetFileId() );
  380. m_ParticleFunction[type].AddToTail( pFunction );
  381. pFunction->SetFunction( list[i] );
  382. return pFunction;
  383. }
  384. return NULL;
  385. }
  386. CDmeParticleFunction* CDmeParticleSystemDefinition::AddChild( CDmeParticleSystemDefinition *pChild )
  387. {
  388. Assert( pChild );
  389. CUtlVector< IParticleOperatorDefinition *> &list = g_pParticleSystemMgr->GetAvailableParticleOperatorList( FUNCTION_CHILDREN );
  390. Assert( list.Count() == 1 );
  391. CDmeParticleChild *pFunction = CreateElement< CDmeParticleChild >( pChild->GetName(), GetFileId() );
  392. m_ParticleFunction[FUNCTION_CHILDREN].AddToTail( pFunction );
  393. pFunction->SetChildParticleSystem( pChild, list[0] );
  394. return pFunction;
  395. }
  396. //-----------------------------------------------------------------------------
  397. // Remove
  398. void CDmeParticleSystemDefinition::RemoveFunction( ParticleFunctionType_t type, CDmeParticleFunction *pFunction )
  399. {
  400. int nIndex = FindFunction( type, pFunction );
  401. RemoveFunction( type, nIndex );
  402. }
  403. void CDmeParticleSystemDefinition::RemoveFunction( ParticleFunctionType_t type, int nIndex )
  404. {
  405. if ( nIndex >= 0 )
  406. {
  407. m_ParticleFunction[type].Remove(nIndex);
  408. }
  409. }
  410. //-----------------------------------------------------------------------------
  411. // Find
  412. //-----------------------------------------------------------------------------
  413. int CDmeParticleSystemDefinition::FindFunction( ParticleFunctionType_t type, CDmeParticleFunction *pParticleFunction )
  414. {
  415. int nCount = m_ParticleFunction[type].Count();
  416. for ( int i = 0; i < nCount; ++i )
  417. {
  418. if ( pParticleFunction == m_ParticleFunction[type][i] )
  419. return i;
  420. }
  421. return -1;
  422. }
  423. int CDmeParticleSystemDefinition::FindFunction( ParticleFunctionType_t type, const char *pFunctionName )
  424. {
  425. int nCount = m_ParticleFunction[type].Count();
  426. for ( int i = 0; i < nCount; ++i )
  427. {
  428. if ( !Q_stricmp( pFunctionName, m_ParticleFunction[type][i]->GetFunctionType() ) )
  429. return i;
  430. }
  431. return -1;
  432. }
  433. //-----------------------------------------------------------------------------
  434. // Iteration
  435. //-----------------------------------------------------------------------------
  436. int CDmeParticleSystemDefinition::GetParticleFunctionCount( ParticleFunctionType_t type ) const
  437. {
  438. return m_ParticleFunction[type].Count();
  439. }
  440. CDmeParticleFunction *CDmeParticleSystemDefinition::GetParticleFunction( ParticleFunctionType_t type, int nIndex )
  441. {
  442. return m_ParticleFunction[type][nIndex];
  443. }
  444. //-----------------------------------------------------------------------------
  445. // Reordering
  446. //-----------------------------------------------------------------------------
  447. void CDmeParticleSystemDefinition::MoveFunctionUp( ParticleFunctionType_t type, CDmeParticleFunction *pElement )
  448. {
  449. int nIndex = FindFunction( type, pElement );
  450. if ( nIndex > 0 )
  451. {
  452. m_ParticleFunction[type].Swap( nIndex, nIndex - 1 );
  453. }
  454. }
  455. void CDmeParticleSystemDefinition::MoveFunctionDown( ParticleFunctionType_t type, CDmeParticleFunction *pElement )
  456. {
  457. int nIndex = FindFunction( type, pElement );
  458. int nLastIndex = m_ParticleFunction[type].Count() - 1;
  459. if ( nIndex >= 0 && nIndex < nLastIndex )
  460. {
  461. m_ParticleFunction[type].Swap( nIndex, nIndex + 1 );
  462. }
  463. }
  464. //-----------------------------------------------------------------------------
  465. // Marks a particle system as a new instance
  466. // This is basically a workaround to prevent newly-copied particle functions
  467. // from recompiling themselves a zillion times
  468. //-----------------------------------------------------------------------------
  469. void CDmeParticleSystemDefinition::MarkNewInstance()
  470. {
  471. for ( int i = 0; i < PARTICLE_FUNCTION_COUNT; ++i )
  472. {
  473. int nCount = m_ParticleFunction[i].Count();
  474. for ( int j = 0; j < nCount; ++j )
  475. {
  476. m_ParticleFunction[i][j]->MarkNewInstance();
  477. }
  478. }
  479. }
  480. //-----------------------------------------------------------------------------
  481. // Recompiles the particle system when a change occurs
  482. //-----------------------------------------------------------------------------
  483. void CDmeParticleSystemDefinition::RecompileParticleSystem()
  484. {
  485. const char *pFileFormat = "pcf";
  486. const char *pEncoding = g_pDataModel->GetDefaultEncoding( pFileFormat );
  487. int nFlags = g_pDataModel->IsEncodingBinary( pEncoding ) ? 0 : CUtlBuffer::TEXT_BUFFER;
  488. CUtlBuffer buf( 0, 0, nFlags );
  489. if ( g_pDataModel->Serialize( buf, pEncoding, pFileFormat, GetHandle() ) )
  490. {
  491. g_pParticleSystemMgr->ReadParticleConfigFile( buf, true, NULL );
  492. }
  493. }