summaryrefslogtreecommitdiff
path: root/engine/cl_demosmootherpanel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engine/cl_demosmootherpanel.cpp')
-rw-r--r--engine/cl_demosmootherpanel.cpp2729
1 files changed, 2729 insertions, 0 deletions
diff --git a/engine/cl_demosmootherpanel.cpp b/engine/cl_demosmootherpanel.cpp
new file mode 100644
index 0000000..602afc1
--- /dev/null
+++ b/engine/cl_demosmootherpanel.cpp
@@ -0,0 +1,2729 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+#include "client_pch.h"
+#include "cl_demosmootherpanel.h"
+#include <vgui_controls/Button.h>
+#include <vgui_controls/CheckButton.h>
+#include <vgui_controls/Label.h>
+
+#include <vgui_controls/Controls.h>
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include <vgui_controls/PropertySheet.h>
+#include <vgui/IVGui.h>
+#include <vgui_controls/FileOpenDialog.h>
+#include <vgui_controls/ProgressBar.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/MenuButton.h>
+#include <vgui_controls/Menu.h>
+#include <vgui_controls/TextEntry.h>
+#include <vgui/IInput.h>
+
+#include "cl_demouipanel.h"
+#include "demofile/demoformat.h"
+#include "cl_demoactionmanager.h"
+#include "tier2/renderutils.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+static float Ease_In( float t )
+{
+ float out = sqrt( t );
+ return out;
+}
+
+static float Ease_Out( float t )
+{
+ float out = t * t;
+ return out;
+}
+
+static float Ease_Both( float t )
+{
+ return SimpleSpline( t );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: A menu button that knows how to parse cvar/command menu data from gamedir\scripts\debugmenu.txt
+//-----------------------------------------------------------------------------
+class CSmoothingTypeButton : public vgui::MenuButton
+{
+ typedef vgui::MenuButton BaseClass;
+
+public:
+ // Construction
+ CSmoothingTypeButton( vgui::Panel *parent, const char *panelName, const char *text );
+
+private:
+ // Menu associated with this button
+ Menu *m_pMenu;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CSmoothingTypeButton::CSmoothingTypeButton(Panel *parent, const char *panelName, const char *text)
+ : BaseClass( parent, panelName, text )
+{
+ // Assume no menu
+ m_pMenu = new Menu( this, "DemoSmootherTypeMenu" );
+
+ m_pMenu->AddMenuItem( "Smooth Selection Angles", "smoothselectionangles", parent );
+ m_pMenu->AddMenuItem( "Smooth Selection Origin", "smoothselectionorigin", parent );
+ m_pMenu->AddMenuItem( "Linear Interp Angles", "smoothlinearinterpolateangles", parent );
+ m_pMenu->AddMenuItem( "Linear Interp Origin", "smoothlinearinterpolateorigin", parent );
+ m_pMenu->AddMenuItem( "Spline Angles", "splineangles", parent );
+ m_pMenu->AddMenuItem( "Spline Origin", "splineorigin", parent );
+ m_pMenu->AddMenuItem( "Look At Points", "lookatpoints", parent );
+ m_pMenu->AddMenuItem( "Look At Points Spline", "lookatpointsspline", parent );
+ m_pMenu->AddMenuItem( "Two Point Origin Ease Out", "origineaseout", parent );
+ m_pMenu->AddMenuItem( "Two Point Origin Ease In", "origineasein", parent );
+ m_pMenu->AddMenuItem( "Two Point Origin Ease In/Out", "origineaseboth", parent );
+ m_pMenu->AddMenuItem( "Auto-setup keys 1/2 second", "keyshalf", parent );
+ m_pMenu->AddMenuItem( "Auto-setup keys 1 second", "keys1", parent );
+ m_pMenu->AddMenuItem( "Auto-setup keys 2 second", "keys2", parent );
+ m_pMenu->AddMenuItem( "Auto-setup keys 4 second", "keys4", parent );
+
+ m_pMenu->MakePopup();
+ MenuButton::SetMenu(m_pMenu);
+ SetOpenDirection(Menu::UP);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: A menu button that knows how to parse cvar/command menu data from gamedir\scripts\debugmenu.txt
+//-----------------------------------------------------------------------------
+class CFixEdgeButton : public vgui::MenuButton
+{
+ typedef vgui::MenuButton BaseClass;
+
+public:
+ // Construction
+ CFixEdgeButton( vgui::Panel *parent, const char *panelName, const char *text );
+
+private:
+ // Menu associated with this button
+ Menu *m_pMenu;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CFixEdgeButton::CFixEdgeButton(Panel *parent, const char *panelName, const char *text)
+ : BaseClass( parent, panelName, text )
+{
+ // Assume no menu
+ m_pMenu = new Menu( this, "DemoSmootherEdgeFixType" );
+
+ m_pMenu->AddMenuItem( "Smooth Left", "smoothleft", parent );
+ m_pMenu->AddMenuItem( "Smooth Right", "smoothright", parent );
+ m_pMenu->AddMenuItem( "Smooth Both", "smoothboth", parent );
+
+ m_pMenu->MakePopup();
+ MenuButton::SetMenu(m_pMenu);
+ SetOpenDirection(Menu::UP);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Basic help dialog
+//-----------------------------------------------------------------------------
+CDemoSmootherPanel::CDemoSmootherPanel( vgui::Panel *parent ) : Frame( parent, "DemoSmootherPanel")
+{
+ int w = 440;
+ int h = 300;
+
+ SetSize( w, h );
+
+ SetTitle("Demo Smoother", true);
+
+ m_pType = new CSmoothingTypeButton( this, "DemoSmootherType", "Process->" );
+
+ m_pRevert = new vgui::Button( this, "DemoSmoothRevert", "Revert" );;
+ m_pOK = new vgui::Button( this, "DemoSmoothOk", "OK" );
+ m_pCancel = new vgui::Button( this, "DemoSmoothCancel", "Cancel" );
+
+ m_pSave = new vgui::Button( this, "DemoSmoothSave", "Save" );
+ m_pReloadFromDisk = new vgui::Button( this, "DemoSmoothReload", "Reload" );
+
+ m_pStartFrame = new vgui::TextEntry( this, "DemoSmoothStartFrame" );
+ m_pEndFrame = new vgui::TextEntry( this, "DemoSmoothEndFrame" );
+
+ m_pPreviewOriginal = new vgui::Button( this, "DemoSmoothPreviewOriginal", "Show Original" );
+ m_pPreviewProcessed = new vgui::Button( this, "DemoSmoothPreviewProcessed", "Show Processed" );
+
+ m_pBackOff = new vgui::CheckButton( this, "DemoSmoothBackoff", "Back off" );
+ m_pHideLegend = new vgui::CheckButton( this, "DemoSmoothHideLegend", "Hide legend" );
+
+ m_pHideOriginal = new vgui::CheckButton( this, "DemoSmoothHideOriginal", "Hide original" );
+ m_pHideProcessed = new vgui::CheckButton( this, "DemoSmoothHideProcessed", "Hide processed" );
+
+ m_pSelectionInfo = new vgui::Label( this, "DemoSmoothSelectionInfo", "" );
+ m_pShowAllSamples = new vgui::CheckButton( this, "DemoSmoothShowAll", "Show All" );
+ m_pSelectSamples = new vgui::Button( this, "DemoSmoothSelect", "Select" );
+
+ m_pPauseResume = new vgui::Button( this, "DemoSmoothPauseResume", "Pause" );
+ m_pStepForward = new vgui::Button( this, "DemoSmoothStepForward", ">>" );
+ m_pStepBackward = new vgui::Button( this, "DemoSmoothStepBackward", "<<" );
+
+ m_pRevertPoint = new vgui::Button( this, "DemoSmoothRevertPoint", "Revert Pt." );
+ m_pToggleKeyFrame = new vgui::Button( this, "DemoSmoothSetKeyFrame", "Mark Keyframe" );
+ m_pToggleLookTarget = new vgui::Button( this, "DemoSmoothSetLookTarget", "Mark Look Target" );
+
+ m_pUndo = new vgui::Button( this, "DemoSmoothUndo", "Undo" );
+ m_pRedo = new vgui::Button( this, "DemoSmoothRedo", "Redo" );
+
+ m_pNextKey = new vgui::Button( this, "DemoSmoothNextKey", "+Key" );
+ m_pPrevKey = new vgui::Button( this, "DemoSmoothPrevKey", "-Key" );
+
+ m_pNextTarget = new vgui::Button( this, "DemoSmoothNextTarget", "+Target" );
+ m_pPrevTarget = new vgui::Button( this, "DemoSmoothPrevTarget", "-Target" );
+
+ m_pMoveCameraToPoint = new vgui::Button( this, "DemoSmoothCameraAtPoint", "Set View" );
+
+ m_pFixEdges = new CFixEdgeButton( this, "DemoSmoothFixFrameButton", "Edge->" );
+ m_pFixEdgeFrames = new vgui::TextEntry( this, "DemoSmoothFixFrames" );
+
+ m_pProcessKey = new vgui::Button( this, "DemoSmoothSaveKey", "Save Key" );
+
+ m_pGotoFrame = new vgui::TextEntry( this, "DemoSmoothGotoFrame" );
+ m_pGoto = new vgui::Button( this, "DemoSmoothGoto", "Jump To" );
+
+ //m_pCurrentDemo = new vgui::Label( this, "DemoName", "" );
+
+ vgui::ivgui()->AddTickSignal( GetVPanel(), 0 );
+
+ LoadControlSettings("Resource\\DemoSmootherPanel.res");
+
+ /*
+ int xpos, ypos;
+ parent->GetPos( xpos, ypos );
+ ypos += parent->GetTall();
+
+ SetPos( xpos, ypos );
+ */
+
+ OnRefresh();
+
+ SetVisible( true );
+ SetSizeable( false );
+ SetMoveable( true );
+
+ Reset();
+
+ m_vecEyeOffset = Vector( 0, 0, 64 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CDemoSmootherPanel::~CDemoSmootherPanel()
+{
+}
+
+void CDemoSmootherPanel::Reset( void )
+{
+ ClearSmoothingInfo( m_Smoothing );
+
+ m_bPreviewing = false;
+ m_bPreviewPaused = false;
+ m_bPreviewOriginal = false;
+ m_iPreviewStartTick = 0;
+ m_fPreviewCurrentTime = 0.0f;
+ m_nPreviewLastFrame = 0;
+
+ m_bHasSelection = false;
+ memset( m_nSelection, 0, sizeof( m_nSelection ) );
+ m_iSelectionTicksSpan = 0;
+
+ m_bInputActive = false;
+ memset( m_nOldCursor, 0, sizeof( m_nOldCursor ) );
+
+ WipeUndo();
+ WipeRedo();
+ m_bRedoPending = false;
+ m_nUndoLevel = 0;
+ m_bDirty = false;
+}
+
+
+void CDemoSmootherPanel::OnTick()
+{
+ BaseClass::OnTick();
+
+ m_pUndo->SetEnabled( CanUndo() );
+ m_pRedo->SetEnabled( CanRedo() );
+
+ m_pPauseResume->SetEnabled( m_bPreviewing );
+ m_pStepForward->SetEnabled( m_bPreviewing );
+ m_pStepBackward->SetEnabled( m_bPreviewing );
+
+ m_pSave->SetEnabled( m_bDirty );
+
+ demosmoothing_t *p = GetCurrent();
+ if ( p )
+ {
+ m_pToggleKeyFrame->SetEnabled( true );
+ m_pToggleLookTarget->SetEnabled( true );
+
+ m_pToggleKeyFrame->SetText( p->samplepoint ? "Delete Key" : "Make Key" );
+ m_pToggleLookTarget->SetText( p->targetpoint ? "Delete Target" : "Make Target" );
+
+ m_pProcessKey->SetEnabled( p->samplepoint );
+ }
+ else
+ {
+ m_pToggleKeyFrame->SetEnabled( false );
+ m_pToggleLookTarget->SetEnabled( false );
+
+ m_pProcessKey->SetEnabled( false );
+ }
+
+ if ( m_bPreviewing )
+ {
+ m_pPauseResume->SetText( m_bPreviewPaused ? "Resume" : "Pause" );
+ }
+
+ if ( !m_Smoothing.active )
+ {
+ m_pSelectionInfo->SetText( "No smoothing info loaded" );
+ return;
+ }
+
+ if ( !demoplayer->IsPlayingBack() )
+ {
+ m_pSelectionInfo->SetText( "Not playing back .dem" );
+ return;
+ }
+
+ if ( !m_bHasSelection )
+ {
+ m_pSelectionInfo->SetText( "No selection." );
+ return;
+ }
+
+ char sz[ 512 ];
+ if ( m_bPreviewing )
+ {
+ Q_snprintf( sz, sizeof( sz ), "%.3f at tick %i (%.3f s)",
+ m_fPreviewCurrentTime,
+ GetTickForFrame( m_nPreviewLastFrame ),
+ TICKS_TO_TIME( m_iSelectionTicksSpan ) );
+ }
+ else
+ {
+ Q_snprintf( sz, sizeof( sz ), "%i to %i (%.3f s)",
+ m_Smoothing.smooth[ m_nSelection[ 0 ] ].frametick,
+ m_Smoothing.smooth[ m_nSelection[ 1 ] ].frametick,
+ TICKS_TO_TIME( m_iSelectionTicksSpan ) );
+ }
+ m_pSelectionInfo->SetText( sz );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CDemoSmootherPanel::CanEdit()
+{
+ if ( !m_Smoothing.active )
+ return false;
+
+ if ( !demoplayer->IsPlayingBack() )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnCommand(const char *command)
+{
+ if ( !Q_strcasecmp( command, "cancel" ) )
+ {
+ OnRevert();
+ MarkForDeletion();
+ Reset();
+ OnClose();
+ }
+ else if ( !Q_strcasecmp( command, "close" ) )
+ {
+ OnSave();
+ MarkForDeletion();
+ Reset();
+ OnClose();
+ }
+ else if ( !Q_strcasecmp( command, "gotoframe" ) )
+ {
+ OnGotoFrame();
+ }
+ else if ( !Q_strcasecmp( command, "undo" ) )
+ {
+ Undo();
+ }
+ else if ( !Q_strcasecmp( command, "redo" ) )
+ {
+ Redo();
+ }
+ else if ( !Q_strcasecmp( command, "revert" ) )
+ {
+ OnRevert();
+ }
+ else if ( !Q_strcasecmp( command, "original" ) )
+ {
+ OnPreview( true );
+ }
+ else if ( !Q_strcasecmp( command, "processed" ) )
+ {
+ OnPreview( false );
+ }
+ else if ( !Q_strcasecmp( command, "save" ) )
+ {
+ OnSave();
+ }
+ else if ( !Q_strcasecmp( command, "reload" ) )
+ {
+ OnReload();
+ }
+ else if ( !Q_strcasecmp( command, "select" ) )
+ {
+ OnSelect();
+ }
+ else if ( !Q_strcasecmp( command, "togglepause" ) )
+ {
+ OnTogglePause();
+ }
+ else if ( !Q_strcasecmp( command, "stepforward" ) )
+ {
+ OnStep( true );
+ }
+ else if ( !Q_strcasecmp( command, "stepbackward" ) )
+ {
+ OnStep( false );
+ }
+ else if ( !Q_strcasecmp( command, "revertpoint" ) )
+ {
+ OnRevertPoint();
+ }
+ else if ( !Q_strcasecmp( command, "keyframe" ) )
+ {
+ OnToggleKeyFrame();
+ }
+ else if ( !Q_strcasecmp( command, "looktarget" ) )
+ {
+ OnToggleLookTarget();
+ }
+ else if ( !Q_strcasecmp( command, "nextkey" ) )
+ {
+ OnNextKey();
+ }
+ else if ( !Q_strcasecmp( command, "prevkey" ) )
+ {
+ OnPrevKey();
+ }
+ else if ( !Q_strcasecmp( command, "nexttarget" ) )
+ {
+ OnNextTarget();
+ }
+ else if ( !Q_strcasecmp( command, "prevtarget" ) )
+ {
+ OnPrevTarget();
+ }
+ else if ( !Q_strcasecmp( command, "smoothselectionangles" ) )
+ {
+ OnSmoothSelectionAngles();
+ }
+ else if ( !Q_strcasecmp( command, "keyshalf" ) )
+ {
+ OnSetKeys( 0.5f );
+ }
+ else if ( !Q_strcasecmp( command, "keys1" ) )
+ {
+ OnSetKeys( 1.0f );
+ }
+ else if ( !Q_strcasecmp( command, "keys2" ) )
+ {
+ OnSetKeys( 2.0f );
+ }
+ else if ( !Q_strcasecmp( command, "keys4" ) )
+ {
+ OnSetKeys( 4.0f );
+ }
+ else if ( !Q_strcasecmp( command, "smoothselectionorigin" ) )
+ {
+ OnSmoothSelectionOrigin();
+ }
+ else if ( !Q_strcasecmp( command, "smoothlinearinterpolateangles" ) )
+ {
+ OnLinearInterpolateAnglesBasedOnEndpoints();
+ }
+ else if ( !Q_strcasecmp( command, "smoothlinearinterpolateorigin" ) )
+ {
+ OnLinearInterpolateOriginBasedOnEndpoints();
+ }
+ else if ( !Q_strcasecmp( command, "splineorigin" ) )
+ {
+ OnSplineSampleOrigin();
+ }
+ else if ( !Q_strcasecmp( command, "splineangles" ) )
+ {
+ OnSplineSampleAngles();
+ }
+ else if ( !Q_strcasecmp( command, "lookatpoints" ) )
+ {
+ OnLookAtPoints( false );
+ }
+ else if ( !Q_strcasecmp( command, "lookatpointsspline" ) )
+ {
+ OnLookAtPoints( true );
+ }
+ else if ( !Q_strcasecmp( command, "smoothleft" ) )
+ {
+ OnSmoothEdges( true, false );
+ }
+ else if ( !Q_strcasecmp( command, "smoothright" ) )
+ {
+ OnSmoothEdges( false, true );
+ }
+ else if ( !Q_strcasecmp( command, "smoothboth" ) )
+ {
+ OnSmoothEdges( true, true );
+ }
+ else if ( !Q_strcasecmp( command, "origineasein" ) )
+ {
+ OnOriginEaseCurve( Ease_In );
+ }
+ else if ( !Q_strcasecmp( command, "origineaseout" ) )
+ {
+ OnOriginEaseCurve( Ease_Out );
+ }
+ else if ( !Q_strcasecmp( command, "origineaseboth" ) )
+ {
+ OnOriginEaseCurve( Ease_Both );
+ }
+ else if ( !Q_strcasecmp( command, "processkey" ) )
+ {
+ OnSaveKey();
+ }
+ else if ( !Q_strcasecmp( command, "setview" ) )
+ {
+ OnSetView();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnSave()
+{
+ if ( !m_Smoothing.active )
+ return;
+
+ SaveSmoothingInfo( demoaction->GetCurrentDemoFile(), m_Smoothing );
+ WipeUndo();
+ m_bDirty = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnReload()
+{
+ WipeUndo();
+ WipeRedo();
+ LoadSmoothingInfo( demoaction->GetCurrentDemoFile(), m_Smoothing );
+ m_bDirty = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnVDMChanged( void )
+{
+ if ( IsVisible() )
+ {
+ OnReload();
+ }
+ else
+ {
+ Reset();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnRevert()
+{
+ OnRefresh();
+ if ( !m_Smoothing.active )
+ {
+ LoadSmoothingInfo( demoaction->GetCurrentDemoFile(), m_Smoothing );
+ WipeUndo();
+ WipeRedo();
+ }
+ else
+ {
+ ClearSmoothingInfo( m_Smoothing );
+ WipeUndo();
+ WipeRedo();
+ }
+
+ m_bDirty = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnRefresh()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pScheme -
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CDemoSmootherPanel::GetStartFrame()
+{
+ char text[ 32 ];
+ m_pStartFrame->GetText( text, sizeof( text ) );
+ int tick = atoi( text );
+ return GetFrameForTick( tick );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CDemoSmootherPanel::GetEndFrame()
+{
+ char text[ 32 ];
+ m_pEndFrame->GetText( text, sizeof( text ) );
+ int tick = atoi( text );
+ return GetFrameForTick( tick );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : original -
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnPreview( bool original )
+{
+ if ( !CanEdit() )
+ return;
+
+ if ( !m_bHasSelection )
+ {
+ ConMsg( "Must have smoothing selection active\n" );
+ return;
+ }
+
+ m_bPreviewing = true;
+ m_bPreviewPaused = false;
+ m_bPreviewOriginal = original;
+ SetLastFrame( false, max( 0, m_nSelection[0] - 10 ) );
+ m_iPreviewStartTick = GetTickForFrame( m_nPreviewLastFrame );
+ m_fPreviewCurrentTime = TICKS_TO_TIME( m_iPreviewStartTick );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : frame -
+// elapsed -
+// info -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CDemoSmootherPanel::OverrideView( democmdinfo_t& info, int tick )
+{
+ if ( !CanEdit() )
+ return false;
+
+ if ( !demoplayer->IsPlaybackPaused() )
+ return false;
+
+ if ( m_bPreviewing )
+ {
+ if ( m_bPreviewPaused && GetCurrent() && GetCurrent()->samplepoint )
+ {
+ info.viewOrigin = GetCurrent()->vecmoved;
+ info.viewAngles = GetCurrent()->angmoved;
+ info.localViewAngles = info.viewAngles;
+
+ bool back_off = m_pBackOff->IsSelected();
+ if ( back_off )
+ {
+ Vector fwd;
+ AngleVectors( info.viewAngles, &fwd, NULL, NULL );
+
+ info.viewOrigin -= fwd * 75.0f;
+ }
+
+ return true;
+ }
+
+ // TODO: Hook up previewing view
+ if ( !m_bPreviewPaused )
+ {
+ m_fPreviewCurrentTime += host_frametime;
+ }
+
+ if ( GetInterpolatedViewPoint( info.viewOrigin, info.viewAngles ) )
+ {
+ info.localViewAngles = info.viewAngles;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ bool back_off = m_pBackOff->IsSelected();
+ if ( back_off )
+ {
+ int useframe = GetFrameForTick( tick );
+
+ if ( useframe < m_Smoothing.smooth.Count() && useframe >= 0 )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ useframe ];
+ Vector fwd;
+ AngleVectors( p->info.viewAngles, &fwd, NULL, NULL );
+
+ info.viewOrigin = p->info.viewOrigin - fwd * 75.0f;
+ }
+ }
+
+ return false;
+}
+
+void DrawVecForward( bool active, const Vector& origin, const QAngle& angles, int r, int g, int b )
+{
+ Vector fwd;
+ AngleVectors( angles, &fwd, NULL, NULL );
+
+ Vector end;
+ end = origin + fwd * ( active ? 64 : 16 );
+
+ RenderLine( origin, end, Color( r, g, b, 255 ), true );
+}
+
+void GetColorForSample( bool original, bool samplepoint, bool targetpoint, demosmoothing_t *sample, int& r, int& g, int& b )
+{
+ if ( samplepoint && sample->samplepoint )
+ {
+ r = 0;
+ g = 255;
+ b = 0;
+ return;
+ }
+
+ if ( targetpoint && sample->targetpoint )
+ {
+ r = 255;
+ g = 0;
+ b = 0;
+ return;
+ }
+
+ if ( sample->selected )
+ {
+ if( original )
+ {
+ r = 255;
+ g = 200;
+ b = 100;
+ }
+ else
+ {
+ r = 200;
+ g = 100;
+ b = 255;
+ }
+
+ if ( sample->samplepoint || sample->targetpoint )
+ {
+ r = 255;
+ g = 255;
+ b = 0;
+ }
+
+ return;
+ }
+
+ if ( original )
+ {
+ r = g = b = 255;
+ }
+ else
+ {
+ r = 150;
+ g = 255;
+ b = 100;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : origin -
+// mins -
+// maxs -
+// angles -
+// r -
+// g -
+// b -
+// a -
+//-----------------------------------------------------------------------------
+void Draw_Box( const Vector& origin, const Vector& mins, const Vector& maxs, const QAngle& angles, int r, int g, int b, int a )
+{
+ RenderBox( origin, angles, mins, maxs, Color( r, g, b, a ), false );
+ RenderWireframeBox( origin, angles, mins, maxs, Color( r, g, b, a ), true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *sample -
+// *next -
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::DrawSmoothingSample( bool original, bool processed, int samplenumber, demosmoothing_t *sample, demosmoothing_t *next )
+{
+ int r, g, b;
+
+ if ( original )
+ {
+ RenderLine( sample->info.viewOrigin + m_vecEyeOffset, next->info.viewOrigin + m_vecEyeOffset,
+ Color( 180, 180, 180, 255 ), true );
+
+ GetColorForSample( true, false, false, sample, r, g, b );
+
+ DrawVecForward( false, sample->info.viewOrigin + m_vecEyeOffset, sample->info.viewAngles, r, g, b );
+ }
+
+ if ( processed && sample->info.flags != 0 )
+ {
+ RenderLine( sample->info.GetViewOrigin() + m_vecEyeOffset, next->info.GetViewOrigin() + m_vecEyeOffset,
+ Color( 255, 255, 180, 255 ), true );
+
+ GetColorForSample( false, false, false, sample, r, g, b );
+
+ DrawVecForward( false, sample->info.GetViewOrigin() + m_vecEyeOffset, sample->info.GetViewAngles(), r, g, b );
+ }
+ if ( sample->samplepoint )
+ {
+ GetColorForSample( false, true, false, sample, r, g, b );
+ RenderBox( sample->vecmoved + m_vecEyeOffset, sample->angmoved, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), Color( r, g, b, 127 ), false );
+ DrawVecForward( false, sample->vecmoved + m_vecEyeOffset, sample->angmoved, r, g, b );
+ }
+
+ if ( sample->targetpoint )
+ {
+ GetColorForSample( false, false, true, sample, r, g, b );
+ RenderBox( sample->vectarget, vec3_angle, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), Color( r, g, b, 127 ), false );
+ }
+
+ if ( samplenumber == m_nPreviewLastFrame + 1 )
+ {
+ r = 50;
+ g = 100;
+ b = 250;
+ RenderBox( sample->info.GetViewOrigin() + m_vecEyeOffset, sample->info.GetViewAngles(), Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), Color( r, g, b, 92 ), false );
+ }
+
+ if ( sample->targetpoint )
+ {
+ r = 200;
+ g = 200;
+ b = 220;
+
+ RenderLine( sample->info.GetViewOrigin() + m_vecEyeOffset, sample->vectarget, Color( r, g, b, 255 ), true );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::DrawDebuggingInfo( int frame, float elapsed )
+{
+ if ( !CanEdit() )
+ return;
+
+ if ( !IsVisible() )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+ if ( c < 2 )
+ return;
+
+ int start = 0;
+ int end = c - 1;
+
+ bool showall = m_pShowAllSamples->IsSelected();
+ if ( !showall )
+ {
+ start = max( frame - 200, 0 );
+ end = min( frame + 200, c - 1 );
+ }
+
+ if ( m_bHasSelection && !showall )
+ {
+ start = max( m_nSelection[ 0 ] - 10, 0 );
+ end = min( m_nSelection[ 1 ] + 10, c - 1 );
+ }
+
+ bool draworiginal = !m_pHideOriginal->IsSelected();
+ bool drawprocessed = !m_pHideProcessed->IsSelected();
+ int i;
+
+ demosmoothing_t *p = NULL;
+ demosmoothing_t *prev = NULL;
+ for ( i = start; i < end; i++ )
+ {
+ p = &m_Smoothing.smooth[ i ];
+ if ( prev && p )
+ {
+ DrawSmoothingSample( draworiginal, drawprocessed, i, prev, p );
+ }
+ prev = p;
+ }
+
+ Vector org;
+ QAngle ang;
+
+ if ( m_bPreviewing )
+ {
+ if ( GetInterpolatedOriginAndAngles( true, org, ang ) )
+ {
+ DrawVecForward( true, org + m_vecEyeOffset, ang, 200, 10, 50 );
+ }
+ }
+
+ int useframe = frame;
+
+ useframe = clamp( useframe, 0, c - 1 );
+ if ( useframe < c )
+ {
+ p = &m_Smoothing.smooth[ useframe ];
+ org = p->info.GetViewOrigin();
+ ang = p->info.GetViewAngles();
+
+ DrawVecForward( true, org + m_vecEyeOffset, ang, 100, 220, 250 );
+ Draw_Box( org + m_vecEyeOffset, Vector( -1, -1, -1 ), Vector( 1, 1, 1 ), ang, 100, 220, 250, 127 );
+ }
+
+ DrawKeySpline();
+ DrawTargetSpline();
+
+
+ if ( !m_pHideLegend->IsSelected() )
+ {
+ DrawLegend( start, end );
+ }
+}
+
+void CDemoSmootherPanel::OnSelect()
+{
+ if ( !CanEdit() )
+ return;
+
+ m_bHasSelection = false;
+ m_iSelectionTicksSpan = 0;
+ memset( m_nSelection, 0, sizeof( m_nSelection ) );
+
+ int start, end;
+ start = GetStartFrame();
+ end = GetEndFrame();
+
+ int c = m_Smoothing.smooth.Count();
+ if ( c < 2 )
+ return;
+
+ start = clamp( start, 0, c - 1 );
+ end = clamp( end, 0, c - 1 );
+
+ if ( start >= end )
+ return;
+
+ m_nSelection[ 0 ] = start;
+ m_nSelection[ 1 ] = end;
+ m_bHasSelection = true;
+
+ demosmoothing_t *startsample = &m_Smoothing.smooth[ start ];
+ demosmoothing_t *endsample = &m_Smoothing.smooth[ end ];
+
+ m_bDirty = true;
+ PushUndo( "select" );
+
+ int i = 0;
+ for ( i = 0; i < c; i++ )
+ {
+ if ( i >= start && i <= end )
+ {
+ m_Smoothing.smooth[ i ].selected = true;
+ }
+ else
+ {
+ m_Smoothing.smooth[ i ].selected = false;
+ }
+ }
+
+ PushRedo( "select" );
+
+ m_iSelectionTicksSpan = endsample->frametick - startsample->frametick;
+}
+
+int CDemoSmootherPanel::GetFrameForTick( int tick )
+{
+ int count = m_Smoothing.smooth.Count();
+ int last = count - 1;
+ int first = m_Smoothing.m_nFirstSelectableSample;
+
+ if ( first > last )
+ return -1;
+
+ if ( count <= 0 )
+ {
+ return -1; // no valid index
+ }
+ else if ( count == 1 )
+ {
+ return 0; // return the one and only frame we have
+ }
+
+ if ( tick <= m_Smoothing.smooth[ first ].frametick )
+ return first;
+
+ if ( tick >= m_Smoothing.smooth[ last ].frametick )
+ return last;
+
+ // binary search
+ int middle;
+
+ while ( true )
+ {
+ middle = (first+last)/2;
+
+ int middleTick = m_Smoothing.smooth[ middle ].frametick;
+
+ if ( tick == middleTick )
+ return middle;
+
+ if ( tick > middleTick )
+ {
+ if ( first == middle )
+ return first;
+
+ first = middle;
+ }
+ else
+ {
+ if ( last == middle )
+ return last;
+
+ last = middle;
+ }
+ }
+
+
+}
+
+
+int CDemoSmootherPanel::GetTickForFrame( int frame )
+{
+ if ( !CanEdit() )
+ return -1;
+
+ int c = m_Smoothing.smooth.Count();
+ if ( c < 1 )
+ return -1;
+
+ if ( frame < 0 )
+ return m_Smoothing.smooth[ 0 ].frametick;
+
+ if ( frame >= c )
+ return m_Smoothing.smooth[ c - 1 ].frametick;
+
+
+ return m_Smoothing.smooth[ frame ].frametick;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Interpolate Euler angles using quaternions to avoid singularities
+// Input : start -
+// end -
+// output -
+// frac -
+//-----------------------------------------------------------------------------
+static void InterpolateAngles( const QAngle& start, const QAngle& end, QAngle& output, float frac )
+{
+ Quaternion src, dest;
+
+ // Convert to quaternions
+ AngleQuaternion( start, src );
+ AngleQuaternion( end, dest );
+
+ Quaternion result;
+
+ // Slerp
+ QuaternionSlerp( src, dest, frac, result );
+
+ // Convert to euler
+ QuaternionAngles( result, output );
+}
+
+bool CDemoSmootherPanel::GetInterpolatedOriginAndAngles( bool readonly, Vector& origin, QAngle& angles )
+{
+ origin.Init();
+ angles.Init();
+
+ Assert( m_bPreviewing );
+
+ // Figure out the best samples
+ int startframe = m_nPreviewLastFrame;
+ int nextframe = startframe + 1;
+
+ float time = m_fPreviewCurrentTime;
+
+ int c = m_Smoothing.smooth.Count();
+
+ do
+ {
+ if ( startframe >= c || nextframe >= c )
+ {
+ if ( !readonly )
+ {
+ //m_bPreviewing = false;
+ }
+ return false;
+ }
+
+ demosmoothing_t *startsample = &m_Smoothing.smooth[ startframe ];
+ demosmoothing_t *endsample = &m_Smoothing.smooth[ nextframe ];
+
+ if ( nextframe >= min( m_nSelection[1] + 10, c - 1 ) )
+ {
+ if ( !readonly )
+ {
+ OnPreview( m_bPreviewOriginal );
+ }
+ return false;
+ }
+
+ // If large dt, then jump ahead quickly in time
+ float dt = TICKS_TO_TIME( endsample->frametick - startsample->frametick );
+ if ( dt > 1.0f )
+ {
+ startframe++;
+ nextframe++;
+ continue;
+ }
+
+ if ( TICKS_TO_TIME( endsample->frametick ) >= time )
+ {
+ // Found a spot
+ dt = TICKS_TO_TIME( endsample->frametick - startsample->frametick );
+ // Should never occur!!!
+ if ( dt <= 0.0f )
+ {
+ return false;
+ }
+
+ float frac = (float)( time - TICKS_TO_TIME(startsample->frametick) ) / dt;
+
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ // Compute render origin/angles
+ Vector renderOrigin;
+ QAngle renderAngles;
+
+ if ( m_bPreviewOriginal )
+ {
+ VectorLerp( startsample->info.viewOrigin, endsample->info.viewOrigin, frac, renderOrigin );
+ InterpolateAngles( startsample->info.viewAngles, endsample->info.viewAngles, renderAngles, frac );
+ }
+ else
+ {
+ VectorLerp( startsample->info.GetViewOrigin(), endsample->info.GetViewOrigin(), frac, renderOrigin );
+ InterpolateAngles( startsample->info.GetViewAngles(), endsample->info.GetViewAngles(), renderAngles, frac );
+ }
+
+ origin = renderOrigin;
+ angles = renderAngles;
+
+ if ( !readonly )
+ {
+ SetLastFrame( false, startframe );
+ }
+
+ break;
+ }
+
+ startframe++;
+ nextframe++;
+
+ } while ( true );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : t -
+//-----------------------------------------------------------------------------
+bool CDemoSmootherPanel::GetInterpolatedViewPoint( Vector& origin, QAngle& angles )
+{
+ Assert( m_bPreviewing );
+
+ if ( !GetInterpolatedOriginAndAngles( false, origin, angles ) )
+ return false;
+
+ bool back_off = m_pBackOff->IsSelected();
+ if ( back_off )
+ {
+ Vector fwd;
+ AngleVectors( angles, &fwd, NULL, NULL );
+
+ origin = origin - fwd * 75.0f;
+ }
+
+ return true;
+}
+
+void CDemoSmootherPanel::OnTogglePause()
+{
+ if ( !m_bPreviewing )
+ return;
+
+ m_bPreviewPaused = !m_bPreviewPaused;
+}
+
+void CDemoSmootherPanel::OnStep( bool forward )
+{
+ if ( !m_bPreviewing )
+ return;
+
+ if ( !m_bPreviewPaused )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+
+ SetLastFrame( false, m_nPreviewLastFrame + ( forward ? 1 : -1 ) );
+ SetLastFrame( false, clamp( m_nPreviewLastFrame, max( m_nSelection[ 0 ] - 10, 0 ), min( m_nSelection[ 1 ] + 10, c - 1 ) ) );
+ m_fPreviewCurrentTime = TICKS_TO_TIME( GetTickForFrame( m_nPreviewLastFrame ) );
+}
+
+void CDemoSmootherPanel::DrawLegend( int startframe, int endframe )
+{
+ int i;
+ int skip = 20;
+
+ bool back_off = m_pBackOff->IsSelected();
+
+ for ( i = startframe; i <= endframe; i++ )
+ {
+ bool show = ( i % skip ) == 0;
+ demosmoothing_t *sample = &m_Smoothing.smooth[ i ];
+
+ if ( sample->samplepoint || sample->targetpoint )
+ show = true;
+
+ if ( !show )
+ continue;
+
+ char sz[ 512 ];
+ Q_snprintf( sz, sizeof( sz ), "%.3f", TICKS_TO_TIME(sample->frametick) );
+
+ Vector fwd;
+ AngleVectors( sample->info.GetViewAngles(), &fwd, NULL, NULL );
+
+ CDebugOverlay::AddTextOverlay( sample->info.GetViewOrigin() + m_vecEyeOffset + fwd * ( back_off ? 5.0f : 50.0f ), 0, -1.0f, sz );
+ }
+}
+
+#define EASE_TIME 0.2f
+
+Quaternion SmoothAngles( CUtlVector< Quaternion >& stack )
+{
+ int c = stack.Count();
+ Assert( c >= 1 );
+
+ float weight = 1.0f / (float)c;
+
+ Quaternion output;
+ output.Init();
+
+ int i;
+ for ( i = 0; i < c; i++ )
+ {
+ Quaternion t = stack[ i ];
+ QuaternionBlend( output, t, weight, output );
+ }
+
+ return output;
+}
+
+Vector SmoothOrigin( CUtlVector< Vector >& stack )
+{
+ int c = stack.Count();
+ Assert( c >= 1 );
+
+ Vector output;
+ output.Init();
+
+ int i;
+ for ( i = 0; i < c; i++ )
+ {
+ Vector t = stack[ i ];
+ VectorAdd( output, t, output );
+ }
+
+ VectorScale( output, 1.0f / (float)c, output );
+
+ return output;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnSetKeys(float interval)
+{
+ if ( !m_bHasSelection )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "OnSetKeys" );
+
+ int c = m_Smoothing.smooth.Count();
+ int i;
+
+ demosmoothing_t *lastkey = NULL;
+
+ for ( i = 0; i < c; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+ if ( !p->selected )
+ continue;
+
+ p->angmoved = p->info.GetViewAngles();;
+ p->vecmoved = p->info.GetViewOrigin();
+ p->samplepoint = false;
+
+ if ( !lastkey ||
+ TICKS_TO_TIME( p->frametick - lastkey->frametick ) >= interval )
+ {
+ lastkey = p;
+ p->samplepoint = true;
+ }
+ }
+
+ PushRedo( "OnSetKeys" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnSmoothSelectionAngles( void )
+{
+ if ( !m_bHasSelection )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+ int i;
+
+ CUtlVector< Quaternion > stack;
+
+ m_bDirty = true;
+ PushUndo( "smooth angles" );
+
+ for ( i = 0; i < c; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+ if ( !p->selected )
+ continue;
+
+ while ( stack.Count() > 10 )
+ {
+ stack.Remove( 0 );
+ }
+
+ Quaternion q;
+ AngleQuaternion( p->info.GetViewAngles(), q );
+ stack.AddToTail( q );
+
+ p->info.flags |= FDEMO_USE_ANGLES2;
+
+ Quaternion aveq = SmoothAngles( stack );
+
+ QAngle outangles;
+ QuaternionAngles( aveq, outangles );
+
+ p->info.viewAngles2 = outangles;
+ p->info.localViewAngles2 = outangles;
+ }
+
+ PushRedo( "smooth angles" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnSmoothSelectionOrigin( void )
+{
+ if ( !m_bHasSelection )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+ int i;
+
+ CUtlVector< Vector > stack;
+
+ m_bDirty = true;
+ PushUndo( "smooth origin" );
+
+ for ( i = 0; i < c; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+ if ( !p->selected )
+ continue;
+
+ if ( i < 2 )
+ continue;
+
+ if ( i >= c - 2 )
+ continue;
+
+ stack.RemoveAll();
+
+ for ( int j = -2; j <= 2; j++ )
+ {
+ stack.AddToTail( m_Smoothing.smooth[ i + j ].info.GetViewOrigin() );
+ }
+
+ p->info.flags |= FDEMO_USE_ORIGIN2;
+
+ Vector org = SmoothOrigin( stack );
+
+ p->info.viewOrigin2 = org;
+ }
+
+ PushRedo( "smooth origin" );
+}
+
+void CDemoSmootherPanel::PerformLinearInterpolatedAngleSmoothing( int startframe, int endframe )
+{
+ demosmoothing_t *pstart = &m_Smoothing.smooth[ startframe ];
+ demosmoothing_t *pend = &m_Smoothing.smooth[ endframe ];
+
+ int dt = pend->frametick - pstart->frametick;
+ if ( dt <= 0 )
+ {
+ dt = 1;
+ }
+
+ CUtlVector< Quaternion > stack;
+
+ Quaternion qstart, qend;
+ AngleQuaternion( pstart->info.GetViewAngles(), qstart );
+ AngleQuaternion( pend->info.GetViewAngles(), qend );
+
+ for ( int i = startframe; i <= endframe; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+
+ int elapsed = p->frametick - pstart->frametick;
+ float frac = (float)elapsed / (float)dt;
+
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ p->info.flags |= FDEMO_USE_ANGLES2;
+
+ Quaternion interpolated;
+
+ QuaternionSlerp( qstart, qend, frac, interpolated );
+
+ QAngle outangles;
+ QuaternionAngles( interpolated, outangles );
+
+ p->info.viewAngles2 = outangles;
+ p->info.localViewAngles2 = outangles;
+ }
+}
+
+void CDemoSmootherPanel::OnLinearInterpolateAnglesBasedOnEndpoints( void )
+{
+ if ( !m_bHasSelection )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+ if ( c < 2 )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "linear interp angles" );
+
+ PerformLinearInterpolatedAngleSmoothing( m_nSelection[ 0 ], m_nSelection[ 1 ] );
+
+ PushRedo( "linear interp angles" );
+}
+
+void CDemoSmootherPanel::OnLinearInterpolateOriginBasedOnEndpoints( void )
+{
+ if ( !m_bHasSelection )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+
+ if ( c < 2 )
+ return;
+
+ demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
+ demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
+
+ int dt = pend->frametick - pstart->frametick;
+ if ( dt <= 0 )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "linear interp origin" );
+
+ Vector vstart, vend;
+ vstart = pstart->info.GetViewOrigin();
+ vend = pend->info.GetViewOrigin();
+
+ for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+
+ float elapsed = p->frametick - pstart->frametick;
+ float frac = elapsed / (float)dt;
+
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ p->info.flags |= FDEMO_USE_ORIGIN2;
+
+ Vector interpolated;
+
+ VectorLerp( vstart, vend, frac, interpolated );
+
+ p->info.viewOrigin2 = interpolated;
+ }
+
+ PushRedo( "linear interp origin" );
+
+}
+
+void CDemoSmootherPanel::OnRevertPoint( void )
+{
+ demosmoothing_t *p = GetCurrent();
+ if ( !p )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "revert point" );
+
+ p->angmoved = p->info.GetViewAngles();
+ p->vecmoved = p->info.GetViewOrigin();
+ p->samplepoint = false;
+
+ p->vectarget = p->info.GetViewOrigin();
+ p->targetpoint = false;
+
+// m_ViewOrigin = p->info.viewOrigin;
+// m_ViewAngles = p->info.viewAngles;
+
+ PushRedo( "revert point" );
+}
+
+demosmoothing_t *CDemoSmootherPanel::GetCurrent( void )
+{
+ if ( !CanEdit() )
+ return NULL;
+
+ int c = m_Smoothing.smooth.Count();
+ if ( c < 1 )
+ return NULL;
+
+ int frame = clamp( m_nPreviewLastFrame, 0, c - 1 );
+
+ return &m_Smoothing.smooth[ frame ];
+}
+
+void CDemoSmootherPanel::AddSamplePoints( bool usetarget, bool includeboundaries, CUtlVector< demosmoothing_t * >& points, int start, int end )
+{
+ points.RemoveAll();
+
+ int i;
+ for ( i = start; i <= end; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+
+ if ( includeboundaries )
+ {
+ if ( i == start )
+ {
+ // Add it twice
+ points.AddToTail( p );
+ continue;
+ }
+ else if ( i == end )
+ {
+ // Add twice
+ points.AddToTail( p );
+ continue;
+ }
+ }
+
+ if ( usetarget && p->targetpoint )
+ {
+ points.AddToTail( p );
+ }
+ if ( !usetarget && p->samplepoint )
+ {
+ points.AddToTail( p );
+ }
+ }
+}
+
+demosmoothing_t *CDemoSmootherPanel::GetBoundedSample( CUtlVector< demosmoothing_t * >& points, int sample )
+{
+ int c = points.Count();
+ if ( sample < 0 )
+ return points[ 0 ];
+ else if ( sample >= c )
+ return points[ c - 1 ];
+ return points[ sample ];
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : t -
+// points -
+// prev -
+// next -
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::FindSpanningPoints( int tick, CUtlVector< demosmoothing_t * >& points, int& prev, int& next )
+{
+ prev = -1;
+ next = 0;
+ int c = points.Count();
+ int i;
+
+ for ( i = 0; i < c; i++ )
+ {
+ demosmoothing_t *p = points[ i ];
+
+ if ( tick < p->frametick )
+ break;
+ }
+
+ next = i;
+ prev = i - 1;
+
+ next = clamp( next, 0, c - 1 );
+ prev = clamp( prev, 0, c - 1 );
+}
+
+void CDemoSmootherPanel::OnSplineSampleOrigin( void )
+{
+ if ( !m_bHasSelection )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+
+ if ( c < 2 )
+ return;
+
+ demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
+ demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
+
+ if ( pend->frametick - pstart->frametick <= 0 )
+ return;
+
+ CUtlVector< demosmoothing_t * > points;
+ AddSamplePoints( false, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
+
+ if ( points.Count() <= 0 )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "spline origin" );
+
+ for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+
+ demosmoothing_t *earliest;
+ demosmoothing_t *current;
+ demosmoothing_t *next;
+ demosmoothing_t *latest;
+
+ int cur;
+ int cur2;
+
+ FindSpanningPoints( p->frametick, points, cur, cur2 );
+
+ earliest = GetBoundedSample( points, cur - 1 );
+ current = GetBoundedSample( points, cur );
+ next = GetBoundedSample( points, cur2 );
+ latest = GetBoundedSample( points, cur2 + 1 );
+
+ float frac = 0.0f;
+ float dt = next->frametick - current->frametick;
+ if ( dt > 0.0f )
+ {
+ frac = (float)( p->frametick - current->frametick ) / dt;
+ }
+
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ Vector splined;
+
+ Catmull_Rom_Spline_Normalize( earliest->vecmoved, current->vecmoved, next->vecmoved, latest->vecmoved, frac, splined );
+
+ p->info.flags |= FDEMO_USE_ORIGIN2;
+ p->info.viewOrigin2 = splined;
+ }
+
+ PushRedo( "spline origin" );
+
+}
+
+void CDemoSmootherPanel::OnSplineSampleAngles( void )
+{
+ if ( !m_bHasSelection )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+
+ if ( c < 2 )
+ return;
+
+ demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
+ demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
+
+ if ( pend->frametick - pstart->frametick <= 0 )
+ return;
+
+ CUtlVector< demosmoothing_t * > points;
+ AddSamplePoints( false, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
+
+ if ( points.Count() <= 0 )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "spline angles" );
+
+ for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+
+ demosmoothing_t *current;
+ demosmoothing_t *next;
+
+ int cur;
+ int cur2;
+
+ FindSpanningPoints( p->frametick, points, cur, cur2 );
+
+ current = GetBoundedSample( points, cur );
+ next = GetBoundedSample( points, cur2 );
+
+ float frac = 0.0f;
+ float dt = next->frametick - current->frametick;
+ if ( dt > 0.0f )
+ {
+ frac = (float)( p->frametick - current->frametick ) / dt;
+ }
+
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ frac = SimpleSpline( frac );
+
+ QAngle splined;
+
+ InterpolateAngles( current->angmoved, next->angmoved, splined, frac );
+
+ p->info.flags |= FDEMO_USE_ANGLES2;
+ p->info.viewAngles2 = splined;
+ p->info.localViewAngles2 = splined;
+ }
+
+ PushRedo( "spline angles" );
+}
+
+void CDemoSmootherPanel::OnLookAtPoints( bool spline )
+{
+ if ( !m_bHasSelection )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+ int i;
+
+ if ( c < 2 )
+ return;
+
+ demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
+ demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
+
+ if ( pend->frametick - pstart->frametick <= 0 )
+ return;
+
+ CUtlVector< demosmoothing_t * > points;
+ AddSamplePoints( true, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
+
+ if ( points.Count() < 1 )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "lookat points" );
+
+ for ( i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+
+ demosmoothing_t *earliest;
+ demosmoothing_t *current;
+ demosmoothing_t *next;
+ demosmoothing_t *latest;
+
+ int cur;
+ int cur2;
+
+ FindSpanningPoints( p->frametick, points, cur, cur2 );
+
+ earliest = GetBoundedSample( points, cur - 1 );
+ current = GetBoundedSample( points, cur );
+ next = GetBoundedSample( points, cur2 );
+ latest = GetBoundedSample( points, cur2 + 1 );
+
+ float frac = 0.0f;
+ float dt = next->frametick - current->frametick;
+ if ( dt > 0.0f )
+ {
+ frac = (float)( p->frametick - current->frametick ) / dt;
+ }
+
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ Vector splined;
+
+ if ( spline )
+ {
+ Catmull_Rom_Spline_Normalize( earliest->vectarget, current->vectarget, next->vectarget, latest->vectarget, frac, splined );
+ }
+ else
+ {
+ Vector d = next->vectarget - current->vectarget;
+ VectorMA( current->vectarget, frac, d, splined );
+ }
+
+ Vector vecToTarget = splined - ( p->info.GetViewOrigin() + m_vecEyeOffset );
+ VectorNormalize( vecToTarget );
+
+ QAngle angles;
+ VectorAngles( vecToTarget, angles );
+
+ p->info.flags |= FDEMO_USE_ANGLES2;
+ p->info.viewAngles2 = angles;
+ p->info.localViewAngles2 = angles;
+ }
+
+ PushRedo( "lookat points" );
+}
+
+void CDemoSmootherPanel::SetLastFrame( bool jumptotarget, int frame )
+{
+ // bool changed = frame != m_nPreviewLastFrame;
+
+ int useFrame = max( m_Smoothing.m_nFirstSelectableSample, frame );
+
+ m_nPreviewLastFrame = useFrame;
+
+ /* if ( changed && !m_pLockCamera->IsSelected() )
+ {
+ // Reset default view/angles
+ demosmoothing_t *p = GetCurrent();
+ if ( p )
+ {
+ if ( p->samplepoint && !jumptotarget )
+ {
+ m_ViewOrigin = p->vecmoved;
+ m_ViewAngles = p->angmoved;
+ }
+ else if ( p->targetpoint && jumptotarget )
+ {
+ m_ViewOrigin = p->vectarget - m_vecEyeOffset;
+ }
+ else
+ {
+ if ( m_bPreviewing && m_bPreviewOriginal )
+ {
+ m_ViewOrigin = p->info.viewOrigin;
+ m_ViewAngles = p->info.viewAngles;
+ }
+ else
+ {
+ m_ViewOrigin = p->info.GetViewOrigin();
+ m_ViewAngles = p->info.GetViewAngles();
+ }
+ }
+ }
+ } */
+}
+
+// Undo/Redo
+void CDemoSmootherPanel::Undo( void )
+{
+ if ( m_UndoStack.Size() > 0 && m_nUndoLevel > 0 )
+ {
+ m_nUndoLevel--;
+ DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
+ Assert( u->undo );
+
+ m_Smoothing = *(u->undo);
+ }
+ InvalidateLayout();
+}
+
+void CDemoSmootherPanel::Redo( void )
+{
+ if ( m_UndoStack.Size() > 0 && m_nUndoLevel <= m_UndoStack.Size() - 1 )
+ {
+ DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
+ Assert( u->redo );
+
+ m_Smoothing = *(u->redo);
+ m_nUndoLevel++;
+ }
+
+ InvalidateLayout();
+}
+
+void CDemoSmootherPanel::PushUndo( const char *description )
+{
+ Assert( !m_bRedoPending );
+ m_bRedoPending = true;
+ WipeRedo();
+
+ // Copy current data
+ CSmoothingContext *u = new CSmoothingContext;
+ *u = m_Smoothing;
+ DemoSmoothUndo *undo = new DemoSmoothUndo;
+ undo->undo = u;
+ undo->redo = NULL;
+ undo->udescription = COM_StringCopy( description );
+ undo->rdescription = NULL;
+ m_UndoStack.AddToTail( undo );
+ m_nUndoLevel++;
+}
+
+void CDemoSmootherPanel::PushRedo( const char *description )
+{
+ Assert( m_bRedoPending );
+ m_bRedoPending = false;
+
+ // Copy current data
+ CSmoothingContext *r = new CSmoothingContext;
+ *r = m_Smoothing;
+ DemoSmoothUndo *undo = m_UndoStack[ m_nUndoLevel - 1 ];
+ undo->redo = r;
+ undo->rdescription = COM_StringCopy( description );
+}
+
+void CDemoSmootherPanel::WipeUndo( void )
+{
+ while ( m_UndoStack.Size() > 0 )
+ {
+ DemoSmoothUndo *u = m_UndoStack[ 0 ];
+ delete u->undo;
+ delete u->redo;
+ delete[] u->udescription;
+ delete[] u->rdescription;
+ delete u;
+ m_UndoStack.Remove( 0 );
+ }
+ m_nUndoLevel = 0;
+}
+
+void CDemoSmootherPanel::WipeRedo( void )
+{
+ // Wipe everything above level
+ while ( m_UndoStack.Size() > m_nUndoLevel )
+ {
+ DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
+ delete u->undo;
+ delete u->redo;
+ delete[] u->udescription;
+ delete[] u->rdescription;
+ delete u;
+ m_UndoStack.Remove( m_nUndoLevel );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : const char
+//-----------------------------------------------------------------------------
+const char *CDemoSmootherPanel::GetUndoDescription( void )
+{
+ if ( m_nUndoLevel != 0 )
+ {
+ DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel - 1 ];
+ return u->udescription;
+ }
+ return "???undo";
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : const char
+//-----------------------------------------------------------------------------
+const char *CDemoSmootherPanel::GetRedoDescription( void )
+{
+ if ( m_nUndoLevel != m_UndoStack.Size() )
+ {
+ DemoSmoothUndo *u = m_UndoStack[ m_nUndoLevel ];
+ return u->rdescription;
+ }
+ return "???redo";
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CDemoSmootherPanel::CanRedo( void )
+{
+ if ( !m_UndoStack.Count() )
+ return false;
+
+ if ( m_nUndoLevel == m_UndoStack.Count() )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CDemoSmootherPanel::CanUndo( void )
+{
+ if ( !m_UndoStack.Count() )
+ return false;
+
+ if ( m_nUndoLevel == 0 )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnToggleKeyFrame( void )
+{
+ demosmoothing_t *p = GetCurrent();
+ if ( !p )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "toggle keyframe" );
+
+ // use orginal data by default
+ p->angmoved = p->info.GetViewAngles();
+ p->vecmoved = p->info.GetViewOrigin();
+
+ if ( !p->samplepoint )
+ {
+ if ( g_pDemoUI->IsInDriveMode() )
+ {
+ g_pDemoUI->GetDriveViewPoint( p->vecmoved, p->angmoved );
+ }
+
+ if ( g_pDemoUI2->IsInDriveMode() )
+ {
+ g_pDemoUI2->GetDriveViewPoint( p->vecmoved, p->angmoved );
+ }
+
+ p->samplepoint = true;
+ }
+ else
+ {
+ p->samplepoint = false;
+ }
+
+ PushRedo( "toggle keyframe" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnToggleLookTarget( void )
+{
+ demosmoothing_t *p = GetCurrent();
+ if ( !p )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "toggle look target" );
+
+ // use orginal data by default
+ p->vectarget = p->info.GetViewOrigin();
+
+ if ( !p->targetpoint )
+ {
+ QAngle angles;
+ g_pDemoUI->GetDriveViewPoint( p->vectarget, angles );
+ g_pDemoUI2->GetDriveViewPoint( p->vectarget, angles );
+
+ p->targetpoint = true;
+ }
+ else
+ {
+ p->targetpoint = false;
+ }
+
+ PushRedo( "toggle look target" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnNextKey()
+{
+ if( !m_bHasSelection )
+ return;
+
+ int start = m_nPreviewLastFrame + 1;
+ int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
+
+ int moved = 0;
+
+ while ( moved < maxmove )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ start ];
+ if ( p->samplepoint )
+ {
+ SetLastFrame( false, start );
+ break;
+ }
+
+ start++;
+
+ if ( start > m_nSelection[1] )
+ start = m_nSelection[0];
+
+ moved++;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnPrevKey()
+{
+ if( !m_bHasSelection )
+ return;
+
+ int start = m_nPreviewLastFrame - 1;
+ int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
+
+ int moved = 0;
+
+ while ( moved < maxmove && start >= 0 )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ start ];
+ if ( p->samplepoint )
+ {
+ SetLastFrame( false, start );
+ break;
+ }
+
+ start--;
+
+ if ( start < m_nSelection[0] )
+ start = m_nSelection[1];
+
+ moved++;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnNextTarget()
+{
+ if( !m_bHasSelection )
+ return;
+
+ int start = m_nPreviewLastFrame + 1;
+ int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
+
+ int moved = 0;
+
+ while ( moved < maxmove )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ start ];
+ if ( p->targetpoint )
+ {
+ SetLastFrame( true, start );
+ break;
+ }
+
+ start++;
+
+ if ( start > m_nSelection[1] )
+ start = m_nSelection[0];
+
+ moved++;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnPrevTarget()
+{
+ if( !m_bHasSelection )
+ return;
+
+ int start = m_nPreviewLastFrame - 1;
+ int maxmove = m_nSelection[1] - m_nSelection[0] + 1;
+
+ int moved = 0;
+
+ while ( moved < maxmove )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ start ];
+ if ( p->targetpoint )
+ {
+ SetLastFrame( true, start );
+ break;
+ }
+
+ start--;
+
+ if ( start < m_nSelection[0] )
+ start = m_nSelection[1];
+
+ moved++;
+ }
+}
+
+void CDemoSmootherPanel::DrawTargetSpline()
+{
+ if ( !m_bHasSelection )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+ int i;
+
+ if ( c < 2 )
+ return;
+
+ demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
+ demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
+
+ if ( pend->frametick - pstart->frametick <= 0 )
+ return;
+
+ CUtlVector< demosmoothing_t * > points;
+ AddSamplePoints( true, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
+
+ if ( points.Count() < 1 )
+ return;
+
+ Vector previous(0,0,0);
+
+ for ( i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+
+ demosmoothing_t *earliest;
+ demosmoothing_t *current;
+ demosmoothing_t *next;
+ demosmoothing_t *latest;
+
+ int cur;
+ int cur2;
+
+ FindSpanningPoints( p->frametick, points, cur, cur2 );
+
+ earliest = GetBoundedSample( points, cur - 1 );
+ current = GetBoundedSample( points, cur );
+ next = GetBoundedSample( points, cur2 );
+ latest = GetBoundedSample( points, cur2 + 1 );
+
+ float frac = 0.0f;
+ float dt = next->frametick - current->frametick;
+ if ( dt > 0.0f )
+ {
+ frac = (float)( p->frametick - current->frametick ) / dt;
+ }
+
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ Vector splined;
+
+ Catmull_Rom_Spline_Normalize( earliest->vectarget, current->vectarget, next->vectarget, latest->vectarget, frac, splined );
+
+ if ( i > m_nSelection[0] )
+ {
+ RenderLine( previous, splined, Color( 0, 255, 0, 255 ), true );
+ }
+
+ previous = splined;
+ }
+}
+
+void CDemoSmootherPanel::DrawKeySpline()
+{
+ if ( !m_bHasSelection )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+ int i;
+
+ if ( c < 2 )
+ return;
+
+ demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
+ demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
+
+ if ( pend->frametick - pstart->frametick <= 0 )
+ return;
+
+ CUtlVector< demosmoothing_t * > points;
+ AddSamplePoints( false, false, points, m_nSelection[ 0 ], m_nSelection[ 1 ] );
+
+ if ( points.Count() < 1 )
+ return;
+
+ Vector previous(0,0,0);
+
+ for ( i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+
+ demosmoothing_t *earliest;
+ demosmoothing_t *current;
+ demosmoothing_t *next;
+ demosmoothing_t *latest;
+
+ int cur;
+ int cur2;
+
+ FindSpanningPoints( p->frametick, points, cur, cur2 );
+
+ earliest = GetBoundedSample( points, cur - 1 );
+ current = GetBoundedSample( points, cur );
+ next = GetBoundedSample( points, cur2 );
+ latest = GetBoundedSample( points, cur2 + 1 );
+
+ float frac = 0.0f;
+ float dt = next->frametick - current->frametick;
+ if ( dt > 0.0f )
+ {
+ frac = (float)( p->frametick - current->frametick ) / dt;
+ }
+
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ Vector splined;
+
+ Catmull_Rom_Spline_Normalize( earliest->vecmoved, current->vecmoved, next->vecmoved, latest->vecmoved, frac, splined );
+
+ splined += m_vecEyeOffset;
+
+ if ( i > m_nSelection[0] )
+ {
+ RenderLine( previous, splined, Color( 0, 255, 0, 255 ), true );
+ }
+
+ previous = splined;
+ }
+}
+
+void CDemoSmootherPanel::OnSmoothEdges( bool left, bool right )
+{
+ if ( !m_bHasSelection )
+ return;
+
+ if ( !left && !right )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+
+ // Get number of frames
+ char sz[ 512 ];
+ m_pFixEdgeFrames->GetText( sz, sizeof( sz ) );
+
+ int frames = atoi( sz );
+ if ( frames <= 2 )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "smooth edges" );
+
+ if ( left && m_nSelection[0] > 0 )
+ {
+ PerformLinearInterpolatedAngleSmoothing( m_nSelection[ 0 ] - 1, m_nSelection[ 0 ] + frames );
+ }
+ if ( right && m_nSelection[1] < c - 1 )
+ {
+ PerformLinearInterpolatedAngleSmoothing( m_nSelection[ 1 ] - frames, m_nSelection[ 1 ] + 1 );
+ }
+
+ PushRedo( "smooth edges" );
+}
+
+void CDemoSmootherPanel::OnSaveKey()
+{
+ if ( !m_bHasSelection )
+ return;
+
+ demosmoothing_t *p = GetCurrent();
+ if ( !p )
+ return;
+
+ if ( !p->samplepoint )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "save key" );
+
+ p->info.viewAngles2 = p->angmoved;
+ p->info.localViewAngles2 = p->angmoved;
+ p->info.viewOrigin2 = p->vecmoved;
+ p->info.flags |= FDEMO_USE_ORIGIN2;
+ p->info.flags |= FDEMO_USE_ANGLES2;
+
+ PushRedo( "save key" );
+}
+
+void CDemoSmootherPanel::OnSetView()
+{
+ if ( !m_bHasSelection )
+ return;
+
+ demosmoothing_t *p = GetCurrent();
+ if ( !p )
+ return;
+
+ Vector origin = p->info.GetViewOrigin();
+ QAngle angle = p->info.GetViewAngles();
+
+ g_pDemoUI->SetDriveViewPoint( origin, angle );
+ g_pDemoUI2->SetDriveViewPoint( origin, angle );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CDemoSmootherPanel::OnGotoFrame()
+{
+ int c = m_Smoothing.smooth.Count();
+ if ( c < 2 )
+ return;
+
+ char sz[ 256 ];
+ m_pGotoFrame->GetText( sz, sizeof( sz ) );
+ int frame = atoi( sz );
+
+ if ( !m_bPreviewing )
+ {
+ if ( !m_bHasSelection )
+ {
+ m_pStartFrame->SetText( va( "%i", 0 ) );
+ m_pEndFrame->SetText( va( "%i", c - 1 ) );
+ OnSelect();
+ }
+ OnPreview( false );
+ OnTogglePause();
+ }
+
+ if ( !m_bPreviewing )
+ return;
+
+ SetLastFrame( false, frame );
+ m_iPreviewStartTick = GetTickForFrame( m_nPreviewLastFrame );
+ m_fPreviewCurrentTime = TICKS_TO_TIME( m_iPreviewStartTick );
+}
+
+void CDemoSmootherPanel::OnOriginEaseCurve( EASEFUNC easefunc )
+{
+ if ( !m_bHasSelection )
+ return;
+
+ int c = m_Smoothing.smooth.Count();
+
+ if ( c < 2 )
+ return;
+
+ demosmoothing_t *pstart = &m_Smoothing.smooth[ m_nSelection[ 0 ] ];
+ demosmoothing_t *pend = &m_Smoothing.smooth[ m_nSelection[ 1 ] ];
+
+ float dt = pend->frametick - pstart->frametick;
+ if ( dt <= 0.0f )
+ return;
+
+ m_bDirty = true;
+ PushUndo( "ease origin" );
+
+ Vector vstart, vend;
+ vstart = pstart->info.GetViewOrigin();
+ vend = pend->info.GetViewOrigin();
+
+ for ( int i = m_nSelection[0]; i <= m_nSelection[1]; i++ )
+ {
+ demosmoothing_t *p = &m_Smoothing.smooth[ i ];
+
+ float elapsed = p->frametick - pstart->frametick;
+ float frac = elapsed / dt;
+
+ // Apply ease function
+ frac = (*easefunc)( frac );
+
+ frac = clamp( frac, 0.0f, 1.0f );
+
+ p->info.flags |= FDEMO_USE_ORIGIN2;
+
+ Vector interpolated;
+
+ VectorLerp( vstart, vend, frac, interpolated );
+
+ p->info.viewOrigin2 = interpolated;
+ }
+
+ PushRedo( "ease origin" );
+}
+
+void CDemoSmootherPanel::ParseSmoothingInfo( CDemoFile &demoFile, CSmoothingContext& smoothing )
+{
+ democmdinfo_t info;
+ int dummy;
+
+ bool foundFirstSelectable = false;
+
+ bool demofinished = false;
+ while ( !demofinished )
+ {
+ int tick = 0;
+ byte cmd;
+
+ bool swallowmessages = true;
+ do
+ {
+ demoFile.ReadCmdHeader( cmd, tick );
+
+ // COMMAND HANDLERS
+ switch ( cmd )
+ {
+ case dem_synctick:
+ break;
+ case dem_stop:
+ {
+ swallowmessages = false;
+ demofinished = true;
+ }
+ break;
+ case dem_consolecmd:
+ {
+ demoFile.ReadConsoleCommand();
+ }
+ break;
+ case dem_datatables:
+ {
+ demoFile.ReadNetworkDataTables( NULL );
+ }
+ break;
+ case dem_stringtables:
+ {
+ demoFile.ReadStringTables( NULL );
+ }
+ break;
+ case dem_usercmd:
+ {
+ demoFile.ReadUserCmd( NULL, dummy );
+
+ }
+ break;
+ default:
+ {
+ swallowmessages = false;
+ }
+ break;
+ }
+ }
+ while ( swallowmessages );
+
+ if ( demofinished )
+ {
+ // StopPlayback();
+ return;
+ }
+
+ int curpos = demoFile.GetCurPos( true );
+
+ demoFile.ReadCmdInfo( info );
+ demoFile.ReadSequenceInfo( dummy, dummy );
+ demoFile.ReadRawData( NULL, 0 );
+
+ // Add to end of list
+ demosmoothing_t smoothing_entry;
+
+ smoothing_entry.file_offset = curpos;
+ smoothing_entry.frametick = tick;
+ smoothing_entry.info = info;
+ smoothing_entry.samplepoint = false;
+ smoothing_entry.vecmoved = info.GetViewOrigin();
+ smoothing_entry.angmoved = info.GetViewAngles();
+ smoothing_entry.targetpoint = false;
+ smoothing_entry.vectarget = info.GetViewOrigin();
+
+ int sampleIndex = smoothing.smooth.AddToTail( smoothing_entry );
+
+ if ( !foundFirstSelectable &&
+ smoothing_entry.vecmoved.LengthSqr() > 0.0f )
+ {
+ foundFirstSelectable = true;
+ smoothing.m_nFirstSelectableSample = sampleIndex;
+ }
+ }
+}
+
+void CDemoSmootherPanel::LoadSmoothingInfo( const char *filename, CSmoothingContext& smoothing )
+{
+ char name[ MAX_OSPATH ];
+ Q_strncpy (name, filename, sizeof(name) );
+ Q_DefaultExtension( name, ".dem", sizeof( name ) );
+
+ CDemoFile demoFile;
+
+ if ( !demoFile.Open( filename, true ) )
+ {
+ ConMsg( "ERROR: couldn't open %s.\n", name );
+ return;
+ }
+
+ demoheader_t * header = demoFile.ReadDemoHeader();
+
+ if ( !header )
+ {
+ demoFile.Close();
+ return;
+ }
+
+ ConMsg ("Smoothing demo from %s ...", name );
+
+ smoothing.active = true;
+ Q_strncpy( smoothing.filename, name, sizeof(smoothing.filename) );
+
+ smoothing.smooth.RemoveAll();
+
+ ClearSmoothingInfo( smoothing );
+
+ ParseSmoothingInfo( demoFile, smoothing );
+
+ demoFile.Close();
+
+ //Performsmoothing( smooth );
+ //SaveSmoothedDemo( name, smooth );
+
+ ConMsg ( " done.\n" );
+}
+
+void CDemoSmootherPanel::ClearSmoothingInfo( CSmoothingContext& smoothing )
+{
+ int c = smoothing.smooth.Count();
+ int i;
+
+ for ( i = 0; i < c; i++ )
+ {
+ demosmoothing_t *p = &smoothing.smooth[ i ];
+ p->info.Reset();
+ p->vecmoved = p->info.GetViewOrigin();
+ p->angmoved = p->info.GetViewAngles();
+ p->samplepoint = false;
+ p->vectarget = p->info.GetViewOrigin();
+ p->targetpoint = false;
+ }
+}
+
+void CDemoSmootherPanel::SaveSmoothingInfo( char const *filename, CSmoothingContext& smoothing )
+{
+ // Nothing to do
+ int c = smoothing.smooth.Count();
+ if ( !c )
+ return;
+
+ IFileSystem *fs = g_pFileSystem;
+
+ FileHandle_t infile, outfile;
+
+ COM_OpenFile( filename, &infile );
+ if ( infile == FILESYSTEM_INVALID_HANDLE )
+ return;
+
+ int filesize = fs->Size( infile );
+
+ char outfilename[ 512 ];
+ Q_StripExtension( filename, outfilename, sizeof( outfilename ) );
+ Q_strncat( outfilename, "_smooth", sizeof(outfilename), COPY_ALL_CHARACTERS );
+ Q_DefaultExtension( outfilename, ".dem", sizeof( outfilename ) );
+ outfile = fs->Open( outfilename, "wb" );
+ if ( outfile == FILESYSTEM_INVALID_HANDLE )
+ {
+ fs->Close( infile );
+ return;
+ }
+
+ int i;
+
+ int lastwritepos = 0;
+ for ( i = 0; i < c; i++ )
+ {
+ demosmoothing_t *p = &smoothing.smooth[ i ];
+
+ int copyamount = p->file_offset - lastwritepos;
+
+ COM_CopyFileChunk( outfile, infile, copyamount );
+
+ fs->Seek( infile, p->file_offset, FILESYSTEM_SEEK_HEAD );
+
+ // wacky hacky overwriting
+ fs->Write( &p->info, sizeof( democmdinfo_t ), outfile );
+
+ lastwritepos = fs->Tell( outfile );
+ fs->Seek( infile, p->file_offset + sizeof( democmdinfo_t ), FILESYSTEM_SEEK_HEAD );
+ }
+
+ int final = filesize - lastwritepos;
+
+ COM_CopyFileChunk( outfile, infile, final );
+
+ fs->Close( outfile );
+ fs->Close( infile );
+}