Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2729 lines
61 KiB

  1. //========= Copyright 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. if ( !CanEdit() )
  573. return false;
  574. if ( !demoplayer->IsPlaybackPaused() )
  575. return false;
  576. if ( m_bPreviewing )
  577. {
  578. if ( m_bPreviewPaused && GetCurrent() && GetCurrent()->samplepoint )
  579. {
  580. info.viewOrigin = GetCurrent()->vecmoved;
  581. info.viewAngles = GetCurrent()->angmoved;
  582. info.localViewAngles = info.viewAngles;
  583. bool back_off = m_pBackOff->IsSelected();
  584. if ( back_off )
  585. {
  586. Vector fwd;
  587. AngleVectors( info.viewAngles, &fwd, NULL, NULL );
  588. info.viewOrigin -= fwd * 75.0f;
  589. }
  590. return true;
  591. }
  592. // TODO: Hook up previewing view
  593. if ( !m_bPreviewPaused )
  594. {
  595. m_fPreviewCurrentTime += host_frametime;
  596. }
  597. if ( GetInterpolatedViewPoint( info.viewOrigin, info.viewAngles ) )
  598. {
  599. info.localViewAngles = info.viewAngles;
  600. return true;
  601. }
  602. else
  603. {
  604. return false;
  605. }
  606. }
  607. bool back_off = m_pBackOff->IsSelected();
  608. if ( back_off )
  609. {
  610. int useframe = GetFrameForTick( tick );
  611. if ( useframe < m_Smoothing.smooth.Count() && useframe >= 0 )
  612. {
  613. demosmoothing_t *p = &m_Smoothing.smooth[ useframe ];
  614. Vector fwd;
  615. AngleVectors( p->info.viewAngles, &fwd, NULL, NULL );
  616. info.viewOrigin = p->info.viewOrigin - fwd * 75.0f;
  617. }
  618. }
  619. return false;
  620. }
  621. void DrawVecForward( bool active, const Vector& origin, const QAngle& angles, int r, int g, int b )
  622. {
  623. Vector fwd;
  624. AngleVectors( angles, &fwd, NULL, NULL );
  625. Vector end;
  626. end = origin + fwd * ( active ? 64 : 16 );
  627. RenderLine( origin, end, Color( r, g, b, 255 ), true );
  628. }
  629. void GetColorForSample( bool original, bool samplepoint, bool targetpoint, demosmoothing_t *sample, int& r, int& g, int& b )
  630. {
  631. if ( samplepoint && sample->samplepoint )
  632. {
  633. r = 0;
  634. g = 255;
  635. b = 0;
  636. return;
  637. }
  638. if ( targetpoint && sample->targetpoint )
  639. {
  640. r = 255;
  641. g = 0;
  642. b = 0;
  643. return;
  644. }
  645. if ( sample->selected )
  646. {
  647. if( original )
  648. {
  649. r = 255;
  650. g = 200;
  651. b = 100;
  652. }
  653. else
  654. {
  655. r = 200;
  656. g = 100;
  657. b = 255;
  658. }
  659. if ( sample->samplepoint || sample->targetpoint )
  660. {
  661. r = 255;
  662. g = 255;
  663. b = 0;
  664. }
  665. return;
  666. }
  667. if ( original )
  668. {
  669. r = g = b = 255;
  670. }
  671. else
  672. {
  673. r = 150;
  674. g = 255;
  675. b = 100;
  676. }
  677. }
  678. //-----------------------------------------------------------------------------
  679. // Purpose:
  680. // Input : origin -
  681. // mins -
  682. // maxs -
  683. // angles -
  684. // r -
  685. // g -
  686. // b -
  687. // a -
  688. //-----------------------------------------------------------------------------
  689. void Draw_Box( const Vector& origin, const Vector& mins, const Vector& maxs, const QAngle& angles, int r, int g, int b, int a )
  690. {
  691. RenderBox( origin, angles, mins, maxs, Color( r, g, b, a ), false );
  692. RenderWireframeBox( origin, angles, mins, maxs, Color( r, g, b, a ), true );
  693. }
  694. //-----------------------------------------------------------------------------
  695. // Purpose:
  696. // Input : *sample -
  697. // *next -
  698. //-----------------------------------------------------------------------------
  699. void CDemoSmootherPanel::DrawSmoothingSample( bool original, bool processed, int samplenumber, demosmoothing_t *sample, demosmoothing_t *next )
  700. {
  701. int r, g, b;
  702. if ( original )
  703. {
  704. RenderLine( sample->info.viewOrigin + m_vecEyeOffset, next->info.viewOrigin + m_vecEyeOffset,
  705. Color( 180, 180, 180, 255 ), true );
  706. GetColorForSample( true, false, false, sample, r, g, b );
  707. DrawVecForward( false, sample->info.viewOrigin + m_vecEyeOffset, sample->info.viewAngles, r, g, b );
  708. }
  709. if ( processed && sample->info.flags != 0 )
  710. {
  711. RenderLine( sample->info.GetViewOrigin() + m_vecEyeOffset, next->info.GetViewOrigin() + m_vecEyeOffset,
  712. Color( 255, 255, 180, 255 ), true );
  713. GetColorForSample( false, false, false, sample, r, g, b );
  714. DrawVecForward( false, sample->info.GetViewOrigin() + m_vecEyeOffset, sample->info.GetViewAngles(), r, g, b );
  715. }
  716. if ( sample->samplepoint )
  717. {
  718. GetColorForSample( false, true, false, sample, r, g, b );
  719. RenderBox( sample->vecmoved + m_vecEyeOffset, sample->angmoved, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), Color( r, g, b, 127 ), false );
  720. DrawVecForward( false, sample->vecmoved + m_vecEyeOffset, sample->angmoved, r, g, b );
  721. }
  722. if ( sample->targetpoint )
  723. {
  724. GetColorForSample( false, false, true, sample, r, g, b );
  725. RenderBox( sample->vectarget, vec3_angle, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), Color( r, g, b, 127 ), false );
  726. }
  727. if ( samplenumber == m_nPreviewLastFrame + 1 )
  728. {
  729. r = 50;
  730. g = 100;
  731. b = 250;
  732. RenderBox( sample->info.GetViewOrigin() + m_vecEyeOffset, sample->info.GetViewAngles(), Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), Color( r, g, b, 92 ), false );
  733. }
  734. if ( sample->targetpoint )
  735. {
  736. r = 200;
  737. g = 200;
  738. b = 220;
  739. RenderLine( sample->info.GetViewOrigin() + m_vecEyeOffset, sample->vectarget, Color( r, g, b, 255 ), true );
  740. }
  741. }
  742. //-----------------------------------------------------------------------------
  743. // Purpose:
  744. //-----------------------------------------------------------------------------
  745. void CDemoSmootherPanel::DrawDebuggingInfo( int frame, float elapsed )
  746. {
  747. if ( !CanEdit() )
  748. return;
  749. if ( !IsVisible() )
  750. return;
  751. int c = m_Smoothing.smooth.Count();
  752. if ( c < 2 )
  753. return;
  754. int start = 0;
  755. int end = c - 1;
  756. bool showall = m_pShowAllSamples->IsSelected();
  757. if ( !showall )
  758. {
  759. start = max( frame - 200, 0 );
  760. end = min( frame + 200, c - 1 );
  761. }
  762. if ( m_bHasSelection && !showall )
  763. {
  764. start = max( m_nSelection[ 0 ] - 10, 0 );
  765. end = min( m_nSelection[ 1 ] + 10, c - 1 );
  766. }
  767. bool draworiginal = !m_pHideOriginal->IsSelected();
  768. bool drawprocessed = !m_pHideProcessed->IsSelected();
  769. int i;
  770. demosmoothing_t *p = NULL;
  771. demosmoothing_t *prev = NULL;
  772. for ( i = start; i < end; i++ )
  773. {
  774. p = &m_Smoothing.smooth[ i ];
  775. if ( prev && p )
  776. {
  777. DrawSmoothingSample( draworiginal, drawprocessed, i, prev, p );
  778. }
  779. prev = p;
  780. }
  781. Vector org;
  782. QAngle ang;
  783. if ( m_bPreviewing )
  784. {
  785. if ( GetInterpolatedOriginAndAngles( true, org, ang ) )
  786. {
  787. DrawVecForward( true, org + m_vecEyeOffset, ang, 200, 10, 50 );
  788. }
  789. }
  790. int useframe = frame;
  791. useframe = clamp( useframe, 0, c - 1 );
  792. if ( useframe < c )
  793. {
  794. p = &m_Smoothing.smooth[ useframe ];
  795. org = p->info.GetViewOrigin();
  796. ang = p->info.GetViewAngles();
  797. DrawVecForward( true, org + m_vecEyeOffset, ang, 100, 220, 250 );
  798. Draw_Box( org + m_vecEyeOffset, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), ang, 100, 220, 250, 127 );
  799. }
  800. DrawKeySpline();
  801. DrawTargetSpline();
  802. if ( !m_pHideLegend->IsSelected() )
  803. {
  804. DrawLegend( start, end );
  805. }
  806. }
  807. void CDemoSmootherPanel::OnSelect()
  808. {
  809. if ( !CanEdit() )
  810. return;
  811. m_bHasSelection = false;
  812. m_iSelectionTicksSpan = 0;
  813. memset( m_nSelection, 0, sizeof( m_nSelection ) );
  814. int start, end;
  815. start = GetStartFrame();
  816. end = GetEndFrame();
  817. int c = m_Smoothing.smooth.Count();
  818. if ( c < 2 )
  819. return;
  820. start = clamp( start, 0, c - 1 );
  821. end = clamp( end, 0, c - 1 );
  822. if ( start >= end )
  823. return;
  824. m_nSelection[ 0 ] = start;
  825. m_nSelection[ 1 ] = end;
  826. m_bHasSelection = true;
  827. demosmoothing_t *startsample = &m_Smoothing.smooth[ start ];
  828. demosmoothing_t *endsample = &m_Smoothing.smooth[ end ];
  829. m_bDirty = true;
  830. PushUndo( "select" );
  831. int i = 0;
  832. for ( i = 0; i < c; i++ )
  833. {
  834. if ( i >= start && i <= end )
  835. {
  836. m_Smoothing.smooth[ i ].selected = true;
  837. }
  838. else
  839. {
  840. m_Smoothing.smooth[ i ].selected = false;
  841. }
  842. }
  843. PushRedo( "select" );
  844. m_iSelectionTicksSpan = endsample->frametick - startsample->frametick;
  845. }
  846. int CDemoSmootherPanel::GetFrameForTick( int tick )
  847. {
  848. int count = m_Smoothing.smooth.Count();
  849. int last = count - 1;
  850. int first = m_Smoothing.m_nFirstSelectableSample;
  851. if ( first > last )
  852. return -1;
  853. if ( count <= 0 )
  854. {
  855. return -1; // no valid index
  856. }
  857. else if ( count == 1 )
  858. {
  859. return 0; // return the one and only frame we have
  860. }
  861. if ( tick <= m_Smoothing.smooth[ first ].frametick )
  862. return first;
  863. if ( tick >= m_Smoothing.smooth[ last ].frametick )
  864. return last;
  865. // binary search
  866. int middle;
  867. while ( true )
  868. {
  869. middle = (first+last)/2;
  870. int middleTick = m_Smoothing.smooth[ middle ].frametick;
  871. if ( tick == middleTick )
  872. return middle;
  873. if ( tick > middleTick )
  874. {
  875. if ( first == middle )
  876. return first;
  877. first = middle;
  878. }
  879. else
  880. {
  881. if ( last == middle )
  882. return last;
  883. last = middle;
  884. }
  885. }
  886. }
  887. int CDemoSmootherPanel::GetTickForFrame( int frame )
  888. {
  889. if ( !CanEdit() )
  890. return -1;
  891. int c = m_Smoothing.smooth.Count();
  892. if ( c < 1 )
  893. return -1;
  894. if ( frame < 0 )
  895. return m_Smoothing.smooth[ 0 ].frametick;
  896. if ( frame >= c )
  897. return m_Smoothing.smooth[ c - 1 ].frametick;
  898. return m_Smoothing.smooth[ frame ].frametick;
  899. }
  900. //-----------------------------------------------------------------------------
  901. // Purpose: Interpolate Euler angles using quaternions to avoid singularities
  902. // Input : start -
  903. // end -
  904. // output -
  905. // frac -
  906. //-----------------------------------------------------------------------------
  907. static void InterpolateAngles( const QAngle& start, const QAngle& end, QAngle& output, float frac )
  908. {
  909. Quaternion src, dest;
  910. // Convert to quaternions
  911. AngleQuaternion( start, src );
  912. AngleQuaternion( end, dest );
  913. Quaternion result;
  914. // Slerp
  915. QuaternionSlerp( src, dest, frac, result );
  916. // Convert to euler
  917. QuaternionAngles( result, output );
  918. }
  919. bool CDemoSmootherPanel::GetInterpolatedOriginAndAngles( bool readonly, Vector& origin, QAngle& angles )
  920. {
  921. origin.Init();
  922. angles.Init();
  923. Assert( m_bPreviewing );
  924. // Figure out the best samples
  925. int startframe = m_nPreviewLastFrame;
  926. int nextframe = startframe + 1;
  927. float time = m_fPreviewCurrentTime;
  928. int c = m_Smoothing.smooth.Count();
  929. do
  930. {
  931. if ( startframe >= c || nextframe >= c )
  932. {
  933. if ( !readonly )
  934. {
  935. //m_bPreviewing = false;
  936. }
  937. return false;
  938. }
  939. demosmoothing_t *startsample = &m_Smoothing.smooth[ startframe ];
  940. demosmoothing_t *endsample = &m_Smoothing.smooth[ nextframe ];
  941. if ( nextframe >= min( m_nSelection[1] + 10, c - 1 ) )
  942. {
  943. if ( !readonly )
  944. {
  945. OnPreview( m_bPreviewOriginal );
  946. }
  947. return false;
  948. }
  949. // If large dt, then jump ahead quickly in time
  950. float dt = TICKS_TO_TIME( endsample->frametick - startsample->frametick );
  951. if ( dt > 1.0f )
  952. {
  953. startframe++;
  954. nextframe++;
  955. continue;
  956. }
  957. if ( TICKS_TO_TIME( endsample->frametick ) >= time )
  958. {
  959. // Found a spot
  960. dt = TICKS_TO_TIME( endsample->frametick - startsample->frametick );
  961. // Should never occur!!!
  962. if ( dt <= 0.0f )
  963. {
  964. return false;
  965. }
  966. float frac = (float)( time - TICKS_TO_TIME(startsample->frametick) ) / dt;
  967. frac = clamp( frac, 0.0f, 1.0f );
  968. // Compute render origin/angles
  969. Vector renderOrigin;
  970. QAngle renderAngles;
  971. if ( m_bPreviewOriginal )
  972. {
  973. VectorLerp( startsample->info.viewOrigin, endsample->info.viewOrigin, frac, renderOrigin );
  974. InterpolateAngles( startsample->info.viewAngles, endsample->info.viewAngles, renderAngles, frac );
  975. }
  976. else
  977. {
  978. VectorLerp( startsample->info.GetViewOrigin(), endsample->info.GetViewOrigin(), frac, renderOrigin );
  979. InterpolateAngles( startsample->info.GetViewAngles(), endsample->info.GetViewAngles(), renderAngles, frac );
  980. }
  981. origin = renderOrigin;
  982. angles = renderAngles;
  983. if ( !readonly )
  984. {
  985. SetLastFrame( false, startframe );
  986. }
  987. break;
  988. }
  989. startframe++;
  990. nextframe++;
  991. } while ( true );
  992. return true;
  993. }
  994. //-----------------------------------------------------------------------------
  995. // Purpose:
  996. // Input : t -
  997. //-----------------------------------------------------------------------------
  998. bool CDemoSmootherPanel::GetInterpolatedViewPoint( Vector& origin, QAngle& angles )
  999. {
  1000. Assert( m_bPreviewing );
  1001. if ( !GetInterpolatedOriginAndAngles( false, origin, angles ) )
  1002. return false;
  1003. bool back_off = m_pBackOff->IsSelected();
  1004. if ( back_off )
  1005. {
  1006. Vector fwd;
  1007. AngleVectors( angles, &fwd, NULL, NULL );
  1008. origin = origin - fwd * 75.0f;
  1009. }
  1010. return true;
  1011. }
  1012. void CDemoSmootherPanel::OnTogglePause()
  1013. {
  1014. if ( !m_bPreviewing )
  1015. return;
  1016. m_bPreviewPaused = !m_bPreviewPaused;
  1017. }
  1018. void CDemoSmootherPanel::OnStep( bool forward )
  1019. {
  1020. if ( !m_bPreviewing )
  1021. return;
  1022. if ( !m_bPreviewPaused )
  1023. return;
  1024. int c = m_Smoothing.smooth.Count();
  1025. SetLastFrame( false, m_nPreviewLastFrame + ( forward ? 1 : -1 ) );
  1026. SetLastFrame( false, clamp( m_nPreviewLastFrame, max( m_nSelection[ 0 ] - 10, 0 ), min( m_nSelection[ 1 ] + 10, c - 1 ) ) );
  1027. m_fPreviewCurrentTime = TICKS_TO_TIME( GetTickForFrame( m_nPreviewLastFrame ) );
  1028. }
  1029. void CDemoSmootherPanel::DrawLegend( int startframe, int endframe )
  1030. {
  1031. int i;
  1032. int skip = 20;
  1033. bool back_off = m_pBackOff->IsSelected();
  1034. for ( i = startframe; i <= endframe; i++ )
  1035. {
  1036. bool show = ( i % skip ) == 0;
  1037. demosmoothing_t *sample = &m_Smoothing.smooth[ i ];
  1038. if ( sample->samplepoint || sample->targetpoint )
  1039. show = true;
  1040. if ( !show )
  1041. continue;
  1042. char sz[ 512 ];
  1043. Q_snprintf( sz, sizeof( sz ), "%.3f", TICKS_TO_TIME(sample->frametick) );
  1044. Vector fwd;
  1045. AngleVectors( sample->info.GetViewAngles(), &fwd, NULL, NULL );
  1046. CDebugOverlay::AddTextOverlay( sample->info.GetViewOrigin() + m_vecEyeOffset + fwd * ( back_off ? 5.0f : 50.0f ), 0, -1.0f, sz );
  1047. }
  1048. }
  1049. #define EASE_TIME 0.2f
  1050. Quaternion SmoothAngles( CUtlVector< Quaternion >& stack )
  1051. {
  1052. int c = stack.Count();
  1053. Assert( c >= 1 );
  1054. float weight = 1.0f / (float)c;
  1055. Quaternion output;
  1056. output.Init();
  1057. int i;
  1058. for ( i = 0; i < c; i++ )
  1059. {
  1060. Quaternion t = stack[ i ];
  1061. QuaternionBlend( output, t, weight, output );
  1062. }
  1063. return output;
  1064. }
  1065. Vector SmoothOrigin( CUtlVector< Vector >& stack )
  1066. {
  1067. int c = stack.Count();
  1068. Assert( c >= 1 );
  1069. Vector output;
  1070. output.Init();
  1071. int i;
  1072. for ( i = 0; i < c; i++ )
  1073. {
  1074. Vector t = stack[ i ];
  1075. VectorAdd( output, t, output );
  1076. }
  1077. VectorScale( output, 1.0f / (float)c, output );
  1078. return output;
  1079. }
  1080. //-----------------------------------------------------------------------------
  1081. // Purpose:
  1082. //-----------------------------------------------------------------------------
  1083. void CDemoSmootherPanel::OnSetKeys(float interval)
  1084. {
  1085. if ( !m_bHasSelection )
  1086. return;
  1087. m_bDirty = true;
  1088. PushUndo( "OnSetKeys" );
  1089. int c = m_Smoothing.smooth.Count();
  1090. int i;
  1091. demosmoothing_t *lastkey = NULL;
  1092. for ( i = 0; i < c; i++ )
  1093. {
  1094. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1095. if ( !p->selected )
  1096. continue;
  1097. p->angmoved = p->info.GetViewAngles();;
  1098. p->vecmoved = p->info.GetViewOrigin();
  1099. p->samplepoint = false;
  1100. if ( !lastkey ||
  1101. TICKS_TO_TIME( p->frametick - lastkey->frametick ) >= interval )
  1102. {
  1103. lastkey = p;
  1104. p->samplepoint = true;
  1105. }
  1106. }
  1107. PushRedo( "OnSetKeys" );
  1108. }
  1109. //-----------------------------------------------------------------------------
  1110. // Purpose:
  1111. //-----------------------------------------------------------------------------
  1112. void CDemoSmootherPanel::OnSmoothSelectionAngles( void )
  1113. {
  1114. if ( !m_bHasSelection )
  1115. return;
  1116. int c = m_Smoothing.smooth.Count();
  1117. int i;
  1118. CUtlVector< Quaternion > stack;
  1119. m_bDirty = true;
  1120. PushUndo( "smooth angles" );
  1121. for ( i = 0; i < c; i++ )
  1122. {
  1123. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1124. if ( !p->selected )
  1125. continue;
  1126. while ( stack.Count() > 10 )
  1127. {
  1128. stack.Remove( 0 );
  1129. }
  1130. Quaternion q;
  1131. AngleQuaternion( p->info.GetViewAngles(), q );
  1132. stack.AddToTail( q );
  1133. p->info.flags |= FDEMO_USE_ANGLES2;
  1134. Quaternion aveq = SmoothAngles( stack );
  1135. QAngle outangles;
  1136. QuaternionAngles( aveq, outangles );
  1137. p->info.viewAngles2 = outangles;
  1138. p->info.localViewAngles2 = outangles;
  1139. }
  1140. PushRedo( "smooth angles" );
  1141. }
  1142. //-----------------------------------------------------------------------------
  1143. // Purpose:
  1144. //-----------------------------------------------------------------------------
  1145. void CDemoSmootherPanel::OnSmoothSelectionOrigin( void )
  1146. {
  1147. if ( !m_bHasSelection )
  1148. return;
  1149. int c = m_Smoothing.smooth.Count();
  1150. int i;
  1151. CUtlVector< Vector > stack;
  1152. m_bDirty = true;
  1153. PushUndo( "smooth origin" );
  1154. for ( i = 0; i < c; i++ )
  1155. {
  1156. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1157. if ( !p->selected )
  1158. continue;
  1159. if ( i < 2 )
  1160. continue;
  1161. if ( i >= c - 2 )
  1162. continue;
  1163. stack.RemoveAll();
  1164. for ( int j = -2; j <= 2; j++ )
  1165. {
  1166. stack.AddToTail( m_Smoothing.smooth[ i + j ].info.GetViewOrigin() );
  1167. }
  1168. p->info.flags |= FDEMO_USE_ORIGIN2;
  1169. Vector org = SmoothOrigin( stack );
  1170. p->info.viewOrigin2 = org;
  1171. }
  1172. PushRedo( "smooth origin" );
  1173. }
  1174. void CDemoSmootherPanel::PerformLinearInterpolatedAngleSmoothing( int startframe, int endframe )
  1175. {
  1176. demosmoothing_t *pstart = &m_Smoothing.smooth[ startframe ];
  1177. demosmoothing_t *pend = &m_Smoothing.smooth[ endframe ];
  1178. int dt = pend->frametick - pstart->frametick;
  1179. if ( dt <= 0 )
  1180. {
  1181. dt = 1;
  1182. }
  1183. CUtlVector< Quaternion > stack;
  1184. Quaternion qstart, qend;
  1185. AngleQuaternion( pstart->info.GetViewAngles(), qstart );
  1186. AngleQuaternion( pend->info.GetViewAngles(), qend );
  1187. for ( int i = startframe; i <= endframe; i++ )
  1188. {
  1189. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1190. int elapsed = p->frametick - pstart->frametick;
  1191. float frac = (float)elapsed / (float)dt;
  1192. frac = clamp( frac, 0.0f, 1.0f );
  1193. p->info.flags |= FDEMO_USE_ANGLES2;
  1194. Quaternion interpolated;
  1195. QuaternionSlerp( qstart, qend, frac, interpolated );
  1196. QAngle outangles;
  1197. QuaternionAngles( interpolated, outangles );
  1198. p->info.viewAngles2 = outangles;
  1199. p->info.localViewAngles2 = outangles;
  1200. }
  1201. }
  1202. void CDemoSmootherPanel::OnLinearInterpolateAnglesBasedOnEndpoints( void )
  1203. {
  1204. if ( !m_bHasSelection )
  1205. return;
  1206. int c = m_Smoothing.smooth.Count();
  1207. if ( c < 2 )
  1208. return;
  1209. m_bDirty = true;
  1210. PushUndo( "linear interp angles" );
  1211. PerformLinearInterpolatedAngleSmoothing( m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1212. PushRedo( "linear interp angles" );
  1213. }
  1214. void CDemoSmootherPanel::OnLinearInterpolateOriginBasedOnEndpoints( void )
  1215. {
  1216. if ( !m_bHasSelection )
  1217. return;
  1218. int c = m_Smoothing.smooth.Count();
  1219. if ( c < 2 )
  1220. return;
  1221. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1222. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1223. int dt = pend->frametick - pstart->frametick;
  1224. if ( dt <= 0 )
  1225. return;
  1226. m_bDirty = true;
  1227. PushUndo( "linear interp origin" );
  1228. Vector vstart, vend;
  1229. vstart = pstart->info.GetViewOrigin();
  1230. vend = pend->info.GetViewOrigin();
  1231. for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1232. {
  1233. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1234. float elapsed = p->frametick - pstart->frametick;
  1235. float frac = elapsed / (float)dt;
  1236. frac = clamp( frac, 0.0f, 1.0f );
  1237. p->info.flags |= FDEMO_USE_ORIGIN2;
  1238. Vector interpolated;
  1239. VectorLerp( vstart, vend, frac, interpolated );
  1240. p->info.viewOrigin2 = interpolated;
  1241. }
  1242. PushRedo( "linear interp origin" );
  1243. }
  1244. void CDemoSmootherPanel::OnRevertPoint( void )
  1245. {
  1246. demosmoothing_t *p = GetCurrent();
  1247. if ( !p )
  1248. return;
  1249. m_bDirty = true;
  1250. PushUndo( "revert point" );
  1251. p->angmoved = p->info.GetViewAngles();
  1252. p->vecmoved = p->info.GetViewOrigin();
  1253. p->samplepoint = false;
  1254. p->vectarget = p->info.GetViewOrigin();
  1255. p->targetpoint = false;
  1256. // m_ViewOrigin = p->info.viewOrigin;
  1257. // m_ViewAngles = p->info.viewAngles;
  1258. PushRedo( "revert point" );
  1259. }
  1260. demosmoothing_t *CDemoSmootherPanel::GetCurrent( void )
  1261. {
  1262. if ( !CanEdit() )
  1263. return NULL;
  1264. int c = m_Smoothing.smooth.Count();
  1265. if ( c < 1 )
  1266. return NULL;
  1267. int frame = clamp( m_nPreviewLastFrame, 0, c - 1 );
  1268. return &m_Smoothing.smooth[ frame ];
  1269. }
  1270. void CDemoSmootherPanel::AddSamplePoints( bool usetarget, bool includeboundaries, CUtlVector< demosmoothing_t * >& points, int start, int end )
  1271. {
  1272. points.RemoveAll();
  1273. int i;
  1274. for ( i = start; i <= end; i++ )
  1275. {
  1276. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1277. if ( includeboundaries )
  1278. {
  1279. if ( i == start )
  1280. {
  1281. // Add it twice
  1282. points.AddToTail( p );
  1283. continue;
  1284. }
  1285. else if ( i == end )
  1286. {
  1287. // Add twice
  1288. points.AddToTail( p );
  1289. continue;
  1290. }
  1291. }
  1292. if ( usetarget && p->targetpoint )
  1293. {
  1294. points.AddToTail( p );
  1295. }
  1296. if ( !usetarget && p->samplepoint )
  1297. {
  1298. points.AddToTail( p );
  1299. }
  1300. }
  1301. }
  1302. demosmoothing_t *CDemoSmootherPanel::GetBoundedSample( CUtlVector< demosmoothing_t * >& points, int sample )
  1303. {
  1304. int c = points.Count();
  1305. if ( sample < 0 )
  1306. return points[ 0 ];
  1307. else if ( sample >= c )
  1308. return points[ c - 1 ];
  1309. return points[ sample ];
  1310. }
  1311. //-----------------------------------------------------------------------------
  1312. // Purpose:
  1313. // Input : t -
  1314. // points -
  1315. // prev -
  1316. // next -
  1317. //-----------------------------------------------------------------------------
  1318. void CDemoSmootherPanel::FindSpanningPoints( int tick, CUtlVector< demosmoothing_t * >& points, int& prev, int& next )
  1319. {
  1320. prev = -1;
  1321. next = 0;
  1322. int c = points.Count();
  1323. int i;
  1324. for ( i = 0; i < c; i++ )
  1325. {
  1326. demosmoothing_t *p = points[ i ];
  1327. if ( tick < p->frametick )
  1328. break;
  1329. }
  1330. next = i;
  1331. prev = i - 1;
  1332. next = clamp( next, 0, c - 1 );
  1333. prev = clamp( prev, 0, c - 1 );
  1334. }
  1335. void CDemoSmootherPanel::OnSplineSampleOrigin( void )
  1336. {
  1337. if ( !m_bHasSelection )
  1338. return;
  1339. int c = m_Smoothing.smooth.Count();
  1340. if ( c < 2 )
  1341. return;
  1342. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1343. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1344. if ( pend->frametick - pstart->frametick <= 0 )
  1345. return;
  1346. CUtlVector< demosmoothing_t * > points;
  1347. AddSamplePoints( false, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1348. if ( points.Count() <= 0 )
  1349. return;
  1350. m_bDirty = true;
  1351. PushUndo( "spline origin" );
  1352. for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1353. {
  1354. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1355. demosmoothing_t *earliest;
  1356. demosmoothing_t *current;
  1357. demosmoothing_t *next;
  1358. demosmoothing_t *latest;
  1359. int cur;
  1360. int cur2;
  1361. FindSpanningPoints( p->frametick, points, cur, cur2 );
  1362. earliest = GetBoundedSample( points, cur - 1 );
  1363. current = GetBoundedSample( points, cur );
  1364. next = GetBoundedSample( points, cur2 );
  1365. latest = GetBoundedSample( points, cur2 + 1 );
  1366. float frac = 0.0f;
  1367. float dt = next->frametick - current->frametick;
  1368. if ( dt > 0.0f )
  1369. {
  1370. frac = (float)( p->frametick - current->frametick ) / dt;
  1371. }
  1372. frac = clamp( frac, 0.0f, 1.0f );
  1373. Vector splined;
  1374. Catmull_Rom_Spline_Normalize( earliest->vecmoved, current->vecmoved, next->vecmoved, latest->vecmoved, frac, splined );
  1375. p->info.flags |= FDEMO_USE_ORIGIN2;
  1376. p->info.viewOrigin2 = splined;
  1377. }
  1378. PushRedo( "spline origin" );
  1379. }
  1380. void CDemoSmootherPanel::OnSplineSampleAngles( void )
  1381. {
  1382. if ( !m_bHasSelection )
  1383. return;
  1384. int c = m_Smoothing.smooth.Count();
  1385. if ( c < 2 )
  1386. return;
  1387. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1388. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1389. if ( pend->frametick - pstart->frametick <= 0 )
  1390. return;
  1391. CUtlVector< demosmoothing_t * > points;
  1392. AddSamplePoints( false, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1393. if ( points.Count() <= 0 )
  1394. return;
  1395. m_bDirty = true;
  1396. PushUndo( "spline angles" );
  1397. for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1398. {
  1399. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1400. demosmoothing_t *current;
  1401. demosmoothing_t *next;
  1402. int cur;
  1403. int cur2;
  1404. FindSpanningPoints( p->frametick, points, cur, cur2 );
  1405. current = GetBoundedSample( points, cur );
  1406. next = GetBoundedSample( points, cur2 );
  1407. float frac = 0.0f;
  1408. float dt = next->frametick - current->frametick;
  1409. if ( dt > 0.0f )
  1410. {
  1411. frac = (float)( p->frametick - current->frametick ) / dt;
  1412. }
  1413. frac = clamp( frac, 0.0f, 1.0f );
  1414. frac = SimpleSpline( frac );
  1415. QAngle splined;
  1416. InterpolateAngles( current->angmoved, next->angmoved, splined, frac );
  1417. p->info.flags |= FDEMO_USE_ANGLES2;
  1418. p->info.viewAngles2 = splined;
  1419. p->info.localViewAngles2 = splined;
  1420. }
  1421. PushRedo( "spline angles" );
  1422. }
  1423. void CDemoSmootherPanel::OnLookAtPoints( bool spline )
  1424. {
  1425. if ( !m_bHasSelection )
  1426. return;
  1427. int c = m_Smoothing.smooth.Count();
  1428. int i;
  1429. if ( c < 2 )
  1430. return;
  1431. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1432. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1433. if ( pend->frametick - pstart->frametick <= 0 )
  1434. return;
  1435. CUtlVector< demosmoothing_t * > points;
  1436. AddSamplePoints( true, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1437. if ( points.Count() < 1 )
  1438. return;
  1439. m_bDirty = true;
  1440. PushUndo( "lookat points" );
  1441. for ( i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1442. {
  1443. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1444. demosmoothing_t *earliest;
  1445. demosmoothing_t *current;
  1446. demosmoothing_t *next;
  1447. demosmoothing_t *latest;
  1448. int cur;
  1449. int cur2;
  1450. FindSpanningPoints( p->frametick, points, cur, cur2 );
  1451. earliest = GetBoundedSample( points, cur - 1 );
  1452. current = GetBoundedSample( points, cur );
  1453. next = GetBoundedSample( points, cur2 );
  1454. latest = GetBoundedSample( points, cur2 + 1 );
  1455. float frac = 0.0f;
  1456. float dt = next->frametick - current->frametick;
  1457. if ( dt > 0.0f )
  1458. {
  1459. frac = (float)( p->frametick - current->frametick ) / dt;
  1460. }
  1461. frac = clamp( frac, 0.0f, 1.0f );
  1462. Vector splined;
  1463. if ( spline )
  1464. {
  1465. Catmull_Rom_Spline_Normalize( earliest->vectarget, current->vectarget, next->vectarget, latest->vectarget, frac, splined );
  1466. }
  1467. else
  1468. {
  1469. Vector d = next->vectarget - current->vectarget;
  1470. VectorMA( current->vectarget, frac, d, splined );
  1471. }
  1472. Vector vecToTarget = splined - ( p->info.GetViewOrigin() + m_vecEyeOffset );
  1473. VectorNormalize( vecToTarget );
  1474. QAngle angles;
  1475. VectorAngles( vecToTarget, angles );
  1476. p->info.flags |= FDEMO_USE_ANGLES2;
  1477. p->info.viewAngles2 = angles;
  1478. p->info.localViewAngles2 = angles;
  1479. }
  1480. PushRedo( "lookat points" );
  1481. }
  1482. void CDemoSmootherPanel::SetLastFrame( bool jumptotarget, int frame )
  1483. {
  1484. // bool changed = frame != m_nPreviewLastFrame;
  1485. int useFrame = max( m_Smoothing.m_nFirstSelectableSample, frame );
  1486. m_nPreviewLastFrame = useFrame;
  1487. /* if ( changed && !m_pLockCamera->IsSelected() )
  1488. {
  1489. // Reset default view/angles
  1490. demosmoothing_t *p = GetCurrent();
  1491. if ( p )
  1492. {
  1493. if ( p->samplepoint && !jumptotarget )
  1494. {
  1495. m_ViewOrigin = p->vecmoved;
  1496. m_ViewAngles = p->angmoved;
  1497. }
  1498. else if ( p->targetpoint && jumptotarget )
  1499. {
  1500. m_ViewOrigin = p->vectarget - m_vecEyeOffset;
  1501. }
  1502. else
  1503. {
  1504. if ( m_bPreviewing && m_bPreviewOriginal )
  1505. {
  1506. m_ViewOrigin = p->info.viewOrigin;
  1507. m_ViewAngles = p->info.viewAngles;
  1508. }
  1509. else
  1510. {
  1511. m_ViewOrigin = p->info.GetViewOrigin();
  1512. m_ViewAngles = p->info.GetViewAngles();
  1513. }
  1514. }
  1515. }
  1516. } */
  1517. }
  1518. // Undo/Redo
  1519. void CDemoSmootherPanel::Undo( void )
  1520. {
  1521. if ( m_UndoStack.Size() > 0 && m_nUndoLevel > 0 )
  1522. {
  1523. m_nUndoLevel--;
  1524. DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
  1525. Assert( u->undo );
  1526. m_Smoothing = *(u->undo);
  1527. }
  1528. InvalidateLayout();
  1529. }
  1530. void CDemoSmootherPanel::Redo( void )
  1531. {
  1532. if ( m_UndoStack.Size() > 0 && m_nUndoLevel <= m_UndoStack.Size() - 1 )
  1533. {
  1534. DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
  1535. Assert( u->redo );
  1536. m_Smoothing = *(u->redo);
  1537. m_nUndoLevel++;
  1538. }
  1539. InvalidateLayout();
  1540. }
  1541. void CDemoSmootherPanel::PushUndo( const char *description )
  1542. {
  1543. Assert( !m_bRedoPending );
  1544. m_bRedoPending = true;
  1545. WipeRedo();
  1546. // Copy current data
  1547. CSmoothingContext *u = new CSmoothingContext;
  1548. *u = m_Smoothing;
  1549. DemoSmoothUndo *undo = new DemoSmoothUndo;
  1550. undo->undo = u;
  1551. undo->redo = NULL;
  1552. undo->udescription = COM_StringCopy( description );
  1553. undo->rdescription = NULL;
  1554. m_UndoStack.AddToTail( undo );
  1555. m_nUndoLevel++;
  1556. }
  1557. void CDemoSmootherPanel::PushRedo( const char *description )
  1558. {
  1559. Assert( m_bRedoPending );
  1560. m_bRedoPending = false;
  1561. // Copy current data
  1562. CSmoothingContext *r = new CSmoothingContext;
  1563. *r = m_Smoothing;
  1564. DemoSmoothUndo *undo = m_UndoStack[ m_nUndoLevel - 1 ];
  1565. undo->redo = r;
  1566. undo->rdescription = COM_StringCopy( description );
  1567. }
  1568. void CDemoSmootherPanel::WipeUndo( void )
  1569. {
  1570. while ( m_UndoStack.Size() > 0 )
  1571. {
  1572. DemoSmoothUndo *u = m_UndoStack[ 0 ];
  1573. delete u->undo;
  1574. delete u->redo;
  1575. delete[] u->udescription;
  1576. delete[] u->rdescription;
  1577. delete u;
  1578. m_UndoStack.Remove( 0 );
  1579. }
  1580. m_nUndoLevel = 0;
  1581. }
  1582. void CDemoSmootherPanel::WipeRedo( void )
  1583. {
  1584. // Wipe everything above level
  1585. while ( m_UndoStack.Size() > m_nUndoLevel )
  1586. {
  1587. DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
  1588. delete u->undo;
  1589. delete u->redo;
  1590. delete[] u->udescription;
  1591. delete[] u->rdescription;
  1592. delete u;
  1593. m_UndoStack.Remove( m_nUndoLevel );
  1594. }
  1595. }
  1596. //-----------------------------------------------------------------------------
  1597. // Purpose:
  1598. // Output : const char
  1599. //-----------------------------------------------------------------------------
  1600. const char *CDemoSmootherPanel::GetUndoDescription( void )
  1601. {
  1602. if ( m_nUndoLevel != 0 )
  1603. {
  1604. DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel - 1 ];
  1605. return u->udescription;
  1606. }
  1607. return "???undo";
  1608. }
  1609. //-----------------------------------------------------------------------------
  1610. // Purpose:
  1611. // Output : const char
  1612. //-----------------------------------------------------------------------------
  1613. const char *CDemoSmootherPanel::GetRedoDescription( void )
  1614. {
  1615. if ( m_nUndoLevel != m_UndoStack.Size() )
  1616. {
  1617. DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
  1618. return u->rdescription;
  1619. }
  1620. return "???redo";
  1621. }
  1622. //-----------------------------------------------------------------------------
  1623. // Purpose:
  1624. // Output : Returns true on success, false on failure.
  1625. //-----------------------------------------------------------------------------
  1626. bool CDemoSmootherPanel::CanRedo( void )
  1627. {
  1628. if ( !m_UndoStack.Count() )
  1629. return false;
  1630. if ( m_nUndoLevel == m_UndoStack.Count() )
  1631. return false;
  1632. return true;
  1633. }
  1634. //-----------------------------------------------------------------------------
  1635. // Purpose:
  1636. // Output : Returns true on success, false on failure.
  1637. //-----------------------------------------------------------------------------
  1638. bool CDemoSmootherPanel::CanUndo( void )
  1639. {
  1640. if ( !m_UndoStack.Count() )
  1641. return false;
  1642. if ( m_nUndoLevel == 0 )
  1643. return false;
  1644. return true;
  1645. }
  1646. //-----------------------------------------------------------------------------
  1647. // Purpose:
  1648. //-----------------------------------------------------------------------------
  1649. void CDemoSmootherPanel::OnToggleKeyFrame( void )
  1650. {
  1651. demosmoothing_t *p = GetCurrent();
  1652. if ( !p )
  1653. return;
  1654. m_bDirty = true;
  1655. PushUndo( "toggle keyframe" );
  1656. // use orginal data by default
  1657. p->angmoved = p->info.GetViewAngles();
  1658. p->vecmoved = p->info.GetViewOrigin();
  1659. if ( !p->samplepoint )
  1660. {
  1661. if ( g_pDemoUI->IsInDriveMode() )
  1662. {
  1663. g_pDemoUI->GetDriveViewPoint( p->vecmoved, p->angmoved );
  1664. }
  1665. if ( g_pDemoUI2->IsInDriveMode() )
  1666. {
  1667. g_pDemoUI2->GetDriveViewPoint( p->vecmoved, p->angmoved );
  1668. }
  1669. p->samplepoint = true;
  1670. }
  1671. else
  1672. {
  1673. p->samplepoint = false;
  1674. }
  1675. PushRedo( "toggle keyframe" );
  1676. }
  1677. //-----------------------------------------------------------------------------
  1678. // Purpose:
  1679. //-----------------------------------------------------------------------------
  1680. void CDemoSmootherPanel::OnToggleLookTarget( void )
  1681. {
  1682. demosmoothing_t *p = GetCurrent();
  1683. if ( !p )
  1684. return;
  1685. m_bDirty = true;
  1686. PushUndo( "toggle look target" );
  1687. // use orginal data by default
  1688. p->vectarget = p->info.GetViewOrigin();
  1689. if ( !p->targetpoint )
  1690. {
  1691. QAngle angles;
  1692. g_pDemoUI->GetDriveViewPoint( p->vectarget, angles );
  1693. g_pDemoUI2->GetDriveViewPoint( p->vectarget, angles );
  1694. p->targetpoint = true;
  1695. }
  1696. else
  1697. {
  1698. p->targetpoint = false;
  1699. }
  1700. PushRedo( "toggle look target" );
  1701. }
  1702. //-----------------------------------------------------------------------------
  1703. // Purpose:
  1704. //-----------------------------------------------------------------------------
  1705. void CDemoSmootherPanel::OnNextKey()
  1706. {
  1707. if( !m_bHasSelection )
  1708. return;
  1709. int start = m_nPreviewLastFrame + 1;
  1710. int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
  1711. int moved = 0;
  1712. while ( moved < maxmove )
  1713. {
  1714. demosmoothing_t *p = &m_Smoothing.smooth[ start ];
  1715. if ( p->samplepoint )
  1716. {
  1717. SetLastFrame( false, start );
  1718. break;
  1719. }
  1720. start++;
  1721. if ( start > m_nSelection[1] )
  1722. start = m_nSelection[0];
  1723. moved++;
  1724. }
  1725. }
  1726. //-----------------------------------------------------------------------------
  1727. // Purpose:
  1728. //-----------------------------------------------------------------------------
  1729. void CDemoSmootherPanel::OnPrevKey()
  1730. {
  1731. if( !m_bHasSelection )
  1732. return;
  1733. int start = m_nPreviewLastFrame - 1;
  1734. int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
  1735. int moved = 0;
  1736. while ( moved < maxmove && start >= 0 )
  1737. {
  1738. demosmoothing_t *p = &m_Smoothing.smooth[ start ];
  1739. if ( p->samplepoint )
  1740. {
  1741. SetLastFrame( false, start );
  1742. break;
  1743. }
  1744. start--;
  1745. if ( start < m_nSelection[0] )
  1746. start = m_nSelection[1];
  1747. moved++;
  1748. }
  1749. }
  1750. //-----------------------------------------------------------------------------
  1751. // Purpose:
  1752. //-----------------------------------------------------------------------------
  1753. void CDemoSmootherPanel::OnNextTarget()
  1754. {
  1755. if( !m_bHasSelection )
  1756. return;
  1757. int start = m_nPreviewLastFrame + 1;
  1758. int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
  1759. int moved = 0;
  1760. while ( moved < maxmove )
  1761. {
  1762. demosmoothing_t *p = &m_Smoothing.smooth[ start ];
  1763. if ( p->targetpoint )
  1764. {
  1765. SetLastFrame( true, start );
  1766. break;
  1767. }
  1768. start++;
  1769. if ( start > m_nSelection[1] )
  1770. start = m_nSelection[0];
  1771. moved++;
  1772. }
  1773. }
  1774. //-----------------------------------------------------------------------------
  1775. // Purpose:
  1776. //-----------------------------------------------------------------------------
  1777. void CDemoSmootherPanel::OnPrevTarget()
  1778. {
  1779. if( !m_bHasSelection )
  1780. return;
  1781. int start = m_nPreviewLastFrame - 1;
  1782. int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
  1783. int moved = 0;
  1784. while ( moved < maxmove )
  1785. {
  1786. demosmoothing_t *p = &m_Smoothing.smooth[ start ];
  1787. if ( p->targetpoint )
  1788. {
  1789. SetLastFrame( true, start );
  1790. break;
  1791. }
  1792. start--;
  1793. if ( start < m_nSelection[0] )
  1794. start = m_nSelection[1];
  1795. moved++;
  1796. }
  1797. }
  1798. void CDemoSmootherPanel::DrawTargetSpline()
  1799. {
  1800. if ( !m_bHasSelection )
  1801. return;
  1802. int c = m_Smoothing.smooth.Count();
  1803. int i;
  1804. if ( c < 2 )
  1805. return;
  1806. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1807. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1808. if ( pend->frametick - pstart->frametick <= 0 )
  1809. return;
  1810. CUtlVector< demosmoothing_t * > points;
  1811. AddSamplePoints( true, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1812. if ( points.Count() < 1 )
  1813. return;
  1814. Vector previous(0,0,0);
  1815. for ( i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1816. {
  1817. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1818. demosmoothing_t *earliest;
  1819. demosmoothing_t *current;
  1820. demosmoothing_t *next;
  1821. demosmoothing_t *latest;
  1822. int cur;
  1823. int cur2;
  1824. FindSpanningPoints( p->frametick, points, cur, cur2 );
  1825. earliest = GetBoundedSample( points, cur - 1 );
  1826. current = GetBoundedSample( points, cur );
  1827. next = GetBoundedSample( points, cur2 );
  1828. latest = GetBoundedSample( points, cur2 + 1 );
  1829. float frac = 0.0f;
  1830. float dt = next->frametick - current->frametick;
  1831. if ( dt > 0.0f )
  1832. {
  1833. frac = (float)( p->frametick - current->frametick ) / dt;
  1834. }
  1835. frac = clamp( frac, 0.0f, 1.0f );
  1836. Vector splined;
  1837. Catmull_Rom_Spline_Normalize( earliest->vectarget, current->vectarget, next->vectarget, latest->vectarget, frac, splined );
  1838. if ( i > m_nSelection[0] )
  1839. {
  1840. RenderLine( previous, splined, Color( 0, 255, 0, 255 ), true );
  1841. }
  1842. previous = splined;
  1843. }
  1844. }
  1845. void CDemoSmootherPanel::DrawKeySpline()
  1846. {
  1847. if ( !m_bHasSelection )
  1848. return;
  1849. int c = m_Smoothing.smooth.Count();
  1850. int i;
  1851. if ( c < 2 )
  1852. return;
  1853. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1854. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1855. if ( pend->frametick - pstart->frametick <= 0 )
  1856. return;
  1857. CUtlVector< demosmoothing_t * > points;
  1858. AddSamplePoints( false, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
  1859. if ( points.Count() < 1 )
  1860. return;
  1861. Vector previous(0,0,0);
  1862. for ( i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1863. {
  1864. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1865. demosmoothing_t *earliest;
  1866. demosmoothing_t *current;
  1867. demosmoothing_t *next;
  1868. demosmoothing_t *latest;
  1869. int cur;
  1870. int cur2;
  1871. FindSpanningPoints( p->frametick, points, cur, cur2 );
  1872. earliest = GetBoundedSample( points, cur - 1 );
  1873. current = GetBoundedSample( points, cur );
  1874. next = GetBoundedSample( points, cur2 );
  1875. latest = GetBoundedSample( points, cur2 + 1 );
  1876. float frac = 0.0f;
  1877. float dt = next->frametick - current->frametick;
  1878. if ( dt > 0.0f )
  1879. {
  1880. frac = (float)( p->frametick - current->frametick ) / dt;
  1881. }
  1882. frac = clamp( frac, 0.0f, 1.0f );
  1883. Vector splined;
  1884. Catmull_Rom_Spline_Normalize( earliest->vecmoved, current->vecmoved, next->vecmoved, latest->vecmoved, frac, splined );
  1885. splined += m_vecEyeOffset;
  1886. if ( i > m_nSelection[0] )
  1887. {
  1888. RenderLine( previous, splined, Color( 0, 255, 0, 255 ), true );
  1889. }
  1890. previous = splined;
  1891. }
  1892. }
  1893. void CDemoSmootherPanel::OnSmoothEdges( bool left, bool right )
  1894. {
  1895. if ( !m_bHasSelection )
  1896. return;
  1897. if ( !left && !right )
  1898. return;
  1899. int c = m_Smoothing.smooth.Count();
  1900. // Get number of frames
  1901. char sz[ 512 ];
  1902. m_pFixEdgeFrames->GetText( sz, sizeof( sz ) );
  1903. int frames = atoi( sz );
  1904. if ( frames <= 2 )
  1905. return;
  1906. m_bDirty = true;
  1907. PushUndo( "smooth edges" );
  1908. if ( left && m_nSelection[0] > 0 )
  1909. {
  1910. PerformLinearInterpolatedAngleSmoothing( m_nSelection[ 0 ] - 1, m_nSelection[ 0 ] + frames );
  1911. }
  1912. if ( right && m_nSelection[1] < c - 1 )
  1913. {
  1914. PerformLinearInterpolatedAngleSmoothing( m_nSelection[ 1 ] - frames, m_nSelection[ 1 ] + 1 );
  1915. }
  1916. PushRedo( "smooth edges" );
  1917. }
  1918. void CDemoSmootherPanel::OnSaveKey()
  1919. {
  1920. if ( !m_bHasSelection )
  1921. return;
  1922. demosmoothing_t *p = GetCurrent();
  1923. if ( !p )
  1924. return;
  1925. if ( !p->samplepoint )
  1926. return;
  1927. m_bDirty = true;
  1928. PushUndo( "save key" );
  1929. p->info.viewAngles2 = p->angmoved;
  1930. p->info.localViewAngles2 = p->angmoved;
  1931. p->info.viewOrigin2 = p->vecmoved;
  1932. p->info.flags |= FDEMO_USE_ORIGIN2;
  1933. p->info.flags |= FDEMO_USE_ANGLES2;
  1934. PushRedo( "save key" );
  1935. }
  1936. void CDemoSmootherPanel::OnSetView()
  1937. {
  1938. if ( !m_bHasSelection )
  1939. return;
  1940. demosmoothing_t *p = GetCurrent();
  1941. if ( !p )
  1942. return;
  1943. Vector origin = p->info.GetViewOrigin();
  1944. QAngle angle = p->info.GetViewAngles();
  1945. g_pDemoUI->SetDriveViewPoint( origin, angle );
  1946. g_pDemoUI2->SetDriveViewPoint( origin, angle );
  1947. }
  1948. //-----------------------------------------------------------------------------
  1949. // Purpose:
  1950. //-----------------------------------------------------------------------------
  1951. void CDemoSmootherPanel::OnGotoFrame()
  1952. {
  1953. int c = m_Smoothing.smooth.Count();
  1954. if ( c < 2 )
  1955. return;
  1956. char sz[ 256 ];
  1957. m_pGotoFrame->GetText( sz, sizeof( sz ) );
  1958. int frame = atoi( sz );
  1959. if ( !m_bPreviewing )
  1960. {
  1961. if ( !m_bHasSelection )
  1962. {
  1963. m_pStartFrame->SetText( va( "%i", 0 ) );
  1964. m_pEndFrame->SetText( va( "%i", c - 1 ) );
  1965. OnSelect();
  1966. }
  1967. OnPreview( false );
  1968. OnTogglePause();
  1969. }
  1970. if ( !m_bPreviewing )
  1971. return;
  1972. SetLastFrame( false, frame );
  1973. m_iPreviewStartTick = GetTickForFrame( m_nPreviewLastFrame );
  1974. m_fPreviewCurrentTime = TICKS_TO_TIME( m_iPreviewStartTick );
  1975. }
  1976. void CDemoSmootherPanel::OnOriginEaseCurve( EASEFUNC easefunc )
  1977. {
  1978. if ( !m_bHasSelection )
  1979. return;
  1980. int c = m_Smoothing.smooth.Count();
  1981. if ( c < 2 )
  1982. return;
  1983. demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
  1984. demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
  1985. float dt = pend->frametick - pstart->frametick;
  1986. if ( dt <= 0.0f )
  1987. return;
  1988. m_bDirty = true;
  1989. PushUndo( "ease origin" );
  1990. Vector vstart, vend;
  1991. vstart = pstart->info.GetViewOrigin();
  1992. vend = pend->info.GetViewOrigin();
  1993. for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
  1994. {
  1995. demosmoothing_t *p = &m_Smoothing.smooth[ i ];
  1996. float elapsed = p->frametick - pstart->frametick;
  1997. float frac = elapsed / dt;
  1998. // Apply ease function
  1999. frac = (*easefunc)( frac );
  2000. frac = clamp( frac, 0.0f, 1.0f );
  2001. p->info.flags |= FDEMO_USE_ORIGIN2;
  2002. Vector interpolated;
  2003. VectorLerp( vstart, vend, frac, interpolated );
  2004. p->info.viewOrigin2 = interpolated;
  2005. }
  2006. PushRedo( "ease origin" );
  2007. }
  2008. void CDemoSmootherPanel::ParseSmoothingInfo( CDemoFile &demoFile, CSmoothingContext& smoothing )
  2009. {
  2010. democmdinfo_t info;
  2011. int dummy;
  2012. bool foundFirstSelectable = false;
  2013. bool demofinished = false;
  2014. while ( !demofinished )
  2015. {
  2016. int tick = 0;
  2017. byte cmd;
  2018. bool swallowmessages = true;
  2019. do
  2020. {
  2021. demoFile.ReadCmdHeader( cmd, tick );
  2022. // COMMAND HANDLERS
  2023. switch ( cmd )
  2024. {
  2025. case dem_synctick:
  2026. break;
  2027. case dem_stop:
  2028. {
  2029. swallowmessages = false;
  2030. demofinished = true;
  2031. }
  2032. break;
  2033. case dem_consolecmd:
  2034. {
  2035. demoFile.ReadConsoleCommand();
  2036. }
  2037. break;
  2038. case dem_datatables:
  2039. {
  2040. demoFile.ReadNetworkDataTables( NULL );
  2041. }
  2042. break;
  2043. case dem_stringtables:
  2044. {
  2045. demoFile.ReadStringTables( NULL );
  2046. }
  2047. break;
  2048. case dem_usercmd:
  2049. {
  2050. demoFile.ReadUserCmd( NULL, dummy );
  2051. }
  2052. break;
  2053. default:
  2054. {
  2055. swallowmessages = false;
  2056. }
  2057. break;
  2058. }
  2059. }
  2060. while ( swallowmessages );
  2061. if ( demofinished )
  2062. {
  2063. // StopPlayback();
  2064. return;
  2065. }
  2066. int curpos = demoFile.GetCurPos( true );
  2067. demoFile.ReadCmdInfo( info );
  2068. demoFile.ReadSequenceInfo( dummy, dummy );
  2069. demoFile.ReadRawData( NULL, 0 );
  2070. // Add to end of list
  2071. demosmoothing_t smoothing_entry;
  2072. smoothing_entry.file_offset = curpos;
  2073. smoothing_entry.frametick = tick;
  2074. smoothing_entry.info = info;
  2075. smoothing_entry.samplepoint = false;
  2076. smoothing_entry.vecmoved = info.GetViewOrigin();
  2077. smoothing_entry.angmoved = info.GetViewAngles();
  2078. smoothing_entry.targetpoint = false;
  2079. smoothing_entry.vectarget = info.GetViewOrigin();
  2080. int sampleIndex = smoothing.smooth.AddToTail( smoothing_entry );
  2081. if ( !foundFirstSelectable &&
  2082. smoothing_entry.vecmoved.LengthSqr() > 0.0f )
  2083. {
  2084. foundFirstSelectable = true;
  2085. smoothing.m_nFirstSelectableSample = sampleIndex;
  2086. }
  2087. }
  2088. }
  2089. void CDemoSmootherPanel::LoadSmoothingInfo( const char *filename, CSmoothingContext& smoothing )
  2090. {
  2091. char name[ MAX_OSPATH ];
  2092. Q_strncpy (name, filename, sizeof(name) );
  2093. Q_DefaultExtension( name, ".dem", sizeof( name ) );
  2094. CDemoFile demoFile;
  2095. if ( !demoFile.Open( filename, true ) )
  2096. {
  2097. ConMsg( "ERROR: couldn't open %s.\n", name );
  2098. return;
  2099. }
  2100. demoheader_t * header = demoFile.ReadDemoHeader();
  2101. if ( !header )
  2102. {
  2103. demoFile.Close();
  2104. return;
  2105. }
  2106. ConMsg ("Smoothing demo from %s ...", name );
  2107. smoothing.active = true;
  2108. Q_strncpy( smoothing.filename, name, sizeof(smoothing.filename) );
  2109. smoothing.smooth.RemoveAll();
  2110. ClearSmoothingInfo( smoothing );
  2111. ParseSmoothingInfo( demoFile, smoothing );
  2112. demoFile.Close();
  2113. //Performsmoothing( smooth );
  2114. //SaveSmoothedDemo( name, smooth );
  2115. ConMsg ( " done.\n" );
  2116. }
  2117. void CDemoSmootherPanel::ClearSmoothingInfo( CSmoothingContext& smoothing )
  2118. {
  2119. int c = smoothing.smooth.Count();
  2120. int i;
  2121. for ( i = 0; i < c; i++ )
  2122. {
  2123. demosmoothing_t *p = &smoothing.smooth[ i ];
  2124. p->info.Reset();
  2125. p->vecmoved = p->info.GetViewOrigin();
  2126. p->angmoved = p->info.GetViewAngles();
  2127. p->samplepoint = false;
  2128. p->vectarget = p->info.GetViewOrigin();
  2129. p->targetpoint = false;
  2130. }
  2131. }
  2132. void CDemoSmootherPanel::SaveSmoothingInfo( char const *filename, CSmoothingContext& smoothing )
  2133. {
  2134. // Nothing to do
  2135. int c = smoothing.smooth.Count();
  2136. if ( !c )
  2137. return;
  2138. IFileSystem *fs = g_pFileSystem;
  2139. FileHandle_t infile, outfile;
  2140. COM_OpenFile( filename, &infile );
  2141. if ( infile == FILESYSTEM_INVALID_HANDLE )
  2142. return;
  2143. int filesize = fs->Size( infile );
  2144. char outfilename[ 512 ];
  2145. Q_StripExtension( filename, outfilename, sizeof( outfilename ) );
  2146. Q_strncat( outfilename, "_smooth", sizeof(outfilename), COPY_ALL_CHARACTERS );
  2147. Q_DefaultExtension( outfilename, ".dem", sizeof( outfilename ) );
  2148. outfile = fs->Open( outfilename, "wb" );
  2149. if ( outfile == FILESYSTEM_INVALID_HANDLE )
  2150. {
  2151. fs->Close( infile );
  2152. return;
  2153. }
  2154. int i;
  2155. int lastwritepos = 0;
  2156. for ( i = 0; i < c; i++ )
  2157. {
  2158. demosmoothing_t *p = &smoothing.smooth[ i ];
  2159. int copyamount = p->file_offset - lastwritepos;
  2160. COM_CopyFileChunk( outfile, infile, copyamount );
  2161. fs->Seek( infile, p->file_offset, FILESYSTEM_SEEK_HEAD );
  2162. // wacky hacky overwriting
  2163. fs->Write( &p->info, sizeof( democmdinfo_t ), outfile );
  2164. lastwritepos = fs->Tell( outfile );
  2165. fs->Seek( infile, p->file_offset + sizeof( democmdinfo_t ), FILESYSTEM_SEEK_HEAD );
  2166. }
  2167. int final = filesize - lastwritepos;
  2168. COM_CopyFileChunk( outfile, infile, final );
  2169. fs->Close( outfile );
  2170. fs->Close( infile );
  2171. }