Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

616 lines
18 KiB

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