Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

474 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. //=======================================================================================//
  4. #include "cl_replaymoviemanager.h"
  5. #include "replay/ireplaymoviemanager.h"
  6. #include "replay/ireplaymovierenderer.h"
  7. #include "replay/replay.h"
  8. #include "replay/replayutils.h"
  9. #include "replay/rendermovieparams.h"
  10. #include "replay/shared_defs.h"
  11. #include "cl_replaymovie.h"
  12. #include "cl_renderqueue.h"
  13. #include "cl_replaycontext.h"
  14. #include "filesystem.h"
  15. #include "KeyValues.h"
  16. #include "replaysystem.h"
  17. #include "cl_replaymanager.h"
  18. #include "materialsystem/imaterialsystem.h"
  19. #include "materialsystem/materialsystem_config.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. //----------------------------------------------------------------------------------------
  23. #define MOVIE_MANAGER_VERSION 1
  24. //----------------------------------------------------------------------------------------
  25. extern IMaterialSystem *materials;
  26. //----------------------------------------------------------------------------------------
  27. CReplayMovieManager::CReplayMovieManager()
  28. : m_pPendingMovie( NULL ),
  29. m_pVidModeSettings( NULL ),
  30. m_pRenderMovieSettings( NULL ),
  31. m_bIsRendering( false ),
  32. m_bRenderingCancelled( false )
  33. {
  34. m_pVidModeSettings = new MaterialSystem_Config_t();
  35. m_pRenderMovieSettings = new RenderMovieParams_t();
  36. m_wszCachedMovieTitle[0] = L'\0';
  37. }
  38. CReplayMovieManager::~CReplayMovieManager()
  39. {
  40. delete m_pVidModeSettings;
  41. }
  42. bool CReplayMovieManager::Init()
  43. {
  44. // Create "rendered" dir
  45. const char *pRenderedDir = Replay_va( "%s%s%c", CL_GetReplayBaseDir(), SUBDIR_RENDERED, CORRECT_PATH_SEPARATOR );
  46. g_pFullFileSystem->CreateDirHierarchy( pRenderedDir );
  47. return BaseClass::Init();
  48. }
  49. int CReplayMovieManager::GetMovieCount()
  50. {
  51. return Count();
  52. }
  53. void CReplayMovieManager::GetMovieList( CUtlLinkedList< IReplayMovie * > &list )
  54. {
  55. FOR_EACH_OBJ( this, i )
  56. {
  57. list.AddToTail( ToMovie( m_vecObjs[ i ] ) );
  58. }
  59. }
  60. IReplayMovie *CReplayMovieManager::GetMovie( ReplayHandle_t hMovie )
  61. {
  62. return ToMovie( Find( hMovie ) );
  63. }
  64. void CReplayMovieManager::AddMovie( CReplayMovie *pNewMovie )
  65. {
  66. Add( pNewMovie );
  67. Save();
  68. }
  69. CReplayMovie *CReplayMovieManager::Create()
  70. {
  71. return new CReplayMovie();
  72. }
  73. const char *CReplayMovieManager::GetRelativeIndexPath() const
  74. {
  75. return Replay_va( "%s%c", SUBDIR_MOVIES, CORRECT_PATH_SEPARATOR );
  76. }
  77. IReplayMovie *CReplayMovieManager::CreateAndAddMovie( ReplayHandle_t hReplay )
  78. {
  79. CReplayMovie *pNewMovie = CreateAndGenerateHandle(); // Sets m_hThis (which is accessed via GetHandle())
  80. // Cache replay handle.
  81. pNewMovie->m_hReplay = hReplay;
  82. // Copy cached render settings to the movie itself.
  83. V_memcpy( &pNewMovie->m_RenderSettings, &m_pRenderMovieSettings->m_Settings, sizeof( ReplayRenderSettings_t ) );
  84. AddMovie( pNewMovie );
  85. return pNewMovie;
  86. }
  87. void CReplayMovieManager::DeleteMovie( ReplayHandle_t hMovie )
  88. {
  89. // Cache owner replay
  90. CReplayMovie *pMovie = Find( hMovie );
  91. CReplay *pOwnerReplay = pMovie ? CL_GetReplayManager()->GetReplay( pMovie->m_hReplay ) : NULL;
  92. Remove( hMovie );
  93. // If no more movies for the given replay, mark as unrendered & save
  94. if ( pOwnerReplay && GetNumMoviesDependentOnReplay( pOwnerReplay ) == 0 )
  95. {
  96. pOwnerReplay->m_bRendered = false;
  97. CL_GetReplayManager()->FlagReplayForFlush( pOwnerReplay, false );
  98. }
  99. }
  100. int CReplayMovieManager::GetNumMoviesDependentOnReplay( const CReplay *pReplay )
  101. {
  102. if ( !pReplay )
  103. return 0;
  104. // Go through all movies and find any that depend on the given replay
  105. int nNumMovies = 0;
  106. FOR_EACH_OBJ( this, i )
  107. {
  108. CReplayMovie *pMovie = ToMovie( m_vecObjs[ i ] );
  109. if ( pMovie->m_hReplay == pReplay->GetHandle() )
  110. {
  111. ++nNumMovies;
  112. }
  113. }
  114. return nNumMovies;
  115. }
  116. void CReplayMovieManager::SetPendingMovie( IReplayMovie *pMovie )
  117. {
  118. m_pPendingMovie = pMovie;
  119. }
  120. IReplayMovie *CReplayMovieManager::GetPendingMovie()
  121. {
  122. return m_pPendingMovie;
  123. }
  124. void CReplayMovieManager::FlagMovieForFlush( IReplayMovie *pMovie, bool bImmediate )
  125. {
  126. FlagForFlush( CastMovie( pMovie ), bImmediate );
  127. }
  128. CReplayMovie *CReplayMovieManager::CastMovie( IReplayMovie *pMovie )
  129. {
  130. return static_cast< CReplayMovie * >( pMovie );
  131. }
  132. int CReplayMovieManager::GetVersion() const
  133. {
  134. return MOVIE_MANAGER_VERSION;
  135. }
  136. IReplayContext *CReplayMovieManager::GetReplayContext() const
  137. {
  138. return g_pClientReplayContextInternal;
  139. }
  140. float CReplayMovieManager::GetNextThinkTime() const
  141. {
  142. return 0.1f;
  143. }
  144. void CReplayMovieManager::CacheMovieTitle( const wchar_t *pTitle )
  145. {
  146. V_wcsncpy( m_wszCachedMovieTitle, pTitle, sizeof( m_wszCachedMovieTitle ) );
  147. }
  148. void CReplayMovieManager::GetCachedMovieTitleAndClear( wchar_t *pOut, int nOutBufLength )
  149. {
  150. const int nLength = wcslen( m_wszCachedMovieTitle );
  151. wcsncpy( pOut, m_wszCachedMovieTitle, nOutBufLength );
  152. pOut[ nLength ] = L'\0';
  153. m_wszCachedMovieTitle[0] = L'\0';
  154. }
  155. void CReplayMovieManager::AddReplayForRender( CReplay *pReplay, int iPerformance )
  156. {
  157. if ( !g_pClientReplayContextInternal->ReconstructReplayIfNecessary( pReplay ) )
  158. {
  159. CL_GetErrorSystem()->AddErrorFromTokenName( "#Replay_Err_Render_ReconstructFailed" );
  160. return;
  161. }
  162. // Store in the demo player's list
  163. g_pReplayDemoPlayer->AddReplayToList( pReplay->GetHandle(), iPerformance );
  164. }
  165. void CReplayMovieManager::ClearRenderCancelledFlag()
  166. {
  167. m_bRenderingCancelled = false;
  168. }
  169. void CReplayMovieManager::RenderMovie( RenderMovieParams_t const& params )
  170. {
  171. // Save state
  172. m_bIsRendering = true;
  173. // Change video settings for recording
  174. SetupVideo( params );
  175. // Clear any old replays in the player
  176. g_pReplayDemoPlayer->ClearReplayList();
  177. // Render all unrendered replays
  178. if ( params.m_hReplay == REPLAY_HANDLE_INVALID )
  179. {
  180. CRenderQueue *pRenderQueue = g_pClientReplayContextInternal->m_pRenderQueue;
  181. const int nQueueCount = pRenderQueue->GetCount();
  182. for ( int i = 0; i < nQueueCount; ++i )
  183. {
  184. ReplayHandle_t hCurReplay;
  185. int iCurPerformance;
  186. if ( !pRenderQueue->GetEntryData( i, &hCurReplay, &iCurPerformance ) )
  187. continue;
  188. CReplay *pReplay = CL_GetReplayManager()->GetReplay( hCurReplay );
  189. if ( !pReplay )
  190. continue;
  191. AddReplayForRender( pReplay, iCurPerformance );
  192. }
  193. }
  194. else
  195. {
  196. // Cache the title
  197. CReplayMovieManager *pMovieManager = CL_GetMovieManager();
  198. pMovieManager->CacheMovieTitle( params.m_wszTitle );
  199. // Only render the specified replay
  200. AddReplayForRender( CL_GetReplayManager()->GetReplay( params.m_hReplay ), params.m_iPerformance );
  201. }
  202. g_pReplayDemoPlayer->PlayNextReplay();
  203. }
  204. void CReplayMovieManager::RenderNextMovie()
  205. {
  206. m_bIsRendering = true;
  207. g_pReplayDemoPlayer->PlayNextReplay();
  208. }
  209. void CReplayMovieManager::SetupHighDetailModels()
  210. {
  211. g_pEngine->Cbuf_AddText( "r_rootlod 0\n" );
  212. }
  213. void CReplayMovieManager::SetupHighDetailTextures()
  214. {
  215. g_pEngine->Cbuf_AddText( "mat_picmip -1\n" );
  216. }
  217. void CReplayMovieManager::SetupHighQualityAntialiasing()
  218. {
  219. int nNumSamples = 1;
  220. int nQualityLevel = 0;
  221. if ( materials->SupportsCSAAMode(8, 2) )
  222. {
  223. nNumSamples = 8;
  224. nQualityLevel = 2;
  225. }
  226. else if ( materials->SupportsMSAAMode(8) )
  227. {
  228. nNumSamples = 8;
  229. nQualityLevel = 0;
  230. }
  231. else if ( materials->SupportsCSAAMode(4, 4) )
  232. {
  233. nNumSamples = 4;
  234. nQualityLevel = 4;
  235. }
  236. else if ( materials->SupportsCSAAMode(4, 2) )
  237. {
  238. nNumSamples = 4;
  239. nQualityLevel = 2;
  240. }
  241. else if ( materials->SupportsMSAAMode(6) )
  242. {
  243. nNumSamples = 6;
  244. nQualityLevel = 0;
  245. }
  246. else if ( materials->SupportsMSAAMode(4) )
  247. {
  248. nNumSamples = 4;
  249. nQualityLevel = 0;
  250. }
  251. else if ( materials->SupportsMSAAMode(2) )
  252. {
  253. nNumSamples = 2;
  254. nQualityLevel = 0;
  255. }
  256. g_pEngine->Cbuf_AddText( Replay_va( "mat_antialias %i\n", nNumSamples ) );
  257. g_pEngine->Cbuf_AddText( Replay_va( "mat_aaquality %i\n", nQualityLevel ) );
  258. }
  259. void CReplayMovieManager::SetupHighQualityFiltering()
  260. {
  261. g_pEngine->Cbuf_AddText( "mat_forceaniso\n" );
  262. }
  263. void CReplayMovieManager::SetupHighQualityShadowDetail()
  264. {
  265. if ( materials->SupportsShadowDepthTextures() )
  266. {
  267. g_pEngine->Cbuf_AddText( "r_shadowrendertotexture 1\n" );
  268. g_pEngine->Cbuf_AddText( "r_flashlightdepthtexture 1\n" );
  269. }
  270. else
  271. {
  272. g_pEngine->Cbuf_AddText( "r_shadowrendertotexture 1\n" );
  273. g_pEngine->Cbuf_AddText( "r_flashlightdepthtexture 0\n" );
  274. }
  275. }
  276. void CReplayMovieManager::SetupHighQualityHDR()
  277. {
  278. ConVarRef mat_dxlevel( "mat_dxlevel" );
  279. if ( mat_dxlevel.GetInt() < 80 )
  280. return;
  281. g_pEngine->Cbuf_AddText( Replay_va( "mat_hdr_level %i\n", materials->SupportsHDRMode( HDR_TYPE_INTEGER ) ? 2 : 1 ) );
  282. }
  283. void CReplayMovieManager::SetupHighQualityWaterDetail()
  284. {
  285. #ifndef _X360
  286. g_pEngine->Cbuf_AddText( "r_waterforceexpensive 1\n" );
  287. #endif
  288. g_pEngine->Cbuf_AddText( "r_waterforcereflectentities 1\n" );
  289. }
  290. void CReplayMovieManager::SetupMulticoreRender()
  291. {
  292. g_pEngine->Cbuf_AddText( "mat_queue_mode 0\n" );
  293. }
  294. void CReplayMovieManager::SetupHighQualityShaderDetail()
  295. {
  296. g_pEngine->Cbuf_AddText( "mat_reducefillrate 0\n" );
  297. }
  298. void CReplayMovieManager::SetupColorCorrection()
  299. {
  300. g_pEngine->Cbuf_AddText( "mat_colorcorrection 1\n" );
  301. }
  302. void CReplayMovieManager::SetupMotionBlur()
  303. {
  304. g_pEngine->Cbuf_AddText( "mat_motion_blur_enabled 1\n" );
  305. }
  306. void CReplayMovieManager::SetupVideo( RenderMovieParams_t const &params )
  307. {
  308. // Get current video config
  309. const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
  310. // Cache config
  311. V_memcpy( m_pVidModeSettings, &config, sizeof( config ) );
  312. // Cache quit when done
  313. V_memcpy( m_pRenderMovieSettings, &params, sizeof( params ) );
  314. g_pEngine->Cbuf_Execute();
  315. }
  316. void CReplayMovieManager::CompleteRender( bool bSuccess, bool bShowBrowser )
  317. {
  318. // Store state
  319. m_bIsRendering = false;
  320. // Shutdown renderer
  321. IReplayMovieRenderer *pRenderer = CL_GetMovieRenderer();
  322. if ( pRenderer )
  323. {
  324. pRenderer->ShutdownRenderer();
  325. }
  326. if ( !bSuccess )
  327. {
  328. // Delete the movie from the manager
  329. IReplayMovie *pMovie = CL_GetMovieManager()->GetPendingMovie();
  330. if ( pMovie )
  331. {
  332. CL_GetMovieManager()->DeleteMovie( pMovie->GetMovieHandle() );
  333. }
  334. }
  335. // Clear render queue if we're done
  336. if ( bShowBrowser )
  337. {
  338. CL_GetRenderQueue()->Clear();
  339. }
  340. // Notify UI that rendering is complete
  341. g_pClient->OnRenderComplete( *m_pRenderMovieSettings, m_bRenderingCancelled, bSuccess, bShowBrowser );
  342. // Quit now?
  343. if ( m_pRenderMovieSettings->m_bQuitWhenFinished )
  344. {
  345. g_pEngine->HostState_Shutdown();
  346. return;
  347. }
  348. // Otherwise, play a sound.
  349. g_pClient->PlaySound( "replay\\rendercomplete.wav" );
  350. }
  351. void CReplayMovieManager::CancelRender()
  352. {
  353. m_bRenderingCancelled = true;
  354. CompleteRender( false, true );
  355. g_pEngine->Host_Disconnect( false ); // CReplayDemoPlayer::StopPlayback() will be called
  356. }
  357. void CReplayMovieManager::GetMoviesAsQueryableItems( CUtlLinkedList< IQueryableReplayItem *, int > &lstMovies )
  358. {
  359. lstMovies.RemoveAll();
  360. FOR_EACH_OBJ( this, i )
  361. {
  362. lstMovies.AddToHead( ToMovie( m_vecObjs[ i ] ) );
  363. }
  364. }
  365. const char *CReplayMovieManager::GetRenderDir() const
  366. {
  367. return Replay_va( "%s%s%c", g_pClientReplayContextInternal->GetBaseDir(), SUBDIR_RENDERED, CORRECT_PATH_SEPARATOR );
  368. }
  369. const char *CReplayMovieManager::GetRawExportDir() const
  370. {
  371. static CFmtStr s_fmtExportDir;
  372. CReplayTime time;
  373. time.InitDateAndTimeToNow();
  374. int nDay, nMonth, nYear;
  375. time.GetDate( nDay, nMonth, nYear );
  376. int nHour, nMin, nSec;
  377. time.GetTime( nHour, nMin, nSec );
  378. s_fmtExportDir.sprintf(
  379. "%smovie_%02i%02i%04i_%02i%02i%02i%c",
  380. GetRenderDir(),
  381. nMonth, nDay, nYear,
  382. nHour, nMin, nSec,
  383. CORRECT_PATH_SEPARATOR
  384. );
  385. return s_fmtExportDir.Access();
  386. }
  387. //----------------------------------------------------------------------------------------