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.

536 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. #include "petdoc.h"
  9. #include "tier1/KeyValues.h"
  10. #include "tier1/utlbuffer.h"
  11. #include "toolutils/enginetools_int.h"
  12. #include "filesystem.h"
  13. #include "pettool.h"
  14. #include "toolframework/ienginetool.h"
  15. #include "movieobjects/dmeparticlesystemdefinition.h"
  16. #include "datamodel/idatamodel.h"
  17. #include "toolutils/attributeelementchoicelist.h"
  18. #include "particlesystemdefinitionbrowser.h"
  19. #include "vgui_controls/messagebox.h"
  20. #include "particles/particles.h"
  21. #include "particlesystempropertiescontainer.h"
  22. #include "dme_controls/particlesystempanel.h"
  23. #include "dme_controls/dmecontrols.h"
  24. //-----------------------------------------------------------------------------
  25. // Constructor
  26. //-----------------------------------------------------------------------------
  27. CPetDoc::CPetDoc( IPetDocCallback *pCallback ) : m_pCallback( pCallback )
  28. {
  29. m_hRoot = NULL;
  30. m_pFileName[0] = 0;
  31. m_bDirty = false;
  32. g_pDataModel->InstallNotificationCallback( this );
  33. SetElementPropertiesChoices( this );
  34. }
  35. CPetDoc::~CPetDoc()
  36. {
  37. if ( m_hRoot.Get() )
  38. {
  39. g_pDataModel->RemoveFileId( m_hRoot->GetFileId() );
  40. m_hRoot = NULL;
  41. }
  42. g_pDataModel->RemoveNotificationCallback( this );
  43. SetElementPropertiesChoices( NULL );
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Inherited from INotifyUI
  47. //-----------------------------------------------------------------------------
  48. void CPetDoc::NotifyDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
  49. {
  50. OnDataChanged( pReason, nNotifySource, nNotifyFlags );
  51. }
  52. bool CPetDoc::GetIntChoiceList( const char *pChoiceListType, CDmElement *pElement,
  53. const char *pAttributeName, bool bArrayElement, IntChoiceList_t &list )
  54. {
  55. if ( !Q_stricmp( pChoiceListType, "particlefield" ) )
  56. {
  57. for ( int i = 0; i < MAX_PARTICLE_ATTRIBUTES; ++i )
  58. {
  59. const char *pName = g_pParticleSystemMgr->GetParticleFieldName( i );
  60. if ( pName )
  61. {
  62. int j = list.AddToTail();
  63. list[j].m_nValue = i;
  64. list[j].m_pChoiceString = pName;
  65. }
  66. }
  67. return true;
  68. }
  69. if ( !Q_stricmp( pChoiceListType, "particlefield_scalar" ) )
  70. {
  71. for ( int i = 0; i < MAX_PARTICLE_ATTRIBUTES; ++i )
  72. {
  73. if ( ( ATTRIBUTES_WHICH_ARE_VEC3S_MASK & ( 1 << i ) ) != 0 )
  74. continue;
  75. const char *pName = g_pParticleSystemMgr->GetParticleFieldName( i );
  76. if ( pName )
  77. {
  78. int j = list.AddToTail();
  79. list[j].m_nValue = i;
  80. list[j].m_pChoiceString = pName;
  81. }
  82. }
  83. return true;
  84. }
  85. if ( !Q_stricmp( pChoiceListType, "particlefield_vector" ) )
  86. {
  87. for ( int i = 0; i < MAX_PARTICLE_ATTRIBUTES; ++i )
  88. {
  89. if ( ( ATTRIBUTES_WHICH_ARE_VEC3S_MASK & ( 1 << i ) ) == 0 )
  90. continue;
  91. const char *pName = g_pParticleSystemMgr->GetParticleFieldName( i );
  92. if ( pName )
  93. {
  94. int j = list.AddToTail();
  95. list[j].m_nValue = i;
  96. list[j].m_pChoiceString = pName;
  97. }
  98. }
  99. return true;
  100. }
  101. return false;
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Gets the file name
  105. //-----------------------------------------------------------------------------
  106. const char *CPetDoc::GetFileName()
  107. {
  108. return m_pFileName;
  109. }
  110. void CPetDoc::SetFileName( const char *pFileName )
  111. {
  112. Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
  113. Q_FixSlashes( m_pFileName );
  114. SetDirty( true );
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Dirty bits
  118. //-----------------------------------------------------------------------------
  119. void CPetDoc::SetDirty( bool bDirty )
  120. {
  121. m_bDirty = bDirty;
  122. }
  123. bool CPetDoc::IsDirty() const
  124. {
  125. return m_bDirty;
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Creates the root element
  129. //-----------------------------------------------------------------------------
  130. bool CPetDoc::CreateRootElement()
  131. {
  132. Assert( !m_hRoot.Get() );
  133. DmFileId_t fileid = g_pDataModel->FindOrCreateFileId( GetFileName() );
  134. // Create the main element
  135. m_hRoot = g_pDataModel->CreateElement( "DmElement", GetFileName(), fileid );
  136. if ( m_hRoot == DMELEMENT_HANDLE_INVALID )
  137. return false;
  138. g_pDataModel->SetFileRoot( fileid, m_hRoot );
  139. // We need to create an element array attribute storing particle system definitions
  140. m_hRoot->AddAttribute( "particleSystemDefinitions", AT_ELEMENT_ARRAY );
  141. return true;
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Creates a new document
  145. //-----------------------------------------------------------------------------
  146. void CPetDoc::CreateNew()
  147. {
  148. Assert( !m_hRoot.Get() );
  149. // This is not undoable
  150. CDisableUndoScopeGuard guard;
  151. Q_strncpy( m_pFileName, "untitled", sizeof( m_pFileName ) );
  152. // Create the main element
  153. if ( !CreateRootElement() )
  154. return;
  155. SetDirty( false );
  156. }
  157. //-----------------------------------------------------------------------------
  158. // Saves/loads from file
  159. //-----------------------------------------------------------------------------
  160. bool CPetDoc::LoadFromFile( const char *pFileName )
  161. {
  162. Assert( !m_hRoot.Get() );
  163. CAppDisableUndoScopeGuard guard( "CPetDoc::LoadFromFile", NOTIFY_CHANGE_OTHER );
  164. SetDirty( false );
  165. if ( !pFileName[0] )
  166. return false;
  167. Q_strncpy( m_pFileName, pFileName, sizeof( m_pFileName ) );
  168. CDmElement *pRoot = NULL;
  169. DmFileId_t fileid = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pRoot, CR_DELETE_OLD );
  170. if ( fileid == DMFILEID_INVALID )
  171. {
  172. m_pFileName[0] = 0;
  173. return false;
  174. }
  175. m_hRoot = pRoot;
  176. SetDirty( false );
  177. return true;
  178. }
  179. void CPetDoc::SaveToFile( )
  180. {
  181. if ( m_hRoot.Get() && m_pFileName && m_pFileName[0] )
  182. {
  183. g_pDataModel->SaveToFile( m_pFileName, NULL, "binary", PET_FILE_FORMAT, m_hRoot );
  184. }
  185. SetDirty( false );
  186. }
  187. //-----------------------------------------------------------------------------
  188. // Returns the root object
  189. //-----------------------------------------------------------------------------
  190. CDmElement *CPetDoc::GetRootObject()
  191. {
  192. return m_hRoot;
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Returns the root object fileid
  196. //-----------------------------------------------------------------------------
  197. DmFileId_t CPetDoc::GetFileId()
  198. {
  199. return m_hRoot.Get() ? m_hRoot->GetFileId() : DMFILEID_INVALID;
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Returns the particle system definition list
  203. //-----------------------------------------------------------------------------
  204. CDmAttribute *CPetDoc::GetParticleSystemDefinitionList()
  205. {
  206. CDmrElementArray<> array( m_hRoot, "particleSystemDefinitions" );
  207. return array.GetAttribute();
  208. }
  209. void CPetDoc::AddNewParticleSystemDefinition( CDmeParticleSystemDefinition *pNew, CUndoScopeGuard &Guard )
  210. {
  211. CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
  212. particleSystemList.AddToTail( pNew );
  213. Guard.Release();
  214. // Force a resolve to get the particle created
  215. g_pDmElementFramework->Operate( true );
  216. g_pDmElementFramework->BeginEdit();
  217. UpdateParticleDefinition( pNew );
  218. }
  219. //-----------------------------------------------------------------------------
  220. // Adds a new particle system definition
  221. //-----------------------------------------------------------------------------
  222. CDmeParticleSystemDefinition* CPetDoc::AddNewParticleSystemDefinition( const char *pName )
  223. {
  224. if ( !pName || !pName[0] )
  225. {
  226. pName = "New Particle System";
  227. }
  228. CDmeParticleSystemDefinition *pParticleSystem;
  229. {
  230. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Add Particle System", "Add Particle System" );
  231. pParticleSystem = CreateElement<CDmeParticleSystemDefinition>( pName, GetFileId() );
  232. AddNewParticleSystemDefinition( pParticleSystem, guard );
  233. }
  234. return pParticleSystem;
  235. }
  236. //-----------------------------------------------------------------------------
  237. // Refresh all particle definitions
  238. //-----------------------------------------------------------------------------
  239. void CPetDoc::UpdateAllParticleSystems( )
  240. {
  241. // Force a resolve to get the particle created
  242. g_pDmElementFramework->Operate( true );
  243. g_pDmElementFramework->BeginEdit();
  244. CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
  245. int nCount = particleSystemList.Count();
  246. for ( int i = 0; i < nCount; ++i )
  247. {
  248. UpdateParticleDefinition( particleSystemList[i] );
  249. }
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Deletes a particle system definition
  253. //-----------------------------------------------------------------------------
  254. void CPetDoc::DeleteParticleSystemDefinition( CDmeParticleSystemDefinition *pParticleSystem )
  255. {
  256. if ( !pParticleSystem )
  257. return;
  258. CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
  259. int nCount = particleSystemList.Count();
  260. for ( int i = 0; i < nCount; ++i )
  261. {
  262. if ( pParticleSystem == particleSystemList[i] )
  263. {
  264. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Delete Particle System", "Delete Particle System" );
  265. particleSystemList.FastRemove( i );
  266. break;
  267. }
  268. }
  269. // Find all CDmeParticleChilds referring to this function
  270. CUtlVector< CDmeParticleChild* > children;
  271. FindAncestorsReferencingElement( pParticleSystem, children );
  272. int nChildCount = children.Count();
  273. for ( int i = 0; i < nChildCount; ++i )
  274. {
  275. CDmeParticleChild *pChildReference = children[i];
  276. CDmeParticleSystemDefinition *pParent = FindReferringElement<CDmeParticleSystemDefinition>( pChildReference, "children" );
  277. if ( !pParent )
  278. continue;
  279. pParent->RemoveFunction( FUNCTION_CHILDREN, pChildReference );
  280. DestroyElement( pChildReference, TD_NONE );
  281. }
  282. DestroyElement( pParticleSystem, TD_DEEP );
  283. }
  284. CDmeParticleSystemDefinition *CPetDoc::FindParticleSystemDefinition( const char *pName )
  285. {
  286. CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
  287. int nCount = particleSystemList.Count();
  288. for ( int i = 0; i < nCount; ++i )
  289. {
  290. CDmeParticleSystemDefinition* pParticleSystem = particleSystemList[i];
  291. if ( !Q_stricmp( pName, pParticleSystem->GetName() ) )
  292. return pParticleSystem;
  293. }
  294. return NULL;
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Deletes a particle system definition
  298. //-----------------------------------------------------------------------------
  299. void CPetDoc::ReplaceParticleSystemDefinition( CDmeParticleSystemDefinition *pParticleSystem )
  300. {
  301. if ( !pParticleSystem )
  302. return;
  303. CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
  304. int nCount = particleSystemList.Count();
  305. int nFoundIndex = -1;
  306. for ( int i = 0; i < nCount; ++i )
  307. {
  308. if ( !particleSystemList[i] )
  309. continue;
  310. if ( !Q_stricmp( particleSystemList[i]->GetName(), pParticleSystem->GetName() ) )
  311. {
  312. nFoundIndex = i;
  313. break;
  314. }
  315. }
  316. if ( nFoundIndex < 0 )
  317. {
  318. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Replace Particle System", "Replace Particle System" );
  319. CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
  320. pParticleSystem->SetFileId( m_hRoot->GetFileId(), TD_ALL );
  321. particleSystemList.AddToTail( pParticleSystem );
  322. return;
  323. }
  324. CDmeParticleSystemDefinition *pOldParticleSystem = particleSystemList[nFoundIndex];
  325. // This can happen if we unserialized w/ replace
  326. if ( pOldParticleSystem == pParticleSystem )
  327. return;
  328. CAppUndoScopeGuard guard( NOTIFY_SETDIRTYFLAG, "Replace Particle System", "Replace Particle System" );
  329. particleSystemList.Set( nFoundIndex, pParticleSystem );
  330. pParticleSystem->SetFileId( m_hRoot->GetFileId(), TD_ALL );
  331. // Find all CDmeParticleChilds referring to this function
  332. CUtlVector< CDmeParticleChild* > children;
  333. FindAncestorsReferencingElement( pOldParticleSystem, children );
  334. int nChildCount = children.Count();
  335. for ( int i = 0; i < nChildCount; ++i )
  336. {
  337. CDmeParticleChild *pChildReference = children[i];
  338. pChildReference->m_Child = pParticleSystem;
  339. }
  340. DestroyElement( pOldParticleSystem, TD_SHALLOW );
  341. }
  342. //-----------------------------------------------------------------------------
  343. // Does a particle system exist already?
  344. //-----------------------------------------------------------------------------
  345. bool CPetDoc::IsParticleSystemDefined( const char *pName )
  346. {
  347. return FindParticleSystemDefinition( pName ) != NULL;
  348. }
  349. //-----------------------------------------------------------------------------
  350. // Updates a specific particle defintion
  351. //-----------------------------------------------------------------------------
  352. void CPetDoc::UpdateParticleDefinition( CDmeParticleSystemDefinition *pDef )
  353. {
  354. if ( !pDef )
  355. return;
  356. CUtlBuffer buf;
  357. g_pDataModel->Serialize( buf, "binary", PET_FILE_FORMAT, pDef->GetHandle() );
  358. // Tell the game about the new definitions
  359. if ( clienttools )
  360. {
  361. clienttools->ReloadParticleDefintions( GetFileName(), buf.Base(), buf.TellMaxPut() );
  362. }
  363. if ( servertools )
  364. {
  365. servertools->ReloadParticleDefintions( GetFileName(), buf.Base(), buf.TellMaxPut() );
  366. }
  367. // Let the other tools know
  368. KeyValues *pMessage = new KeyValues( "ParticleSystemUpdated" );
  369. pMessage->SetPtr( "definitionBits", buf.Base() );
  370. pMessage->SetInt( "definitionSize", buf.TellMaxPut() );
  371. g_pPetTool->PostMessageToAllTools( pMessage );
  372. pMessage->deleteThis();
  373. }
  374. //-----------------------------------------------------------------------------
  375. // Populate string choice lists
  376. //-----------------------------------------------------------------------------
  377. bool CPetDoc::GetStringChoiceList( const char *pChoiceListType, CDmElement *pElement,
  378. const char *pAttributeName, bool bArrayElement, StringChoiceList_t &list )
  379. {
  380. if ( !Q_stricmp( pChoiceListType, "particleSystemDefinitions" ) )
  381. {
  382. CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
  383. StringChoice_t sChoice;
  384. sChoice.m_pValue = "";
  385. sChoice.m_pChoiceString = "";
  386. list.AddToTail( sChoice );
  387. int nCount = particleSystemList.Count();
  388. for ( int i = 0; i < nCount; ++i )
  389. {
  390. CDmeParticleSystemDefinition *pParticleSystem = particleSystemList[ i ];
  391. StringChoice_t sChoice;
  392. sChoice.m_pValue = pParticleSystem->GetName();
  393. sChoice.m_pChoiceString = pParticleSystem->GetName();
  394. list.AddToTail( sChoice );
  395. }
  396. return true;
  397. }
  398. return false;
  399. }
  400. //-----------------------------------------------------------------------------
  401. // Populate element choice lists
  402. //-----------------------------------------------------------------------------
  403. bool CPetDoc::GetElementChoiceList( const char *pChoiceListType, CDmElement *pElement,
  404. const char *pAttributeName, bool bArrayElement, ElementChoiceList_t &list )
  405. {
  406. if ( !Q_stricmp( pChoiceListType, "allelements" ) )
  407. {
  408. AddElementsRecursively( m_hRoot, list );
  409. return true;
  410. }
  411. if ( !Q_stricmp( pChoiceListType, "particleSystemDefinitions" ) )
  412. {
  413. CDmrParticleSystemList particleSystemList( GetParticleSystemDefinitionList() );
  414. int nCount = particleSystemList.Count();
  415. for ( int i = 0; i < nCount; ++i )
  416. {
  417. CDmeParticleSystemDefinition *pParticleSystem = particleSystemList[ i ];
  418. ElementChoice_t sChoice;
  419. sChoice.m_pValue = pParticleSystem;
  420. sChoice.m_pChoiceString = pParticleSystem->GetName();
  421. list.AddToTail( sChoice );
  422. }
  423. return ( nCount > 0 );
  424. }
  425. // by default, try to treat the choice list type as a Dme element type
  426. AddElementsRecursively( m_hRoot, list, pChoiceListType );
  427. return list.Count() > 0;
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Called when data changes
  431. //-----------------------------------------------------------------------------
  432. void CPetDoc::OnDataChanged( const char *pReason, int nNotifySource, int nNotifyFlags )
  433. {
  434. SetDirty( nNotifyFlags & NOTIFY_SETDIRTYFLAG ? true : false );
  435. m_pCallback->OnDocChanged( pReason, nNotifySource, nNotifyFlags );
  436. }