summaryrefslogtreecommitdiff
path: root/utils/demoinfo
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/demoinfo
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/demoinfo')
-rw-r--r--utils/demoinfo/demoinfo.cpp527
-rw-r--r--utils/demoinfo/demoinfo.vcproj549
-rw-r--r--utils/demoinfo/demosmoothersamplesource.cpp2705
-rw-r--r--utils/demoinfo/demosmoothersamplesource.h233
-rw-r--r--utils/demoinfo/demosmoothersamplesource.txt22
-rw-r--r--utils/demoinfo/tooldemofile.cpp295
-rw-r--r--utils/demoinfo/tooldemofile.h58
7 files changed, 4389 insertions, 0 deletions
diff --git a/utils/demoinfo/demoinfo.cpp b/utils/demoinfo/demoinfo.cpp
new file mode 100644
index 0000000..85d740e
--- /dev/null
+++ b/utils/demoinfo/demoinfo.cpp
@@ -0,0 +1,527 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: A simple application demonstrating the HL2 demo file format ( subject to change!!! )
+//
+// $NoKeywords: $
+//=============================================================================//
+#include <windows.h>
+#include "tier0/dbg.h"
+#include "filesystem.h"
+#include "FileSystem_Tools.h"
+#include "cmdlib.h"
+#include "tooldemofile.h"
+
+static bool uselogfile = false;
+static bool spewed = false;
+
+#define LOGFILE_NAME "log.txt"
+
+#define COM_COPY_CHUNK_SIZE 8192
+
+//-----------------------------------------------------------------------------
+// Purpose: Prints to stdout and to the developer console and optionally to a log file
+// Input : depth -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void vprint( int depth, const char *fmt, ... )
+{
+ char string[ 8192 ];
+ va_list va;
+ va_start( va, fmt );
+ vsprintf( string, fmt, va );
+ va_end( va );
+
+ FILE *fp = NULL;
+
+ if ( uselogfile )
+ {
+ fp = fopen( LOGFILE_NAME, "ab" );
+ }
+
+ while ( depth-- > 0 )
+ {
+ printf( " " );
+ OutputDebugString( " " );
+ if ( fp )
+ {
+ fprintf( fp, " " );
+ }
+ }
+
+ ::printf( "%s", string );
+ OutputDebugString( string );
+
+ if ( fp )
+ {
+ char *p = string;
+ while ( *p )
+ {
+ if ( *p == '\n' )
+ {
+ fputc( '\r', fp );
+ }
+ fputc( *p, fp );
+ p++;
+ }
+ fclose( fp );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Warning/Msg call back through this API
+// Input : type -
+// *pMsg -
+// Output : SpewRetval_t
+//-----------------------------------------------------------------------------
+SpewRetval_t SpewFunc( SpewType_t type, char const *pMsg )
+{
+ spewed = true;
+
+ switch ( type )
+ {
+
+ default:
+ case SPEW_MESSAGE:
+ case SPEW_ASSERT:
+ case SPEW_LOG:
+ vprint( 0, "%s", pMsg );
+ break;
+ case SPEW_WARNING:
+
+ if ( verbose )
+ {
+ vprint( 0, "%s", pMsg );
+ }
+ break;
+ case SPEW_ERROR:
+ vprint( 0, "%s\n", pMsg );
+ break;
+ }
+
+ return SPEW_CONTINUE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Shows usage information
+//-----------------------------------------------------------------------------
+void printusage( void )
+{
+ vprint( 0, "usage: demoinfo <.dem file>\n\
+ \t-v = verbose output\n\
+ \t-l = log to file log.txt\n\
+ \ne.g.: demoinfo -v u:/hl2/hl2/foo.dem\n" );
+
+ // Exit app
+ exit( 1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Removes previous log file
+//-----------------------------------------------------------------------------
+void CheckLogFile( void )
+{
+ if ( uselogfile )
+ {
+ _unlink( LOGFILE_NAME );
+ vprint( 0, " Outputting to log.txt\n" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Prints banner
+//-----------------------------------------------------------------------------
+void PrintHeader()
+{
+ vprint( 0, "Valve Software - demoinfo.exe (%s)\n", __DATE__ );
+ vprint( 0, "--- Demo File Info Sample ---\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Parses all "smoothing" info from .dem file
+// Input : &demoFile -
+// smooth -
+//-----------------------------------------------------------------------------
+void ParseSmoothingInfo( CToolDemoFile &demoFile, CUtlVector< demosmoothing_t >& smooth )
+{
+ democmdinfo_t info;
+ int dummy;
+
+ 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_usercmd:
+ {
+ demoFile.ReadUserCmd( NULL, dummy );
+
+ }
+ break;
+ default:
+ {
+ swallowmessages = false;
+ }
+ break;
+ }
+ }
+ while ( swallowmessages );
+
+ if ( demofinished )
+ {
+ // StopPlayback();
+ return;
+ }
+
+ int curpos = demoFile.GetCurPos();
+
+ demoFile.ReadCmdInfo( info );
+ demoFile.ReadSequenceInfo( dummy, dummy );
+ demoFile.ReadRawData( NULL, 0 );
+
+ 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();
+
+ // Add to end of list
+
+ smooth.AddToTail( smoothing_entry );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Resets all smoothing data back to original values
+// Input : smoothing -
+//-----------------------------------------------------------------------------
+void 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;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper for copying sub-chunk of file
+// Input : dst -
+// src -
+// nSize -
+//-----------------------------------------------------------------------------
+void COM_CopyFileChunk( FileHandle_t dst, FileHandle_t src, int nSize )
+{
+ int copysize = nSize;
+ char copybuf[COM_COPY_CHUNK_SIZE];
+
+ while (copysize > COM_COPY_CHUNK_SIZE)
+ {
+ g_pFileSystem->Read ( copybuf, COM_COPY_CHUNK_SIZE, src );
+ g_pFileSystem->Write( copybuf, COM_COPY_CHUNK_SIZE, dst );
+ copysize -= COM_COPY_CHUNK_SIZE;
+ }
+
+ g_pFileSystem->Read ( copybuf, copysize, src );
+ g_pFileSystem->Write( copybuf, copysize, dst );
+
+ g_pFileSystem->Flush ( src );
+ g_pFileSystem->Flush ( dst );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Writes out a new .dem file based on the existing dem file with new camera positions saved into the dem file
+// Note: The new file is named filename_smooth.dem
+// Input : *filename -
+// smoothing -
+//-----------------------------------------------------------------------------
+void SaveSmoothingInfo( char const *filename, CSmoothingContext& smoothing )
+{
+ // Nothing to do
+ int c = smoothing.smooth.Count();
+ if ( !c )
+ return;
+
+ IBaseFileSystem *fs = g_pFileSystem;
+
+ FileHandle_t infile, outfile;
+
+ infile = fs->Open( filename, "rb", "GAME" );
+ 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", "GAME" );
+ if ( outfile == FILESYSTEM_INVALID_HANDLE )
+ {
+ fs->Close( infile );
+ return;
+ }
+
+ int i;
+
+ // The basic algorithm is to seek to each sample and "overwrite" it during copy with the new data...
+ 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 );
+ }
+
+ // Copy the final bit of data, if any...
+ int final = filesize - lastwritepos;
+
+ COM_CopyFileChunk( outfile, infile, final );
+
+ fs->Close( outfile );
+ fs->Close( infile );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper for spewing verbose sample information
+// Input : flags -
+// Output : char const
+//-----------------------------------------------------------------------------
+char const *DescribeFlags( int flags )
+{
+ static char outbuf[ 256 ];
+
+ outbuf[ 0 ] = 0;
+
+ if ( flags & FDEMO_USE_ORIGIN2 )
+ {
+ Q_strncat( outbuf, "USE_ORIGIN2, ", sizeof( outbuf ), COPY_ALL_CHARACTERS );
+ }
+ if ( flags & FDEMO_USE_ANGLES2 )
+ {
+ Q_strncat( outbuf, "USE_ANGLES2, ", sizeof( outbuf ), COPY_ALL_CHARACTERS );
+ }
+ if ( flags & FDEMO_NOINTERP )
+ {
+ Q_strncat( outbuf, "NOINTERP, ", sizeof( outbuf ), COPY_ALL_CHARACTERS );
+ }
+
+ int len = Q_strlen( outbuf );
+ if ( len > 2 )
+ {
+ outbuf[ len - 2 ] = 0;
+ }
+ else
+ {
+ Q_strncpy( outbuf, "N/A", sizeof( outbuf ) );
+ }
+ return outbuf;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads up all camera samples from a .dem file into the passed in context.
+// Input : *filename -
+// smoothing -
+//-----------------------------------------------------------------------------
+void LoadSmoothingInfo( const char *filename, CSmoothingContext& smoothing )
+{
+ char name[ MAX_OSPATH ];
+ Q_strncpy (name, filename, sizeof(name) );
+ Q_DefaultExtension( name, ".dem", sizeof( name ) );
+
+ CToolDemoFile demoFile;
+
+ if ( !demoFile.Open( filename, true ) )
+ {
+ Warning( "ERROR: couldn't open %s.\n", name );
+ return;
+ }
+
+ demoheader_t * header = demoFile.ReadDemoHeader();
+
+ if ( !header )
+ {
+ demoFile.Close();
+ return;
+ }
+
+ Msg( "\n\n" );
+ Msg( "--------------------------------------------------------------\n" );
+ Msg( "demofilestamp: '%s'\n", header->demofilestamp );
+ Msg( "demoprotocol: %i\n", header->demoprotocol );
+ Msg( "networkprotocol: %i\n", header->networkprotocol );
+ Msg( "servername: '%s'\n", header->servername );
+ Msg( "clientname: '%s'\n", header->clientname );
+ Msg( "mapname: '%s'\n", header->mapname );
+ Msg( "gamedirectory: '%s'\n", header->gamedirectory );
+ Msg( "playback_time: %f seconds\n", header->playback_time );
+ Msg( "playback_ticks: %i ticks\n", header->playback_ticks );
+ Msg( "playback_frames: %i frames\n", header->playback_frames );
+ Msg( "signonlength: %s\n", Q_pretifymem( header->signonlength ) );
+
+ smoothing.active = true;
+ Q_strncpy( smoothing.filename, name, sizeof(smoothing.filename) );
+
+ smoothing.smooth.RemoveAll();
+
+ ClearSmoothingInfo( smoothing );
+
+ ParseSmoothingInfo( demoFile, smoothing.smooth );
+
+ Msg( "--------------------------------------------------------------\n" );
+ Msg( "smoothing data: %i samples\n", smoothing.smooth.Count() );
+
+ if ( verbose )
+ {
+ int c = smoothing.smooth.Count();
+ for ( int i = 0; i < c; ++i )
+ {
+ demosmoothing_t& sample = smoothing.smooth[ i ];
+
+ Msg( "Sample %i:\n", i );
+ Msg( " file pos: %i\n", sample.file_offset );
+ Msg( " tick: %i\n", sample.frametick );
+ Msg( " flags: %s\n", DescribeFlags( sample.info.flags ) );
+
+ Msg( " Original Data:\n" );
+ Msg( " origin: %.4f %.4f %.4f\n", sample.info.viewOrigin.x, sample.info.viewOrigin.y, sample.info.viewOrigin.z );
+ Msg( " viewangles: %.4f %.4f %.4f\n", sample.info.viewAngles.x, sample.info.viewAngles.y, sample.info.viewAngles.z );
+ Msg( " localviewangles: %.4f %.4f %.4f\n", sample.info.localViewAngles.x, sample.info.localViewAngles.y, sample.info.localViewAngles.z );
+
+ Msg( " Resampled Data:\n" );
+ Msg( " origin: %.4f %.4f %.4f\n", sample.info.viewOrigin2.x, sample.info.viewOrigin2.y, sample.info.viewOrigin2.z );
+ Msg( " viewangles: %.4f %.4f %.4f\n", sample.info.viewAngles2.x, sample.info.viewAngles2.y, sample.info.viewAngles2.z );
+ Msg( " localviewangles: %.4f %.4f %.4f\n", sample.info.localViewAngles2.x, sample.info.localViewAngles2.y, sample.info.localViewAngles2.z );
+
+ Msg( "\n" );
+
+ }
+ }
+
+ demoFile.Close();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : argc -
+// argv[] -
+// Output : int
+//-----------------------------------------------------------------------------
+int main( int argc, char* argv[] )
+{
+ SpewOutputFunc( SpewFunc );
+ SpewActivate( "demoinfo", 2 );
+
+ int i = 1;
+ for ( i ; i<argc ; i++)
+ {
+ if ( argv[ i ][ 0 ] == '-' )
+ {
+ switch( argv[ i ][ 1 ] )
+ {
+ case 'l':
+ uselogfile = true;
+ break;
+ case 'v':
+ verbose = true;
+ break;
+ case 'g':
+ ++i;
+ break;
+ default:
+ printusage();
+ break;
+ }
+ }
+ }
+
+ if ( argc < 2 || ( i != argc ) )
+ {
+ PrintHeader();
+ printusage();
+ }
+
+ CheckLogFile();
+
+ PrintHeader();
+
+ vprint( 0, " Info for %s..\n", argv[ i - 1 ] );
+
+ char workingdir[ 256 ];
+ workingdir[0] = 0;
+ Q_getwd( workingdir, sizeof( workingdir ) );
+
+ if ( !FileSystem_Init( NULL, 0, FS_INIT_FULL ) )
+ return 1;
+
+ // Add this so relative filenames work.
+ g_pFullFileSystem->AddSearchPath( workingdir, "game", PATH_ADD_TO_HEAD );
+
+ // Load the demo
+ CSmoothingContext context;
+
+ LoadSmoothingInfo( argv[ i - 1 ], context );
+
+ // Note to tool makers:
+ // Do your work here!!!
+ //Performsmoothing( context );
+
+ // Save out updated .dem file
+ // UNCOMMENT THIS TO ENABLE OUTPUTTING NEW .DEM FILES!!!
+ // SaveSmoothingInfo( argv[ i - 1 ], context );
+
+ FileSystem_Term();
+
+ return 0;
+}
diff --git a/utils/demoinfo/demoinfo.vcproj b/utils/demoinfo/demoinfo.vcproj
new file mode 100644
index 0000000..63f9c28
--- /dev/null
+++ b/utils/demoinfo/demoinfo.vcproj
@@ -0,0 +1,549 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="demoinfo"
+ ProjectGUID="{4FE3FDCA-9571-44B3-A521-C81448434490}">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ AdditionalIncludeDirectories="..\common,..\..\public,..\..\public\tier1"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\Release/demoinfo.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="if exist ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe attrib -r ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+copy &quot;$(TargetPath)&quot; ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+if exist ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb attrib -r ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb
+copy &quot;$(TargetPath)&quot; ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb
+"
+ Outputs="..\..\..\game\bin\demoinfo.exe;..\..\..\game\bin\demoinfo.pdb"/>
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile=".\Release/demoinfo.exe"
+ LinkIncremental="1"
+ SuppressStartupBanner="TRUE"
+ AdditionalLibraryDirectories="..\..\lib\public"
+ IgnoreDefaultLibraryNames="LIBCMT,LIBCMTD"
+ ProgramDatabaseFile=".\Release/demoinfo.pdb"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\Release/demoinfo.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="1"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\public,..\..\public\tier1,..\common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="5"
+ UsePrecompiledHeader="3"
+ PrecompiledHeaderThrough="stdafx.h"
+ PrecompiledHeaderFile=".\Debug/demoinfo.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ WarningLevel="4"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="3"
+ CompileAs="0"/>
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine="if exist ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe attrib -r ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+copy &quot;$(TargetPath)&quot; ..\..\..\game\bin\&quot;$(TargetName)&quot;.exe
+if exist ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb attrib -r ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb
+copy &quot;$(TargetPath)&quot; ..\..\..\game\bin\&quot;$(TargetName)&quot;.pdb
+"
+ Outputs="..\..\..\game\bin\demoinfo.exe;..\..\..\game\bin\demoinfo.pdb"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/FIXED:NO"
+ OutputFile=".\Debug/demoinfo.exe"
+ LinkIncremental="2"
+ SuppressStartupBanner="TRUE"
+ AdditionalLibraryDirectories="..\..\lib\public"
+ IgnoreAllDefaultLibraries="FALSE"
+ IgnoreDefaultLibraryNames="LIBCMT,LIBCMTD"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile=".\Debug/demoinfo.pdb"
+ GenerateMapFile="TRUE"
+ MapFileName=".\Debug/demoinfo.map"
+ SubSystem="1"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"
+ TypeLibraryName=".\Debug/demoinfo.tlb"
+ HeaderFileName=""/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="..\..\tier1\characterset.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\cmdlib.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\cmdlib.h">
+ </File>
+ <File
+ RelativePath="demoinfo.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\public\filesystem_helpers.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\public\filesystem_init.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\common\filesystem_tools.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\tier1\interface.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\tier1\KeyValues.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="tooldemofile.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\tier1\utlbuffer.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="..\..\tier1\utlsymbol.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"
+ UsePrecompiledHeader="0"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="..\..\Public\tier0\basetypes.h">
+ </File>
+ <File
+ RelativePath="..\..\Public\commonmacros.h">
+ </File>
+ <File
+ RelativePath="..\..\public\tier0\dbg.h">
+ </File>
+ <File
+ RelativePath="..\..\public\demofile\demoformat.h">
+ </File>
+ <File
+ RelativePath="..\..\public\tier0\fasttimer.h">
+ </File>
+ <File
+ RelativePath="..\common\filesystem_tools.h">
+ </File>
+ <File
+ RelativePath="..\..\Public\mathlib\MATHLIB.H">
+ </File>
+ <File
+ RelativePath="..\..\public\tier0\memdbgon.h">
+ </File>
+ <File
+ RelativePath="..\..\public\tier0\platform.h">
+ </File>
+ <File
+ RelativePath="..\..\public\protected_things.h">
+ </File>
+ <File
+ RelativePath="..\..\public\string_t.h">
+ </File>
+ <File
+ RelativePath="..\..\public\vstdlib\strtools.h">
+ </File>
+ <File
+ RelativePath="..\..\Public\studio.h">
+ </File>
+ <File
+ RelativePath="tooldemofile.h">
+ </File>
+ <File
+ RelativePath="..\..\public\tier1\utldict.h">
+ </File>
+ <File
+ RelativePath="..\..\public\tier1\utlmemory.h">
+ </File>
+ <File
+ RelativePath="..\..\public\tier1\utlrbtree.h">
+ </File>
+ <File
+ RelativePath="..\..\public\tier1\utlsymbol.h">
+ </File>
+ <File
+ RelativePath="..\..\public\tier1\utlvector.h">
+ </File>
+ <File
+ RelativePath="..\..\Public\mathlib\vector.h">
+ </File>
+ <File
+ RelativePath="..\..\Public\mathlib\vector2d.h">
+ </File>
+ <File
+ RelativePath="..\..\Public\mathlib\vector4d.h">
+ </File>
+ <File
+ RelativePath="..\..\public\vstdlib\vstdlib.h">
+ </File>
+ </Filter>
+ <Filter
+ Name="DemoSmootherSampleSourceFiles"
+ Filter="*.h;*.cpp">
+ <File
+ RelativePath="demosmoothersamplesource.cpp">
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="demosmoothersamplesource.h">
+ <FileConfiguration
+ Name="Release|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32"
+ ExcludedFromBuild="TRUE">
+ <Tool
+ Name="VCCustomBuildTool"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="demosmoothersamplesource.txt">
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe">
+ </Filter>
+ <File
+ RelativePath="..\..\lib\public\tier0.lib">
+ </File>
+ <File
+ RelativePath="..\..\lib\public\tier1.lib">
+ </File>
+ <File
+ RelativePath="..\..\lib\public\tier1.lib">
+ </File>
+ <File
+ RelativePath="..\..\lib\public\tier2.lib">
+ </File>
+ <File
+ RelativePath="..\..\lib\public\tier2.lib">
+ </File>
+ <File
+ RelativePath="..\..\lib\public\vstdlib.lib">
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/utils/demoinfo/demosmoothersamplesource.cpp b/utils/demoinfo/demosmoothersamplesource.cpp
new file mode 100644
index 0000000..5df5f25
--- /dev/null
+++ b/utils/demoinfo/demosmoothersamplesource.cpp
@@ -0,0 +1,2705 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: 00000000000000Sample Source Code for "demo smoothing" tool in the engine. This could be ported into the client .dll
+// pretty easily -- ywb
+//
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "glquake.h"
+#include "cl_demosmootherpanel.h"
+//#include "vid.h"
+#include "../engine/demo.h"
+#include <vgui_controls/Button.h>
+#include <vgui_controls/CheckButton.h>
+#include <KeyValues.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 "filesystem.h"
+#include "filesystem_engine.h"
+#include "cl_demouipanel.h"
+#include "demofile/demoformat.h"
+#include "cl_demoactionmanager.h"
+#include "proto_version.h"
+#include "iprediction.h"
+#include "debugoverlay.h"
+#include "draw.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(MenuButton::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(MenuButton::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::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 )
+ {
+ Con_Printf( "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 );
+
+ Draw_Line( origin, end, r, g, b, false );
+}
+
+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 )
+{
+ Draw_AlphaBox( origin, mins, maxs, angles, r, g, b, a);
+ Draw_WireframeBox( origin, mins, maxs, angles, r, g, b );
+}
+
+//-----------------------------------------------------------------------------
+// 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 )
+ {
+ Draw_Line( sample->info.viewOrigin + m_vecEyeOffset, next->info.viewOrigin + m_vecEyeOffset,
+ 180, 180, 180, false );
+
+ 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 )
+ {
+ Draw_Line( sample->info.GetViewOrigin() + m_vecEyeOffset, next->info.GetViewOrigin() + m_vecEyeOffset,
+ 255, 255, 180, false );
+
+ 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 );
+ Draw_Box( sample->vecmoved + m_vecEyeOffset, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), sample->angmoved, r, g, b, 127 );
+ DrawVecForward( false, sample->vecmoved + m_vecEyeOffset, sample->angmoved, r, g, b );
+ }
+
+ if ( sample->targetpoint )
+ {
+ GetColorForSample( false, false, true, sample, r, g, b );
+ Draw_Box( sample->vectarget, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), vec3_angle, r, g, b, 127 );
+ }
+
+ if ( samplenumber == m_nPreviewLastFrame + 1 )
+ {
+ r = 50;
+ g = 100;
+ b = 250;
+ Draw_Box( sample->info.GetViewOrigin() + m_vecEyeOffset, Vector( -2, -2, -2 ), Vector( 2, 2, 2 ), sample->info.GetViewAngles(), r, g, b, 92 );
+ }
+
+ if ( sample->targetpoint )
+ {
+ r = 200;
+ g = 200;
+ b = 220;
+
+ Draw_Line( sample->info.GetViewOrigin() + m_vecEyeOffset, sample->vectarget, r, g, b, false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// 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 = 0;
+
+ 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 0;
+
+ 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
+ float 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;
+
+ m_nPreviewLastFrame = frame;
+
+ /* 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( 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( 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] )
+ {
+ Draw_Line( previous, splined, 0, 255, 0, false );
+ }
+
+ 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] )
+ {
+ Draw_Line( previous, splined, 0, 255, 0, false );
+ }
+
+ 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, CUtlVector< demosmoothing_t >& smooth )
+{
+ democmdinfo_t info;
+ int dummy;
+
+ 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_usercmd:
+ {
+ demoFile.ReadUserCmd( NULL, dummy );
+
+ }
+ break;
+ default:
+ {
+ swallowmessages = false;
+ }
+ break;
+ }
+ }
+ while ( swallowmessages );
+
+ if ( demofinished )
+ {
+ // StopPlayback();
+ return;
+ }
+
+ int curpos = demoFile.GetCurPos();
+
+ 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();
+
+ smooth.AddToTail( smoothing_entry );
+ }
+}
+
+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 ) )
+ {
+ Con_Printf( "ERROR: couldn't open %s.\n", name );
+ return;
+ }
+
+ demoheader_t * header = demoFile.ReadDemoHeader();
+
+ if ( !header )
+ {
+ demoFile.Close();
+ return;
+ }
+
+ Con_Printf ("Smoothing demo from %s ...", name );
+
+ smoothing.active = true;
+ Q_strncpy( smoothing.filename, name, sizeof(smoothing.filename) );
+
+ smoothing.smooth.RemoveAll();
+
+ ClearSmoothingInfo( smoothing );
+
+ ParseSmoothingInfo( demoFile, smoothing.smooth );
+
+ demoFile.Close();
+
+ //Performsmoothing( smooth );
+ //SaveSmoothedDemo( name, smooth );
+
+ Con_Printf ( " 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 );
+} \ No newline at end of file
diff --git a/utils/demoinfo/demosmoothersamplesource.h b/utils/demoinfo/demosmoothersamplesource.h
new file mode 100644
index 0000000..bb9590e
--- /dev/null
+++ b/utils/demoinfo/demosmoothersamplesource.h
@@ -0,0 +1,233 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Sample Source Code for "demo smoothing" tool in the engine. This could be ported into the client .dll
+// pretty easily -- ywb
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CL_DEMOSMOOTHERPANEL_H
+#define CL_DEMOSMOOTHERPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+
+namespace vgui
+{
+class Button;
+class Label;
+class ListPanel;
+class IScheme;
+};
+
+#include "demofile/demoformat.h"
+#include "demofile.h"
+
+struct demodirectory_t;
+class CSmoothingTypeButton;
+class CFixEdgeButton;
+
+typedef float (*EASEFUNC)( float t );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CDemoSmootherPanel : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CDemoSmootherPanel, vgui::Frame );
+
+public:
+ CDemoSmootherPanel( vgui::Panel *parent );
+ ~CDemoSmootherPanel();
+
+ virtual void OnTick();
+
+ // Command issued
+ virtual void OnCommand(const char *command);
+
+ void OnRefresh();
+
+ virtual bool OverrideView( democmdinfo_t& info, int tick );
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ virtual void DrawDebuggingInfo( int frame, float elapsed );
+
+
+protected:
+
+ bool CanEdit();
+
+ void Reset( void );
+
+ demosmoothing_t *GetCurrent( void );
+
+ void DrawSmoothingSample( bool original, bool processed, int samplenumber, demosmoothing_t *sample, demosmoothing_t *next );
+ void DrawTargetSpline( void );
+ void DrawKeySpline( void );
+ int GetTickForFrame( int frame );
+ int GetFrameForTick( int tick );
+ bool GetInterpolatedViewPoint( Vector& origin, QAngle& angles );
+ bool GetInterpolatedOriginAndAngles( bool readonly, Vector& origin, QAngle& angles );
+
+ void DrawLegend( int startframe, int endframe );
+
+ void OnRevert();
+ void OnPreview( bool original );
+ void OnSave();
+ void OnReload();
+ void OnSelect();
+ void OnTogglePause();
+ void OnStep( bool forward );
+ void OnGotoFrame();
+
+ void OnToggleKeyFrame( void );
+ void OnToggleLookTarget( void );
+
+ void OnNextKey();
+ void OnPrevKey();
+ void OnNextTarget();
+ void OnPrevTarget();
+
+ void OnRevertPoint( void );
+
+ void PopulateMenuList();
+ int GetStartFrame();
+ int GetEndFrame();
+
+ void OnSaveKey();
+ void OnSetView();
+
+ void OnSmoothEdges( bool left, bool right );
+
+ void PerformLinearInterpolatedAngleSmoothing( int startframe, int endframe );
+
+ void OnSmoothSelectionAngles( void );
+ void OnSmoothSelectionOrigin( void );
+ void OnLinearInterpolateAnglesBasedOnEndpoints( void );
+ void OnLinearInterpolateOriginBasedOnEndpoints( void );
+ void OnSplineSampleOrigin( void );
+ void OnSplineSampleAngles( void );
+ void OnLookAtPoints( bool spline );
+ void OnSetKeys(float interval);
+
+ void OnOriginEaseCurve( EASEFUNC easefunc );
+
+ void SetLastFrame( bool jumptotarget, int frame );
+
+ void AddSamplePoints( bool usetarget, bool includeboundaries, CUtlVector< demosmoothing_t * >& points, int start, int end );
+ demosmoothing_t *GetBoundedSample( CUtlVector< demosmoothing_t * >& points, int sample );
+ void FindSpanningPoints( int tick, CUtlVector< demosmoothing_t * >& points, int& prev, int& next );
+
+ // Undo/Redo
+ void Undo( void );
+ void Redo( void );
+
+ // Do push before changes
+ void PushUndo( char *description );
+ // Do this push after changes, must match pushundo 1for1
+ void PushRedo( char *description );
+
+ void WipeUndo( void );
+ void WipeRedo( void );
+
+ const char *GetUndoDescription( void );
+ const char *GetRedoDescription( void );
+
+ bool CanUndo( void );
+ bool CanRedo( void );
+
+ void ParseSmoothingInfo( CDemoFile &demoFile, CUtlVector< demosmoothing_t >& smooth );
+ void LoadSmoothingInfo( const char *filename, CSmoothingContext& smoothing );
+ void ClearSmoothingInfo( CSmoothingContext& smoothing );
+ void SaveSmoothingInfo( char const *filename, CSmoothingContext& smoothing );
+
+ CSmoothingTypeButton *m_pType;
+
+ vgui::Button *m_pRevert;
+ vgui::Button *m_pOK;
+ vgui::Button *m_pCancel;
+
+ vgui::Button *m_pSave;
+ vgui::Button *m_pReloadFromDisk;
+
+ vgui::TextEntry *m_pStartFrame;
+ vgui::TextEntry *m_pEndFrame;
+
+ vgui::Button *m_pPreviewOriginal;
+ vgui::Button *m_pPreviewProcessed;
+
+ vgui::CheckButton *m_pBackOff;
+
+ vgui::Label *m_pSelectionInfo;
+ vgui::CheckButton *m_pShowAllSamples;
+ vgui::Button *m_pSelectSamples;
+
+ vgui::Button *m_pPauseResume;
+ vgui::Button *m_pStepForward;
+ vgui::Button *m_pStepBackward;
+
+ vgui::CheckButton *m_pHideLegend;
+
+ vgui::CheckButton *m_pHideOriginal;
+ vgui::CheckButton *m_pHideProcessed;
+
+ vgui::Button *m_pToggleKeyFrame;
+ vgui::Button *m_pToggleLookTarget;
+ vgui::Button *m_pRevertPoint;
+
+ vgui::Button *m_pMoveCameraToPoint;
+
+ vgui::Button *m_pUndo;
+ vgui::Button *m_pRedo;
+
+ vgui::Button *m_pNextKey;
+ vgui::Button *m_pPrevKey;
+ vgui::Button *m_pNextTarget;
+ vgui::Button *m_pPrevTarget;
+
+ CFixEdgeButton *m_pFixEdges;
+ vgui::TextEntry *m_pFixEdgeFrames;
+
+ vgui::Button *m_pProcessKey;
+
+ vgui::TextEntry *m_pGotoFrame;
+ vgui::Button *m_pGoto;
+
+ bool m_bHasSelection;
+ int m_nSelection[2];
+ int m_iSelectionTicksSpan;
+
+ bool m_bPreviewing;
+ bool m_bPreviewOriginal;
+ int m_iPreviewStartTick;
+ float m_fPreviewCurrentTime;
+ int m_nPreviewLastFrame;
+ bool m_bPreviewPaused;
+
+ CSmoothingContext m_Smoothing;
+
+ bool m_bInputActive;
+ int m_nOldCursor[2];
+
+
+ struct DemoSmoothUndo
+ {
+ CSmoothingContext *undo;
+ CSmoothingContext *redo;
+ char *udescription;
+ char *rdescription;
+ };
+
+ CUtlVector< DemoSmoothUndo * > m_UndoStack;
+ int m_nUndoLevel;
+ bool m_bRedoPending;
+
+ bool m_bDirty;
+
+ Vector m_vecEyeOffset;
+};
+
+#endif // CL_DEMOSMOOTHERPANEL_H
diff --git a/utils/demoinfo/demosmoothersamplesource.txt b/utils/demoinfo/demosmoothersamplesource.txt
new file mode 100644
index 0000000..f37653b
--- /dev/null
+++ b/utils/demoinfo/demosmoothersamplesource.txt
@@ -0,0 +1,22 @@
+NOTE 2/8/05:
+
+These files are copied directly out of the HL2 engine to use as a
+starting point for writing your own vgui based "smoothing" tools for dem files.
+
+If you decide to use this, then my suggestion would be to copy these into a MOD in the client .dll and
+clean up the #include's so that you can get it basically compiling and showing up.
+
+It should be a "tool" just like the net_graph and other vgui
+based tools in the client .dll (use a ConVar to show/hide it maybe?)
+
+The sample source actually contains all of the reading/writing code for dem files which is also in deminfo.cpp.
+
+Note that CDemoFile should be changed to CToolDemoFile.
+
+As I recall, you might have to reimplement a "driving" interface like the one in the main demo UI panel. I would just implement
+it as part of this UI, etc.
+
+If you have any questions or run into major snags, please let me know and I'll try to help out.
+
+Yahn Bernier
[email protected] \ No newline at end of file
diff --git a/utils/demoinfo/tooldemofile.cpp b/utils/demoinfo/tooldemofile.cpp
new file mode 100644
index 0000000..20abf88
--- /dev/null
+++ b/utils/demoinfo/tooldemofile.cpp
@@ -0,0 +1,295 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include <utlbuffer.h>
+#include "tooldemofile.h"
+#include "filesystem.h"
+#include "demofile/demoformat.h"
+
+extern IBaseFileSystem *g_pFileSystem;
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CToolDemoFile::CToolDemoFile()
+{
+ m_hDemoFile = FILESYSTEM_INVALID_HANDLE;
+}
+
+CToolDemoFile::~CToolDemoFile()
+{
+ if ( IsOpen() )
+ {
+ Close();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CToolDemoFile::ReadSequenceInfo(int &nSeqNrIn, int &nSeqNrOut)
+{
+ Assert( m_hDemoFile != FILESYSTEM_INVALID_HANDLE );
+
+ g_pFileSystem->Read( &nSeqNrIn, sizeof(int), m_hDemoFile );
+ g_pFileSystem->Read( &nSeqNrOut, sizeof(int), m_hDemoFile );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CToolDemoFile::ReadCmdInfo( democmdinfo_t& info )
+{
+ Assert( m_hDemoFile != FILESYSTEM_INVALID_HANDLE );
+ g_pFileSystem->Read( &info, sizeof( democmdinfo_t ), m_hDemoFile );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : cmd -
+// dt -
+// frame -
+//-----------------------------------------------------------------------------
+void CToolDemoFile::ReadCmdHeader( unsigned char& cmd, int& tick )
+{
+ Assert( m_hDemoFile != FILESYSTEM_INVALID_HANDLE );
+
+ // Read the command
+ int r = g_pFileSystem->Read ( &cmd, sizeof(byte), m_hDemoFile );
+
+ if ( r <=0 )
+ {
+ Warning("Missing end tag in demo file.\n");
+ cmd = dem_stop;
+ return;
+ }
+
+ Assert( cmd >= 1 && cmd <= dem_lastcmd );
+
+ // Read the timestamp
+ g_pFileSystem->Read ( &tick, sizeof(int), m_hDemoFile );
+
+ tick = LittleDWord( tick );
+}
+
+const char *CToolDemoFile::ReadConsoleCommand()
+{
+ static char cmdstring[1024];
+
+ ReadRawData( cmdstring, sizeof(cmdstring) );
+
+ return cmdstring;
+}
+
+unsigned int CToolDemoFile::GetCurPos()
+{
+ if ( m_hDemoFile == FILESYSTEM_INVALID_HANDLE )
+ return 0;
+
+ return g_pFileSystem->Tell( m_hDemoFile );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : expected_length -
+// &demofile -
+//-----------------------------------------------------------------------------
+int CToolDemoFile::ReadNetworkDataTables( CUtlBuffer *buf )
+{
+ Assert( m_hDemoFile != FILESYSTEM_INVALID_HANDLE );
+ char data[ 1024 ];
+ int length;
+
+ g_pFileSystem->Read( &length, sizeof( int ), m_hDemoFile );
+
+ while( length > 0 )
+ {
+ int chunk = min( length, 1024 );
+ g_pFileSystem->Read( data, chunk, m_hDemoFile );
+ length -= chunk;
+
+ if ( buf )
+ {
+ buf->Put( data, chunk );
+ }
+ }
+
+ return length;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : discard -
+//-----------------------------------------------------------------------------
+int CToolDemoFile::ReadUserCmd( char *buffer, int &size )
+{
+ Assert( m_hDemoFile != FILESYSTEM_INVALID_HANDLE );
+
+ int outgoing_sequence;
+
+ g_pFileSystem->Read( &outgoing_sequence, sizeof( int ), m_hDemoFile );
+
+ size = ReadRawData( buffer, size );
+
+ return outgoing_sequence;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Rewind from the current spot by the time stamp, byte code and frame counter offsets
+//-----------------------------------------------------------------------------
+void CToolDemoFile::SeekTo( int position )
+{
+ Assert( m_hDemoFile != FILESYSTEM_INVALID_HANDLE );
+ g_pFileSystem->Seek( m_hDemoFile, position, FILESYSTEM_SEEK_HEAD );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+int CToolDemoFile::ReadRawData( char *buffer, int length )
+{
+ Assert( m_hDemoFile != FILESYSTEM_INVALID_HANDLE );
+
+ int size;
+
+ // read length of data block
+ g_pFileSystem->Read( &size, sizeof( int ), m_hDemoFile );
+
+ if ( buffer && (length < size) )
+ {
+ DevMsg("CToolDemoFile::ReadRawData: buffe overflow (%i).\n", size );
+ return -1;
+ }
+
+ if ( buffer )
+ {
+ if ( length < size )
+ {
+ // given buffer is too small
+ DevMsg("CToolDemoFile::ReadRawData: buffe overflow (%i).\n", size );
+ g_pFileSystem->Seek( m_hDemoFile, size, FILESYSTEM_SEEK_CURRENT );
+ size = -1;
+ }
+ else
+ {
+ // read data into buffer
+ int r = g_pFileSystem->Read( buffer, size, m_hDemoFile );
+ if ( r != size )
+ {
+ Warning( "Error reading demo message data.\n");
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ // just skip it
+ g_pFileSystem->Seek( m_hDemoFile, size, FILESYSTEM_SEEK_CURRENT );
+ }
+
+ return size;
+}
+
+demoheader_t *CToolDemoFile::ReadDemoHeader()
+{
+ if ( m_hDemoFile == FILESYSTEM_INVALID_HANDLE )
+ return NULL; // file not open
+
+ // goto file start
+ g_pFileSystem->Seek(m_hDemoFile, 0, FILESYSTEM_SEEK_HEAD);
+
+ Q_memset( &m_DemoHeader, 0, sizeof(m_DemoHeader) );
+
+ int r = g_pFileSystem->Read( &m_DemoHeader, sizeof(demoheader_t), m_hDemoFile );
+
+ if ( r != sizeof(demoheader_t) )
+ return NULL; // reading failed
+
+ if ( Q_strcmp ( m_DemoHeader.demofilestamp, DEMO_HEADER_ID ) )
+ {
+ Warning( "%s has invalid demo header ID.\n", m_szFileName );
+ return NULL;
+ }
+
+ /*
+// The current network protocol version. Changing this makes clients and servers incompatible
+#define PROTOCOL_VERSION 7
+
+ if ( m_DemoHeader.networkprotocol != PROTOCOL_VERSION )
+ {
+ Warning ("ERROR: demo network protocol %i outdated, engine version is %i \n",
+ m_DemoHeader.networkprotocol, PROTOCOL_VERSION );
+
+ return NULL;
+ }
+ */
+
+ if ( m_DemoHeader.demoprotocol != DEMO_PROTOCOL )
+ {
+ Warning ("ERROR: demo file protocol %i outdated, engine version is %i \n",
+ m_DemoHeader.demoprotocol, DEMO_PROTOCOL );
+
+ return NULL;
+ }
+
+ return &m_DemoHeader;
+}
+
+bool CToolDemoFile::Open(const char *name, bool bReadOnly)
+{
+ if ( m_hDemoFile != FILESYSTEM_INVALID_HANDLE )
+ {
+ Warning ("CToolDemoFile::Open: file already open.\n");
+ return false;
+ }
+
+ m_szFileName[0] = 0; // clear name
+ Q_memset( &m_DemoHeader, 0, sizeof(m_DemoHeader) ); // and demo header
+
+ if ( bReadOnly )
+ {
+ // open existing file for reading only
+ m_hDemoFile = g_pFileSystem->Open (name, "rb", "GAME" );
+ }
+ else
+ {
+ // create new file for writing only
+ m_hDemoFile = g_pFileSystem->Open (name, "wb", "GAME" );
+ }
+
+ if ( m_hDemoFile == FILESYSTEM_INVALID_HANDLE )
+ {
+ Warning ("CToolDemoFile::Open: couldn't open file %s for %s.\n",
+ name, bReadOnly?"reading":"writing" );
+ return false;
+ }
+
+ Q_strncpy( m_szFileName, name, sizeof(m_szFileName) );
+
+ return true;
+}
+
+bool CToolDemoFile::IsOpen()
+{
+ return m_hDemoFile != FILESYSTEM_INVALID_HANDLE;
+}
+
+void CToolDemoFile::Close()
+{
+ if ( m_hDemoFile != FILESYSTEM_INVALID_HANDLE )
+ {
+ g_pFileSystem->Close(m_hDemoFile);
+ m_hDemoFile = FILESYSTEM_INVALID_HANDLE;
+ }
+}
+
+int CToolDemoFile::GetSize()
+{
+ return g_pFileSystem->Size( m_hDemoFile );
+}
+
diff --git a/utils/demoinfo/tooldemofile.h b/utils/demoinfo/tooldemofile.h
new file mode 100644
index 0000000..e82e172
--- /dev/null
+++ b/utils/demoinfo/tooldemofile.h
@@ -0,0 +1,58 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef TOOLDEMOFILE_H
+#define TOOLDEMOFILE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "mathlib/vector.h"
+#include "tier0/platform.h"
+#include "utlvector.h"
+#include "filesystem.h"
+#include "demofile/demoformat.h"
+
+class CUtlBuffer;
+
+class CToolDemoFile
+{
+public:
+ CToolDemoFile();
+ virtual ~CToolDemoFile();
+
+ bool Open(const char *name, bool bReadOnly);
+ bool IsOpen();
+ void Close();
+
+ void SeekTo( int position );
+ unsigned int GetCurPos();
+ int GetSize();
+
+ int ReadRawData( char *buffer, int length );
+
+ void ReadSequenceInfo(int &nSeqNrIn, int &nSeqNrOutAck);
+
+ void ReadCmdInfo( democmdinfo_t& info );
+
+ void ReadCmdHeader( unsigned char& cmd, int& tick );
+
+ const char *ReadConsoleCommand( void );
+
+ int ReadNetworkDataTables( CUtlBuffer *buf ); // if buf is NULL, skip it
+
+ int ReadUserCmd( char *buffer, int &size );
+
+ demoheader_t *ReadDemoHeader();
+
+
+public:
+ FileHandle_t m_hDemoFile; // filesystem handle
+ char m_szFileName[MAX_PATH]; //name of current demo file
+ demoheader_t m_DemoHeader; //general demo info
+};
+
+#endif // TOOLDEMOFILE_H