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.

2772 lines
63 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "client_pch.h"
  8. #include "cl_demosmootherpanel.h"
  9. #include <vgui_controls/Button.h>
  10. #include <vgui_controls/CheckButton.h>
  11. #include <vgui_controls/Label.h>
  12. #include <vgui_controls/Controls.h>
  13. #include <vgui/ISystem.h>
  14. #include <vgui/ISurface.h>
  15. #include <vgui_controls/PropertySheet.h>
  16. #include <vgui/IVGui.h>
  17. #include <vgui_controls/FileOpenDialog.h>
  18. #include <vgui_controls/ProgressBar.h>
  19. #include <vgui_controls/ListPanel.h>
  20. #include <vgui_controls/MenuButton.h>
  21. #include <vgui_controls/Menu.h>
  22. #include <vgui_controls/TextEntry.h>
  23. #include <vgui/IInput.h>
  24. #include "cl_demouipanel.h"
  25. #include "demofile/demoformat.h"
  26. #include "cl_demoactionmanager.h"
  27. #include "tier2/renderutils.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include "tier0/memdbgon.h"
  30. using namespace vgui;
  31. static float Ease_In( float t )
  32. {
  33. float out = sqrt( t );
  34. return out;
  35. }
  36. static float Ease_Out( float t )
  37. {
  38. float out = t * t;
  39. return out;
  40. }
  41. static float Ease_Both( float t )
  42. {
  43. return SimpleSpline( t );
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Purpose: A menu button that knows how to parse cvar/command menu data from gamedir\scripts\debugmenu.txt
  47. //-----------------------------------------------------------------------------
  48. class CSmoothingTypeButton : public vgui::MenuButton
  49. {
  50. typedef vgui::MenuButton BaseClass;
  51. public:
  52. // Construction
  53. CSmoothingTypeButton( vgui::Panel *parent, const char *panelName, const char *text );
  54. private:
  55. // Menu associated with this button
  56. Menu *m_pMenu;
  57. };
  58. //-----------------------------------------------------------------------------
  59. // Purpose: Constructor
  60. //-----------------------------------------------------------------------------
  61. CSmoothingTypeButton::CSmoothingTypeButton(Panel *parent, const char *panelName, const char *text)
  62. : BaseClass( parent, panelName, text )
  63. {
  64. // Assume no menu
  65. m_pMenu = new Menu( this, "DemoSmootherTypeMenu" );
  66. m_pMenu->AddMenuItem( "Smooth Selection Angles", "smoothselectionangles", parent );
  67. m_pMenu->AddMenuItem( "Smooth Selection Origin", "smoothselectionorigin", parent );
  68. m_pMenu->AddMenuItem( "Linear Interp Angles", "smoothlinearinterpolateangles", parent );
  69. m_pMenu->AddMenuItem( "Linear Interp Origin", "smoothlinearinterpolateorigin", parent );
  70. m_pMenu->AddMenuItem( "Spline Angles", "splineangles", parent );
  71. m_pMenu->AddMenuItem( "Spline Origin", "splineorigin", parent );
  72. m_pMenu->AddMenuItem( "Look At Points", "lookatpoints", parent );
  73. m_pMenu->AddMenuItem( "Look At Points Spline", "lookatpointsspline", parent );
  74. m_pMenu->AddMenuItem( "Two Point Origin Ease Out", "origineaseout", parent );
  75. m_pMenu->AddMenuItem( "Two Point Origin Ease In", "origineasein", parent );
  76. m_pMenu->AddMenuItem( "Two Point Origin Ease In/Out", "origineaseboth", parent );
  77. m_pMenu->AddMenuItem( "Auto-setup keys 1/2 second", "keyshalf", parent );
  78. m_pMenu->AddMenuItem( "Auto-setup keys 1 second", "keys1", parent );
  79. m_pMenu->AddMenuItem( "Auto-setup keys 2 second", "keys2", parent );
  80. m_pMenu->AddMenuItem( "Auto-setup keys 4 second", "keys4", parent );
  81. m_pMenu->MakePopup();
  82. MenuButton::SetMenu(m_pMenu);
  83. SetOpenDirection(Menu::UP);
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose: A menu button that knows how to parse cvar/command menu data from gamedir\scripts\debugmenu.txt
  87. //-----------------------------------------------------------------------------
  88. class CFixEdgeButton : public vgui::MenuButton
  89. {
  90. typedef vgui::MenuButton BaseClass;
  91. public:
  92. // Construction
  93. CFixEdgeButton( vgui::Panel *parent, const char *panelName, const char *text );
  94. private:
  95. // Menu associated with this button
  96. Menu *m_pMenu;
  97. };
  98. //-----------------------------------------------------------------------------
  99. // Purpose: Constructor
  100. //-----------------------------------------------------------------------------
  101. CFixEdgeButton::CFixEdgeButton(Panel *parent, const char *panelName, const char *text)
  102. : BaseClass( parent, panelName, text )
  103. {
  104. // Assume no menu
  105. m_pMenu = new Menu( this, "DemoSmootherEdgeFixType" );
  106. m_pMenu->AddMenuItem( "Smooth Left", "smoothleft", parent );
  107. m_pMenu->AddMenuItem( "Smooth Right", "smoothright", parent );
  108. m_pMenu->AddMenuItem( "Smooth Both", "smoothboth", parent );
  109. m_pMenu->MakePopup();
  110. MenuButton::SetMenu(m_pMenu);
  111. SetOpenDirection(Menu::UP);
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose: Basic help dialog
  115. //-----------------------------------------------------------------------------
  116. CDemoSmootherPanel::CDemoSmootherPanel( vgui::Panel *parent ) : Frame( parent, "DemoSmootherPanel")
  117. {
  118. int w = 440;
  119. int h = 300;
  120. SetSize( w, h );
  121. SetTitle("Demo Smoother", true);
  122. m_pType = new CSmoothingTypeButton( this, "DemoSmootherType", "Process->" );
  123. m_pRevert = new vgui::Button( this, "DemoSmoothRevert", "Revert" );;
  124. m_pOK = new vgui::Button( this, "DemoSmoothOk", "OK" );
  125. m_pCancel = new vgui::Button( this, "DemoSmoothCancel", "Cancel" );
  126. m_pSave = new vgui::Button( this, "DemoSmoothSave", "Save" );
  127. m_pReloadFromDisk = new vgui::Button( this, "DemoSmoothReload", "Reload" );
  128. m_pStartFrame = new vgui::TextEntry( this, "DemoSmoothStartFrame" );
  129. m_pEndFrame = new vgui::TextEntry( this, "DemoSmoothEndFrame" );
  130. m_pPreviewOriginal = new vgui::Button( this, "DemoSmoothPreviewOriginal", "Show Original" );
  131. m_pPreviewProcessed = new vgui::Button( this, "DemoSmoothPreviewProcessed", "Show Processed" );
  132. m_pBackOff = new vgui::CheckButton( this, "DemoSmoothBackoff", "Back off" );
  133. m_pHideLegend = new vgui::CheckButton( this, "DemoSmoothHideLegend", "Hide legend" );
  134. m_pHideOriginal = new vgui::CheckButton( this, "DemoSmoothHideOriginal", "Hide original" );
  135. m_pHideProcessed = new vgui::CheckButton( this, "DemoSmoothHideProcessed", "Hide processed" );
  136. m_pSelectionInfo = new vgui::Label( this, "DemoSmoothSelectionInfo", "" );
  137. m_pShowAllSamples = new vgui::CheckButton( this, "DemoSmoothShowAll", "Show All" );
  138. m_pSelectSamples = new vgui::Button( this, "DemoSmoothSelect", "Select" );
  139. m_pPauseResume = new vgui::Button( this, "DemoSmoothPauseResume", "Pause" );
  140. m_pStepForward = new vgui::Button( this, "DemoSmoothStepForward", ">>" );
  141. m_pStepBackward = new vgui::Button( this, "DemoSmoothStepBackward", "<<" );
  142. m_pRevertPoint = new vgui::Button( this, "DemoSmoothRevertPoint", "Revert Pt." );
  143. m_pToggleKeyFrame = new vgui::Button( this, "DemoSmoothSetKeyFrame", "Mark Keyframe" );
  144. m_pToggleLookTarget = new vgui::Button( this, "DemoSmoothSetLookTarget", "Mark Look Target" );
  145. m_pUndo = new vgui::Button( this, "DemoSmoothUndo", "Undo" );
  146. m_pRedo = new vgui::Button( this, "DemoSmoothRedo", "Redo" );
  147. m_pNextKey = new vgui::Button( this, "DemoSmoothNextKey", "+Key" );
  148. m_pPrevKey = new vgui::Button( this, "DemoSmoothPrevKey", "-Key" );
  149. m_pNextTarget = new vgui::Button( this, "DemoSmoothNextTarget", "+Target" );
  150. m_pPrevTarget = new vgui::Button( this, "DemoSmoothPrevTarget", "-Target" );
  151. m_pMoveCameraToPoint = new vgui::Button( this, "DemoSmoothCameraAtPoint", "Set View" );
  152. m_pFixEdges = new CFixEdgeButton( this, "DemoSmoothFixFrameButton", "Edge->" );
  153. m_pFixEdgeFrames = new vgui::TextEntry( this, "DemoSmoothFixFrames" );
  154. m_pProcessKey = new vgui::Button( this, "DemoSmoothSaveKey", "Save Key" );
  155. m_pGotoFrame = new vgui::TextEntry( this, "DemoSmoothGotoFrame" );
  156. m_pGoto = new vgui::Button( this, "DemoSmoothGoto", "Jump To" );
  157. //m_pCurrentDemo = new vgui::Label( this, "DemoName", "" );
  158. vgui::ivgui()->AddTickSignal( GetVPanel(), 0 );
  159. LoadControlSettings("Resource\\DemoSmootherPanel.res");
  160. /*
  161. int xpos, ypos;
  162. parent->GetPos( xpos, ypos );
  163. ypos += parent->GetTall();
  164. SetPos( xpos, ypos );
  165. */
  166. OnRefresh();
  167. SetVisible( true );
  168. SetSizeable( false );
  169. SetMoveable( true );
  170. Reset();
  171. m_vecEyeOffset = Vector( 0, 0, 64 );
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose:
  175. //-----------------------------------------------------------------------------
  176. CDemoSmootherPanel::~CDemoSmootherPanel()
  177. {
  178. }
  179. void CDemoSmootherPanel::Reset( void )
  180. {
  181. ClearSmoothingInfo( m_Smoothing );
  182. m_bPreviewing = false;
  183. m_bPreviewPaused = false;
  184. m_bPreviewOriginal = false;
  185. m_iPreviewStartTick = 0;
  186. m_fPreviewCurrentTime = 0.0f;
  187. m_nPreviewLastFrame = 0;
  188. m_bHasSelection = false;
  189. memset( m_nSelection, 0, sizeof( m_nSelection ) );
  190. m_iSelectionTicksSpan = 0;
  191. m_bInputActive = false;
  192. memset( m_nOldCursor, 0, sizeof( m_nOldCursor ) );
  193. WipeUndo();
  194. WipeRedo();
  195. m_bRedoPending = false;
  196. m_nUndoLevel = 0;
  197. m_bDirty = false;
  198. }
  199. void CDemoSmootherPanel::OnTick()
  200. {
  201. BaseClass::OnTick();
  202. m_pUndo->SetEnabled( CanUndo() );
  203. m_pRedo->SetEnabled( CanRedo() );
  204. m_pPauseResume->SetEnabled( m_bPreviewing );
  205. m_pStepForward->SetEnabled( m_bPreviewing );
  206. m_pStepBackward->SetEnabled( m_bPreviewing );
  207. m_pSave->SetEnabled( m_bDirty );
  208. demosmoothing_t *p = GetCurrent();
  209. if ( p )
  210. {
  211. m_pToggleKeyFrame->SetEnabled( true );
  212. m_pToggleLookTarget->SetEnabled( true );
  213. m_pToggleKeyFrame->SetText( p->samplepoint ? "Delete Key" : "Make Key" );
  214. m_pToggleLookTarget->SetText( p->targetpoint ? "Delete Target" : "Make Target" );
  215. m_pProcessKey->SetEnabled( p->samplepoint );
  216. }
  217. else
  218. {
  219. m_pToggleKeyFrame->SetEnabled( false );
  220. m_pToggleLookTarget->SetEnabled( false );
  221. m_pProcessKey->SetEnabled( false );
  222. }
  223. if ( m_bPreviewing )
  224. {
  225. m_pPauseResume->SetText( m_bPreviewPaused ? "Resume" : "Pause" );
  226. }
  227. if ( !m_Smoothing.active )
  228. {
  229. m_pSelectionInfo->SetText( "No smoothing info loaded" );
  230. return;
  231. }
  232. if ( !demoplayer->IsPlayingBack() )
  233. {
  234. m_pSelectionInfo->SetText( "Not playing back .dem" );
  235. return;
  236. }
  237. if ( !m_bHasSelection )
  238. {
  239. m_pSelectionInfo->SetText( "No selection." );
  240. return;
  241. }
  242. char sz[ 512 ];
  243. if ( m_bPreviewing )
  244. {
  245. Q_snprintf( sz, sizeof( sz ), "%.3f at tick %i (%.3f s)",
  246. m_fPreviewCurrentTime,
  247. GetTickForFrame( m_nPreviewLastFrame ),
  248. TICKS_TO_TIME( m_iSelectionTicksSpan ) );
  249. }
  250. else
  251. {
  252. Q_snprintf( sz, sizeof( sz ), "%i to %i (%.3f s)",
  253. m_Smoothing.smooth[ m_nSelection[ 0 ] ].frametick,
  254. m_Smoothing.smooth[ m_nSelection[ 1 ] ].frametick,
  255. TICKS_TO_TIME( m_iSelectionTicksSpan ) );
  256. }
  257. m_pSelectionInfo->SetText( sz );
  258. }
  259. //-----------------------------------------------------------------------------
  260. // Purpose:
  261. // Output : Returns true on success, false on failure.
  262. //-----------------------------------------------------------------------------
  263. bool CDemoSmootherPanel::CanEdit()
  264. {
  265. if ( !m_Smoothing.active )
  266. return false;
  267. if ( !demoplayer->IsPlayingBack() )
  268. return false;
  269. return true;
  270. }
  271. //-----------------------------------------------------------------------------
  272. // Purpose:
  273. // Input : *command -
  274. //-----------------------------------------------------------------------------
  275. void CDemoSmootherPanel::OnCommand(const char *command)
  276. {
  277. if ( !Q_strcasecmp( command, "cancel" ) )
  278. {
  279. OnRevert();
  280. MarkForDeletion();
  281. Reset();
  282. OnClose();
  283. }
  284. else if ( !Q_strcasecmp( command, "close" ) )
  285. {
  286. OnSave();
  287. MarkForDeletion();
  288. Reset();
  289. OnClose();
  290. }
  291. else if ( !Q_strcasecmp( command, "gotoframe" ) )
  292. {
  293. OnGotoFrame();
  294. }
  295. else if ( !Q_strcasecmp( command, "undo" ) )
  296. {
  297. Undo();
  298. }
  299. else if ( !Q_strcasecmp( command, "redo" ) )
  300. {
  301. Redo();
  302. }
  303. else if ( !Q_strcasecmp( command, "revert" ) )
  304. {
  305. OnRevert();
  306. }
  307. else if ( !Q_strcasecmp( command, "original" ) )
  308. {
  309. OnPreview( true );
  310. }
  311. else if ( !Q_strcasecmp( command, "processed" ) )
  312. {
  313. OnPreview( false );
  314. }
  315. else if ( !Q_strcasecmp( command, "save" ) )
  316. {
  317. OnSave();
  318. }
  319. else if ( !Q_strcasecmp( command, "reload" ) )
  320. {
  321. OnReload();
  322. }
  323. else if ( !Q_strcasecmp( command, "select" ) )
  324. {
  325. OnSelect();
  326. }
  327. else if ( !Q_strcasecmp( command, "togglepause" ) )
  328. {
  329. OnTogglePause();
  330. }
  331. else if ( !Q_strcasecmp( command, "stepforward" ) )
  332. {
  333. OnStep( true );
  334. }
  335. else if ( !Q_strcasecmp( command, "stepbackward" ) )
  336. {
  337. OnStep( false );
  338. }
  339. else if ( !Q_strcasecmp( command, "revertpoint" ) )
  340. {
  341. OnRevertPoint();
  342. }
  343. else if ( !Q_strcasecmp( command, "keyframe" ) )
  344. {
  345. OnToggleKeyFrame();
  346. }
  347. else if ( !Q_strcasecmp( command, "looktarget" ) )
  348. {
  349. OnToggleLookTarget();
  350. }
  351. else if ( !Q_strcasecmp( command, "nextkey" ) )
  352. {
  353. OnNextKey();
  354. }
  355. else if ( !Q_strcasecmp( command, "prevkey" ) )
  356. {
  357. OnPrevKey();
  358. }
  359. else if ( !Q_strcasecmp( command, "nexttarget" ) )
  360. {
  361. OnNextTarget();
  362. }
  363. else if ( !Q_strcasecmp( command, "prevtarget" ) )
  364. {
  365. OnPrevTarget();
  366. }
  367. else if ( !Q_strcasecmp( command, "smoothselectionangles" ) )
  368. {
  369. OnSmoothSelectionAngles();
  370. }
  371. else if ( !Q_strcasecmp( command, "keyshalf" ) )
  372. {
  373. OnSetKeys( 0.5f );
  374. }
  375. else if ( !Q_strcasecmp( command, "keys1" ) )
  376. {
  377. OnSetKeys( 1.0f );
  378. }
  379. else if ( !Q_strcasecmp( command, "keys2" ) )
  380. {
  381. OnSetKeys( 2.0f );
  382. }
  383. else if ( !Q_strcasecmp( command, "keys4" ) )
  384. {
  385. OnSetKeys( 4.0f );
  386. }
  387. else if ( !Q_strcasecmp( command, "smoothselectionorigin" ) )
  388. {
  389. OnSmoothSelectionOrigin();
  390. }
  391. else if ( !Q_strcasecmp( command, "smoothlinearinterpolateangles" ) )
  392. {
  393. OnLinearInterpolateAnglesBasedOnEndpoints();
  394. }
  395. else if ( !Q_strcasecmp( command, "smoothlinearinterpolateorigin" ) )
  396. {
  397. OnLinearInterpolateOriginBasedOnEndpoints();
  398. }
  399. else if ( !Q_strcasecmp( command, "splineorigin" ) )
  400. {
  401. OnSplineSampleOrigin();
  402. }
  403. else if ( !Q_strcasecmp( command, "splineangles" ) )
  404. {
  405. OnSplineSampleAngles();
  406. }
  407. else if ( !Q_strcasecmp( command, "lookatpoints" ) )
  408. {
  409. OnLookAtPoints( false );
  410. }
  411. else if ( !Q_strcasecmp( command, "lookatpointsspline" ) )
  412. {
  413. OnLookAtPoints( true );
  414. }
  415. else if ( !Q_strcasecmp( command, "smoothleft" ) )
  416. {
  417. OnSmoothEdges( true, false );
  418. }
  419. else if ( !Q_strcasecmp( command, "smoothright" ) )
  420. {
  421. OnSmoothEdges( false, true );
  422. }
  423. else if ( !Q_strcasecmp( command, "smoothboth" ) )
  424. {
  425. OnSmoothEdges( true, true );
  426. }
  427. else if ( !Q_strcasecmp( command, "origineasein" ) )
  428. {
  429. OnOriginEaseCurve( Ease_In );
  430. }
  431. else if ( !Q_strcasecmp( command, "origineaseout" ) )
  432. {
  433. OnOriginEaseCurve( Ease_Out );
  434. }
  435. else if ( !Q_strcasecmp( command, "origineaseboth" ) )
  436. {
  437. OnOriginEaseCurve( Ease_Both );
  438. }
  439. else if ( !Q_strcasecmp( command, "processkey" ) )
  440. {
  441. OnSaveKey();
  442. }
  443. else if ( !Q_strcasecmp( command, "setview" ) )
  444. {
  445. OnSetView();
  446. }
  447. else
  448. {
  449. BaseClass::OnCommand( command );
  450. }
  451. }
  452. //-----------------------------------------------------------------------------
  453. // Purpose:
  454. //-----------------------------------------------------------------------------
  455. void CDemoSmootherPanel::OnSave()
  456. {
  457. if ( !m_Smoothing.active )
  458. return;
  459. SaveSmoothingInfo( demoaction->GetCurrentDemoFile(), m_Smoothing );
  460. WipeUndo();
  461. m_bDirty = false;
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Purpose:
  465. //-----------------------------------------------------------------------------
  466. void CDemoSmootherPanel::OnReload()
  467. {
  468. WipeUndo();
  469. WipeRedo();
  470. LoadSmoothingInfo( demoaction->GetCurrentDemoFile(), m_Smoothing );
  471. m_bDirty = false;
  472. }
  473. //-----------------------------------------------------------------------------
  474. // Purpose:
  475. //-----------------------------------------------------------------------------
  476. void CDemoSmootherPanel::OnVDMChanged( void )
  477. {
  478. if ( IsVisible() )
  479. {
  480. OnReload();
  481. }
  482. else
  483. {
  484. Reset();
  485. }
  486. }
  487. //-----------------------------------------------------------------------------
  488. // Purpose:
  489. //-----------------------------------------------------------------------------
  490. void CDemoSmootherPanel::OnRevert()
  491. {
  492. OnRefresh();
  493. if ( !m_Smoothing.active )
  494. {
  495. LoadSmoothingInfo( demoaction->GetCurrentDemoFile(), m_Smoothing );
  496. WipeUndo();
  497. WipeRedo();
  498. }
  499. else
  500. {
  501. ClearSmoothingInfo( m_Smoothing );
  502. WipeUndo();
  503. WipeRedo();
  504. }
  505. m_bDirty = false;
  506. }
  507. //-----------------------------------------------------------------------------
  508. // Purpose:
  509. //-----------------------------------------------------------------------------
  510. void CDemoSmootherPanel::OnRefresh()
  511. {
  512. }
  513. //-----------------------------------------------------------------------------
  514. // Purpose:
  515. // Input : *pScheme -
  516. //-----------------------------------------------------------------------------
  517. void CDemoSmootherPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  518. {
  519. BaseClass::ApplySchemeSettings( pScheme );
  520. }
  521. //-----------------------------------------------------------------------------
  522. // Purpose:
  523. // Output : int
  524. //-----------------------------------------------------------------------------
  525. int CDemoSmootherPanel::GetStartFrame()
  526. {
  527. char text[ 32 ];
  528. m_pStartFrame->GetText( text, sizeof( text ) );
  529. int tick = atoi( text );
  530. return GetFrameForTick( tick );
  531. }
  532. //-----------------------------------------------------------------------------
  533. // Purpose:
  534. // Output : int
  535. //-----------------------------------------------------------------------------
  536. int CDemoSmootherPanel::GetEndFrame()
  537. {
  538. char text[ 32 ];
  539. m_pEndFrame->GetText( text, sizeof( text ) );
  540. int tick = atoi( text );
  541. return GetFrameForTick( tick );
  542. }
  543. //-----------------------------------------------------------------------------
  544. // Purpose:
  545. // Input : original -
  546. //-----------------------------------------------------------------------------
  547. void CDemoSmootherPanel::OnPreview( bool original )
  548. {
  549. if ( !CanEdit() )
  550. return;
  551. if ( !m_bHasSelection )
  552. {
  553. ConMsg( "Must have smoothing selection active\n" );
  554. return;
  555. }
  556. m_bPreviewing = true;
  557. m_bPreviewPaused = false;
  558. m_bPreviewOriginal = original;
  559. SetLastFrame( false, MAX( 0, m_nSelection[0] - 10 ) );
  560. m_iPreviewStartTick = GetTickForFrame( m_nPreviewLastFrame );
  561. m_fPreviewCurrentTime = TICKS_TO_TIME( m_iPreviewStartTick );
  562. }
  563. //-----------------------------------------------------------------------------
  564. // Purpose:
  565. // Input : frame -
  566. // elapsed -
  567. // info -
  568. // Output : Returns true on success, false on failure.
  569. //-----------------------------------------------------------------------------
  570. bool CDemoSmootherPanel::OverrideView( democmdinfo_t& info, int tick )
  571. {
  572. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  573. int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
  574. if ( nSlot != 0 )
  575. return false;
  576. if ( !CanEdit() )
  577. return false;
  578. if ( !demoplayer->IsPlaybackPaused() )
  579. return false;
  580. if ( m_bPreviewing )
  581. {
  582. if ( m_bPreviewPaused && GetCurrent() && GetCurrent()->samplepoint )
  583. {
  584. info.u[ nSlot ].viewOrigin = GetCurrent()->vecmoved;
  585. info.u[ nSlot ].viewAngles = GetCurrent()->angmoved;
  586. info.u[ nSlot ].localViewAngles = info.u[ nSlot ].viewAngles;
  587. bool back_off = m_pBackOff->IsSelected();
  588. if ( back_off )
  589. {
  590. Vector fwd;
  591. AngleVectors( info.u[ nSlot ].viewAngles, &fwd, NULL, NULL );
  592. info.u[ nSlot ].viewOrigin -= fwd * 75.0f;
  593. }
  594. return true;
  595. }
  596. // TODO: Hook up previewing view
  597. if ( !m_bPreviewPaused )
  598. {
  599. m_fPreviewCurrentTime += host_frametime;
  600. }
  601. if ( GetInterpolatedViewPoint( nSlot, info.u[ nSlot ].viewOrigin, info.u[ nSlot ].viewAngles ) )
  602. {
  603. info.u[ nSlot ].localViewAngles = info.u[ nSlot ].viewAngles;
  604. return true;
  605. }
  606. else
  607. {
  608. return false;
  609. }
  610. }
  611. bool back_off = m_pBackOff->IsSelected();
  612. if ( back_off )
  613. {
  614. int useframe = GetFrameForTick( tick );
  615. if ( useframe < m_Smoothing.smooth.Count() && useframe >= 0 )
  616. {
  617. demosmoothing_t *p = &m_Smoothing.smooth[ useframe ];
  618. Vector fwd;
  619. AngleVectors( p->info.u[ nSlot ].viewAngles, &fwd, NULL, NULL );
  620. info.u[ nSlot ].viewOrigin = p->info.u[ nSlot ].viewOrigin - fwd * 75.0f;
  621. }
  622. }
  623. return false;
  624. }
  625. void DrawVecForward( bool active, const Vector& origin, const QAngle& angles, int r, int g, int b )
  626. {
  627. Vector fwd;
  628. AngleVectors( angles, &fwd, NULL, NULL );
  629. Vector end;
  630. end = origin + fwd * ( active ? 64 : 16 );
  631. RenderLine( origin, end, Color( r, g, b, 255 ), true );
  632. }
  633. void GetColorForSample( bool original, bool samplepoint, bool targetpoint, demosmoothing_t *sample, int& r, int& g, int& b )
  634. {
  635. if ( samplepoint && sample->samplepoint )
  636. {
  637. r = 0;
  638. g = 255;
  639. b = 0;
  640. return;
  641. }
  642. if ( targetpoint && sample->targetpoint )
  643. {
  644. r = 255;
  645. g = 0;
  646. b = 0;
  647. return;
  648. }
  649. if ( sample->selected )
  650. {
  651. if( original )
  652. {
  653. r = 255;
  654. g = 200;
  655. b = 100;
  656. }
  657. else
  658. {
  659. r = 200;
  660. g = 100;
  661. b = 255;
  662. }
  663. if ( sample->samplepoint || sample->targetpoint )
  664. {
  665. r = 255;
  666. g = 255;
  667. b = 0;
  668. }
  669. return;
  670. }
  671. if ( original )
  672. {
  673. r = g = b = 255;
  674. }
  675. else
  676. {
  677. r = 150;
  678. g = 255;
  679. b = 100;
  680. }
  681. }
  682. //-----------------------------------------------------------------------------
  683. // Purpose:
  684. // Input : origin -
  685. // mins -
  686. // maxs -
  687. // angles -
  688. // r -
  689. // g -
  690. // b -
  691. // a -
  692. //-----------------------------------------------------------------------------
  693. void Draw_Box( const Vector& origin, const Vector& mins, const Vector& maxs, const QAngle& angles, int r, int g, int b, int a )
  694. {
  695. RenderBox( origin, angles, mins, maxs, Color( r, g, b, a ), false );
  696. RenderWireframeBox( origin, angles, mins, maxs, Color( r, g, b, a ), true );
  697. }
  698. //-----------------------------------------------------------------------------
  699. // Purpose:
  700. // Input : *sample -
  701. // *next -
  702. //-----------------------------------------------------------------------------
  703. void CDemoSmootherPanel::DrawSmoothingSample( bool original, bool processed, int samplenumber, demosmoothing_t *sample, demosmoothing_t *next )
  704. {
  705. int r, g, b;
  706. int nSlot = 0;
  707. if ( original )
  708. {
  709. RenderLine( sample->info.u[ nSlot ].viewOrigin + m_vecEyeOffset, next->info.u[ nSlot ].viewOrigin + m_vecEyeOffset,
  710. Color( 180, 180, 180, 255 ), true );
  711. GetColorForSample( true, false, false, sample, r, g, b );
  712. DrawVecForward( false, sample->info.u[ nSlot ].viewOrigin + m_vecEyeOffset, sample->info.u[ nSlot ].viewAngles, r, g, b );
  713. }
  714. if ( processed && sample->info.u[ nSlot ].flags != 0 )
  715. {
  716. RenderLine( sample->info.u[ nSlot ].GetViewOrigin() + m_vecEyeOffset, next->info.u[ nSlot ].GetViewOrigin() + m_vecEyeOffset,
  717. Color( 255, 255, 180, 255 ), true );
  718. GetColorForSample( false, false, false, sample, r, g, b );
  719. DrawVecForward( false, sample->info.u[ nSlot ].GetViewOrigin() + m_vecEyeOffset, sample->info.u[ nSlot ].GetViewAngles(), r, g, b );
  720. }
  721. if ( sample->samplepoint )
  722. {
  723. GetColorForSample( false, true, false, sample, r, g, b );
  724. RenderBox( sample->vecmoved + m_vecEyeOffset, sample->angmoved, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), Color( r, g, b, 127 ), false );
  725. DrawVecForward( false, sample->vecmoved + m_vecEyeOffset, sample->angmoved, r, g, b );
  726. }
  727. if ( sample->targetpoint )
  728. {
  729. GetColorForSample( false, false, true, sample, r, g, b );
  730. RenderBox( sample->vectarget, vec3_angle, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), Color( r, g, b, 127 ), false );
  731. }
  732. if ( samplenumber == m_nPreviewLastFrame + 1 )
  733. {
  734. r = 50;
  735. g = 100;
  736. b = 250;
  737. RenderBox( sample->info.u[ nSlot ].GetViewOrigin() + m_vecEyeOffset, sample->info.u[ nSlot ].GetViewAngles(), Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), Color( r, g, b, 92 ), false );
  738. }
  739. if ( sample->targetpoint )
  740. {
  741. r = 200;
  742. g = 200;
  743. b = 220;
  744. RenderLine( sample->info.u[ nSlot ].GetViewOrigin() + m_vecEyeOffset, sample->vectarget, Color( r, g, b, 255 ), true );
  745. }
  746. }
  747. //-----------------------------------------------------------------------------
  748. // Purpose:
  749. //-----------------------------------------------------------------------------
  750. void CDemoSmootherPanel::DrawDebuggingInfo( int frame, float elapsed )
  751. {
  752. if ( GET_ACTIVE_SPLITSCREEN_SLOT() != 0 )
  753. return;
  754. int nSlot = 0;
  755. if ( !CanEdit() )
  756. return;
  757. if ( !IsVisible() )
  758. return;
  759. int c = m_Smoothing.smooth.Count();
  760. if ( c < 2 )
  761. return;
  762. int start = 0;
  763. int end = c - 1;
  764. bool showall = m_pShowAllSamples->IsSelected();
  765. if ( !showall )
  766. {
  767. start = MAX( frame - 200, 0 );
  768. end = MIN( frame + 200, c - 1 );
  769. }
  770. if ( m_bHasSelection && !showall )
  771. {
  772. start = MAX( m_nSelection[ 0 ] - 10, 0 );
  773. end = MIN( m_nSelection[ 1 ] + 10, c - 1 );
  774. }
  775. bool draworiginal = !m_pHideOriginal->IsSelected();
  776. bool drawprocessed = !m_pHideProcessed->IsSelected();
  777. int i;
  778. demosmoothing_t *p = NULL;
  779. demosmoothing_t *prev = NULL;
  780. for ( i = start; i < end; i++ )
  781. {
  782. p = &m_Smoothing.smooth[ i ];
  783. if ( prev && p )
  784. {
  785. DrawSmoothingSample( draworiginal, drawprocessed, i, prev, p );
  786. }
  787. prev = p;
  788. }
  789. Vector org;
  790. QAngle ang;
  791. if ( m_bPreviewing )
  792. {
  793. if ( GetInterpolatedOriginAndAngles( nSlot, true, org, ang ) )
  794. {
  795. DrawVecForward( true, org + m_vecEyeOffset, ang, 200, 10, 50 );
  796. }
  797. }
  798. int useframe = frame;
  799. useframe = clamp( useframe, 0, c - 1 );
  800. if ( useframe < c )
  801. {
  802. p = &m_Smoothing.smooth[ useframe ];
  803. org = p->info.u[ nSlot ].GetViewOrigin();
  804. ang = p->info.u[ nSlot ].GetViewAngles();
  805. DrawVecForward( true, org + m_vecEyeOffset, ang, 100, 220, 250 );
  806. Draw_Box( org + m_vecEyeOffset, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), ang, 100, 220, 250, 127 );
  807. }
  808. DrawKeySpline();
  809. DrawTargetSpline();
  810. if ( !m_pHideLegend->IsSelected() )
  811. {
  812. DrawLegend( start, end );
  813. }
  814. }
  815. void CDemoSmootherPanel::OnSelect()
  816. {
  817. if ( !CanEdit() )
  818. return;
  819. m_bHasSelection = false;
  820. m_iSelectionTicksSpan = 0;
  821. memset( m_nSelection, 0, sizeof( m_nSelection ) );
  822. int start, end;
  823. start = GetStartFrame();
  824. end = GetEndFrame();
  825. int c = m_Smoothing.smooth.Count();
  826. if ( c < 2 )
  827. return;
  828. start = clamp( start, 0, c - 1 );
  829. end = clamp( end, 0, c - 1 );
  830. if ( start >= end )
  831. return;
  832. m_nSelection[ 0 ] = start;
  833. m_nSelection[ 1 ] = end;
  834. m_bHasSelection = true;
  835. demosmoothing_t *startsample = &m_Smoothing.smooth[ start ];
  836. demosmoothing_t *endsample = &m_Smoothing.smooth[ end ];
  837. m_bDirty = true;
  838. PushUndo( "select" );
  839. int i = 0;
  840. for ( i = 0; i < c; i++ )
  841. {
  842. if ( i >= start && i <= end )
  843. {
  844. m_Smoothing.smooth[ i ].selected = true;
  845. }
  846. else
  847. {
  848. m_Smoothing.smooth[ i ].selected = false;
  849. }
  850. }
  851. PushRedo( "select" );
  852. m_iSelectionTicksSpan = endsample->frametick - startsample->frametick;
  853. }
  854. int CDemoSmootherPanel::GetFrameForTick( int tick )
  855. {
  856. int count = m_Smoothing.smooth.Count();
  857. int last = count - 1;
  858. int first = m_Smoothing.m_nFirstSelectableSample;
  859. if ( first > last )
  860. return -1;
  861. if ( count <= 0 )
  862. {
  863. return -1; // no valid index
  864. }
  865. else if ( count == 1 )
  866. {
  867. return 0; // return the one and only frame we have
  868. }
  869. if ( tick <= m_Smoothing.smooth[ first ].frametick )
  870. return first;
  871. if ( tick >= m_Smoothing.smooth[ last ].frametick )
  872. return last;
  873. // binary search
  874. int middle;
  875. while ( true )
  876. {
  877. middle = (first+last)/2;
  878. int middleTick = m_Smoothing.smooth[ middle ].frametick;
  879. if ( tick == middleTick )
  880. return middle;
  881. if ( tick > middleTick )
  882. {
  883. if ( first == middle )
  884. return first;
  885. first = middle;
  886. }
  887. else
  888. {
  889. if ( last == middle )
  890. return last;
  891. last = middle;
  892. }
  893. }
  894. }
  895. int CDemoSmootherPanel::GetTickForFrame( int frame )
  896. {
  897. if ( !CanEdit() )
  898. return -1;
  899. int c = m_Smoothing.smooth.Count();
  900. if ( c < 1 )
  901. return -1;
  902. if ( frame < 0 )
  903. return m_Smoothing.smooth[ 0 ].frametick;
  904. if ( frame >= c )
  905. return m_Smoothing.smooth[ c - 1 ].frametick;
  906. return m_Smoothing.smooth[ frame ].frametick;
  907. }
  908. //-----------------------------------------------------------------------------
  909. // Purpose: Interpolate Euler angles using quaternions to avoid singularities
  910. // Input : start -
  911. // end -
  912. // output -
  913. // frac -
  914. //-----------------------------------------------------------------------------
  915. static void InterpolateAngles( const QAngle& start, const QAngle& end, QAngle& output, float frac )
  916. {
  917. Quaternion src, dest;
  918. // Convert to quaternions
  919. AngleQuaternion( start, src );
  920. AngleQuaternion( end, dest );
  921. Quaternion result;
  922. // Slerp
  923. QuaternionSlerp( src, dest, frac, result );
  924. // Convert to euler
  925. QuaternionAngles( result, output );
  926. }
  927. bool CDemoSmootherPanel::GetInterpolatedOriginAndAngles( int nSlot, bool readonly, Vector& origin, QAngle& angles )
  928. {
  929. origin.Init();
  930. angles.Init();
  931. Assert( m_bPreviewing );
  932. // Figure out the best samples
  933. int startframe = m_nPreviewLastFrame;
  934. int nextframe = startframe + 1;
  935. float time = m_fPreviewCurrentTime;
  936. int c = m_Smoothing.smooth.Count();
  937. do
  938. {
  939. if ( startframe >= c || nextframe >= c )
  940. {
  941. if ( !readonly )
  942. {
  943. //m_bPreviewing = false;
  944. }
  945. return false;
  946. }
  947. demosmoothing_t *startsample = &m_Smoothing.smooth[ startframe ];
  948. demosmoothing_t *endsample = &m_Smoothing.smooth[ nextframe ];
  949. if ( nextframe >= MIN( m_nSelection[1] + 10, c - 1 ) )
  950. {
  951. if ( !readonly )
  952. {
  953. OnPreview( m_bPreviewOriginal );
  954. }
  955. return false;
  956. }
  957. // If large dt, then jump ahead quickly in time
  958. float dt = TICKS_TO_TIME( endsample->frametick - startsample->frametick );
  959. if ( dt > 1.0f )
  960. {
  961. startframe++;
  962. nextframe++;
  963. continue;
  964. }
  965. if ( TICKS_TO_TIME( endsample->frametick ) >= time )
  966. {
  967. // Found a spot
  968. float dt = TICKS_TO_TIME( endsample->frametick - startsample->frametick );
  969. // Should never occur!!!
  970. if ( dt <= 0.0f )
  971. {
  972. return false;
  973. }
  974. float frac = (float)( time - TICKS_TO_TIME(startsample->frametick) ) / dt;
  975. frac = clamp( frac, 0.0f, 1.0f );
  976. // Compute render origin/angles
  977. Vector renderOrigin;
  978. QAngle renderAngles;
  979. if ( m_bPreviewOriginal )
  980. {
  981. VectorLerp( startsample->info.u[ nSlot ].viewOrigin, endsample->info.u[ nSlot ].viewOrigin, frac, renderOrigin );
  982. InterpolateAngles( startsample->info.u[ nSlot ].viewAngles, endsample->info.u[ nSlot ].viewAngles, renderAngles, frac );
  983. }
  984. else
  985. {
  986. VectorLerp( startsample->info.u[ nSlot ].GetViewOrigin(), endsample->info.u[ nSlot ].GetViewOrigin(), frac, renderOrigin );
  987. InterpolateAngles( startsample->info.u[ nSlot ].GetViewAngles(), endsample->info.u[ nSlot ].GetViewAngles(), renderAngles, frac );
  988. }
  989. origin = renderOrigin;
  990. angles = renderAngles;
  991. if ( !readonly )
  992. {
  993. SetLastFrame( false, startframe );
  994. }
  995. break;
  996. }
  997. startframe++;
  998. nextframe++;
  999. } while ( true );
  1000. return true;
  1001. }
  1002. //-----------------------------------------------------------------------------
  1003. // Purpose:
  1004. // Input : t -
  1005. //-----------------------------------------------------------------------------
  1006. bool CDemoSmootherPanel::GetInterpolatedViewPoint( int nSlot, Vector& origin, QAngle& angles )
  1007. {
  1008. Assert( m_bPreviewing );
  1009. if ( !GetInterpolatedOriginAndAngles( nSlot, false, origin, angles ) )
  1010. return false;
  1011. bool back_off = m_pBackOff->IsSelected();
  1012. if ( back_off )
  1013. {
  1014. Vector fwd;
  1015. AngleVectors( angles, &fwd, NULL, NULL );
  1016. origin = origin - fwd * 75.0f;
  1017. }
  1018. return true;
  1019. }
  1020. void CDemoSmootherPanel::OnTogglePause()
  1021. {
  1022. if ( !m_bPreviewing )
  1023. return;
  1024. m_bPreviewPaused = !m_bPreviewPaused;
  1025. }
  1026. void CDemoSmootherPanel::OnStep( bool forward )
  1027. {
  1028. if ( !m_bPreviewing )
  1029. return;
  1030. if ( !m_bPreviewPaused )
  1031. return;
  1032. int c = m_Smoothing.smooth.Count();
  1033. SetLastFrame( false, m_nPreviewLastFrame + ( forward ? 1 : -1 ) );
  1034. SetLastFrame( false, clamp( m_nPreviewLastFrame, MAX( m_nSelection[ 0 ] - 10, 0 ), MIN( m_nSelection[ 1 ] + 10, c - 1 ) ) );
  1035. m_fPreviewCurrentTime = TICKS_TO_TIME( GetTickForFrame( m_nPreviewLastFrame ) );
  1036. }
  1037. void CDemoSmootherPanel::DrawLegend( int startframe, int endframe )
  1038. {
  1039. int i;
  1040. int skip = 20;
  1041. int nSlot = 0;
  1042. bool back_off = m_pBackOff->IsSelected();
  1043. for ( i = startframe; i <= endframe; i++ )
  1044. {
  1045. bool show = ( i % skip ) == 0;
  1046. demosmoothing_t *sample = &m_Smoothing.smooth[ i ];
  1047. if ( sample->samplepoint || sample->targetpoint )
  1048. show = true;
  1049. if ( !show )
  1050. continue;
  1051. char sz[ 512 ];
  1052. Q_snprintf( sz, sizeof( sz ), "%.3f", TICKS_TO_TIME(sample->frametick) );
  1053. Vector fwd;
  1054. AngleVectors( sample->info.u[ nSlot ].GetViewAngles(), &fwd, NULL, NULL );
  1055. CDebugOverlay::AddTextOverlay( sample->info.u[ nSlot ].GetViewOrigin() + m_vecEyeOffset + fwd * ( back_off ? 5.0f : 50.0f ), 0, -1.0f, sz );
  1056. }
  1057. }
  1058. #define EASE_TIME 0.2f
  1059. Quaternion SmoothAngles( CUtlVector< Quaternion >& stack )
  1060. {
  1061. int c = stack.Count();
  1062. Assert( c >= 1 );
  1063. float weight = 1.0f / (float)c;
  1064. Quaternion output;
  1065. output.Init();
  1066. int i;
  1067. for ( i = 0; i < c; i++ )
  1068. {
  1069. Quaternion t = stack[ i ];
  1070. QuaternionBlend( output, t, weight, output );
  1071. }
  1072. return output;
  1073. }
  1074. Vector SmoothOrigin( CUtlVector< Vector >& stack )
  1075. {
  1076. int c = stack.Count();
  1077. Assert( c >= 1 );
  1078. Vector output;
  1079. output.Init();
  1080. int i;
  1081. for ( i = 0; i < c; i++ )
  1082. {
  1083. Vector t = stack[ i ];
  1084. VectorAdd( output, t, output );
  1085. }
  1086. VectorScale( output, 1.0f / (float)c, output );
  1087. return output;
  1088. }
  1089. //-----------------------------------------------------------------------------
  1090. // Purpose:
  1091. //-----------------------------------------------------------------------------
  1092. void CDemoSmootherPanel::OnSetKeys(float interval)
  1093. {
  1094. if ( !m_bHasSelection )
  1095. return;
  1096. m_bDirty = true;
  1097. PushUndo( "OnSetKeys" );
  1098. int c = m_Smoothing.smooth.Count();
  1099. int i;
  1100. demosmoothing_t *lastkey = NULL;
  1101. int nSlot = 0;
  1102. for ( i = 0; i < c; i++ )
  1103. {
  1104. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1105. if ( !p->selected )
  1106. continue;
  1107. p->angmoved = p->info.u[ nSlot ].GetViewAngles();;
  1108. p->vecmoved = p->info.u[ nSlot ].GetViewOrigin();
  1109. p->samplepoint = false;
  1110. if ( !lastkey ||
  1111. TICKS_TO_TIME( p->frametick - lastkey->frametick ) >= interval )
  1112. {
  1113. lastkey = p;
  1114. p->samplepoint = true;
  1115. }
  1116. }
  1117. PushRedo( "OnSetKeys" );
  1118. }
  1119. //-----------------------------------------------------------------------------
  1120. // Purpose:
  1121. //-----------------------------------------------------------------------------
  1122. void CDemoSmootherPanel::OnSmoothSelectionAngles( void )
  1123. {
  1124. if ( !m_bHasSelection )
  1125. return;
  1126. int nSlot = 0;
  1127. int c = m_Smoothing.smooth.Count();
  1128. int i;
  1129. CUtlVector< Quaternion > stack;
  1130. m_bDirty = true;
  1131. PushUndo( "smooth angles" );
  1132. for ( i = 0; i < c; i++ )
  1133. {
  1134. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1135. if ( !p->selected )
  1136. continue;
  1137. while ( stack.Count() > 10 )
  1138. {
  1139. stack.Remove( 0 );
  1140. }
  1141. Quaternion q;
  1142. AngleQuaternion( p->info.u[ nSlot ].GetViewAngles(), q );
  1143. stack.AddToTail( q );
  1144. p->info.u[ nSlot ].flags |= FDEMO_USE_ANGLES2;
  1145. Quaternion aveq = SmoothAngles( stack );
  1146. QAngle outangles;
  1147. QuaternionAngles( aveq, outangles );
  1148. p->info.u[ nSlot ].viewAngles2 = outangles;
  1149. p->info.u[ nSlot ].localViewAngles2 = outangles;
  1150. }
  1151. PushRedo( "smooth angles" );
  1152. }
  1153. //-----------------------------------------------------------------------------
  1154. // Purpose:
  1155. //-----------------------------------------------------------------------------
  1156. void CDemoSmootherPanel::OnSmoothSelectionOrigin( void )
  1157. {
  1158. if ( !m_bHasSelection )
  1159. return;
  1160. int c = m_Smoothing.smooth.Count();
  1161. int i;
  1162. CUtlVector< Vector > stack;
  1163. m_bDirty = true;
  1164. PushUndo( "smooth origin" );
  1165. int nSlot = 0;
  1166. for ( i = 0; i < c; i++ )
  1167. {
  1168. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1169. if ( !p->selected )
  1170. continue;
  1171. if ( i < 2 )
  1172. continue;
  1173. if ( i >= c - 2 )
  1174. continue;
  1175. stack.RemoveAll();
  1176. for ( int j = -2; j <= 2; j++ )
  1177. {
  1178. stack.AddToTail( m_Smoothing.smooth[ i + j ].info.u[ nSlot ].GetViewOrigin() );
  1179. }
  1180. p->info.u[ nSlot ].flags |= FDEMO_USE_ORIGIN2;
  1181. Vector org = SmoothOrigin( stack );
  1182. p->info.u[ nSlot ].viewOrigin2 = org;
  1183. }
  1184. PushRedo( "smooth origin" );
  1185. }
  1186. void CDemoSmootherPanel::PerformLinearInterpolatedAngleSmoothing( int startframe, int endframe )
  1187. {
  1188. demosmoothing_t *pstart = &m_Smoothing.smooth[ startframe ];
  1189. demosmoothing_t *pend = &m_Smoothing.smooth[ endframe ];
  1190. int dt = pend->frametick - pstart->frametick;
  1191. if ( dt <= 0 )
  1192. {
  1193. dt = 1;
  1194. }
  1195. int nSlot = 0;
  1196. CUtlVector< Quaternion > stack;
  1197. Quaternion qstart, qend;
  1198. AngleQuaternion( pstart->info.u[ nSlot ].GetViewAngles(), qstart );
  1199. AngleQuaternion( pend->info.u[ nSlot ].GetViewAngles(), qend );
  1200. for ( int i = startframe; i <= endframe; i++ )
  1201. {
  1202. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1203. int elapsed = p->frametick - pstart->frametick;
  1204. float frac = (float)elapsed / (float)dt;
  1205. frac = clamp( frac, 0.0f, 1.0f );
  1206. p->info.u[ nSlot ].flags |= FDEMO_USE_ANGLES2;
  1207. Quaternion interpolated;
  1208. QuaternionSlerp( qstart, qend, frac, interpolated );
  1209. QAngle outangles;
  1210. QuaternionAngles( interpolated, outangles );
  1211. p->info.u[ nSlot ].viewAngles2 = outangles;
  1212. p->info.u[ nSlot ].localViewAngles2 = outangles;
  1213. }
  1214. }
  1215. void CDemoSmootherPanel::OnLinearInterpolateAnglesBasedOnEndpoints( void )
  1216. {
  1217. if ( !m_bHasSelection )
  1218. return;
  1219. int c = m_Smoothing.smooth.Count();
  1220. if ( c < 2 )
  1221. return;
  1222. m_bDirty = true;
  1223. PushUndo( "linear interp angles" );
  1224. PerformLinearInterpolatedAngleSmoothing( m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1225. PushRedo( "linear interp angles" );
  1226. }
  1227. void CDemoSmootherPanel::OnLinearInterpolateOriginBasedOnEndpoints( void )
  1228. {
  1229. if ( !m_bHasSelection )
  1230. return;
  1231. int c = m_Smoothing.smooth.Count();
  1232. if ( c < 2 )
  1233. return;
  1234. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1235. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1236. int dt = pend->frametick - pstart->frametick;
  1237. if ( dt <= 0 )
  1238. return;
  1239. m_bDirty = true;
  1240. PushUndo( "linear interp origin" );
  1241. int nSlot = 0;
  1242. Vector vstart, vend;
  1243. vstart = pstart->info.u[ nSlot ].GetViewOrigin();
  1244. vend = pend->info.u[ nSlot ].GetViewOrigin();
  1245. for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1246. {
  1247. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1248. float elapsed = p->frametick - pstart->frametick;
  1249. float frac = elapsed / (float)dt;
  1250. frac = clamp( frac, 0.0f, 1.0f );
  1251. p->info.u[ nSlot ].flags |= FDEMO_USE_ORIGIN2;
  1252. Vector interpolated;
  1253. VectorLerp( vstart, vend, frac, interpolated );
  1254. p->info.u[ nSlot ].viewOrigin2 = interpolated;
  1255. }
  1256. PushRedo( "linear interp origin" );
  1257. }
  1258. void CDemoSmootherPanel::OnRevertPoint( void )
  1259. {
  1260. demosmoothing_t *p = GetCurrent();
  1261. if ( !p )
  1262. return;
  1263. m_bDirty = true;
  1264. PushUndo( "revert point" );
  1265. int nSlot = 0;
  1266. p->angmoved = p->info.u[ nSlot ].GetViewAngles();
  1267. p->vecmoved = p->info.u[ nSlot ].GetViewOrigin();
  1268. p->samplepoint = false;
  1269. p->vectarget = p->info.u[ nSlot ].GetViewOrigin();
  1270. p->targetpoint = false;
  1271. // m_ViewOrigin = p->info.viewOrigin;
  1272. // m_ViewAngles = p->info.viewAngles;
  1273. PushRedo( "revert point" );
  1274. }
  1275. demosmoothing_t *CDemoSmootherPanel::GetCurrent( void )
  1276. {
  1277. if ( !CanEdit() )
  1278. return NULL;
  1279. int c = m_Smoothing.smooth.Count();
  1280. if ( c < 1 )
  1281. return NULL;
  1282. int frame = clamp( m_nPreviewLastFrame, 0, c - 1 );
  1283. return &m_Smoothing.smooth[ frame ];
  1284. }
  1285. void CDemoSmootherPanel::AddSamplePoints( bool usetarget, bool includeboundaries, CUtlVector< demosmoothing_t * >& points, int start, int end )
  1286. {
  1287. points.RemoveAll();
  1288. int i;
  1289. for ( i = start; i <= end; i++ )
  1290. {
  1291. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1292. if ( includeboundaries )
  1293. {
  1294. if ( i == start )
  1295. {
  1296. // Add it twice
  1297. points.AddToTail( p );
  1298. continue;
  1299. }
  1300. else if ( i == end )
  1301. {
  1302. // Add twice
  1303. points.AddToTail( p );
  1304. continue;
  1305. }
  1306. }
  1307. if ( usetarget && p->targetpoint )
  1308. {
  1309. points.AddToTail( p );
  1310. }
  1311. if ( !usetarget && p->samplepoint )
  1312. {
  1313. points.AddToTail( p );
  1314. }
  1315. }
  1316. }
  1317. demosmoothing_t *CDemoSmootherPanel::GetBoundedSample( CUtlVector< demosmoothing_t * >& points, int sample )
  1318. {
  1319. int c = points.Count();
  1320. if ( sample < 0 )
  1321. return points[ 0 ];
  1322. else if ( sample >= c )
  1323. return points[ c - 1 ];
  1324. return points[ sample ];
  1325. }
  1326. //-----------------------------------------------------------------------------
  1327. // Purpose:
  1328. // Input : t -
  1329. // points -
  1330. // prev -
  1331. // next -
  1332. //-----------------------------------------------------------------------------
  1333. void CDemoSmootherPanel::FindSpanningPoints( int tick, CUtlVector< demosmoothing_t * >& points, int& prev, int& next )
  1334. {
  1335. prev = -1;
  1336. next = 0;
  1337. int c = points.Count();
  1338. int i;
  1339. for ( i = 0; i < c; i++ )
  1340. {
  1341. demosmoothing_t *p = points[ i ];
  1342. if ( tick < p->frametick )
  1343. break;
  1344. }
  1345. next = i;
  1346. prev = i - 1;
  1347. next = clamp( next, 0, c - 1 );
  1348. prev = clamp( prev, 0, c - 1 );
  1349. }
  1350. void CDemoSmootherPanel::OnSplineSampleOrigin( void )
  1351. {
  1352. if ( !m_bHasSelection )
  1353. return;
  1354. int c = m_Smoothing.smooth.Count();
  1355. if ( c < 2 )
  1356. return;
  1357. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1358. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1359. if ( pend->frametick - pstart->frametick <= 0 )
  1360. return;
  1361. CUtlVector< demosmoothing_t * > points;
  1362. AddSamplePoints( false, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1363. if ( points.Count() <= 0 )
  1364. return;
  1365. m_bDirty = true;
  1366. PushUndo( "spline origin" );
  1367. int nSlot = 0;
  1368. for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1369. {
  1370. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1371. demosmoothing_t *earliest;
  1372. demosmoothing_t *current;
  1373. demosmoothing_t *next;
  1374. demosmoothing_t *latest;
  1375. int cur;
  1376. int cur2;
  1377. FindSpanningPoints( p->frametick, points, cur, cur2 );
  1378. earliest = GetBoundedSample( points, cur - 1 );
  1379. current = GetBoundedSample( points, cur );
  1380. next = GetBoundedSample( points, cur2 );
  1381. latest = GetBoundedSample( points, cur2 + 1 );
  1382. float frac = 0.0f;
  1383. float dt = next->frametick - current->frametick;
  1384. if ( dt > 0.0f )
  1385. {
  1386. frac = (float)( p->frametick - current->frametick ) / dt;
  1387. }
  1388. frac = clamp( frac, 0.0f, 1.0f );
  1389. Vector splined;
  1390. Catmull_Rom_Spline_Normalize( earliest->vecmoved, current->vecmoved, next->vecmoved, latest->vecmoved, frac, splined );
  1391. p->info.u[ nSlot ].flags |= FDEMO_USE_ORIGIN2;
  1392. p->info.u[ nSlot ].viewOrigin2 = splined;
  1393. }
  1394. PushRedo( "spline origin" );
  1395. }
  1396. void CDemoSmootherPanel::OnSplineSampleAngles( void )
  1397. {
  1398. if ( !m_bHasSelection )
  1399. return;
  1400. int c = m_Smoothing.smooth.Count();
  1401. if ( c < 2 )
  1402. return;
  1403. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1404. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1405. if ( pend->frametick - pstart->frametick <= 0 )
  1406. return;
  1407. CUtlVector< demosmoothing_t * > points;
  1408. AddSamplePoints( false, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1409. if ( points.Count() <= 0 )
  1410. return;
  1411. m_bDirty = true;
  1412. PushUndo( "spline angles" );
  1413. int nSlot = 0;
  1414. for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1415. {
  1416. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1417. demosmoothing_t *current;
  1418. demosmoothing_t *next;
  1419. int cur;
  1420. int cur2;
  1421. FindSpanningPoints( p->frametick, points, cur, cur2 );
  1422. current = GetBoundedSample( points, cur );
  1423. next = GetBoundedSample( points, cur2 );
  1424. float frac = 0.0f;
  1425. float dt = next->frametick - current->frametick;
  1426. if ( dt > 0.0f )
  1427. {
  1428. frac = (float)( p->frametick - current->frametick ) / dt;
  1429. }
  1430. frac = clamp( frac, 0.0f, 1.0f );
  1431. frac = SimpleSpline( frac );
  1432. QAngle splined;
  1433. InterpolateAngles( current->angmoved, next->angmoved, splined, frac );
  1434. p->info.u[ nSlot ].flags |= FDEMO_USE_ANGLES2;
  1435. p->info.u[ nSlot ].viewAngles2 = splined;
  1436. p->info.u[ nSlot ].localViewAngles2 = splined;
  1437. }
  1438. PushRedo( "spline angles" );
  1439. }
  1440. void CDemoSmootherPanel::OnLookAtPoints( bool spline )
  1441. {
  1442. if ( !m_bHasSelection )
  1443. return;
  1444. int c = m_Smoothing.smooth.Count();
  1445. int i;
  1446. if ( c < 2 )
  1447. return;
  1448. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1449. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1450. if ( pend->frametick - pstart->frametick <= 0 )
  1451. return;
  1452. CUtlVector< demosmoothing_t * > points;
  1453. AddSamplePoints( true, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1454. if ( points.Count() < 1 )
  1455. return;
  1456. m_bDirty = true;
  1457. PushUndo( "lookat points" );
  1458. int nSlot = 0;
  1459. for ( i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1460. {
  1461. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1462. demosmoothing_t *earliest;
  1463. demosmoothing_t *current;
  1464. demosmoothing_t *next;
  1465. demosmoothing_t *latest;
  1466. int cur;
  1467. int cur2;
  1468. FindSpanningPoints( p->frametick, points, cur, cur2 );
  1469. earliest = GetBoundedSample( points, cur - 1 );
  1470. current = GetBoundedSample( points, cur );
  1471. next = GetBoundedSample( points, cur2 );
  1472. latest = GetBoundedSample( points, cur2 + 1 );
  1473. float frac = 0.0f;
  1474. float dt = next->frametick - current->frametick;
  1475. if ( dt > 0.0f )
  1476. {
  1477. frac = (float)( p->frametick - current->frametick ) / dt;
  1478. }
  1479. frac = clamp( frac, 0.0f, 1.0f );
  1480. Vector splined;
  1481. if ( spline )
  1482. {
  1483. Catmull_Rom_Spline_Normalize( earliest->vectarget, current->vectarget, next->vectarget, latest->vectarget, frac, splined );
  1484. }
  1485. else
  1486. {
  1487. Vector d = next->vectarget - current->vectarget;
  1488. VectorMA( current->vectarget, frac, d, splined );
  1489. }
  1490. Vector vecToTarget = splined - ( p->info.u[ nSlot ].GetViewOrigin() + m_vecEyeOffset );
  1491. VectorNormalize( vecToTarget );
  1492. QAngle angles;
  1493. VectorAngles( vecToTarget, angles );
  1494. p->info.u[ nSlot ].flags |= FDEMO_USE_ANGLES2;
  1495. p->info.u[ nSlot ].viewAngles2 = angles;
  1496. p->info.u[ nSlot ].localViewAngles2 = angles;
  1497. }
  1498. PushRedo( "lookat points" );
  1499. }
  1500. void CDemoSmootherPanel::SetLastFrame( bool jumptotarget, int frame )
  1501. {
  1502. // bool changed = frame != m_nPreviewLastFrame;
  1503. int useFrame = MAX( m_Smoothing.m_nFirstSelectableSample, frame );
  1504. m_nPreviewLastFrame = useFrame;
  1505. /* if ( changed && !m_pLockCamera->IsSelected() )
  1506. {
  1507. // Reset default view/angles
  1508. demosmoothing_t *p = GetCurrent();
  1509. if ( p )
  1510. {
  1511. if ( p->samplepoint && !jumptotarget )
  1512. {
  1513. m_ViewOrigin = p->vecmoved;
  1514. m_ViewAngles = p->angmoved;
  1515. }
  1516. else if ( p->targetpoint && jumptotarget )
  1517. {
  1518. m_ViewOrigin = p->vectarget - m_vecEyeOffset;
  1519. }
  1520. else
  1521. {
  1522. if ( m_bPreviewing && m_bPreviewOriginal )
  1523. {
  1524. m_ViewOrigin = p->info.viewOrigin;
  1525. m_ViewAngles = p->info.viewAngles;
  1526. }
  1527. else
  1528. {
  1529. m_ViewOrigin = p->info.GetViewOrigin();
  1530. m_ViewAngles = p->info.GetViewAngles();
  1531. }
  1532. }
  1533. }
  1534. } */
  1535. }
  1536. // Undo/Redo
  1537. void CDemoSmootherPanel::Undo( void )
  1538. {
  1539. if ( m_UndoStack.Count() > 0 && m_nUndoLevel > 0 )
  1540. {
  1541. m_nUndoLevel--;
  1542. DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
  1543. Assert( u->undo );
  1544. m_Smoothing = *(u->undo);
  1545. }
  1546. InvalidateLayout();
  1547. }
  1548. void CDemoSmootherPanel::Redo( void )
  1549. {
  1550. if ( m_UndoStack.Count() > 0 && m_nUndoLevel <= m_UndoStack.Count() - 1 )
  1551. {
  1552. DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
  1553. Assert( u->redo );
  1554. m_Smoothing = *(u->redo);
  1555. m_nUndoLevel++;
  1556. }
  1557. InvalidateLayout();
  1558. }
  1559. void CDemoSmootherPanel::PushUndo( char *description )
  1560. {
  1561. Assert( !m_bRedoPending );
  1562. m_bRedoPending = true;
  1563. WipeRedo();
  1564. // Copy current data
  1565. CSmoothingContext *u = new CSmoothingContext;
  1566. *u = m_Smoothing;
  1567. DemoSmoothUndo *undo = new DemoSmoothUndo;
  1568. undo->undo = u;
  1569. undo->redo = NULL;
  1570. undo->udescription = COM_StringCopy( description );
  1571. undo->rdescription = NULL;
  1572. m_UndoStack.AddToTail( undo );
  1573. m_nUndoLevel++;
  1574. }
  1575. void CDemoSmootherPanel::PushRedo( char *description )
  1576. {
  1577. Assert( m_bRedoPending );
  1578. m_bRedoPending = false;
  1579. // Copy current data
  1580. CSmoothingContext *r = new CSmoothingContext;
  1581. *r = m_Smoothing;
  1582. DemoSmoothUndo *undo = m_UndoStack[ m_nUndoLevel - 1 ];
  1583. undo->redo = r;
  1584. undo->rdescription = COM_StringCopy( description );
  1585. }
  1586. void CDemoSmootherPanel::WipeUndo( void )
  1587. {
  1588. while ( m_UndoStack.Count() > 0 )
  1589. {
  1590. DemoSmoothUndo *u = m_UndoStack[ 0 ];
  1591. delete u->undo;
  1592. delete u->redo;
  1593. delete[] u->udescription;
  1594. delete[] u->rdescription;
  1595. delete u;
  1596. m_UndoStack.Remove( 0 );
  1597. }
  1598. m_nUndoLevel = 0;
  1599. }
  1600. void CDemoSmootherPanel::WipeRedo( void )
  1601. {
  1602. // Wipe everything above level
  1603. while ( m_UndoStack.Count() > m_nUndoLevel )
  1604. {
  1605. DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
  1606. delete u->undo;
  1607. delete u->redo;
  1608. delete[] u->udescription;
  1609. delete[] u->rdescription;
  1610. delete u;
  1611. m_UndoStack.Remove( m_nUndoLevel );
  1612. }
  1613. }
  1614. //-----------------------------------------------------------------------------
  1615. // Purpose:
  1616. // Output : const char
  1617. //-----------------------------------------------------------------------------
  1618. const char *CDemoSmootherPanel::GetUndoDescription( void )
  1619. {
  1620. if ( m_nUndoLevel != 0 )
  1621. {
  1622. DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel - 1 ];
  1623. return u->udescription;
  1624. }
  1625. return "???undo";
  1626. }
  1627. //-----------------------------------------------------------------------------
  1628. // Purpose:
  1629. // Output : const char
  1630. //-----------------------------------------------------------------------------
  1631. const char *CDemoSmootherPanel::GetRedoDescription( void )
  1632. {
  1633. if ( m_nUndoLevel != m_UndoStack.Count() )
  1634. {
  1635. DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
  1636. return u->rdescription;
  1637. }
  1638. return "???redo";
  1639. }
  1640. //-----------------------------------------------------------------------------
  1641. // Purpose:
  1642. // Output : Returns true on success, false on failure.
  1643. //-----------------------------------------------------------------------------
  1644. bool CDemoSmootherPanel::CanRedo( void )
  1645. {
  1646. if ( !m_UndoStack.Count() )
  1647. return false;
  1648. if ( m_nUndoLevel == m_UndoStack.Count() )
  1649. return false;
  1650. return true;
  1651. }
  1652. //-----------------------------------------------------------------------------
  1653. // Purpose:
  1654. // Output : Returns true on success, false on failure.
  1655. //-----------------------------------------------------------------------------
  1656. bool CDemoSmootherPanel::CanUndo( void )
  1657. {
  1658. if ( !m_UndoStack.Count() )
  1659. return false;
  1660. if ( m_nUndoLevel == 0 )
  1661. return false;
  1662. return true;
  1663. }
  1664. //-----------------------------------------------------------------------------
  1665. // Purpose:
  1666. //-----------------------------------------------------------------------------
  1667. void CDemoSmootherPanel::OnToggleKeyFrame( void )
  1668. {
  1669. demosmoothing_t *p = GetCurrent();
  1670. if ( !p )
  1671. return;
  1672. m_bDirty = true;
  1673. PushUndo( "toggle keyframe" );
  1674. int nSlot = 0;
  1675. // use orginal data by default
  1676. p->angmoved = p->info.u[ nSlot ].GetViewAngles();
  1677. p->vecmoved = p->info.u[ nSlot ].GetViewOrigin();
  1678. if ( !p->samplepoint )
  1679. {
  1680. if ( g_pDemoUI->IsInDriveMode() )
  1681. {
  1682. g_pDemoUI->GetDriveViewPoint( p->vecmoved, p->angmoved );
  1683. }
  1684. //if ( g_pDemoUI2->IsInDriveMode() )
  1685. //{
  1686. // g_pDemoUI2->GetDriveViewPoint( p->vecmoved, p->angmoved );
  1687. //}
  1688. p->samplepoint = true;
  1689. }
  1690. else
  1691. {
  1692. p->samplepoint = false;
  1693. }
  1694. PushRedo( "toggle keyframe" );
  1695. }
  1696. //-----------------------------------------------------------------------------
  1697. // Purpose:
  1698. //-----------------------------------------------------------------------------
  1699. void CDemoSmootherPanel::OnToggleLookTarget( void )
  1700. {
  1701. demosmoothing_t *p = GetCurrent();
  1702. if ( !p )
  1703. return;
  1704. m_bDirty = true;
  1705. PushUndo( "toggle look target" );
  1706. int nSlot = 0;
  1707. // use orginal data by default
  1708. p->vectarget = p->info.u[ nSlot ].GetViewOrigin();
  1709. if ( !p->targetpoint )
  1710. {
  1711. QAngle angles;
  1712. g_pDemoUI->GetDriveViewPoint( p->vectarget, angles );
  1713. //g_pDemoUI2->GetDriveViewPoint( p->vectarget, angles );
  1714. p->targetpoint = true;
  1715. }
  1716. else
  1717. {
  1718. p->targetpoint = false;
  1719. }
  1720. PushRedo( "toggle look target" );
  1721. }
  1722. //-----------------------------------------------------------------------------
  1723. // Purpose:
  1724. //-----------------------------------------------------------------------------
  1725. void CDemoSmootherPanel::OnNextKey()
  1726. {
  1727. if( !m_bHasSelection )
  1728. return;
  1729. int start = m_nPreviewLastFrame + 1;
  1730. int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
  1731. int moved = 0;
  1732. while ( moved < maxmove )
  1733. {
  1734. demosmoothing_t *p = &m_Smoothing.smooth[ start ];
  1735. if ( p->samplepoint )
  1736. {
  1737. SetLastFrame( false, start );
  1738. break;
  1739. }
  1740. start++;
  1741. if ( start > m_nSelection[1] )
  1742. start = m_nSelection[0];
  1743. moved++;
  1744. }
  1745. }
  1746. //-----------------------------------------------------------------------------
  1747. // Purpose:
  1748. //-----------------------------------------------------------------------------
  1749. void CDemoSmootherPanel::OnPrevKey()
  1750. {
  1751. if( !m_bHasSelection )
  1752. return;
  1753. int start = m_nPreviewLastFrame - 1;
  1754. int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
  1755. int moved = 0;
  1756. while ( moved < maxmove && start >= 0 )
  1757. {
  1758. demosmoothing_t *p = &m_Smoothing.smooth[ start ];
  1759. if ( p->samplepoint )
  1760. {
  1761. SetLastFrame( false, start );
  1762. break;
  1763. }
  1764. start--;
  1765. if ( start < m_nSelection[0] )
  1766. start = m_nSelection[1];
  1767. moved++;
  1768. }
  1769. }
  1770. //-----------------------------------------------------------------------------
  1771. // Purpose:
  1772. //-----------------------------------------------------------------------------
  1773. void CDemoSmootherPanel::OnNextTarget()
  1774. {
  1775. if( !m_bHasSelection )
  1776. return;
  1777. int start = m_nPreviewLastFrame + 1;
  1778. int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
  1779. int moved = 0;
  1780. while ( moved < maxmove )
  1781. {
  1782. demosmoothing_t *p = &m_Smoothing.smooth[ start ];
  1783. if ( p->targetpoint )
  1784. {
  1785. SetLastFrame( true, start );
  1786. break;
  1787. }
  1788. start++;
  1789. if ( start > m_nSelection[1] )
  1790. start = m_nSelection[0];
  1791. moved++;
  1792. }
  1793. }
  1794. //-----------------------------------------------------------------------------
  1795. // Purpose:
  1796. //-----------------------------------------------------------------------------
  1797. void CDemoSmootherPanel::OnPrevTarget()
  1798. {
  1799. if( !m_bHasSelection )
  1800. return;
  1801. int start = m_nPreviewLastFrame - 1;
  1802. int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
  1803. int moved = 0;
  1804. while ( moved < maxmove )
  1805. {
  1806. demosmoothing_t *p = &m_Smoothing.smooth[ start ];
  1807. if ( p->targetpoint )
  1808. {
  1809. SetLastFrame( true, start );
  1810. break;
  1811. }
  1812. start--;
  1813. if ( start < m_nSelection[0] )
  1814. start = m_nSelection[1];
  1815. moved++;
  1816. }
  1817. }
  1818. void CDemoSmootherPanel::DrawTargetSpline()
  1819. {
  1820. if ( !m_bHasSelection )
  1821. return;
  1822. int c = m_Smoothing.smooth.Count();
  1823. int i;
  1824. if ( c < 2 )
  1825. return;
  1826. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1827. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1828. if ( pend->frametick - pstart->frametick <= 0 )
  1829. return;
  1830. CUtlVector< demosmoothing_t * > points;
  1831. AddSamplePoints( true, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1832. if ( points.Count() < 1 )
  1833. return;
  1834. Vector previous(0,0,0);
  1835. for ( i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1836. {
  1837. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1838. demosmoothing_t *earliest;
  1839. demosmoothing_t *current;
  1840. demosmoothing_t *next;
  1841. demosmoothing_t *latest;
  1842. int cur;
  1843. int cur2;
  1844. FindSpanningPoints( p->frametick, points, cur, cur2 );
  1845. earliest = GetBoundedSample( points, cur - 1 );
  1846. current = GetBoundedSample( points, cur );
  1847. next = GetBoundedSample( points, cur2 );
  1848. latest = GetBoundedSample( points, cur2 + 1 );
  1849. float frac = 0.0f;
  1850. float dt = next->frametick - current->frametick;
  1851. if ( dt > 0.0f )
  1852. {
  1853. frac = (float)( p->frametick - current->frametick ) / dt;
  1854. }
  1855. frac = clamp( frac, 0.0f, 1.0f );
  1856. Vector splined;
  1857. Catmull_Rom_Spline_Normalize( earliest->vectarget, current->vectarget, next->vectarget, latest->vectarget, frac, splined );
  1858. if ( i > m_nSelection[0] )
  1859. {
  1860. RenderLine( previous, splined, Color( 0, 255, 0, 255 ), true );
  1861. }
  1862. previous = splined;
  1863. }
  1864. }
  1865. void CDemoSmootherPanel::DrawKeySpline()
  1866. {
  1867. if ( !m_bHasSelection )
  1868. return;
  1869. int c = m_Smoothing.smooth.Count();
  1870. int i;
  1871. if ( c < 2 )
  1872. return;
  1873. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1874. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1875. if ( pend->frametick - pstart->frametick <= 0 )
  1876. return;
  1877. CUtlVector< demosmoothing_t * > points;
  1878. AddSamplePoints( false, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1879. if ( points.Count() < 1 )
  1880. return;
  1881. Vector previous(0,0,0);
  1882. for ( i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1883. {
  1884. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1885. demosmoothing_t *earliest;
  1886. demosmoothing_t *current;
  1887. demosmoothing_t *next;
  1888. demosmoothing_t *latest;
  1889. int cur;
  1890. int cur2;
  1891. FindSpanningPoints( p->frametick, points, cur, cur2 );
  1892. earliest = GetBoundedSample( points, cur - 1 );
  1893. current = GetBoundedSample( points, cur );
  1894. next = GetBoundedSample( points, cur2 );
  1895. latest = GetBoundedSample( points, cur2 + 1 );
  1896. float frac = 0.0f;
  1897. float dt = next->frametick - current->frametick;
  1898. if ( dt > 0.0f )
  1899. {
  1900. frac = (float)( p->frametick - current->frametick ) / dt;
  1901. }
  1902. frac = clamp( frac, 0.0f, 1.0f );
  1903. Vector splined;
  1904. Catmull_Rom_Spline_Normalize( earliest->vecmoved, current->vecmoved, next->vecmoved, latest->vecmoved, frac, splined );
  1905. splined += m_vecEyeOffset;
  1906. if ( i > m_nSelection[0] )
  1907. {
  1908. RenderLine( previous, splined, Color( 0, 255, 0, 255 ), true );
  1909. }
  1910. previous = splined;
  1911. }
  1912. }
  1913. void CDemoSmootherPanel::OnSmoothEdges( bool left, bool right )
  1914. {
  1915. if ( !m_bHasSelection )
  1916. return;
  1917. if ( !left && !right )
  1918. return;
  1919. int c = m_Smoothing.smooth.Count();
  1920. // Get number of frames
  1921. char sz[ 512 ];
  1922. m_pFixEdgeFrames->GetText( sz, sizeof( sz ) );
  1923. int frames = atoi( sz );
  1924. if ( frames <= 2 )
  1925. return;
  1926. m_bDirty = true;
  1927. PushUndo( "smooth edges" );
  1928. if ( left && m_nSelection[0] > 0 )
  1929. {
  1930. PerformLinearInterpolatedAngleSmoothing( m_nSelection[ 0 ] - 1, m_nSelection[ 0 ] + frames );
  1931. }
  1932. if ( right && m_nSelection[1] < c - 1 )
  1933. {
  1934. PerformLinearInterpolatedAngleSmoothing( m_nSelection[ 1 ] - frames, m_nSelection[ 1 ] + 1 );
  1935. }
  1936. PushRedo( "smooth edges" );
  1937. }
  1938. void CDemoSmootherPanel::OnSaveKey()
  1939. {
  1940. if ( !m_bHasSelection )
  1941. return;
  1942. demosmoothing_t *p = GetCurrent();
  1943. if ( !p )
  1944. return;
  1945. if ( !p->samplepoint )
  1946. return;
  1947. m_bDirty = true;
  1948. PushUndo( "save key" );
  1949. int nSlot = 0;
  1950. p->info.u[ nSlot ].viewAngles2 = p->angmoved;
  1951. p->info.u[ nSlot ].localViewAngles2 = p->angmoved;
  1952. p->info.u[ nSlot ].viewOrigin2 = p->vecmoved;
  1953. p->info.u[ nSlot ].flags |= FDEMO_USE_ORIGIN2;
  1954. p->info.u[ nSlot ].flags |= FDEMO_USE_ANGLES2;
  1955. PushRedo( "save key" );
  1956. }
  1957. void CDemoSmootherPanel::OnSetView()
  1958. {
  1959. if ( !m_bHasSelection )
  1960. return;
  1961. demosmoothing_t *p = GetCurrent();
  1962. if ( !p )
  1963. return;
  1964. int nSlot = 0;
  1965. Vector origin = p->info.u[ nSlot ].GetViewOrigin();
  1966. QAngle angle = p->info.u[ nSlot ].GetViewAngles();
  1967. g_pDemoUI->SetDriveViewPoint( origin, angle );
  1968. //g_pDemoUI2->SetDriveViewPoint( origin, angle );
  1969. }
  1970. //-----------------------------------------------------------------------------
  1971. // Purpose:
  1972. //-----------------------------------------------------------------------------
  1973. void CDemoSmootherPanel::OnGotoFrame()
  1974. {
  1975. int c = m_Smoothing.smooth.Count();
  1976. if ( c < 2 )
  1977. return;
  1978. char sz[ 256 ];
  1979. m_pGotoFrame->GetText( sz, sizeof( sz ) );
  1980. int frame = atoi( sz );
  1981. if ( !m_bPreviewing )
  1982. {
  1983. if ( !m_bHasSelection )
  1984. {
  1985. m_pStartFrame->SetText( va( "%i", 0 ) );
  1986. m_pEndFrame->SetText( va( "%i", c - 1 ) );
  1987. OnSelect();
  1988. }
  1989. OnPreview( false );
  1990. OnTogglePause();
  1991. }
  1992. if ( !m_bPreviewing )
  1993. return;
  1994. SetLastFrame( false, frame );
  1995. m_iPreviewStartTick = GetTickForFrame( m_nPreviewLastFrame );
  1996. m_fPreviewCurrentTime = TICKS_TO_TIME( m_iPreviewStartTick );
  1997. }
  1998. void CDemoSmootherPanel::OnOriginEaseCurve( EASEFUNC easefunc )
  1999. {
  2000. if ( !m_bHasSelection )
  2001. return;
  2002. int c = m_Smoothing.smooth.Count();
  2003. if ( c < 2 )
  2004. return;
  2005. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  2006. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  2007. float dt = pend->frametick - pstart->frametick;
  2008. if ( dt <= 0.0f )
  2009. return;
  2010. m_bDirty = true;
  2011. PushUndo( "ease origin" );
  2012. int nSlot = 0;
  2013. Vector vstart, vend;
  2014. vstart = pstart->info.u[ nSlot ].GetViewOrigin();
  2015. vend = pend->info.u[ nSlot ].GetViewOrigin();
  2016. for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  2017. {
  2018. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  2019. float elapsed = p->frametick - pstart->frametick;
  2020. float frac = elapsed / dt;
  2021. // Apply ease function
  2022. frac = (*easefunc)( frac );
  2023. frac = clamp( frac, 0.0f, 1.0f );
  2024. p->info.u[ nSlot ].flags |= FDEMO_USE_ORIGIN2;
  2025. Vector interpolated;
  2026. VectorLerp( vstart, vend, frac, interpolated );
  2027. p->info.u[ nSlot ].viewOrigin2 = interpolated;
  2028. }
  2029. PushRedo( "ease origin" );
  2030. }
  2031. void CDemoSmootherPanel::ParseSmoothingInfo( CDemoFile &demoFile, CSmoothingContext& smoothing )
  2032. {
  2033. democmdinfo_t info;
  2034. int dummy;
  2035. bool foundFirstSelectable = false;
  2036. bool demofinished = false;
  2037. while ( !demofinished )
  2038. {
  2039. int tick = 0;
  2040. byte cmd;
  2041. bool swallowmessages = true;
  2042. do
  2043. {
  2044. int nPlayerSlot = 0;
  2045. demoFile.ReadCmdHeader( cmd, tick, nPlayerSlot );
  2046. // COMMAND HANDLERS
  2047. switch ( cmd )
  2048. {
  2049. case dem_synctick:
  2050. break;
  2051. case dem_stop:
  2052. {
  2053. swallowmessages = false;
  2054. demofinished = true;
  2055. }
  2056. break;
  2057. case dem_consolecmd:
  2058. {
  2059. ACTIVE_SPLITSCREEN_PLAYER_GUARD( nPlayerSlot );
  2060. demoFile.ReadConsoleCommand();
  2061. }
  2062. break;
  2063. case dem_datatables:
  2064. {
  2065. demoFile.ReadNetworkDataTables( NULL );
  2066. }
  2067. break;
  2068. case dem_stringtables:
  2069. {
  2070. demoFile.ReadStringTables( NULL );
  2071. }
  2072. break;
  2073. case dem_usercmd:
  2074. {
  2075. ACTIVE_SPLITSCREEN_PLAYER_GUARD( nPlayerSlot );
  2076. demoFile.ReadUserCmd( NULL, dummy );
  2077. }
  2078. break;
  2079. default:
  2080. {
  2081. swallowmessages = false;
  2082. }
  2083. break;
  2084. }
  2085. }
  2086. while ( swallowmessages );
  2087. if ( demofinished )
  2088. {
  2089. // StopPlayback();
  2090. return;
  2091. }
  2092. int curpos = demoFile.GetCurPos( true );
  2093. demoFile.ReadCmdInfo( info );
  2094. demoFile.ReadSequenceInfo( dummy, dummy );
  2095. demoFile.ReadRawData( NULL, 0 );
  2096. // Add to end of list
  2097. demosmoothing_t smoothing_entry;
  2098. int nSlot = 0;
  2099. smoothing_entry.file_offset = curpos;
  2100. smoothing_entry.frametick = tick;
  2101. smoothing_entry.info = info;
  2102. smoothing_entry.samplepoint = false;
  2103. smoothing_entry.vecmoved = info.u[ nSlot ].GetViewOrigin();
  2104. smoothing_entry.angmoved = info.u[ nSlot ].GetViewAngles();
  2105. smoothing_entry.targetpoint = false;
  2106. smoothing_entry.vectarget = info.u[ nSlot ].GetViewOrigin();
  2107. int sampleIndex = smoothing.smooth.AddToTail( smoothing_entry );
  2108. if ( !foundFirstSelectable &&
  2109. smoothing_entry.vecmoved.LengthSqr() > 0.0f )
  2110. {
  2111. foundFirstSelectable = true;
  2112. smoothing.m_nFirstSelectableSample = sampleIndex;
  2113. }
  2114. }
  2115. }
  2116. void CDemoSmootherPanel::LoadSmoothingInfo( const char *filename, CSmoothingContext& smoothing )
  2117. {
  2118. char name[ MAX_OSPATH ];
  2119. Q_strncpy (name, filename, sizeof(name) );
  2120. Q_DefaultExtension( name, ".dem", sizeof( name ) );
  2121. CDemoFile demoFile;
  2122. if ( !demoFile.Open( filename, true ) )
  2123. {
  2124. ConMsg( "ERROR: couldn't open %s.\n", name );
  2125. return;
  2126. }
  2127. demoheader_t * header = demoFile.ReadDemoHeader( NULL );
  2128. if ( !header )
  2129. {
  2130. demoFile.Close();
  2131. return;
  2132. }
  2133. ConMsg ("Smoothing demo from %s ...", name );
  2134. smoothing.active = true;
  2135. Q_strncpy( smoothing.filename, name, sizeof(smoothing.filename) );
  2136. smoothing.smooth.RemoveAll();
  2137. ClearSmoothingInfo( smoothing );
  2138. ParseSmoothingInfo( demoFile, smoothing );
  2139. demoFile.Close();
  2140. //Performsmoothing( smooth );
  2141. //SaveSmoothedDemo( name, smooth );
  2142. ConMsg ( " done.\n" );
  2143. }
  2144. void CDemoSmootherPanel::ClearSmoothingInfo( CSmoothingContext& smoothing )
  2145. {
  2146. int c = smoothing.smooth.Count();
  2147. int i;
  2148. for ( i = 0; i < c; i++ )
  2149. {
  2150. demosmoothing_t *p = &smoothing.smooth[ i ];
  2151. int nSlot = 0;
  2152. p->info.Reset();
  2153. p->vecmoved = p->info.u[ nSlot ].GetViewOrigin();
  2154. p->angmoved = p->info.u[ nSlot ].GetViewAngles();
  2155. p->samplepoint = false;
  2156. p->vectarget = p->info.u[ nSlot ].GetViewOrigin();
  2157. p->targetpoint = false;
  2158. }
  2159. }
  2160. void CDemoSmootherPanel::SaveSmoothingInfo( char const *filename, CSmoothingContext& smoothing )
  2161. {
  2162. // Nothing to do
  2163. int c = smoothing.smooth.Count();
  2164. if ( !c )
  2165. return;
  2166. IFileSystem *fs = g_pFileSystem;
  2167. FileHandle_t infile, outfile;
  2168. COM_OpenFile( filename, &infile );
  2169. if ( infile == FILESYSTEM_INVALID_HANDLE )
  2170. return;
  2171. int filesize = fs->Size( infile );
  2172. char outfilename[ 512 ];
  2173. Q_StripExtension( filename, outfilename, sizeof( outfilename ) );
  2174. Q_strncat( outfilename, "_smooth", sizeof(outfilename), COPY_ALL_CHARACTERS );
  2175. Q_DefaultExtension( outfilename, ".dem", sizeof( outfilename ) );
  2176. outfile = fs->Open( outfilename, "wb" );
  2177. if ( outfile == FILESYSTEM_INVALID_HANDLE )
  2178. {
  2179. fs->Close( infile );
  2180. return;
  2181. }
  2182. int i;
  2183. int lastwritepos = 0;
  2184. for ( i = 0; i < c; i++ )
  2185. {
  2186. demosmoothing_t *p = &smoothing.smooth[ i ];
  2187. int copyamount = p->file_offset - lastwritepos;
  2188. COM_CopyFileChunk( outfile, infile, copyamount );
  2189. fs->Seek( infile, p->file_offset, FILESYSTEM_SEEK_HEAD );
  2190. // wacky hacky overwriting
  2191. fs->Write( &p->info, sizeof( democmdinfo_t ), outfile );
  2192. lastwritepos = fs->Tell( outfile );
  2193. fs->Seek( infile, p->file_offset + sizeof( democmdinfo_t ), FILESYSTEM_SEEK_HEAD );
  2194. }
  2195. int final = filesize - lastwritepos;
  2196. COM_CopyFileChunk( outfile, infile, final );
  2197. fs->Close( outfile );
  2198. fs->Close( infile );
  2199. }