diff options
Diffstat (limited to 'utils/demoinfo')
| -rw-r--r-- | utils/demoinfo/demoinfo.cpp | 527 | ||||
| -rw-r--r-- | utils/demoinfo/demoinfo.vcproj | 549 | ||||
| -rw-r--r-- | utils/demoinfo/demosmoothersamplesource.cpp | 2705 | ||||
| -rw-r--r-- | utils/demoinfo/demosmoothersamplesource.h | 233 | ||||
| -rw-r--r-- | utils/demoinfo/demosmoothersamplesource.txt | 22 | ||||
| -rw-r--r-- | utils/demoinfo/tooldemofile.cpp | 295 | ||||
| -rw-r--r-- | utils/demoinfo/tooldemofile.h | 58 |
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\"$(TargetName)".exe attrib -r ..\..\..\game\bin\"$(TargetName)".exe +copy "$(TargetPath)" ..\..\..\game\bin\"$(TargetName)".exe +if exist ..\..\..\game\bin\"$(TargetName)".pdb attrib -r ..\..\..\game\bin\"$(TargetName)".pdb +copy "$(TargetPath)" ..\..\..\game\bin\"$(TargetName)".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\"$(TargetName)".exe attrib -r ..\..\..\game\bin\"$(TargetName)".exe +copy "$(TargetPath)" ..\..\..\game\bin\"$(TargetName)".exe +if exist ..\..\..\game\bin\"$(TargetName)".pdb attrib -r ..\..\..\game\bin\"$(TargetName)".pdb +copy "$(TargetPath)" ..\..\..\game\bin\"$(TargetName)".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 |