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.

1311 lines
33 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "matsys_controls/particlepicker.h"
  7. #include "tier1/keyvalues.h"
  8. #include "tier1/utldict.h"
  9. #include "filesystem.h"
  10. #include "studio.h"
  11. #include "matsys_controls/matsyscontrols.h"
  12. #include "matsys_controls/mdlpanel.h"
  13. #include "vgui_controls/Splitter.h"
  14. #include "vgui_controls/ComboBox.h"
  15. #include "vgui_controls/Button.h"
  16. #include "vgui_controls/PropertySheet.h"
  17. #include "vgui_controls/MessageBox.h"
  18. #include "vgui_controls/MenuItem.h"
  19. #include "vgui_controls/MenuButton.h"
  20. #include "vgui_controls/PropertyPage.h"
  21. #include "vgui_controls/CheckButton.h"
  22. #include "vgui_controls/ScrollableEditablePanel.h"
  23. #include "vgui_controls/ScrollBar.h"
  24. #include "vgui_controls/Tooltip.h"
  25. #include "vgui/IVGui.h"
  26. #include "vgui/IInput.h"
  27. #include "vgui/ISurface.h"
  28. #include "vgui/Cursor.h"
  29. #include "matsys_controls/assetpicker.h"
  30. #include "dmxloader/dmxloader.h"
  31. #include "particles/particles.h"
  32. #include "vstdlib/jobthread.h"
  33. #include "dme_controls/particlesystempanel.h"
  34. // memdbgon must be the last include file in a .cpp file!!!
  35. #include "tier0/memdbgon.h"
  36. using namespace vgui;
  37. //-----------------------------------------------------------------------------
  38. struct CachedParticleInfo_t
  39. {
  40. CachedAssetInfo_t m_AssetInfo;
  41. CUtlString m_FileName;
  42. };
  43. struct PCFToLoad_t
  44. {
  45. CUtlString m_FileName;
  46. int m_ModId;
  47. };
  48. static CUtlVector<PCFToLoad_t> sCacheUnloadedPCFs;
  49. static CUtlVector<CachedParticleInfo_t> sCacheParticleList;
  50. //-----------------------------------------------------------------------------
  51. class CParticleSnapshotPanel: public vgui::EditablePanel
  52. {
  53. DECLARE_CLASS_SIMPLE( CParticleSnapshotPanel, vgui::EditablePanel );
  54. public:
  55. CParticleSnapshotPanel( vgui::Panel *pParent, const char *pName );
  56. virtual ~CParticleSnapshotPanel( );
  57. MESSAGE_FUNC( OnSetFocus, "SetFocus" );
  58. MESSAGE_FUNC_CHARPTR( OnParticleSystemSelected, "ParticleSystemSelected", SystemName );
  59. virtual void OnMousePressed(MouseCode code);
  60. virtual void OnMouseDoublePressed(MouseCode code);
  61. virtual void ApplySchemeSettings(IScheme *pScheme);
  62. virtual void Paint();
  63. void SetParticleSystem( const char *szSystemName, int nId );
  64. void Simulate();
  65. void SetSelected( bool bSelected );
  66. const char *GetSystemName() const;
  67. bool IsSelected();
  68. CParticleCollection* GetSystem();
  69. int GetId();
  70. void SetPreviewEnabled( bool bEnabled );
  71. void UpdateRelatives( IImage *pIcon, CUtlVector<CParticleSnapshotGrid::PSysRelativeInfo_t>& sysParents, CUtlVector<CParticleSnapshotGrid::PSysRelativeInfo_t>& sysChildren );
  72. protected:
  73. CParticleSystemPanel *m_pParticlePanel;
  74. MenuButton *m_pParentsButton;
  75. MenuButton *m_pChildrenButton;
  76. vgui::Label *m_pLabel;
  77. int m_nSystemIndex;
  78. CUtlString m_SystemName;
  79. bool m_bSelected;
  80. int m_nSystemId;
  81. bool m_bPreviewEnabled;
  82. Color m_SelectedBgColor;
  83. Color m_SelectedTextColor;
  84. };
  85. CParticleSnapshotPanel::CParticleSnapshotPanel( vgui::Panel *pParent, const char *pName ):
  86. BaseClass(pParent,pName)
  87. {
  88. m_bSelected = false;
  89. m_bPreviewEnabled = true;
  90. m_pParticlePanel = new CParticleSystemPanel( this, pName );
  91. m_pParticlePanel->SetSelfSimulation(false);
  92. m_pParticlePanel->SetGridColor( 128, 128, 128 );
  93. m_pParticlePanel->RenderGrid(true);
  94. m_pParticlePanel->SetParentMouseNotify(true);
  95. m_pParticlePanel->EnableAutoViewing(true);
  96. m_pLabel = new Label( this, "SystemLabel", "Unnamed" );
  97. m_pLabel->SetContentAlignment( Label::a_center );
  98. m_pLabel->SetPaintBackgroundEnabled( false );
  99. m_pLabel->SetMouseInputEnabled( false );
  100. CBoxSizer *pSizer = new CBoxSizer(ESLD_VERTICAL);
  101. pSizer->AddPanel( m_pParticlePanel, SizerAddArgs_t().Expand( 1.0f ).Padding( 5 ) );
  102. {
  103. CBoxSizer *pRow = new CBoxSizer(ESLD_HORIZONTAL);
  104. m_pParentsButton = new MenuButton( this, "ParentsButton", "P" );
  105. pRow->AddPanel( m_pParentsButton, SizerAddArgs_t().Expand( 0.0f ).Padding( 0 ) );
  106. m_pChildrenButton = new MenuButton( this, "ChildrenButton", "C" );
  107. pRow->AddPanel( m_pChildrenButton, SizerAddArgs_t().Expand( 0.0f ).Padding( 0 ) );
  108. pRow->AddPanel( m_pLabel, SizerAddArgs_t().Expand( 0.0f ).Padding( 2 ) );
  109. pSizer->AddSizer( pRow, SizerAddArgs_t().Expand( 0.0f ).Padding( 5 ) );
  110. }
  111. pSizer->AddSpacer( SizerAddArgs_t().Padding( 5 ) );
  112. SetSizer( pSizer );
  113. InvalidateLayout(true);
  114. m_pParticlePanel->ResetView();
  115. m_pParticlePanel->LookAt( 50.f );
  116. }
  117. void CParticleSnapshotPanel::SetPreviewEnabled( bool bEnabled )
  118. {
  119. m_bPreviewEnabled = bEnabled;
  120. m_pParticlePanel->SetVisible(m_bPreviewEnabled);
  121. InvalidateLayout();
  122. }
  123. CParticleSnapshotPanel::~CParticleSnapshotPanel( )
  124. {
  125. }
  126. void CParticleSnapshotPanel::OnParticleSystemSelected( const char *SystemName )
  127. {
  128. // hand the signal up
  129. PostActionSignal( new KeyValues( "ParticleSystemSelected", "SystemName", SystemName ) );
  130. }
  131. int CParticleSnapshotPanel::GetId()
  132. {
  133. return m_nSystemId;
  134. }
  135. CParticleCollection* CParticleSnapshotPanel::GetSystem()
  136. {
  137. return m_pParticlePanel->GetParticleSystem();
  138. }
  139. void CParticleSnapshotPanel::OnSetFocus()
  140. {
  141. BaseClass::OnSetFocus();
  142. }
  143. void CParticleSnapshotPanel::UpdateRelatives( IImage *pIcon, CUtlVector<CParticleSnapshotGrid::PSysRelativeInfo_t>& sysParents, CUtlVector<CParticleSnapshotGrid::PSysRelativeInfo_t>& sysChildren )
  144. {
  145. char countBuf[8];
  146. // parents
  147. if ( sysParents.Count() )
  148. {
  149. Menu *pParentsMenu = new Menu(GetParent()->GetParent(), "ParentsMenu");
  150. for ( int i = 0; i < sysParents.Count(); ++i )
  151. {
  152. int nItemIdx = pParentsMenu->AddMenuItem( sysParents[i].relName, new KeyValues( "ParticleSystemSelected", "SystemName", sysParents[i].relName ), this );
  153. pParentsMenu->GetMenuItem(nItemIdx)->SetEnabled( sysParents[i].bVisibleInCurrentView );
  154. }
  155. m_pParentsButton->SetEnabled( true );
  156. V_snprintf( countBuf, sizeof(countBuf), "%d", sysParents.Count() );
  157. m_pParentsButton->SetText( countBuf );
  158. m_pParentsButton->SetMenu( pParentsMenu );
  159. }
  160. else
  161. {
  162. m_pParentsButton->SetEnabled( false );
  163. m_pParentsButton->SetText( "P" );
  164. m_pParentsButton->SetMenu( NULL );
  165. }
  166. // children
  167. if ( sysChildren.Count() )
  168. {
  169. Menu *pChildrenMenu = new Menu(GetParent()->GetParent(), "ChildrenMenu");
  170. for ( int i = 0; i < sysChildren.Count(); ++i )
  171. {
  172. int nItemIdx = pChildrenMenu->AddMenuItem( sysChildren[i].relName, new KeyValues( "ParticleSystemSelected", "SystemName", sysChildren[i].relName ), this );
  173. pChildrenMenu->GetMenuItem(nItemIdx)->SetEnabled( sysChildren[i].bVisibleInCurrentView );
  174. }
  175. m_pChildrenButton->SetEnabled( true );
  176. V_snprintf( countBuf, sizeof(countBuf), "%d", sysChildren.Count() );
  177. m_pChildrenButton->SetText( countBuf );
  178. m_pChildrenButton->SetMenu( pChildrenMenu );
  179. }
  180. else
  181. {
  182. m_pChildrenButton->SetEnabled( false );
  183. m_pChildrenButton->SetText( "C" );
  184. m_pChildrenButton->SetMenu( NULL );
  185. }
  186. }
  187. void CParticleSnapshotPanel::OnMousePressed( MouseCode code )
  188. {
  189. BaseClass::OnMousePressed( code );
  190. if ( code == MOUSE_LEFT )
  191. {
  192. if ( input()->IsKeyDown(KEY_LSHIFT) || input()->IsKeyDown(KEY_RSHIFT) )
  193. {
  194. PostActionSignal( new KeyValues( "ParticleSystemShiftSelected", "SystemName", m_SystemName ) );
  195. }
  196. else if ( input()->IsKeyDown(KEY_LCONTROL) || input()->IsKeyDown(KEY_RCONTROL) )
  197. {
  198. PostActionSignal( new KeyValues( "ParticleSystemCtrlSelected", "SystemName", m_SystemName ) );
  199. }
  200. else
  201. {
  202. PostActionSignal( new KeyValues( "ParticleSystemSelected", "SystemName", m_SystemName ) );
  203. }
  204. }
  205. }
  206. void CParticleSnapshotPanel::OnMouseDoublePressed( MouseCode code )
  207. {
  208. BaseClass::OnMouseDoublePressed( code );
  209. if ( code == MOUSE_LEFT )
  210. {
  211. PostActionSignal( new KeyValues( "ParticleSystemPicked", "SystemName", m_SystemName ) );
  212. }
  213. }
  214. void CParticleSnapshotPanel::SetParticleSystem( const char *szSystemName, int nId )
  215. {
  216. bool bSameSystem = !V_strcmp( m_SystemName, szSystemName );
  217. m_SystemName = szSystemName;
  218. m_nSystemId = nId;
  219. if ( !bSameSystem || m_pParticlePanel->GetParticleSystem() == NULL )
  220. {
  221. m_pParticlePanel->SetParticleSystem(szSystemName);
  222. m_pParticlePanel->SetControlPointValue( 0, Vector(0.f,0.f,0.f) );
  223. m_pParticlePanel->SetControlPointValue( 1, Vector(100.f,0.f,0.f) );
  224. m_pParticlePanel->LookAt( 50.f );
  225. m_pLabel->SetText( m_SystemName );
  226. m_pParticlePanel->ResetView();
  227. }
  228. if ( !m_pParticlePanel->GetParticleSystem() )
  229. {
  230. CUtlString errStr = "ERROR: ";
  231. errStr += m_SystemName;
  232. m_pLabel->SetText( errStr );
  233. m_pParticlePanel->SetBackgroundColor( 64,0,0 );
  234. }
  235. else
  236. {
  237. m_pParticlePanel->SetBackgroundColor( 32, 32, 32 );
  238. }
  239. InvalidateLayout();
  240. }
  241. void CParticleSnapshotPanel::ApplySchemeSettings(IScheme *pScheme)
  242. {
  243. BaseClass::ApplySchemeSettings(pScheme);
  244. m_SelectedBgColor = pScheme->GetColor( "ListPanel.SelectedBgColor", Color(255, 255, 255, 0) );
  245. m_SelectedTextColor = pScheme->GetColor( "ListPanel.SelectedTextColor", Color(255, 255, 255, 0) );
  246. // override the colors because alpha = 0 is bad
  247. Color btnFgColor = pScheme->GetColor("Button.TextColor", Color(255, 255, 255, 255) );
  248. Color btnBgColor = pScheme->GetColor("ListPanel.BgColor", Color(128, 128, 128, 255) );
  249. m_pChildrenButton->SetDefaultColor( btnFgColor, btnBgColor );
  250. m_pChildrenButton->SetArmedColor( btnFgColor, btnBgColor );
  251. m_pChildrenButton->SetDepressedColor( btnFgColor, btnBgColor );
  252. m_pParentsButton->SetDefaultColor( btnFgColor, btnBgColor );
  253. m_pParentsButton->SetArmedColor( btnFgColor, btnBgColor );
  254. m_pParentsButton->SetDepressedColor( btnFgColor, btnBgColor );
  255. }
  256. void CParticleSnapshotPanel::Simulate()
  257. {
  258. if( !m_bPreviewEnabled )
  259. {
  260. return;
  261. }
  262. Panel* pParent = GetParent();
  263. int x0,y0,x1, y1;
  264. GetClipRect( x0, y0, x1, y1 );
  265. int nPX0, nPY0, nPX1, nPY1;
  266. pParent->GetClipRect( nPX0, nPY0, nPX1, nPY1 );
  267. if( x1 < nPX0 || x0 > nPX1 ||
  268. y1 < nPY0 || y0 > nPY1 )
  269. {
  270. // out of bounds
  271. return;
  272. }
  273. m_pParticlePanel->Simulate();
  274. }
  275. void CParticleSnapshotPanel::Paint()
  276. {
  277. BaseClass::Paint();
  278. if( m_bSelected )
  279. {
  280. DrawBox( 1, 1, GetWide()-2, GetTall()-2, m_SelectedBgColor, 1.0f );
  281. }
  282. if( m_bPreviewEnabled )
  283. {
  284. // black border around the preview
  285. int x, y, w, t;
  286. m_pParticlePanel->GetBounds( x, y, w, t );
  287. surface()->DrawSetColor( Color(0,0,0,255) );
  288. surface()->DrawOutlinedRect( x-1, y-1, x+w+1, y+t+1 );
  289. }
  290. }
  291. const char *CParticleSnapshotPanel::GetSystemName() const
  292. {
  293. return m_SystemName;
  294. }
  295. void CParticleSnapshotPanel::SetSelected( bool bSelected )
  296. {
  297. m_bSelected = bSelected;
  298. }
  299. bool CParticleSnapshotPanel::IsSelected( )
  300. {
  301. return m_bSelected;
  302. }
  303. //-----------------------------------------------------------------------------
  304. //
  305. // Particle Snapshot Grid
  306. //
  307. //-----------------------------------------------------------------------------
  308. const int MIN_PANEL_SIZE = 200;
  309. const int MAX_PANEL_SIZE = 250;
  310. const int MIN_NUM_COLS = 1;
  311. const int OFFSET = 4;
  312. const int TOOLBAR_HEIGHT = 30;
  313. CParticleSnapshotGrid::CParticleSnapshotGrid( vgui::Panel *pParent, const char *pName ):
  314. BaseClass(pParent,pName)
  315. {
  316. m_pRelativesImgNeither = scheme()->GetImage( "tools/particles/icon_particles_rel_neither", false );
  317. m_pRelativesImgPOnly = scheme()->GetImage( "tools/particles/icon_particles_rel_ponly", false );
  318. m_pRelativesImgCOnly = scheme()->GetImage( "tools/particles/icon_particles_rel_conly", false );
  319. m_pRelativesImgBoth = scheme()->GetImage( "tools/particles/icon_particles_rel_both", false );
  320. m_pScrollBar = new ScrollBar( this, "ScrollBar", true );
  321. m_pScrollBar->SetWide( 16 );
  322. m_pScrollBar->SetAutoResize( PIN_TOPRIGHT, AUTORESIZE_DOWN, 0, TOOLBAR_HEIGHT, -16, 0 );
  323. m_pScrollBar->AddActionSignalTarget( this );
  324. m_pScrollPanel = new Panel( this, "ScrollPanel" );
  325. m_pScrollPanel->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_DOWNANDRIGHT, 0, TOOLBAR_HEIGHT, -16, 0 );
  326. m_pScrollPanel->DisableMouseInputForThisPanel(true);
  327. m_pToolPanel = new Panel( this, "ToolPanel" );
  328. m_pToolPanel->SetTall(TOOLBAR_HEIGHT);
  329. m_pToolPanel->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_RIGHT, 0, 0, -16, 0 );
  330. m_pToolPanel->SetSizer( new CBoxSizer(ESLD_HORIZONTAL) );
  331. m_pPreviewCheckbox = new CheckButton( m_pToolPanel, "PreviewCheckbox", "Show Previews" );
  332. m_pPreviewCheckbox->SetSelected(true);
  333. m_pPreviewCheckbox->AddActionSignalTarget( this );
  334. m_pToolPanel->GetSizer()->AddPanel( m_pPreviewCheckbox, SizerAddArgs_t() );
  335. m_pNoSystemsLabel = new Label( m_pScrollPanel, "NoSystemsLabel", "<No Systems>" );
  336. m_nCurrentColCount = MIN_NUM_COLS;
  337. m_nMostRecentSelectedIndex = -1;
  338. vgui::ivgui()->AddTickSignal( GetVPanel(), 0 );
  339. SetKeyBoardInputEnabled(true);
  340. }
  341. void CParticleSnapshotGrid::MapSystemRelatives( )
  342. {
  343. // somewhat slow, but doesn't get called frequently or with large enough data sets to optimize
  344. m_ParentsMap.RemoveAll();
  345. m_ParentsMap.AddMultipleToTail( m_Panels.Count() );
  346. m_ChildrenMap.RemoveAll();
  347. m_ChildrenMap.AddMultipleToTail( m_Panels.Count() );
  348. for ( int i = 0; i < g_pParticleSystemMgr->GetParticleSystemCount(); i++ )
  349. {
  350. const char *pPotentialParentName = g_pParticleSystemMgr->GetParticleSystemNameFromIndex(i);
  351. CParticleSystemDefinition *pPotentialParent = g_pParticleSystemMgr->FindParticleSystem( pPotentialParentName );
  352. //////////////////////
  353. // see if this system is visible
  354. int nParentVisibileIndex = -1;
  355. for ( int p = 0; p < m_Panels.Count(); ++p )
  356. {
  357. CParticleCollection *pVisible = m_Panels[p]->GetSystem();
  358. if( pVisible == NULL )
  359. continue;
  360. if ( pVisible->m_pDef == pPotentialParent )
  361. {
  362. nParentVisibileIndex = p;
  363. break;
  364. }
  365. }
  366. //////////////////////
  367. // see if this system is a parent of any visible system; check all its children
  368. for ( int c = 0; c < pPotentialParent->m_Children.Count(); ++c )
  369. {
  370. CParticleSystemDefinition *pChild = NULL;
  371. if ( pPotentialParent->m_Children[c].m_bUseNameBasedLookup )
  372. {
  373. pChild = g_pParticleSystemMgr->FindParticleSystem( pPotentialParent->m_Children[c].m_Name );
  374. }
  375. else
  376. {
  377. pChild = g_pParticleSystemMgr->FindParticleSystem( pPotentialParent->m_Children[c].m_Id );
  378. }
  379. if ( pChild == NULL )
  380. continue;
  381. //////////////////////
  382. // is the child visible?
  383. int nChildVisibleIndex = -1;
  384. for ( int p = 0; p < m_Panels.Count(); ++p )
  385. {
  386. CParticleCollection *pVisible = m_Panels[p]->GetSystem();
  387. if( pVisible == NULL )
  388. continue;
  389. if ( pVisible->m_pDef == pChild )
  390. {
  391. // this child is visible; add entry, and mark parent if visible
  392. PSysRelativeInfo_t parentInfo;
  393. parentInfo.relName = pPotentialParent->GetName();
  394. parentInfo.bVisibleInCurrentView = ( nParentVisibileIndex != -1 );
  395. m_ParentsMap[p].AddToTail( parentInfo );
  396. nChildVisibleIndex = p;
  397. break;
  398. }
  399. }
  400. if ( nParentVisibileIndex != -1 )
  401. {
  402. // this parent is visible; add entry, and mark child if visible
  403. PSysRelativeInfo_t childInfo;
  404. childInfo.relName = pChild->GetName();
  405. childInfo.bVisibleInCurrentView = ( nChildVisibleIndex != -1 );
  406. m_ChildrenMap[nParentVisibileIndex].AddToTail( childInfo );
  407. }
  408. }
  409. }
  410. }
  411. void CParticleSnapshotGrid::UpdatePanelRelatives( int nIndex )
  412. {
  413. CParticleSnapshotPanel* pPanel = m_Panels[nIndex];
  414. CUtlVector<PSysRelativeInfo_t>& sysParents = m_ParentsMap[nIndex];
  415. CUtlVector<PSysRelativeInfo_t>& sysChildren = m_ChildrenMap[nIndex];
  416. IImage *pImg = m_pRelativesImgNeither;
  417. if ( sysParents.Count() && sysChildren.Count() )
  418. {
  419. pImg = m_pRelativesImgBoth;
  420. }
  421. else if ( sysParents.Count() )
  422. {
  423. pImg = m_pRelativesImgPOnly;
  424. }
  425. else if ( sysChildren.Count() )
  426. {
  427. pImg = m_pRelativesImgCOnly;
  428. }
  429. pPanel->UpdateRelatives( pImg, sysParents, sysChildren );
  430. }
  431. void CParticleSnapshotGrid::OnScrollBarSliderMoved()
  432. {
  433. LayoutScrolled();
  434. }
  435. void CParticleSnapshotGrid::OnCheckButtonChecked( KeyValues *kv )
  436. {
  437. SetAllPreviewEnabled( m_pPreviewCheckbox->IsSelected() );
  438. }
  439. void CParticleSnapshotGrid::ApplySchemeSettings(IScheme *pScheme)
  440. {
  441. BaseClass::ApplySchemeSettings(pScheme);
  442. }
  443. void CParticleSnapshotGrid::UpdateAllRelatives()
  444. {
  445. MapSystemRelatives();
  446. for ( int i = 0; i < m_Panels.Count(); ++i )
  447. {
  448. UpdatePanelRelatives( i );
  449. }
  450. }
  451. void CParticleSnapshotGrid::OnMousePressed(MouseCode code)
  452. {
  453. BaseClass::OnMousePressed( code );
  454. SelectSystem("",false,false);
  455. PostActionSignal( new KeyValues( "ParticleSystemSelectionChanged" ) );
  456. }
  457. static int PanelSortHelperI( CParticleSnapshotPanel *const *a, CParticleSnapshotPanel * const *b )
  458. {
  459. return V_stricmp((*a)->GetSystemName(),(*b)->GetSystemName());
  460. }
  461. void CParticleSnapshotGrid::SetParticleList( const CUtlVector<const char *>& ParticleNames )
  462. {
  463. bool bPreviewEnabled = m_pPreviewCheckbox->IsSelected();
  464. // might have too many panels
  465. while ( m_Panels.Count() > ParticleNames.Count() )
  466. {
  467. delete m_Panels.Tail();
  468. m_Panels.RemoveMultipleFromTail(1);
  469. }
  470. // might have too few panels
  471. while ( m_Panels.Count() < ParticleNames.Count() )
  472. {
  473. char szPanelName[32];
  474. V_snprintf( szPanelName, sizeof(szPanelName), "ParticlePanel%d", m_Panels.Count() );
  475. CParticleSnapshotPanel *pPanel = new CParticleSnapshotPanel( m_pScrollPanel, szPanelName );
  476. pPanel->SetPreviewEnabled(bPreviewEnabled);
  477. pPanel->AddActionSignalTarget(this);
  478. m_Panels.AddToTail( pPanel );
  479. }
  480. // reinit them all, with the new system names
  481. for ( int i = 0; i < m_Panels.Count(); ++i )
  482. {
  483. if( i < ParticleNames.Count() )
  484. {
  485. m_Panels[i]->SetParticleSystem( ParticleNames[i], i );
  486. }
  487. else
  488. {
  489. m_Panels[i]->SetParticleSystem( "", i );
  490. }
  491. m_Panels[i]->SetSelected(false);
  492. }
  493. // now sort the panels however we want
  494. m_Panels.Sort( PanelSortHelperI );
  495. UpdateAllRelatives();
  496. m_nMostRecentSelectedIndex = -1;
  497. InvalidateLayout();
  498. }
  499. int CParticleSnapshotGrid::GetPanelWide()
  500. {
  501. int nWide = GetWide() - OFFSET*2 - m_pScrollBar->GetWide();
  502. return MIN(MAX_PANEL_SIZE,nWide/m_nCurrentColCount);
  503. }
  504. int CParticleSnapshotGrid::GetPanelTall()
  505. {
  506. if ( m_pPreviewCheckbox->IsSelected() )
  507. {
  508. return GetPanelWide();
  509. }
  510. else
  511. {
  512. return 30; // TODO: This shouldn't be hard-coded :|
  513. }
  514. }
  515. void CParticleSnapshotGrid::PerformLayout()
  516. {
  517. BaseClass::PerformLayout();
  518. int nWide = GetWide() - OFFSET*2 - m_pScrollBar->GetWide();
  519. m_nCurrentColCount = MAX(MIN_NUM_COLS,nWide/MIN_PANEL_SIZE);
  520. LayoutScrolled();
  521. }
  522. void CParticleSnapshotGrid::SetAllPreviewEnabled( bool bEnabled )
  523. {
  524. for ( int i = 0; i < m_Panels.Count(); ++i )
  525. {
  526. m_Panels[i]->SetPreviewEnabled(bEnabled);
  527. }
  528. InvalidateLayout(true);
  529. LayoutScrolled();
  530. }
  531. void CParticleSnapshotGrid::LayoutScrolled()
  532. {
  533. // int nWide = GetWide() - m_pScrollBar->GetWide();
  534. int nPanels = m_Panels.Count();
  535. int nRows = (nPanels+m_nCurrentColCount-1)/m_nCurrentColCount; // panels/cols rounded up
  536. // int nRemainder = (nWide - m_nCurrentColCount*m_nCurrentPanelSize - OFFSET*2);
  537. int nScrollPos = m_pScrollBar->GetValue();
  538. int nPanelW = GetPanelWide();
  539. int nPanelT = GetPanelTall();
  540. m_pScrollBar->SetRange( 0, nRows*nPanelT+OFFSET*2 );
  541. m_pScrollBar->SetRangeWindow( m_pScrollPanel->GetTall() );
  542. for( int r = 0; r < nRows; ++r )
  543. {
  544. for( int c = 0; c < m_nCurrentColCount; ++c )
  545. {
  546. int i = c + r*m_nCurrentColCount;
  547. if( i >= nPanels ) continue;
  548. if( IsSystemVisible( i ) )
  549. {
  550. m_Panels[i]->SetSize(nPanelW,nPanelT);
  551. m_Panels[i]->SetPos(OFFSET+c*nPanelW,OFFSET-nScrollPos+r*nPanelT);
  552. m_Panels[i]->SetVisible(true);
  553. }
  554. else
  555. {
  556. m_Panels[i]->SetSize(1,1);
  557. m_Panels[i]->SetPos(-10,-10);
  558. m_Panels[i]->SetVisible(false);
  559. }
  560. }
  561. }
  562. if ( nPanels == 0 )
  563. {
  564. m_pNoSystemsLabel->SetVisible( true );
  565. int w,t;
  566. m_pNoSystemsLabel->GetContentSize(w,t);
  567. w *= 2;
  568. m_pNoSystemsLabel->SetWide( w );
  569. m_pNoSystemsLabel->SetPos( (m_pScrollPanel->GetWide()-w)/2, (m_pScrollPanel->GetTall()-t)/2 );
  570. }
  571. else
  572. {
  573. m_pNoSystemsLabel->SetVisible( false );
  574. }
  575. }
  576. void CParticleSnapshotGrid::OnMouseWheeled(int delta)
  577. {
  578. int val = m_pScrollBar->GetValue();
  579. val -= (delta * 30);
  580. m_pScrollBar->SetValue(val);
  581. RequestFocus();
  582. }
  583. bool CParticleSnapshotGrid::IsSystemVisible( int nIndex )
  584. {
  585. int nViewTall = m_pScrollPanel->GetTall();
  586. int nRow = (nIndex / m_nCurrentColCount);
  587. int nTopOfPanel = nRow * GetPanelTall();
  588. int nBottomOfPanel = nTopOfPanel + GetPanelTall();
  589. int nCurrentScrollValue = m_pScrollBar->GetValue();
  590. return ( nTopOfPanel < nCurrentScrollValue+nViewTall &&
  591. nBottomOfPanel > nCurrentScrollValue );
  592. }
  593. void CParticleSnapshotGrid::SelectIndex( int nIndex, bool bAddToSelection, bool bToggle )
  594. {
  595. // not the most efficient, but easy
  596. SelectSystem( m_Panels[nIndex]->GetSystemName(), bAddToSelection, bToggle );
  597. }
  598. void CParticleSnapshotGrid::SelectId( int nId, bool bAddToSelection, bool bToggle )
  599. {
  600. // not the most efficient, but easy
  601. SelectSystem( GetSystemName(nId), bAddToSelection, bToggle );
  602. }
  603. void CParticleSnapshotGrid::DeselectAll()
  604. {
  605. for ( int i = 0; i < m_Panels.Count(); ++i )
  606. {
  607. m_Panels[i]->SetSelected(false);
  608. }
  609. m_nMostRecentSelectedIndex = -1;
  610. }
  611. int CParticleSnapshotGrid::GetSelectedSystemCount()
  612. {
  613. int nSelected = 0;
  614. for ( int i = 0; i < m_Panels.Count(); ++i )
  615. {
  616. if( m_Panels[i]->IsSelected() )
  617. {
  618. nSelected++;
  619. }
  620. }
  621. return nSelected;
  622. }
  623. const char *CParticleSnapshotGrid::GetSystemName( int nSystemId )
  624. {
  625. int nInternalIndex = IdToIndex( nSystemId );
  626. if ( nInternalIndex < 0 || nInternalIndex >= m_Panels.Count() )
  627. {
  628. return "";
  629. }
  630. else
  631. {
  632. return m_Panels[nInternalIndex]->GetSystemName();
  633. }
  634. }
  635. int CParticleSnapshotGrid::GetSelectedSystemId( int nSelectionIndex )
  636. {
  637. for ( int i = 0; i < m_Panels.Count(); ++i )
  638. {
  639. if( m_Panels[i]->IsSelected() )
  640. {
  641. nSelectionIndex--;
  642. if( nSelectionIndex < 0 )
  643. {
  644. return m_Panels[i]->GetId();
  645. }
  646. }
  647. }
  648. return -1;
  649. }
  650. void CParticleSnapshotGrid::SelectSystem( const char *pSystemName, bool bAddToSelection, bool bToggle )
  651. {
  652. int nSelectedIndex = -1;
  653. for ( int i = 0; i < m_Panels.Count(); ++i )
  654. {
  655. if ( !V_strcmp(m_Panels[i]->GetSystemName(),pSystemName) )
  656. {
  657. if ( m_Panels[i]->IsSelected() )
  658. {
  659. if ( bAddToSelection && bToggle )
  660. {
  661. m_Panels[i]->SetSelected( false );
  662. }
  663. }
  664. else
  665. {
  666. nSelectedIndex = i;
  667. m_Panels[i]->SetSelected( true );
  668. m_Panels[i]->RequestFocus();
  669. }
  670. m_nMostRecentSelectedIndex = i;
  671. }
  672. else if( !bAddToSelection )
  673. {
  674. m_Panels[i]->SetSelected(false);
  675. }
  676. }
  677. if ( nSelectedIndex != -1 )
  678. {
  679. int nViewTall = m_pScrollPanel->GetTall();
  680. int nRow = (nSelectedIndex / m_nCurrentColCount);
  681. int nTopOfPanel = nRow * GetPanelTall() + OFFSET;
  682. int nBottomOfPanel = nTopOfPanel + GetPanelTall() + OFFSET;
  683. int nCurrentScrollValue = m_pScrollBar->GetValue();
  684. if( nTopOfPanel < nCurrentScrollValue )
  685. {
  686. m_pScrollBar->SetValue(nTopOfPanel);
  687. }
  688. else if( nBottomOfPanel > nCurrentScrollValue+nViewTall )
  689. {
  690. m_pScrollBar->SetValue(nBottomOfPanel-nViewTall);
  691. }
  692. }
  693. Repaint();
  694. }
  695. /*
  696. static void ProcessPSystem( CParticleSnapshotPanel *&pPanel )
  697. {
  698. pPanel->Simulate();
  699. }
  700. */
  701. void CParticleSnapshotGrid::OnTick()
  702. {
  703. // ParallelProcess( m_Panels.Base(), m_Panels.Count(), ProcessPSystem );
  704. for ( int i = 0; i < m_Panels.Count(); ++i )
  705. {
  706. m_Panels[i]->Simulate();
  707. }
  708. }
  709. void CParticleSnapshotGrid::OnParticleSystemSelected( const char *SystemName )
  710. {
  711. SelectSystem( SystemName, false, false );
  712. PostActionSignal( new KeyValues( "ParticleSystemSelectionChanged" ) );
  713. }
  714. void CParticleSnapshotGrid::OnParticleSystemCtrlSelected( const char *SystemName )
  715. {
  716. SelectSystem( SystemName, true, true );
  717. PostActionSignal( new KeyValues( "ParticleSystemSelectionChanged" ) );
  718. }
  719. void CParticleSnapshotGrid::OnParticleSystemShiftSelected( const char *SystemName )
  720. {
  721. int nIdx = InternalFindSystemIndexByName( SystemName );
  722. if ( nIdx != -1 && m_nMostRecentSelectedIndex != -1 )
  723. {
  724. int nFrom = MIN( nIdx, m_nMostRecentSelectedIndex );
  725. int nTo = MAX( nIdx, m_nMostRecentSelectedIndex );
  726. for ( int i = nFrom; i <= nTo; ++i )
  727. {
  728. SelectIndex( i, true, false );
  729. }
  730. PostActionSignal( new KeyValues( "ParticleSystemSelectionChanged" ) );
  731. }
  732. }
  733. int CParticleSnapshotGrid::InternalFindSystemIndexByName( const char *pSystemName )
  734. {
  735. for ( int i = 0; i < m_Panels.Count(); ++i )
  736. {
  737. if ( !V_strcmp(m_Panels[i]->GetSystemName(),pSystemName) )
  738. {
  739. return i;
  740. }
  741. }
  742. return -1;
  743. }
  744. void CParticleSnapshotGrid::OnParticleSystemPicked( const char *SystemName )
  745. {
  746. PostActionSignal( new KeyValues( "ParticleSystemPicked", "SystemName", SystemName ) );
  747. }
  748. int CParticleSnapshotGrid::IdToIndex( int nId )
  749. {
  750. for ( int i = 0; i < m_Panels.Count(); ++i )
  751. {
  752. if ( m_Panels[i]->GetId() == nId )
  753. {
  754. return i;
  755. }
  756. }
  757. return -1;
  758. }
  759. void CParticleSnapshotGrid::OnKeyCodeTyped( vgui::KeyCode code )
  760. {
  761. if ( code == KEY_UP ||
  762. code == KEY_DOWN ||
  763. code == KEY_LEFT ||
  764. code == KEY_RIGHT )
  765. {
  766. if ( m_nMostRecentSelectedIndex != -1 )
  767. {
  768. int nNextIndex = m_nMostRecentSelectedIndex;
  769. if ( code == KEY_UP )
  770. {
  771. nNextIndex -= m_nCurrentColCount;
  772. }
  773. else if ( code == KEY_DOWN )
  774. {
  775. nNextIndex += m_nCurrentColCount;
  776. }
  777. else if ( code == KEY_LEFT )
  778. {
  779. nNextIndex--;
  780. }
  781. else if ( code == KEY_RIGHT )
  782. {
  783. nNextIndex++;
  784. }
  785. int nPanels = m_Panels.Count();
  786. int nCurrentRowCount = (nPanels+m_nCurrentColCount-1)/m_nCurrentColCount;
  787. if ( nNextIndex/m_nCurrentColCount >= nCurrentRowCount-1 &&
  788. nNextIndex >= nPanels )
  789. {
  790. // if you're not on the last row and hit down,
  791. // but nothing is below you, still pop to the last
  792. // item in the list
  793. nNextIndex = nPanels-1;
  794. }
  795. if( nNextIndex >= 0 && nNextIndex < nPanels )
  796. {
  797. SelectIndex( nNextIndex, false, false );
  798. PostActionSignal( new KeyValues( "ParticleSystemSelectionChanged" ) );
  799. RequestFocus();
  800. }
  801. }
  802. }
  803. else
  804. {
  805. BaseClass::OnKeyCodeTyped( code );
  806. }
  807. }
  808. //-----------------------------------------------------------------------------
  809. //
  810. // Particle Picker
  811. //
  812. //-----------------------------------------------------------------------------
  813. static int StringSortHelperI( const char * const *a, const char * const *b )
  814. {
  815. return V_stricmp(*a,*b);
  816. }
  817. void CParticlePicker::OnAssetListChanged( )
  818. {
  819. CUtlVector<const char*> assetNames;
  820. int nCount = GetAssetCount();
  821. for ( int i = 0; i < nCount; ++i )
  822. {
  823. if ( IsAssetVisible( i ) )
  824. {
  825. assetNames.AddToTail( GetAssetName(i) );
  826. }
  827. }
  828. assetNames.Sort( StringSortHelperI );
  829. m_pSnapshotGrid->SetParticleList( assetNames );
  830. }
  831. //-----------------------------------------------------------------------------
  832. // Purpose: Constructor
  833. //-----------------------------------------------------------------------------
  834. CParticlePicker::CParticlePicker( vgui::Panel *pParent ) :
  835. BaseClass( pParent, "Particle Systems", "pcf", "particles", "pcfName" )
  836. {
  837. m_pFileBrowserSplitter = new Splitter( this, "FileBrowserSplitter", SPLITTER_MODE_VERTICAL, 1 );
  838. float flFractions[] = { 0.33f, 0.67f };
  839. m_pFileBrowserSplitter->RespaceSplitters( flFractions );
  840. vgui::Panel *pSplitterLeftSide = m_pFileBrowserSplitter->GetChild( 0 );
  841. vgui::Panel *pSplitterRightSide = m_pFileBrowserSplitter->GetChild( 1 );
  842. pSplitterLeftSide->RequestFocus();
  843. CreateStandardControls( pSplitterLeftSide, false );
  844. AutoLayoutStandardControls();
  845. m_pSnapshotGrid = new CParticleSnapshotGrid( pSplitterRightSide, "ParticleSystemPanel" );
  846. m_pSnapshotGrid->SetAutoResize( PIN_TOPLEFT, AUTORESIZE_DOWNANDRIGHT, 0, 0, 0, 0 );
  847. m_pSnapshotGrid->AddActionSignalTarget(this);
  848. }
  849. //-----------------------------------------------------------------------------
  850. // Purpose: Destructor
  851. //-----------------------------------------------------------------------------
  852. CParticlePicker::~CParticlePicker()
  853. {
  854. }
  855. //-----------------------------------------------------------------------------
  856. // Performs layout
  857. //-----------------------------------------------------------------------------
  858. void CParticlePicker::PerformLayout()
  859. {
  860. // NOTE: This call should cause auto-resize to occur
  861. // which should fix up the width of the panels
  862. BaseClass::PerformLayout();
  863. int w, h;
  864. GetSize( w, h );
  865. // Layout the mdl splitter
  866. m_pFileBrowserSplitter->SetBounds( 0, 0, w, h );
  867. }
  868. //-----------------------------------------------------------------------------
  869. // Buttons on various pages
  870. //-----------------------------------------------------------------------------
  871. void CParticlePicker::OnAssetSelected( KeyValues *pParams )
  872. {
  873. }
  874. //-----------------------------------------------------------------------------
  875. // A particle system was selected
  876. //-----------------------------------------------------------------------------
  877. void CParticlePicker::OnSelectedAssetPicked( const char *pParticleSysName )
  878. {
  879. SelectParticleSys( pParticleSysName );
  880. m_pSnapshotGrid->SelectSystem( pParticleSysName, false, false );
  881. }
  882. void CParticlePicker::OnMousePressed(MouseCode code)
  883. {
  884. SelectParticleSys( "" );
  885. m_pSnapshotGrid->SelectSystem( "", false, false );
  886. }
  887. //-----------------------------------------------------------------------------
  888. // Allows external apps to select a particle system
  889. //-----------------------------------------------------------------------------
  890. void CParticlePicker::SelectParticleSys( const char *pRelativePath )
  891. {
  892. PostActionSignal( new KeyValues( "SelectedParticleSysChanged", "particle", pRelativePath ? pRelativePath : "" ) );
  893. }
  894. void CParticlePicker::GetSelectedParticleSysName( char *pBuffer, int nMaxLen )
  895. {
  896. Assert( nMaxLen > 0 );
  897. if ( GetSelectedAssetCount() > 0 )
  898. {
  899. Q_snprintf( pBuffer, nMaxLen, "%s", GetSelectedAsset() );
  900. }
  901. else
  902. {
  903. pBuffer[0] = 0;
  904. }
  905. }
  906. void CParticlePicker::OnParticleSystemSelectionChanged()
  907. {
  908. const char *SystemName = m_pSnapshotGrid->GetSystemName( m_pSnapshotGrid->GetSelectedSystemId(0) );
  909. SetSelection( SystemName );
  910. }
  911. void CParticlePicker::OnParticleSystemPicked( const char *SystemName )
  912. {
  913. OnKeyCodeTyped(KEY_ENTER);
  914. }
  915. int CParticlePicker::GetAssetCount()
  916. {
  917. return sCacheParticleList.Count();
  918. }
  919. const char *CParticlePicker::GetAssetName( int nAssetIndex )
  920. {
  921. return sCacheParticleList[nAssetIndex].m_AssetInfo.m_AssetName;
  922. }
  923. const CachedAssetInfo_t& CParticlePicker::GetCachedAsset( int nAssetIndex )
  924. {
  925. return sCacheParticleList[nAssetIndex].m_AssetInfo;
  926. }
  927. int CParticlePicker::GetCachedAssetCount()
  928. {
  929. return sCacheParticleList.Count();
  930. }
  931. void CParticlePicker::CachePCFInfo( int nModIndex, const char *pFileName )
  932. {
  933. const CacheModInfo_t& modInfo = ModInfo(nModIndex);
  934. if ( pFileName[0] == '!' )
  935. {
  936. ++pFileName;
  937. }
  938. CUtlBuffer buf;
  939. CUtlString pcfPath = modInfo.m_Path;
  940. pcfPath += "/";
  941. pcfPath += pFileName;
  942. // cache the particles into the manager
  943. g_pParticleSystemMgr->ReadParticleConfigFile( pcfPath, true );
  944. // and read it ourselves to see what came out
  945. if ( !g_pFullFileSystem->ReadFile( pcfPath, modInfo.m_Path, buf ) )
  946. {
  947. return;
  948. }
  949. DECLARE_DMX_CONTEXT_DECOMMIT( true );
  950. CDmxElement *pRoot;
  951. if ( !UnserializeDMX( buf, &pRoot, pFileName ) )
  952. {
  953. return;
  954. }
  955. if ( !Q_stricmp( pRoot->GetTypeString(), "DmeParticleSystemDefinition" ) )
  956. {
  957. CachedParticleInfo_t &info = sCacheParticleList[sCacheParticleList.AddToTail()];
  958. info.m_AssetInfo.m_AssetName = pRoot->GetName();
  959. info.m_AssetInfo.m_nModIndex = nModIndex;
  960. info.m_FileName = pFileName;
  961. return;
  962. }
  963. const CDmxAttribute *pDefinitions = pRoot->GetAttribute( "particleSystemDefinitions" );
  964. if ( !pDefinitions || pDefinitions->GetType() != AT_ELEMENT_ARRAY )
  965. {
  966. CleanupDMX( pRoot );
  967. return;
  968. }
  969. const CUtlVector< CDmxElement* >& definitions = pDefinitions->GetArray<CDmxElement*>( );
  970. int nCount = definitions.Count();
  971. for ( int i = 0; i < nCount; ++i )
  972. {
  973. CachedParticleInfo_t &info = sCacheParticleList[sCacheParticleList.AddToTail()];
  974. info.m_AssetInfo.m_AssetName = definitions[i]->GetName();
  975. info.m_AssetInfo.m_nModIndex = nModIndex;
  976. info.m_FileName = pFileName;
  977. }
  978. CleanupDMX( pRoot );
  979. }
  980. void CParticlePicker::HandleModParticles( int nModIndex )
  981. {
  982. const CacheModInfo_t &modInfo = ModInfo(nModIndex);
  983. CUtlString manifestPath = modInfo.m_Path;
  984. manifestPath += "/particles/particles_manifest.txt" ;
  985. CUtlVector<CUtlString> pcfList;
  986. GetParticleManifest( pcfList, manifestPath );
  987. int nCount = pcfList.Count();
  988. for ( int i = 0; i < nCount; ++i )
  989. {
  990. PCFToLoad_t &p = sCacheUnloadedPCFs[sCacheUnloadedPCFs.AddToTail()];
  991. p.m_FileName = pcfList[i];
  992. p.m_ModId = nModIndex;
  993. }
  994. }
  995. bool CParticlePicker::BeginCacheAssets( bool bForceRecache )
  996. {
  997. if ( bForceRecache )
  998. {
  999. sCacheParticleList.RemoveAll();
  1000. sCacheUnloadedPCFs.RemoveAll();
  1001. }
  1002. if ( sCacheParticleList.Count() )
  1003. {
  1004. return true;
  1005. }
  1006. int nCount = ModCount();
  1007. for ( int i = 0; i < nCount; ++i )
  1008. {
  1009. HandleModParticles( i );
  1010. }
  1011. return false;
  1012. }
  1013. bool CParticlePicker::IncrementalCacheAssets( float flTimeAllowed )
  1014. {
  1015. float flStartTime = Plat_FloatTime();
  1016. while ( sCacheUnloadedPCFs.Count() )
  1017. {
  1018. PCFToLoad_t &p = sCacheUnloadedPCFs.Tail();
  1019. CachePCFInfo( p.m_ModId, p.m_FileName );
  1020. sCacheUnloadedPCFs.RemoveMultipleFromTail(1);
  1021. // might have run out of time
  1022. if ( Plat_FloatTime() - flStartTime >= flTimeAllowed )
  1023. break;
  1024. }
  1025. return (sCacheUnloadedPCFs.Count() == 0);
  1026. }
  1027. CUtlString CParticlePicker::GetSelectedAssetFullPath( int nSelectionIndex )
  1028. {
  1029. int nAssetIndex = GetSelectedAssetIndex( nSelectionIndex );
  1030. if( nAssetIndex < 0 || nAssetIndex >= sCacheParticleList.Count() )
  1031. {
  1032. return CUtlString("ERROR");
  1033. }
  1034. CachedParticleInfo_t &p = sCacheParticleList[nAssetIndex];
  1035. const CacheModInfo_t &m = ModInfo( p.m_AssetInfo.m_nModIndex );
  1036. char pBuf[MAX_PATH+128];
  1037. Q_snprintf( pBuf, sizeof(pBuf), "%s\\%s::%s",
  1038. m.m_Path.Get(), p.m_FileName.Get(), p.m_AssetInfo.m_AssetName.Get() );
  1039. Q_FixSlashes( pBuf );
  1040. return CUtlString(pBuf);
  1041. }
  1042. //-----------------------------------------------------------------------------
  1043. //
  1044. // Purpose: Modal picker frame
  1045. //
  1046. //-----------------------------------------------------------------------------
  1047. CParticlePickerFrame::CParticlePickerFrame( vgui::Panel *pParent, const char *pTitle ) :
  1048. BaseClass( pParent )
  1049. {
  1050. SetAssetPicker( new CParticlePicker( this ) );
  1051. LoadControlSettingsAndUserConfig( "resource/mdlpickerframe.res" );
  1052. SetTitle( pTitle, false );
  1053. }
  1054. CParticlePickerFrame::~CParticlePickerFrame()
  1055. {
  1056. }
  1057. void CParticlePickerFrame::SelectParticleSys( const char *pRelativePath )
  1058. {
  1059. static_cast<CParticlePicker*>( GetAssetPicker() )->SelectParticleSys( pRelativePath );
  1060. }