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.

2704 lines
61 KiB

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