Counter Strike : Global Offensive Source Code
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.

662 lines
19 KiB

  1. //====== Copyright � 1996-2005, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "avi/iavi.h"
  7. #include "avi.h"
  8. #include "filesystem.h"
  9. #include "tier1/strtools.h"
  10. #include "tier1/utllinkedlist.h"
  11. #include "tier1/keyvalues.h"
  12. #include "materialsystem/imaterial.h"
  13. #include "materialsystem/imaterialsystem.h"
  14. #include "materialsystem/materialsystemutil.h"
  15. #include "materialsystem/itexture.h"
  16. #include "vtf/vtf.h"
  17. #include "pixelwriter.h"
  18. #include "tier3/tier3.h"
  19. //-----------------------------------------------------------------------------
  20. //
  21. // Class used to write out AVI files
  22. //
  23. //-----------------------------------------------------------------------------
  24. class CAviFile
  25. {
  26. public:
  27. CAviFile();
  28. void Init( const AVIParams_t& params, void *hWnd );
  29. void Shutdown();
  30. void AppendMovieSound( short *buf, size_t bufsize );
  31. void AppendMovieFrame( const BGR888_t *pRGBData );
  32. private:
  33. void Reset();
  34. void CreateVideoStreams( const AVIParams_t& params, void *hWnd );
  35. void CreateAudioStream();
  36. bool m_bValid;
  37. int m_nWidth;
  38. int m_nHeight;
  39. int m_nFrameRate;
  40. int m_nFrameScale;
  41. int m_nFrame;
  42. int m_nSample;
  43. };
  44. //-----------------------------------------------------------------------------
  45. // Constructor
  46. //-----------------------------------------------------------------------------
  47. CAviFile::CAviFile()
  48. {
  49. Reset();
  50. }
  51. //-----------------------------------------------------------------------------
  52. // Reset the avi file
  53. //-----------------------------------------------------------------------------
  54. void CAviFile::Reset()
  55. {
  56. m_bValid = false;
  57. m_nWidth = 0;
  58. m_nHeight = 0;
  59. m_nFrameRate = 0;
  60. m_nFrameScale = 1;
  61. m_nFrame = 0;
  62. m_nSample = 0;
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Start recording an AVI
  66. //-----------------------------------------------------------------------------
  67. void CAviFile::Init( const AVIParams_t& params, void *hWnd )
  68. {
  69. Reset();
  70. char avifilename[ 512 ];
  71. char fullavifilename[ 512 ];
  72. Q_snprintf( avifilename, sizeof( avifilename ), "%s", params.m_pFileName );
  73. Q_SetExtension( avifilename, ".avi", sizeof( avifilename ) );
  74. g_pFullFileSystem->RelativePathToFullPath( avifilename, params.m_pPathID, fullavifilename, sizeof( fullavifilename ) );
  75. if ( g_pFullFileSystem->FileExists( fullavifilename, params.m_pPathID ) )
  76. {
  77. g_pFullFileSystem->RemoveFile( fullavifilename, params.m_pPathID );
  78. }
  79. m_nFrameRate = params.m_nFrameRate;
  80. m_nFrameScale = params.m_nFrameScale;
  81. m_bValid = true;
  82. m_nHeight = params.m_nHeight;
  83. m_nWidth = params.m_nWidth;
  84. CreateVideoStreams( params, hWnd );
  85. CreateAudioStream();
  86. }
  87. void CAviFile::Shutdown()
  88. {
  89. Reset();
  90. }
  91. void CAviFile::CreateVideoStreams( const AVIParams_t& params, void *hWnd )
  92. {
  93. }
  94. void CAviFile::CreateAudioStream()
  95. {
  96. }
  97. void CAviFile::AppendMovieSound( short *buf, size_t bufsize )
  98. {
  99. if ( !m_bValid )
  100. return;
  101. unsigned long numsamps = bufsize / sizeof( short ); // numbytes*8 / au->wfx.wBitsPerSample;
  102. m_nSample += numsamps;
  103. }
  104. //-----------------------------------------------------------------------------
  105. // Adds a frame of the movie to the AVI
  106. //-----------------------------------------------------------------------------
  107. void CAviFile::AppendMovieFrame( const BGR888_t *pRGBData )
  108. {
  109. if ( !m_bValid )
  110. return;
  111. ++m_nFrame;
  112. }
  113. //-----------------------------------------------------------------------------
  114. //
  115. // Class used to associated AVI files with IMaterials
  116. //
  117. //-----------------------------------------------------------------------------
  118. class CAVIMaterial : public ITextureRegenerator
  119. {
  120. public:
  121. CAVIMaterial();
  122. // Initializes, shuts down the material
  123. bool Init( const char *pMaterialName, const char *pFileName, const char *pPathID );
  124. void Shutdown();
  125. // Inherited from ITextureRegenerator
  126. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect );
  127. virtual void Release();
  128. // Returns the material
  129. IMaterial *GetMaterial();
  130. // Returns the texcoord range
  131. void GetTexCoordRange( float *pMaxU, float *pMaxV );
  132. // Returns the frame size of the AVI (stored in a subrect of the material itself)
  133. void GetFrameSize( int *pWidth, int *pHeight );
  134. // Sets the current time
  135. void SetTime( float flTime );
  136. // Returns the frame rate/count of the AVI
  137. int GetFrameRate( );
  138. int GetFrameCount( );
  139. // Sets the frame for an AVI material (use instead of SetTime)
  140. void SetFrame( float flFrame );
  141. private:
  142. // Initializes, shuts down the procedural texture
  143. void CreateProceduralTexture( const char *pTextureName );
  144. void DestroyProceduralTexture();
  145. // Initializes, shuts down the procedural material
  146. void CreateProceduralMaterial( const char *pMaterialName );
  147. void DestroyProceduralMaterial();
  148. // Initializes, shuts down the video stream
  149. void CreateVideoStream( );
  150. void DestroyVideoStream( );
  151. CMaterialReference m_Material;
  152. CTextureReference m_Texture;
  153. int m_nAVIWidth;
  154. int m_nAVIHeight;
  155. int m_nFrameRate;
  156. int m_nFrameCount;
  157. int m_nCurrentSample;
  158. };
  159. //-----------------------------------------------------------------------------
  160. // Constructor
  161. //-----------------------------------------------------------------------------
  162. CAVIMaterial::CAVIMaterial()
  163. {
  164. }
  165. //-----------------------------------------------------------------------------
  166. // Initializes the material
  167. //-----------------------------------------------------------------------------
  168. bool CAVIMaterial::Init( const char *pMaterialName, const char *pFileName, const char *pPathID )
  169. {
  170. // Determine the full path name of the AVI
  171. char pAVIFileName[ 512 ];
  172. char pFullAVIFileName[ 512 ];
  173. Q_snprintf( pAVIFileName, sizeof( pAVIFileName ), "%s", pFileName );
  174. Q_DefaultExtension( pAVIFileName, ".avi", sizeof( pAVIFileName ) );
  175. g_pFullFileSystem->RelativePathToFullPath( pAVIFileName, pPathID, pFullAVIFileName, sizeof( pFullAVIFileName ) );
  176. CreateProceduralTexture( pMaterialName );
  177. CreateProceduralMaterial( pMaterialName );
  178. CreateVideoStream();
  179. m_Texture->Download();
  180. return true;
  181. }
  182. void CAVIMaterial::Shutdown()
  183. {
  184. DestroyVideoStream();
  185. DestroyProceduralMaterial( );
  186. DestroyProceduralTexture( );
  187. }
  188. //-----------------------------------------------------------------------------
  189. // Returns the material
  190. //-----------------------------------------------------------------------------
  191. IMaterial *CAVIMaterial::GetMaterial()
  192. {
  193. return m_Material;
  194. }
  195. //-----------------------------------------------------------------------------
  196. // Returns the texcoord range
  197. //-----------------------------------------------------------------------------
  198. void CAVIMaterial::GetTexCoordRange( float *pMaxU, float *pMaxV )
  199. {
  200. if ( !m_Texture )
  201. {
  202. *pMaxU = *pMaxV = 1.0f;
  203. return;
  204. }
  205. int nTextureWidth = m_Texture->GetActualWidth();
  206. int nTextureHeight = m_Texture->GetActualHeight();
  207. *pMaxU = (float)m_nAVIWidth / (float)nTextureWidth;
  208. *pMaxV = (float)m_nAVIHeight / (float)nTextureHeight;
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Returns the frame size of the AVI (stored in a subrect of the material itself)
  212. //-----------------------------------------------------------------------------
  213. void CAVIMaterial::GetFrameSize( int *pWidth, int *pHeight )
  214. {
  215. *pWidth = m_nAVIWidth;
  216. *pHeight = m_nAVIHeight;
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Computes a power of two at least as big as the passed-in number
  220. //-----------------------------------------------------------------------------
  221. static inline int ComputeGreaterPowerOfTwo( int n )
  222. {
  223. int i = 1;
  224. while ( i < n )
  225. {
  226. i <<= 1;
  227. }
  228. return i;
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Initializes, shuts down the procedural texture
  232. //-----------------------------------------------------------------------------
  233. void CAVIMaterial::CreateProceduralTexture( const char *pTextureName )
  234. {
  235. // Choose power-of-two textures which are at least as big as the AVI
  236. int nWidth = ComputeGreaterPowerOfTwo( m_nAVIWidth );
  237. int nHeight = ComputeGreaterPowerOfTwo( m_nAVIHeight );
  238. m_Texture.InitProceduralTexture( pTextureName, "avi", nWidth, nHeight,
  239. IMAGE_FORMAT_RGBA8888, TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_NOMIP |
  240. TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY );
  241. m_Texture->SetTextureRegenerator( this );
  242. }
  243. void CAVIMaterial::DestroyProceduralTexture()
  244. {
  245. if (m_Texture)
  246. {
  247. m_Texture->SetTextureRegenerator( NULL );
  248. m_Texture.Shutdown();
  249. }
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Initializes, shuts down the procedural material
  253. //-----------------------------------------------------------------------------
  254. void CAVIMaterial::CreateProceduralMaterial( const char *pMaterialName )
  255. {
  256. // FIXME: gak, this is backwards. Why doesn't the material just see that it has a funky basetexture?
  257. char vmtfilename[ 512 ];
  258. Q_strcpy( vmtfilename, pMaterialName );
  259. Q_SetExtension( vmtfilename, ".vmt", sizeof( vmtfilename ) );
  260. KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  261. if (!pVMTKeyValues->LoadFromFile( g_pFullFileSystem , vmtfilename, "GAME" ))
  262. {
  263. pVMTKeyValues->SetString( "$basetexture", m_Texture->GetName() );
  264. pVMTKeyValues->SetInt( "$nofog", 1 );
  265. pVMTKeyValues->SetInt( "$spriteorientation", 3 );
  266. pVMTKeyValues->SetInt( "$translucent", 1 );
  267. }
  268. m_Material.Init( pMaterialName, pVMTKeyValues );
  269. m_Material->Refresh();
  270. }
  271. void CAVIMaterial::DestroyProceduralMaterial()
  272. {
  273. m_Material.Shutdown();
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Sets the current time
  277. //-----------------------------------------------------------------------------
  278. void CAVIMaterial::SetTime( float flTime )
  279. {
  280. }
  281. //-----------------------------------------------------------------------------
  282. // Returns the frame rate of the AVI
  283. //-----------------------------------------------------------------------------
  284. int CAVIMaterial::GetFrameRate( )
  285. {
  286. return m_nFrameRate;
  287. }
  288. int CAVIMaterial::GetFrameCount( )
  289. {
  290. return m_nFrameCount;
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Sets the frame for an AVI material (use instead of SetTime)
  294. //-----------------------------------------------------------------------------
  295. void CAVIMaterial::SetFrame( float flFrame )
  296. {
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Initializes, shuts down the video stream
  300. //-----------------------------------------------------------------------------
  301. void CAVIMaterial::CreateVideoStream( )
  302. {
  303. }
  304. void CAVIMaterial::DestroyVideoStream( )
  305. {
  306. }
  307. //-----------------------------------------------------------------------------
  308. // Inherited from ITextureRegenerator
  309. //-----------------------------------------------------------------------------
  310. void CAVIMaterial::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
  311. {
  312. }
  313. void CAVIMaterial::Release()
  314. {
  315. }
  316. //-----------------------------------------------------------------------------
  317. //
  318. // Implementation of IAvi
  319. //
  320. //-----------------------------------------------------------------------------
  321. class CAvi : public CTier3AppSystem< IAvi >
  322. {
  323. typedef CTier3AppSystem< IAvi > BaseClass;
  324. public:
  325. CAvi();
  326. // Inherited from IAppSystem
  327. virtual bool Connect( CreateInterfaceFn factory );
  328. virtual void *QueryInterface( const char *pInterfaceName );
  329. virtual InitReturnVal_t Init();
  330. virtual void Shutdown();
  331. // Inherited from IAvi
  332. virtual void SetMainWindow( void* hWnd );
  333. virtual AVIHandle_t StartAVI( const AVIParams_t& params );
  334. virtual void FinishAVI( AVIHandle_t h );
  335. virtual void AppendMovieSound( AVIHandle_t h, short *buf, size_t bufsize );
  336. virtual void AppendMovieFrame( AVIHandle_t h, const BGR888_t *pRGBData );
  337. virtual AVIMaterial_t CreateAVIMaterial( const char *pMaterialName, const char *pFileName, const char *pPathID );
  338. virtual void DestroyAVIMaterial( AVIMaterial_t hMaterial );
  339. virtual void SetTime( AVIMaterial_t hMaterial, float flTime );
  340. virtual IMaterial* GetMaterial( AVIMaterial_t hMaterial );
  341. virtual void GetTexCoordRange( AVIMaterial_t hMaterial, float *pMaxU, float *pMaxV );
  342. virtual void GetFrameSize( AVIMaterial_t hMaterial, int *pWidth, int *pHeight );
  343. virtual int GetFrameRate( AVIMaterial_t hMaterial );
  344. virtual void SetFrame( AVIMaterial_t hMaterial, float flFrame );
  345. virtual int GetFrameCount( AVIMaterial_t hMaterial );
  346. private:
  347. CUtlLinkedList< CAviFile, AVIHandle_t > m_AVIFiles;
  348. // NOTE: Have to use pointers here since AVIMaterials inherit from ITextureRegenerator
  349. // The realloc screws up the pointers held to ITextureRegenerators in the material system.
  350. CUtlLinkedList< CAVIMaterial*, AVIMaterial_t > m_AVIMaterials;
  351. };
  352. //-----------------------------------------------------------------------------
  353. // Singleton
  354. //-----------------------------------------------------------------------------
  355. static CAvi g_AVI;
  356. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CAvi, IAvi, AVI_INTERFACE_VERSION, g_AVI );
  357. //-----------------------------------------------------------------------------
  358. // Constructor/destructor
  359. //-----------------------------------------------------------------------------
  360. CAvi::CAvi()
  361. {
  362. }
  363. //-----------------------------------------------------------------------------
  364. // Connect/disconnect
  365. //-----------------------------------------------------------------------------
  366. bool CAvi::Connect( CreateInterfaceFn factory )
  367. {
  368. if ( !BaseClass::Connect( factory ) )
  369. return false;
  370. if ( !( g_pFullFileSystem && materials ) )
  371. {
  372. Msg( "Avi failed to connect to a required system\n" );
  373. }
  374. return ( g_pFullFileSystem && materials );
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Query Interface
  378. //-----------------------------------------------------------------------------
  379. void *CAvi::QueryInterface( const char *pInterfaceName )
  380. {
  381. if (!Q_strncmp( pInterfaceName, AVI_INTERFACE_VERSION, Q_strlen(AVI_INTERFACE_VERSION) + 1))
  382. return (IAvi*)this;
  383. return NULL;
  384. }
  385. //-----------------------------------------------------------------------------
  386. // Init/shutdown
  387. //-----------------------------------------------------------------------------
  388. InitReturnVal_t CAvi::Init()
  389. {
  390. InitReturnVal_t nRetVal = BaseClass::Init();
  391. if ( nRetVal != INIT_OK )
  392. return nRetVal;
  393. return INIT_OK;
  394. }
  395. void CAvi::Shutdown()
  396. {
  397. BaseClass::Shutdown();
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Sets the main window
  401. //-----------------------------------------------------------------------------
  402. void CAvi::SetMainWindow( void* hWnd )
  403. {
  404. Assert( false );
  405. }
  406. //-----------------------------------------------------------------------------
  407. // Start, finish recording an AVI
  408. //-----------------------------------------------------------------------------
  409. AVIHandle_t CAvi::StartAVI( const AVIParams_t& params )
  410. {
  411. AVIHandle_t h = m_AVIFiles.AddToTail();
  412. m_AVIFiles[h].Init( params, NULL /*hwnd*/ );
  413. return h;
  414. }
  415. void CAvi::FinishAVI( AVIHandle_t h )
  416. {
  417. if ( h != AVIHANDLE_INVALID )
  418. {
  419. m_AVIFiles[h].Shutdown();
  420. m_AVIFiles.Remove( h );
  421. }
  422. }
  423. //-----------------------------------------------------------------------------
  424. // Add sound buffer
  425. //-----------------------------------------------------------------------------
  426. void CAvi::AppendMovieSound( AVIHandle_t h, short *buf, size_t bufsize )
  427. {
  428. if ( h != AVIHANDLE_INVALID )
  429. {
  430. m_AVIFiles[h].AppendMovieSound( buf, bufsize );
  431. }
  432. }
  433. //-----------------------------------------------------------------------------
  434. // Add movie frame
  435. //-----------------------------------------------------------------------------
  436. void CAvi::AppendMovieFrame( AVIHandle_t h, const BGR888_t *pRGBData )
  437. {
  438. if ( h != AVIHANDLE_INVALID )
  439. {
  440. m_AVIFiles[h].AppendMovieFrame( pRGBData );
  441. }
  442. }
  443. //-----------------------------------------------------------------------------
  444. // Create/destroy an AVI material
  445. //-----------------------------------------------------------------------------
  446. AVIMaterial_t CAvi::CreateAVIMaterial( const char *pMaterialName, const char *pFileName, const char *pPathID )
  447. {
  448. AVIMaterial_t h = m_AVIMaterials.AddToTail();
  449. m_AVIMaterials[h] = new CAVIMaterial;
  450. m_AVIMaterials[h]->Init( pMaterialName, pFileName, pPathID );
  451. return h;
  452. }
  453. void CAvi::DestroyAVIMaterial( AVIMaterial_t h )
  454. {
  455. if ( h != AVIMATERIAL_INVALID )
  456. {
  457. m_AVIMaterials[h]->Shutdown();
  458. delete m_AVIMaterials[h];
  459. m_AVIMaterials.Remove( h );
  460. }
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Sets the time for an AVI material
  464. //-----------------------------------------------------------------------------
  465. void CAvi::SetTime( AVIMaterial_t h, float flTime )
  466. {
  467. if ( h != AVIMATERIAL_INVALID )
  468. {
  469. m_AVIMaterials[h]->SetTime( flTime );
  470. }
  471. }
  472. //-----------------------------------------------------------------------------
  473. // Gets the IMaterial associated with an AVI material
  474. //-----------------------------------------------------------------------------
  475. IMaterial* CAvi::GetMaterial( AVIMaterial_t h )
  476. {
  477. if ( h != AVIMATERIAL_INVALID )
  478. return m_AVIMaterials[h]->GetMaterial();
  479. return NULL;
  480. }
  481. //-----------------------------------------------------------------------------
  482. // Returns the max texture coordinate of the AVI
  483. //-----------------------------------------------------------------------------
  484. void CAvi::GetTexCoordRange( AVIMaterial_t h, float *pMaxU, float *pMaxV )
  485. {
  486. if ( h != AVIMATERIAL_INVALID )
  487. {
  488. m_AVIMaterials[h]->GetTexCoordRange( pMaxU, pMaxV );
  489. }
  490. else
  491. {
  492. *pMaxU = *pMaxV = 1.0f;
  493. }
  494. }
  495. //-----------------------------------------------------------------------------
  496. // Returns the frame size of the AVI (is a subrect of the material itself)
  497. //-----------------------------------------------------------------------------
  498. void CAvi::GetFrameSize( AVIMaterial_t h, int *pWidth, int *pHeight )
  499. {
  500. if ( h != AVIMATERIAL_INVALID )
  501. {
  502. m_AVIMaterials[h]->GetFrameSize( pWidth, pHeight );
  503. }
  504. else
  505. {
  506. *pWidth = *pHeight = 1;
  507. }
  508. }
  509. //-----------------------------------------------------------------------------
  510. // Returns the frame rate of the AVI
  511. //-----------------------------------------------------------------------------
  512. int CAvi::GetFrameRate( AVIMaterial_t h )
  513. {
  514. if ( h != AVIMATERIAL_INVALID )
  515. return m_AVIMaterials[h]->GetFrameRate();
  516. return 1;
  517. }
  518. int CAvi::GetFrameCount( AVIMaterial_t h )
  519. {
  520. if ( h != AVIMATERIAL_INVALID )
  521. return m_AVIMaterials[h]->GetFrameCount();
  522. return 1;
  523. }
  524. //-----------------------------------------------------------------------------
  525. // Sets the frame for an AVI material (use instead of SetTime)
  526. //-----------------------------------------------------------------------------
  527. void CAvi::SetFrame( AVIMaterial_t h, float flFrame )
  528. {
  529. if ( h != AVIMATERIAL_INVALID )
  530. {
  531. m_AVIMaterials[h]->SetFrame( flFrame );
  532. }
  533. }