//========= Copyright Valve Corporation, All rights reserved. ============// // //=======================================================================================// #include "cl_replaymoviemanager.h" #include "replay/ireplaymoviemanager.h" #include "replay/ireplaymovierenderer.h" #include "replay/replay.h" #include "replay/replayutils.h" #include "replay/rendermovieparams.h" #include "replay/shared_defs.h" #include "cl_replaymovie.h" #include "cl_renderqueue.h" #include "cl_replaycontext.h" #include "filesystem.h" #include "KeyValues.h" #include "replaysystem.h" #include "cl_replaymanager.h" #include "materialsystem/imaterialsystem.h" #include "materialsystem/materialsystem_config.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" //---------------------------------------------------------------------------------------- #define MOVIE_MANAGER_VERSION 1 //---------------------------------------------------------------------------------------- extern IMaterialSystem *materials; //---------------------------------------------------------------------------------------- CReplayMovieManager::CReplayMovieManager() : m_pPendingMovie( NULL ), m_pVidModeSettings( NULL ), m_pRenderMovieSettings( NULL ), m_bIsRendering( false ), m_bRenderingCancelled( false ) { m_pVidModeSettings = new MaterialSystem_Config_t(); m_pRenderMovieSettings = new RenderMovieParams_t(); m_wszCachedMovieTitle[0] = L'\0'; } CReplayMovieManager::~CReplayMovieManager() { delete m_pVidModeSettings; } bool CReplayMovieManager::Init() { // Create "rendered" dir const char *pRenderedDir = Replay_va( "%s%s%c", CL_GetReplayBaseDir(), SUBDIR_RENDERED, CORRECT_PATH_SEPARATOR ); g_pFullFileSystem->CreateDirHierarchy( pRenderedDir ); return BaseClass::Init(); } int CReplayMovieManager::GetMovieCount() { return Count(); } void CReplayMovieManager::GetMovieList( CUtlLinkedList< IReplayMovie * > &list ) { FOR_EACH_OBJ( this, i ) { list.AddToTail( ToMovie( m_vecObjs[ i ] ) ); } } IReplayMovie *CReplayMovieManager::GetMovie( ReplayHandle_t hMovie ) { return ToMovie( Find( hMovie ) ); } void CReplayMovieManager::AddMovie( CReplayMovie *pNewMovie ) { Add( pNewMovie ); Save(); } CReplayMovie *CReplayMovieManager::Create() { return new CReplayMovie(); } const char *CReplayMovieManager::GetRelativeIndexPath() const { return Replay_va( "%s%c", SUBDIR_MOVIES, CORRECT_PATH_SEPARATOR ); } IReplayMovie *CReplayMovieManager::CreateAndAddMovie( ReplayHandle_t hReplay ) { CReplayMovie *pNewMovie = CreateAndGenerateHandle(); // Sets m_hThis (which is accessed via GetHandle()) // Cache replay handle. pNewMovie->m_hReplay = hReplay; // Copy cached render settings to the movie itself. V_memcpy( &pNewMovie->m_RenderSettings, &m_pRenderMovieSettings->m_Settings, sizeof( ReplayRenderSettings_t ) ); AddMovie( pNewMovie ); return pNewMovie; } void CReplayMovieManager::DeleteMovie( ReplayHandle_t hMovie ) { // Cache owner replay CReplayMovie *pMovie = Find( hMovie ); CReplay *pOwnerReplay = pMovie ? CL_GetReplayManager()->GetReplay( pMovie->m_hReplay ) : NULL; Remove( hMovie ); // If no more movies for the given replay, mark as unrendered & save if ( pOwnerReplay && GetNumMoviesDependentOnReplay( pOwnerReplay ) == 0 ) { pOwnerReplay->m_bRendered = false; CL_GetReplayManager()->FlagReplayForFlush( pOwnerReplay, false ); } } int CReplayMovieManager::GetNumMoviesDependentOnReplay( const CReplay *pReplay ) { if ( !pReplay ) return 0; // Go through all movies and find any that depend on the given replay int nNumMovies = 0; FOR_EACH_OBJ( this, i ) { CReplayMovie *pMovie = ToMovie( m_vecObjs[ i ] ); if ( pMovie->m_hReplay == pReplay->GetHandle() ) { ++nNumMovies; } } return nNumMovies; } void CReplayMovieManager::SetPendingMovie( IReplayMovie *pMovie ) { m_pPendingMovie = pMovie; } IReplayMovie *CReplayMovieManager::GetPendingMovie() { return m_pPendingMovie; } void CReplayMovieManager::FlagMovieForFlush( IReplayMovie *pMovie, bool bImmediate ) { FlagForFlush( CastMovie( pMovie ), bImmediate ); } CReplayMovie *CReplayMovieManager::CastMovie( IReplayMovie *pMovie ) { return static_cast< CReplayMovie * >( pMovie ); } int CReplayMovieManager::GetVersion() const { return MOVIE_MANAGER_VERSION; } IReplayContext *CReplayMovieManager::GetReplayContext() const { return g_pClientReplayContextInternal; } float CReplayMovieManager::GetNextThinkTime() const { return 0.1f; } void CReplayMovieManager::CacheMovieTitle( const wchar_t *pTitle ) { V_wcsncpy( m_wszCachedMovieTitle, pTitle, sizeof( m_wszCachedMovieTitle ) ); } void CReplayMovieManager::GetCachedMovieTitleAndClear( wchar_t *pOut, int nOutBufLength ) { const int nLength = wcslen( m_wszCachedMovieTitle ); wcsncpy( pOut, m_wszCachedMovieTitle, nOutBufLength ); pOut[ nLength ] = L'\0'; m_wszCachedMovieTitle[0] = L'\0'; } void CReplayMovieManager::AddReplayForRender( CReplay *pReplay, int iPerformance ) { if ( !g_pClientReplayContextInternal->ReconstructReplayIfNecessary( pReplay ) ) { CL_GetErrorSystem()->AddErrorFromTokenName( "#Replay_Err_Render_ReconstructFailed" ); return; } // Store in the demo player's list g_pReplayDemoPlayer->AddReplayToList( pReplay->GetHandle(), iPerformance ); } void CReplayMovieManager::ClearRenderCancelledFlag() { m_bRenderingCancelled = false; } void CReplayMovieManager::RenderMovie( RenderMovieParams_t const& params ) { // Save state m_bIsRendering = true; // Change video settings for recording SetupVideo( params ); // Clear any old replays in the player g_pReplayDemoPlayer->ClearReplayList(); // Render all unrendered replays if ( params.m_hReplay == REPLAY_HANDLE_INVALID ) { CRenderQueue *pRenderQueue = g_pClientReplayContextInternal->m_pRenderQueue; const int nQueueCount = pRenderQueue->GetCount(); for ( int i = 0; i < nQueueCount; ++i ) { ReplayHandle_t hCurReplay; int iCurPerformance; if ( !pRenderQueue->GetEntryData( i, &hCurReplay, &iCurPerformance ) ) continue; CReplay *pReplay = CL_GetReplayManager()->GetReplay( hCurReplay ); if ( !pReplay ) continue; AddReplayForRender( pReplay, iCurPerformance ); } } else { // Cache the title CReplayMovieManager *pMovieManager = CL_GetMovieManager(); pMovieManager->CacheMovieTitle( params.m_wszTitle ); // Only render the specified replay AddReplayForRender( CL_GetReplayManager()->GetReplay( params.m_hReplay ), params.m_iPerformance ); } g_pReplayDemoPlayer->PlayNextReplay(); } void CReplayMovieManager::RenderNextMovie() { m_bIsRendering = true; g_pReplayDemoPlayer->PlayNextReplay(); } void CReplayMovieManager::SetupHighDetailModels() { g_pEngine->Cbuf_AddText( "r_rootlod 0\n" ); } void CReplayMovieManager::SetupHighDetailTextures() { g_pEngine->Cbuf_AddText( "mat_picmip -1\n" ); } void CReplayMovieManager::SetupHighQualityAntialiasing() { int nNumSamples = 1; int nQualityLevel = 0; if ( materials->SupportsCSAAMode(8, 2) ) { nNumSamples = 8; nQualityLevel = 2; } else if ( materials->SupportsMSAAMode(8) ) { nNumSamples = 8; nQualityLevel = 0; } else if ( materials->SupportsCSAAMode(4, 4) ) { nNumSamples = 4; nQualityLevel = 4; } else if ( materials->SupportsCSAAMode(4, 2) ) { nNumSamples = 4; nQualityLevel = 2; } else if ( materials->SupportsMSAAMode(6) ) { nNumSamples = 6; nQualityLevel = 0; } else if ( materials->SupportsMSAAMode(4) ) { nNumSamples = 4; nQualityLevel = 0; } else if ( materials->SupportsMSAAMode(2) ) { nNumSamples = 2; nQualityLevel = 0; } g_pEngine->Cbuf_AddText( Replay_va( "mat_antialias %i\n", nNumSamples ) ); g_pEngine->Cbuf_AddText( Replay_va( "mat_aaquality %i\n", nQualityLevel ) ); } void CReplayMovieManager::SetupHighQualityFiltering() { g_pEngine->Cbuf_AddText( "mat_forceaniso\n" ); } void CReplayMovieManager::SetupHighQualityShadowDetail() { if ( materials->SupportsShadowDepthTextures() ) { g_pEngine->Cbuf_AddText( "r_shadowrendertotexture 1\n" ); g_pEngine->Cbuf_AddText( "r_flashlightdepthtexture 1\n" ); } else { g_pEngine->Cbuf_AddText( "r_shadowrendertotexture 1\n" ); g_pEngine->Cbuf_AddText( "r_flashlightdepthtexture 0\n" ); } } void CReplayMovieManager::SetupHighQualityHDR() { ConVarRef mat_dxlevel( "mat_dxlevel" ); if ( mat_dxlevel.GetInt() < 80 ) return; g_pEngine->Cbuf_AddText( Replay_va( "mat_hdr_level %i\n", materials->SupportsHDRMode( HDR_TYPE_INTEGER ) ? 2 : 1 ) ); } void CReplayMovieManager::SetupHighQualityWaterDetail() { #ifndef _X360 g_pEngine->Cbuf_AddText( "r_waterforceexpensive 1\n" ); #endif g_pEngine->Cbuf_AddText( "r_waterforcereflectentities 1\n" ); } void CReplayMovieManager::SetupMulticoreRender() { g_pEngine->Cbuf_AddText( "mat_queue_mode 0\n" ); } void CReplayMovieManager::SetupHighQualityShaderDetail() { g_pEngine->Cbuf_AddText( "mat_reducefillrate 0\n" ); } void CReplayMovieManager::SetupColorCorrection() { g_pEngine->Cbuf_AddText( "mat_colorcorrection 1\n" ); } void CReplayMovieManager::SetupMotionBlur() { g_pEngine->Cbuf_AddText( "mat_motion_blur_enabled 1\n" ); } void CReplayMovieManager::SetupVideo( RenderMovieParams_t const ¶ms ) { // Get current video config const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard(); // Cache config V_memcpy( m_pVidModeSettings, &config, sizeof( config ) ); // Cache quit when done V_memcpy( m_pRenderMovieSettings, ¶ms, sizeof( params ) ); g_pEngine->Cbuf_Execute(); } void CReplayMovieManager::CompleteRender( bool bSuccess, bool bShowBrowser ) { // Store state m_bIsRendering = false; // Shutdown renderer IReplayMovieRenderer *pRenderer = CL_GetMovieRenderer(); if ( pRenderer ) { pRenderer->ShutdownRenderer(); } if ( !bSuccess ) { // Delete the movie from the manager IReplayMovie *pMovie = CL_GetMovieManager()->GetPendingMovie(); if ( pMovie ) { CL_GetMovieManager()->DeleteMovie( pMovie->GetMovieHandle() ); } } // Clear render queue if we're done if ( bShowBrowser ) { CL_GetRenderQueue()->Clear(); } // Notify UI that rendering is complete g_pClient->OnRenderComplete( *m_pRenderMovieSettings, m_bRenderingCancelled, bSuccess, bShowBrowser ); // Quit now? if ( m_pRenderMovieSettings->m_bQuitWhenFinished ) { g_pEngine->HostState_Shutdown(); return; } // Otherwise, play a sound. g_pClient->PlaySound( "replay\\rendercomplete.wav" ); } void CReplayMovieManager::CancelRender() { m_bRenderingCancelled = true; CompleteRender( false, true ); g_pEngine->Host_Disconnect( false ); // CReplayDemoPlayer::StopPlayback() will be called } void CReplayMovieManager::GetMoviesAsQueryableItems( CUtlLinkedList< IQueryableReplayItem *, int > &lstMovies ) { lstMovies.RemoveAll(); FOR_EACH_OBJ( this, i ) { lstMovies.AddToHead( ToMovie( m_vecObjs[ i ] ) ); } } const char *CReplayMovieManager::GetRenderDir() const { return Replay_va( "%s%s%c", g_pClientReplayContextInternal->GetBaseDir(), SUBDIR_RENDERED, CORRECT_PATH_SEPARATOR ); } const char *CReplayMovieManager::GetRawExportDir() const { static CFmtStr s_fmtExportDir; CReplayTime time; time.InitDateAndTimeToNow(); int nDay, nMonth, nYear; time.GetDate( nDay, nMonth, nYear ); int nHour, nMin, nSec; time.GetTime( nHour, nMin, nSec ); s_fmtExportDir.sprintf( "%smovie_%02i%02i%04i_%02i%02i%02i%c", GetRenderDir(), nMonth, nDay, nYear, nHour, nMin, nSec, CORRECT_PATH_SEPARATOR ); return s_fmtExportDir.Access(); } //----------------------------------------------------------------------------------------