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.

1938 lines
60 KiB

  1. //====== Copyright 1996-2006, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #if defined( BINK_VIDEO )
  7. #if !defined( _GAMECONSOLE ) || defined( BINK_ENABLED_FOR_CONSOLE )
  8. #include "avi/ibik.h"
  9. #if defined( _X360 )
  10. # include "bink_x360/bink.h"
  11. #elif defined( _PS3 )
  12. # include "bink_ps3/bink.h"
  13. #else
  14. # include "bink/bink.h"
  15. #endif
  16. #include "filesystem.h"
  17. #include "tier1/strtools.h"
  18. #include "tier1/utllinkedlist.h"
  19. #include "tier1/keyvalues.h"
  20. #include "materialsystem/imaterial.h"
  21. #include "materialsystem/imaterialsystem.h"
  22. #include "materialsystem/MaterialSystemUtil.h"
  23. #include "materialsystem/itexture.h"
  24. #include "callqueue.h"
  25. #include "vtf/vtf.h"
  26. #include "pixelwriter.h"
  27. #include "tier3/tier3.h"
  28. #if defined( _X360 )
  29. #include "snd_dev_xaudio.h"
  30. #endif
  31. // NOTE: This has to be the last file included!
  32. #include "tier0/memdbgon.h"
  33. #pragma warning( disable : 4201 )
  34. #define WIN32_LEAN_AND_MEAN
  35. #pragma warning( default : 4201 )
  36. //#define BINK_TRACK_71_ENABLED // Current movies are in 5.1
  37. #if defined( PLATFORM_X360 )
  38. // On 360, we specifically want a linear format so that we aren't swizzling on the CPU every frame.
  39. #define BINK_SHADER_IMAGE_FORMAT IMAGE_FORMAT_LINEAR_I8
  40. #define BINK_NUMBER_OF_CHANNELS 6 // Up to 5.1
  41. #elif defined( PLATFORM_PS3 )
  42. #define BINK_SHADER_IMAGE_FORMAT IMAGE_FORMAT_I8
  43. #define BINK_NUMBER_OF_CHANNELS 8 // Up to 7.1
  44. #else
  45. #define BINK_SHADER_IMAGE_FORMAT IMAGE_FORMAT_I8
  46. #define BINK_NUMBER_OF_CHANNELS 6 // Up to 5.1
  47. #endif
  48. ConVar bink_mat_queue_mode( "bink_mat_queue_mode", "1", 0, "Update bink on mat queue thread if mat_queue_mode is on (if turned off, always update bink on main thread; may cause stalls!)" );
  49. ConVar bink_try_load_vmt( "bink_try_load_vmt", "0", 0, "Try and load a VMT with the same name as the BIK file to override settings" );
  50. ConVar bink_use_preallocated_scratch_texture( "bink_use_preallocated_scratch_texture", "1", 0, "Use a pre-allocated VTF instead of creating a new one and deleting it for every texture update. Gameconsole only." );
  51. // don't set volume when using the wave out device. This will cause changes to the global volume
  52. // mixer and we can't tell the difference between waveOut setting those and a user doing that.
  53. // Also bink will set our volume to 25% instead of 100% in that case.
  54. static bool g_bDisableVolumeChanges = false;
  55. // We don't support the alpha channel in bink files due to dx8. Can make it work if necessary.
  56. //#define SUPPORT_BINK_ALPHA
  57. class CBIKMaterial;
  58. struct PrecachedMovie_t
  59. {
  60. CUtlString m_BaseName;
  61. CUtlBuffer m_MemoryBuffer;
  62. };
  63. PathTypeFilter_t GetMoviePathFilter()
  64. {
  65. static ConVarRef force_audio_english( "force_audio_english" );
  66. #if defined( _GAMECONSOLE )
  67. if ( XBX_IsAudioLocalized() && force_audio_english.GetBool() )
  68. {
  69. // skip the localized search paths and fall through
  70. return FILTER_CULLLOCALIZED_ANY;
  71. }
  72. #else
  73. if ( force_audio_english.GetBool() )
  74. {
  75. // skip the localized search paths and fall through
  76. return FILTER_CULLLOCALIZED_ANY;
  77. }
  78. #endif
  79. // No movies exists inside of zips, all the movies are external
  80. return FILTER_CULLPACK;
  81. }
  82. class CBIKMaterialYTextureRegenerator : public ITextureRegenerator
  83. {
  84. public:
  85. void SetParentMaterial( CBIKMaterial *pBIKMaterial, int nWidth, int nHeight )
  86. {
  87. m_pBIKMaterial = pBIKMaterial;
  88. m_nSourceWidth = nWidth;
  89. m_nSourceHeight = nHeight;
  90. }
  91. // Inherited from ITextureRegenerator
  92. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect );
  93. virtual void Release();
  94. virtual bool HasPreallocatedScratchTexture() const { return IsGameConsole() ? bink_use_preallocated_scratch_texture.GetBool() : false; }
  95. virtual IVTFTexture *GetPreallocatedScratchTexture();
  96. private:
  97. CBIKMaterial *m_pBIKMaterial;
  98. int m_nSourceWidth;
  99. int m_nSourceHeight;
  100. };
  101. #ifdef SUPPORT_BINK_ALPHA
  102. class CBIKMaterialATextureRegenerator : public ITextureRegenerator
  103. {
  104. public:
  105. void SetParentMaterial( CBIKMaterial *pBIKMaterial, int nWidth, int nHeight )
  106. {
  107. m_pBIKMaterial = pBIKMaterial;
  108. m_nSourceWidth = nWidth;
  109. m_nSourceHeight = nHeight;
  110. }
  111. // Inherited from ITextureRegenerator
  112. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect );
  113. virtual void Release();
  114. virtual bool HasPreallocatedScratchTexture() const { return IsGameConsole() ? bink_use_preallocated_scratch_texture.GetBool() : false; }
  115. virtual IVTFTexture *GetPreallocatedScratchTexture();
  116. private:
  117. CBIKMaterial *m_pBIKMaterial;
  118. int m_nSourceWidth;
  119. int m_nSourceHeight;
  120. };
  121. #endif
  122. class CBIKMaterialCrTextureRegenerator : public ITextureRegenerator
  123. {
  124. public:
  125. void SetParentMaterial( CBIKMaterial *pBIKMaterial, int nWidth, int nHeight )
  126. {
  127. m_pBIKMaterial = pBIKMaterial;
  128. m_nSourceWidth = nWidth;
  129. m_nSourceHeight = nHeight;
  130. }
  131. // Inherited from ITextureRegenerator
  132. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect );
  133. virtual void Release();
  134. virtual bool HasPreallocatedScratchTexture() const { return IsGameConsole() ? bink_use_preallocated_scratch_texture.GetBool() : false; }
  135. virtual IVTFTexture *GetPreallocatedScratchTexture();
  136. private:
  137. CBIKMaterial *m_pBIKMaterial;
  138. int m_nSourceWidth;
  139. int m_nSourceHeight;
  140. };
  141. class CBIKMaterialCbTextureRegenerator : public ITextureRegenerator
  142. {
  143. public:
  144. void SetParentMaterial( CBIKMaterial *pBIKMaterial, int nWidth, int nHeight )
  145. {
  146. m_pBIKMaterial = pBIKMaterial;
  147. m_nSourceWidth = nWidth;
  148. m_nSourceHeight = nHeight;
  149. }
  150. // Inherited from ITextureRegenerator
  151. virtual void RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect );
  152. virtual void Release();
  153. virtual bool HasPreallocatedScratchTexture() const { return IsGameConsole() ? bink_use_preallocated_scratch_texture.GetBool() : false; }
  154. virtual IVTFTexture *GetPreallocatedScratchTexture();
  155. private:
  156. CBIKMaterial *m_pBIKMaterial;
  157. int m_nSourceWidth;
  158. int m_nSourceHeight;
  159. };
  160. //-----------------------------------------------------------------------------
  161. //
  162. // Class used to associated BIK files with IMaterials
  163. //
  164. //-----------------------------------------------------------------------------
  165. class CBIKMaterial
  166. {
  167. public:
  168. CBIKMaterial();
  169. // Initializes, shuts down the material
  170. bool Init( const char *pMaterialName, const char *pFileName, const char *pPathID, int flags );
  171. bool Shutdown();
  172. // Keeps the frames updated
  173. // Work is actually done by UpdateInternal, either on the main thread or on the mat queue thread
  174. bool Update( void );
  175. // Call this in a loop that does nothing or something minor right before calling SwapBuffers.
  176. bool ReadyForSwap();
  177. // Returns the material
  178. IMaterial *GetMaterial();
  179. // Returns the texcoord range
  180. void GetTexCoordRange( float *pMaxU, float *pMaxV );
  181. // Returns the frame size of the BIK (stored in a subrect of the material itself)
  182. void GetFrameSize( int *pWidth, int *pHeight );
  183. // Returns the frame rate/count of the BIK
  184. int GetFrame( void );
  185. int GetFrameRate( void );
  186. int GetFrameCount( void );
  187. // Sets the frame for an BIK material (use instead of SetTime)
  188. void SetFrame( float flFrame );
  189. void SetLooping( bool bLoops = true ) { m_bLoops = bLoops; }
  190. void Pause( void );
  191. void Unpause( void );
  192. // Access cached frame information (takes a mutex; safe to call any time, but may be a frame delayed)
  193. bool IsVideoFinished();
  194. IVTFTexture * GetScratchVTFTexture() { return m_pScratchTexture; }
  195. void UpdateVolume();
  196. bool IsMovieResidentInMemory();
  197. private:
  198. friend class CBIKMaterialYTextureRegenerator;
  199. #ifdef SUPPORT_BINK_ALPHA
  200. friend class CBIKMaterialATextureRegenerator;
  201. #endif
  202. friend class CBIKMaterialCrTextureRegenerator;
  203. friend class CBIKMaterialCbTextureRegenerator;
  204. // Initializes, shuts down the procedural texture
  205. void CreateProceduralTextures( const char *pTextureName );
  206. void DestroyProceduralTexture( CTextureReference &texture );
  207. void DestroyProceduralTextures();
  208. // Initializes, shuts down the procedural material
  209. void CreateProceduralMaterial( const char *pMaterialName );
  210. void DestroyProceduralMaterial();
  211. // Initializes, shuts down the video stream
  212. void CreateVideoStream( );
  213. void DestroyVideoStream( );
  214. // Performs the actual bink texture update, either on the mat queue thread or on the main thread
  215. void UpdateInternal();
  216. void UpdateCurrentFrameIndex();
  217. // Performs the actual bink frame set operation
  218. void SetFrameInternal( int nFrame );
  219. void SetTracks();
  220. CMaterialReference m_Material;
  221. CTextureReference m_TextureY;
  222. #ifdef SUPPORT_BINK_ALPHA
  223. CTextureReference m_TextureA;
  224. #endif
  225. CTextureReference m_TextureCr;
  226. CTextureReference m_TextureCb;
  227. HBINK m_pHBINK;
  228. BINKFRAMEBUFFERS m_buffers;
  229. int m_nBinkFlags;
  230. int m_nBIKWidth;
  231. int m_nBIKHeight;
  232. int m_nFrameRate;
  233. int m_nFrameCount;
  234. int m_nCurrentFrame;
  235. bool m_bLoops;
  236. bool m_bShutdown;
  237. CBIKMaterialYTextureRegenerator m_YTextureRegenerator;
  238. #ifdef SUPPORT_BINK_ALPHA
  239. CBIKMaterialATextureRegenerator m_ATextureRegenerator;
  240. #endif
  241. CBIKMaterialCrTextureRegenerator m_CrTextureRegenerator;
  242. CBIKMaterialCbTextureRegenerator m_CbTextureRegenerator;
  243. // CTexture::Download() will make a temp copy in a scratch texture every time we update the Bink textures,
  244. // so use this instead of re-allocating the scratch texture on every update (4 times per frame per bink movie)
  245. IVTFTexture *m_pScratchTexture;
  246. // Since bink can be updated on the mat queue thread, we need to protect internal class state
  247. CThreadFastMutex m_BinkUpdateMutex;
  248. CThreadFastMutex m_BinkFrameCountMutex;
  249. // The number of outstanding calls to UpdateInternal (gets incremented on Update() and decremented when UpdateInternal() is finished
  250. int m_nQueuedUpdateCount;
  251. #if IsPlatformPS3()
  252. // Indicates if we have to resume the prefetches, and if yes, when.
  253. enum PrefetchResumeMode_t
  254. {
  255. PRM_NO_RESUME_NECESSARY, // Used if the movie is in memory
  256. PRM_RESUME_AT_END_OF_FIRST_FRAME, // Used if the movie is preloaded
  257. PRM_RESUME_AT_END_OF_MOVIE // Used if the movie is streamed
  258. };
  259. PrefetchResumeMode_t m_ResumeMode;
  260. #endif
  261. };
  262. //-----------------------------------------------------------------------------
  263. // Inherited from ITextureRegenerator
  264. //-----------------------------------------------------------------------------
  265. void CBIKMaterialYTextureRegenerator::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
  266. {
  267. int nWidth = m_nSourceWidth;
  268. int nHeight = m_nSourceHeight;
  269. unsigned char *pYData = NULL;
  270. int nBytes = 0;
  271. int y;
  272. CPixelWriter pixelWriter;
  273. int nBufferPitch = 0;
  274. // Error condition
  275. if ( (pVTFTexture->FrameCount() > 1) || (pVTFTexture->FaceCount() > 1) || (pVTFTexture->MipCount() > 1) || (pVTFTexture->Depth() > 1) )
  276. {
  277. goto BIKMaterialError;
  278. }
  279. pYData = (unsigned char *)m_pBIKMaterial->m_buffers.Frames[ m_pBIKMaterial->m_buffers.FrameNum ].YPlane.Buffer;
  280. nBufferPitch = m_pBIKMaterial->m_buffers.Frames[ m_pBIKMaterial->m_buffers.FrameNum ].YPlane.BufferPitch;
  281. Assert( pVTFTexture->Format() == BINK_SHADER_IMAGE_FORMAT );
  282. Assert( pVTFTexture->RowSizeInBytes( 0 ) == pVTFTexture->Width() );
  283. Assert( pVTFTexture->Width() >= m_nSourceWidth );
  284. Assert( pVTFTexture->Height() >= m_nSourceHeight );
  285. // Set up the pixel writer to write into the VTF texture
  286. pixelWriter.SetPixelMemory( pVTFTexture->Format(), pVTFTexture->ImageData(), pVTFTexture->RowSizeInBytes( 0 ) );
  287. for ( y = 0; y < nHeight; ++y )
  288. {
  289. pixelWriter.Seek( 0, y );
  290. memcpy( pixelWriter.GetCurrentPixel(), pYData, nWidth );
  291. pYData += nBufferPitch;
  292. }
  293. return;
  294. BIKMaterialError:
  295. nBytes = pVTFTexture->ComputeTotalSize();
  296. memset( pVTFTexture->ImageData(), 0xFF, nBytes );
  297. return;
  298. }
  299. IVTFTexture *CBIKMaterialYTextureRegenerator::GetPreallocatedScratchTexture()
  300. {
  301. return m_pBIKMaterial->GetScratchVTFTexture();
  302. }
  303. void CBIKMaterialYTextureRegenerator::Release()
  304. {
  305. }
  306. #ifdef SUPPORT_BINK_ALPHA
  307. //-----------------------------------------------------------------------------
  308. // Inherited from ITextureRegenerator
  309. //-----------------------------------------------------------------------------
  310. void CBIKMaterialATextureRegenerator::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
  311. {
  312. CPixelWriter pixelWriter;
  313. int nBufferPitch = 0;
  314. // Error condition
  315. if ( (pVTFTexture->FrameCount() > 1) || (pVTFTexture->FaceCount() > 1) || (pVTFTexture->MipCount() > 1) || (pVTFTexture->Depth() > 1) )
  316. {
  317. goto BIKMaterialError;
  318. }
  319. unsigned char *pAData = (unsigned char *)m_pBIKMaterial->m_buffers.Frames[ m_pBIKMaterial->m_buffers.FrameNum ].APlane.Buffer;
  320. nBufferPitch = m_pBIKMaterial->m_buffers.Frames[ m_pBIKMaterial->m_buffers.FrameNum ].APlane.BufferPitch;
  321. Assert( pVTFTexture->Format() == BINK_SHADER_IMAGE_FORMAT );
  322. Assert( pVTFTexture->RowSizeInBytes( 0 ) == pVTFTexture->Width() );
  323. Assert( pVTFTexture->Width() >= m_nSourceWidth );
  324. Assert( pVTFTexture->Height() >= m_nSourceHeight );
  325. // Set up the pixel writer to write into the VTF texture
  326. pixelWriter.SetPixelMemory( pVTFTexture->Format(), pVTFTexture->ImageData(), pVTFTexture->RowSizeInBytes( 0 ) );
  327. int nWidth = m_nSourceWidth;
  328. int nHeight = m_nSourceHeight;
  329. int y;
  330. if( pAData )
  331. {
  332. for ( y = 0; y < nHeight; ++y )
  333. {
  334. pixelWriter.Seek( 0, y );
  335. memcpy( pixelWriter.GetCurrentPixel(), pAData, nWidth );
  336. pAData += nBufferPitch;
  337. }
  338. }
  339. else
  340. {
  341. for ( y = 0; y < nHeight; ++y )
  342. {
  343. pixelWriter.Seek( 0, y );
  344. memset( pixelWriter.GetCurrentPixel(), 255, nWidth );
  345. }
  346. }
  347. return;
  348. BIKMaterialError:
  349. int nBytes = pVTFTexture->ComputeTotalSize();
  350. memset( pVTFTexture->ImageData(), 0xFF, nBytes );
  351. return;
  352. }
  353. IVTFTexture *CBIKMaterialATextureRegenerator::GetPreallocatedScratchTexture()
  354. {
  355. return m_pBIKMaterial->GetScratchVTFTexture();
  356. }
  357. void CBIKMaterialATextureRegenerator::Release()
  358. {
  359. }
  360. #endif
  361. //-----------------------------------------------------------------------------
  362. // Inherited from ITextureRegenerator
  363. //-----------------------------------------------------------------------------
  364. void CBIKMaterialCrTextureRegenerator::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
  365. {
  366. int nWidth = m_nSourceWidth;
  367. int nHeight = m_nSourceHeight;
  368. unsigned char *pCrData = NULL;
  369. CPixelWriter pixelWriter;
  370. int nBufferPitch = 0;
  371. // Error condition
  372. if ( (pVTFTexture->FrameCount() > 1) || (pVTFTexture->FaceCount() > 1) || (pVTFTexture->MipCount() > 1) || (pVTFTexture->Depth() > 1) )
  373. {
  374. goto BIKMaterialError;
  375. }
  376. pCrData = (unsigned char *)m_pBIKMaterial->m_buffers.Frames[ m_pBIKMaterial->m_buffers.FrameNum ].cRPlane.Buffer;
  377. nBufferPitch = m_pBIKMaterial->m_buffers.Frames[ m_pBIKMaterial->m_buffers.FrameNum ].cRPlane.BufferPitch;
  378. Assert( pVTFTexture->Format() == BINK_SHADER_IMAGE_FORMAT );
  379. Assert( pVTFTexture->RowSizeInBytes( 0 ) == pVTFTexture->Width() );
  380. Assert( pVTFTexture->Width() >= m_nSourceWidth );
  381. Assert( pVTFTexture->Height() >= m_nSourceHeight );
  382. // Set up the pixel writer to write into the VTF texture
  383. pixelWriter.SetPixelMemory( pVTFTexture->Format(), pVTFTexture->ImageData(), pVTFTexture->RowSizeInBytes( 0 ) );
  384. int y;
  385. for ( y = 0; y < nHeight; ++y )
  386. {
  387. pixelWriter.Seek( 0, y );
  388. memcpy( pixelWriter.GetCurrentPixel(), pCrData, nWidth );
  389. pCrData += nBufferPitch;
  390. }
  391. return;
  392. BIKMaterialError:
  393. int nBytes = pVTFTexture->ComputeTotalSize();
  394. memset( pVTFTexture->ImageData(), 0xFF, nBytes );
  395. return;
  396. }
  397. IVTFTexture *CBIKMaterialCrTextureRegenerator::GetPreallocatedScratchTexture()
  398. {
  399. return m_pBIKMaterial->GetScratchVTFTexture();
  400. }
  401. void CBIKMaterialCrTextureRegenerator::Release()
  402. {
  403. }
  404. //-----------------------------------------------------------------------------
  405. // Inherited from ITextureRegenerator
  406. //-----------------------------------------------------------------------------
  407. void CBIKMaterialCbTextureRegenerator::RegenerateTextureBits( ITexture *pTexture, IVTFTexture *pVTFTexture, Rect_t *pRect )
  408. {
  409. int nWidth = m_nSourceWidth;
  410. int nHeight = m_nSourceHeight;
  411. unsigned char *pCbData = NULL;
  412. CPixelWriter pixelWriter;
  413. int nBufferPitch = 0;
  414. // Error condition
  415. if ( (pVTFTexture->FrameCount() > 1) || (pVTFTexture->FaceCount() > 1) || (pVTFTexture->MipCount() > 1) || (pVTFTexture->Depth() > 1) )
  416. {
  417. goto BIKMaterialError;
  418. }
  419. pCbData = (unsigned char *)m_pBIKMaterial->m_buffers.Frames[ m_pBIKMaterial->m_buffers.FrameNum ].cBPlane.Buffer;
  420. nBufferPitch = m_pBIKMaterial->m_buffers.Frames[ m_pBIKMaterial->m_buffers.FrameNum ].cBPlane.BufferPitch;
  421. Assert( pVTFTexture->Format() == BINK_SHADER_IMAGE_FORMAT );
  422. Assert( pVTFTexture->RowSizeInBytes( 0 ) == pVTFTexture->Width() );
  423. Assert( pVTFTexture->Width() >= m_nSourceWidth );
  424. Assert( pVTFTexture->Height() >= m_nSourceHeight );
  425. // Set up the pixel writer to write into the VTF texture
  426. pixelWriter.SetPixelMemory( pVTFTexture->Format(), pVTFTexture->ImageData(), pVTFTexture->RowSizeInBytes( 0 ) );
  427. int y;
  428. for ( y = 0; y < nHeight; ++y )
  429. {
  430. pixelWriter.Seek( 0, y );
  431. memcpy( pixelWriter.GetCurrentPixel(), pCbData, nWidth );
  432. pCbData += nBufferPitch;
  433. }
  434. return;
  435. BIKMaterialError:
  436. int nBytes = pVTFTexture->ComputeTotalSize();
  437. memset( pVTFTexture->ImageData(), 0xFF, nBytes );
  438. return;
  439. }
  440. IVTFTexture *CBIKMaterialCbTextureRegenerator::GetPreallocatedScratchTexture()
  441. {
  442. return m_pBIKMaterial->GetScratchVTFTexture();
  443. }
  444. void CBIKMaterialCbTextureRegenerator::Release()
  445. {
  446. }
  447. //-----------------------------------------------------------------------------
  448. // Constructor
  449. //-----------------------------------------------------------------------------
  450. CBIKMaterial::CBIKMaterial()
  451. {
  452. m_pHBINK = NULL;
  453. Q_memset( &m_buffers, 0, sizeof( m_buffers ) );
  454. m_bLoops = false;
  455. m_nQueuedUpdateCount = 0;
  456. m_bShutdown = false;
  457. #if IsPlatformPS3()
  458. m_ResumeMode = PRM_NO_RESUME_NECESSARY;
  459. #endif
  460. m_pScratchTexture = NULL;
  461. m_nBinkFlags = 0;
  462. }
  463. //-----------------------------------------------------------------------------
  464. // Initializes the material
  465. //-----------------------------------------------------------------------------
  466. bool CBIKMaterial::Init( const char *pMaterialName, const char *pFileName, const char *pPathID, int flags )
  467. {
  468. // Determine the full path name of the BIK
  469. char pBIKFileName[ 512 ];
  470. char pFullBIKFileName[ 512 ];
  471. Q_snprintf( pBIKFileName, sizeof( pBIKFileName ), "%s", pFileName );
  472. Q_DefaultExtension( pBIKFileName, ".bik", sizeof( pBIKFileName ) );
  473. PathTypeQuery_t pathType;
  474. if ( !g_pFullFileSystem->RelativePathToFullPath( pBIKFileName, pPathID, pFullBIKFileName, sizeof( pFullBIKFileName ), GetMoviePathFilter(), &pathType ) )
  475. {
  476. // A file by that name was not found
  477. Assert( 0 );
  478. return false;
  479. }
  480. //Msg( "BinkOpen( %s )\n", pFullBIKFileName );
  481. U32 binkFlags = BINKNOFRAMEBUFFERS | BINKSNDTRACK;
  482. if ( flags & BIK_PRELOAD )
  483. {
  484. binkFlags |= BINKPRELOADALL;
  485. }
  486. if ( ( flags & BIK_NO_AUDIO ) != 0 )
  487. {
  488. // No audio
  489. BinkSetSoundTrack( 0, 0 );
  490. }
  491. else
  492. {
  493. #if BINK_NUMBER_OF_CHANNELS == 8
  494. // Settings for 7.1
  495. // Track ID 0 - A stereo track containing the front left and front right channels.
  496. // Track ID 1 - A mono track containing the center channel.
  497. // Track ID 2 - A mono track containing the sub-woofer channel.
  498. // Track ID 3 - A stereo track containing the back left and back right channels.
  499. // Track ID 4 - A stereo track containing the side left and side right channels.
  500. U32 TrackIDsToPlay[ 5 ] = { 0, 1, 2, 3, 4 };
  501. BinkSetSoundTrack( 5, TrackIDsToPlay );
  502. #elif defined(OSX)
  503. U32 TrackIDsToPlay[ 2 ] = { 0, 1 };
  504. BinkSetSoundTrack( 2, TrackIDsToPlay );
  505. #else
  506. // Setting 8 channels may not seem to make the X360 implementation of Bink happy. Use 4 tracks for the 6 channels.
  507. U32 TrackIDsToPlay[ 4 ] = { 0, 1, 2, 3 };
  508. BinkSetSoundTrack( 4, TrackIDsToPlay );
  509. #endif
  510. }
  511. // perhaps already in memory
  512. void *pBinkInMemory = g_pBIK->GetPrecachedMovie( pFullBIKFileName );
  513. if ( pBinkInMemory )
  514. {
  515. binkFlags &= ~BINKPRELOADALL;
  516. binkFlags |= BINKFROMMEMORY;
  517. }
  518. #if IsPlatformPS3()
  519. if ( ( binkFlags & BINKFROMMEMORY ) != 0 )
  520. {
  521. m_ResumeMode = PRM_NO_RESUME_NECESSARY; // No issue with prefetching in this case
  522. }
  523. else if ( ( binkFlags & BINKPRELOADALL ) != 0 )
  524. {
  525. g_pFullFileSystem->SuspendPrefetches( "Bink movie is going to be preloaded." ); // At the end of the first frame, the movie should be loaded
  526. m_ResumeMode = PRM_RESUME_AT_END_OF_FIRST_FRAME; // prefetches can restart after that. So we can continue prefetching during the movie.
  527. }
  528. else
  529. {
  530. // This is the streamed mode
  531. g_pFullFileSystem->SuspendPrefetches( "Bink movie is going to be streamed."); // As it is streamed, suspend all prefetches until the end
  532. m_ResumeMode = PRM_RESUME_AT_END_OF_MOVIE; // to avoid stuttering while playing the movie
  533. }
  534. #endif
  535. m_nBinkFlags = binkFlags;
  536. m_pHBINK = BinkOpen( pBinkInMemory ? (const char *)pBinkInMemory : pFullBIKFileName, binkFlags );
  537. if ( !m_pHBINK )
  538. {
  539. // The file was unable to be opened
  540. Assert( 0 );
  541. m_nBIKWidth = 64;
  542. m_nBIKHeight = 64;
  543. m_nFrameRate = 1;
  544. m_nFrameCount = 1;
  545. m_Material.Init( "debug/debugempty", TEXTURE_GROUP_OTHER );
  546. return false;
  547. }
  548. SetTracks();
  549. // Get BIK size
  550. m_nBIKWidth = m_pHBINK->Width;
  551. m_nBIKHeight = m_pHBINK->Height;
  552. m_nFrameRate = (int)( (float)m_pHBINK->FrameRate / (float)m_pHBINK->FrameRateDiv );
  553. m_nFrameCount = m_pHBINK->Frames;
  554. m_nCurrentFrame = 0;
  555. CreateVideoStream();
  556. // Now we can properly setup out regenerators
  557. m_YTextureRegenerator.SetParentMaterial( this, m_nBIKWidth, m_nBIKHeight );
  558. #ifdef SUPPORT_BINK_ALPHA
  559. m_ATextureRegenerator.SetParentMaterial( this, m_nBIKWidth, m_nBIKHeight);
  560. #endif
  561. // The Cr and Cb display textures are always HALF the res of the Y/A textures.
  562. // However, the bink framebuffers which get decompressed have their own alignment requirements that may cause them to
  563. // be slightly larger. In such a case, we only use this smaller sub-rect (the rest may be invalid)
  564. m_CrTextureRegenerator.SetParentMaterial( this, m_nBIKWidth >> 1, m_nBIKHeight >> 1 );
  565. m_CbTextureRegenerator.SetParentMaterial( this, m_nBIKWidth >> 1, m_nBIKHeight >> 1 );
  566. CreateProceduralTextures( pMaterialName );
  567. CreateProceduralMaterial( pMaterialName );
  568. SetLooping( ( flags & BIK_LOOP ) != 0 );
  569. UpdateVolume();
  570. return true;
  571. }
  572. #if PLATFORM_X360
  573. // After trying without success to have a the same setup between PC, PS3 and X360,
  574. // I ended up creating specific version for each to make Bink work in all cases.
  575. // Talking with Bink support, they said that the model to follow should be the X360 model.
  576. // I.e. each call is listing the number of channels in the track, instead of listing all channels.
  577. // I did not test it though, and it still seems to be a flaw in their API.
  578. // The other model (X360 following the PS3 model mixed with X360) does not work.
  579. void CBIKMaterial::SetTracks()
  580. {
  581. U32 bins[ 2 ];
  582. // front LR
  583. bins[ 0 ] = 0; // 0 is front left on XAudio
  584. bins[ 1 ] = 1; // 1 is front right on XAudio
  585. BinkSetMixBins( m_pHBINK, 0, bins, 2 );
  586. // center
  587. bins [ 0 ] = 2; // 2 is center on XAudio
  588. BinkSetMixBins( m_pHBINK, 1, bins, 1 );
  589. // sub
  590. bins [ 0 ] = 3; // 3 is sub on XAudio
  591. BinkSetMixBins( m_pHBINK, 2, bins, 1 );
  592. // back LR
  593. bins[ 0 ] = 4; // 4 is back left on XAudio
  594. bins[ 1 ] = 5; // 5 is back right on XAudio
  595. BinkSetMixBins( m_pHBINK, 3, bins, 2 );
  596. }
  597. #elif defined(PLATFORM_PS3)
  598. void CBIKMaterial::SetTracks()
  599. {
  600. int nMasterVolume = 32768;
  601. S32 nVolumes[ BINK_NUMBER_OF_CHANNELS ]; // Up to 8 tracks for 7.1
  602. // front LR
  603. memset( nVolumes, 0, sizeof( nVolumes ) );
  604. nVolumes[ 0 ] = nMasterVolume;
  605. nVolumes[ 1 ] = nMasterVolume;
  606. BinkSetMixBinVolumes( m_pHBINK, 0, NULL, nVolumes, BINK_NUMBER_OF_CHANNELS );
  607. // center
  608. memset( nVolumes, 0, sizeof( nVolumes ) );
  609. nVolumes[ 2 ] = nMasterVolume;
  610. BinkSetMixBinVolumes( m_pHBINK, 1, NULL, nVolumes, BINK_NUMBER_OF_CHANNELS );
  611. // sub
  612. memset( nVolumes, 0, sizeof( nVolumes ) );
  613. nVolumes[ 3 ] = nMasterVolume;
  614. BinkSetMixBinVolumes( m_pHBINK, 2, NULL, nVolumes, BINK_NUMBER_OF_CHANNELS );
  615. #if BINK_TRACK_71_ENABLED
  616. // This is not enabled, we only play 5.1 right now (on Portal 2).
  617. // back LR
  618. memset( nVolumes, 0, sizeof( nVolumes ) );
  619. nVolumes[ 4 ] = nMasterVolume;
  620. nVolumes[ 5 ] = nMasterVolume;
  621. BinkSetMixBinVolumes( m_pHBINK, 3, NULL, nVolumes, BINK_NUMBER_OF_CHANNELS );
  622. #if ( BINK_NUMBER_OF_CHANNELS == 8 )
  623. // side LR
  624. memset( nVolumes, 0, sizeof( nVolumes ) );
  625. nVolumes[ 6 ] = nMasterVolume;
  626. nVolumes[ 7 ] = nMasterVolume;
  627. BinkSetMixBinVolumes( m_pHBINK, 4, NULL, nVolumes, BINK_NUMBER_OF_CHANNELS );
  628. #endif
  629. #else
  630. // route rear bink track to both back and side speakers
  631. memset( nVolumes, 0, sizeof( nVolumes ) );
  632. nVolumes[ 4 ] = nMasterVolume;
  633. nVolumes[ 5 ] = nMasterVolume;
  634. // If we are in 7.1, we want to duplicate the side speakers to the speakers. snd_ps3_back_channel_multiplier will be equal to 1.0f.
  635. // If we are in 5.1, we may not want to do that to create issues with the downmixer. snd_ps3_back_channel_multiplier will be equal to 0.0f.
  636. extern ConVar snd_ps3_back_channel_multiplier;
  637. nMasterVolume = ( int )( ( ( float ) nMasterVolume ) * snd_ps3_back_channel_multiplier.GetFloat() );
  638. #if ( BINK_NUMBER_OF_CHANNELS == 8 )
  639. nVolumes[ 6 ] = nMasterVolume;
  640. nVolumes[ 7 ] = nMasterVolume;
  641. #endif
  642. BinkSetMixBinVolumes( m_pHBINK, 3, NULL, nVolumes, BINK_NUMBER_OF_CHANNELS );
  643. #endif
  644. }
  645. #elif defined(PLATFORM_WINDOWS)
  646. void CBIKMaterial::SetTracks()
  647. {
  648. S32 volumes[ 6 ]; // 6 channels for 5.1
  649. U32 bins[ 6 ];
  650. // turn on the front left and right for the first Bink track
  651. memset( volumes, 0, sizeof( volumes ) );
  652. memset( bins, 0, sizeof( bins ) );
  653. volumes[ 0 ] = 32768;
  654. volumes[ 1 ] = 32768;
  655. bins[ 0 ] = 0;
  656. bins[ 1 ] = 1;
  657. BinkSetMixBinVolumes( m_pHBINK, 0, bins, volumes, 6 );
  658. // turn on the center for the second Bink track
  659. memset( volumes, 0, sizeof( volumes ) );
  660. memset( bins, 0, sizeof( bins ) );
  661. volumes[ 2 ] = 32768;
  662. bins[ 2 ] = 2;
  663. BinkSetMixBinVolumes( m_pHBINK, 1, bins, volumes, 6 );
  664. // turn on the sub woofer for the third Bink track
  665. memset( volumes, 0, sizeof( volumes ) );
  666. memset( bins, 0, sizeof( bins ) );
  667. volumes[ 3 ] = 32768;
  668. bins[ 3 ] = 3;
  669. BinkSetMixBinVolumes( m_pHBINK, 2, bins, volumes, 6 );
  670. // turn on the back left and right for the final Bink track
  671. memset( volumes, 0, sizeof( volumes ) );
  672. memset( bins, 0, sizeof( bins ) );
  673. volumes[ 4 ] = 32768;
  674. volumes[ 5 ] = 32768;
  675. bins[ 4 ] = 4;
  676. bins[ 5 ] = 5;
  677. BinkSetMixBinVolumes( m_pHBINK, 3, bins, volumes, 6 );
  678. }
  679. #elif defined(OSX)
  680. void CBIKMaterial::SetTracks()
  681. {
  682. S32 volumes[ 3 ]; // 2 channels for stero + mix in the center channel to left and right
  683. U32 bins[ 3 ];
  684. // turn on the front left and right for the first Bink track
  685. memset( volumes, 0, sizeof( volumes ) );
  686. memset( bins, 0, sizeof( bins ) );
  687. volumes[ 0 ] = 32768;
  688. volumes[ 1 ] = 32768;
  689. bins[ 0 ] = 0;
  690. bins[ 1 ] = 1;
  691. BinkSetMixBinVolumes( m_pHBINK, 0, bins, volumes, 3 );
  692. // turn on the center for the second Bink track
  693. memset( volumes, 0, sizeof( volumes ) );
  694. memset( bins, 0, sizeof( bins ) );
  695. volumes[ 0 ] = 16535;
  696. volumes[ 1 ] = 16535;
  697. bins[ 2 ] = 2;
  698. BinkSetMixBinVolumes( m_pHBINK, 1, bins, volumes, 3 );
  699. }
  700. #else
  701. void CBIKMaterial::SetTracks()
  702. {
  703. Assert( !"Need some code here please" );
  704. // Do nothing... Mac does not use Bink.
  705. }
  706. #endif
  707. void CBIKMaterial::UpdateVolume()
  708. {
  709. if ( !m_pHBINK || g_bDisableVolumeChanges )
  710. return;
  711. if ( !( m_nBinkFlags & BIK_NO_AUDIO ) )
  712. {
  713. // set the master volume
  714. static ConVarRef volumeConVar( "volume" );
  715. static ConVarRef movieVolumeScaleConVar( "movie_volume_scale" );
  716. float flVolume = volumeConVar.GetFloat() * movieVolumeScaleConVar.GetFloat() * 32768.0f;
  717. static ConVarRef snd_surroundSpeakersConVarRef( "snd_surround_speakers" );
  718. switch ( snd_surroundSpeakersConVarRef.GetInt() )
  719. {
  720. default: // 5.1 or 7.1
  721. case -1: // Not initialized yet, keep the same value
  722. // Keep it the way it is...
  723. break;
  724. case 2:
  725. // The output is in stereo, but the movie is 5.1
  726. // We reduce the volume so when downmixed we have the correct overall volume.
  727. #if defined( PLATFORM_PS3 )
  728. // This value is coming from this formula:
  729. // 8 (7.1)ch -> 2ch [CELL_AUDIO_OUT_DOWNMIXER_TYPE_A]
  730. // L(mix) = 0.707 x L + 0.5 x C + 0.5 x Ls + 0.5 x Le
  731. // R(mix) = 0.707 x R + 0.5 x C + 0.5 x Rs + 0.5 x Re
  732. // In this case Le and Re are 0.0, so the multiplying factor is 1.707
  733. // Thus we have to multiply it by 0.58585858 to re-normalize the volume.
  734. // flVolume *= 0.58585858f;
  735. // However after empirical testing on Portal 2, this value sounds better:
  736. flVolume *= 0.781144f;
  737. #elif defined( PLATFORM_X360 )
  738. // Similar values for X360.
  739. // (potentially the downmixing on X360 is adding 0.25 of the center and 0.25 of the back surround)
  740. flVolume *= 0.66f;
  741. #endif
  742. break;
  743. }
  744. S32 nVolume = (S32)( flVolume );
  745. for ( int i = 0; i != m_pHBINK->NumTracks; ++i )
  746. {
  747. BinkSetVolume( m_pHBINK, BinkGetTrackID( m_pHBINK, i ), nVolume );
  748. }
  749. }
  750. }
  751. bool CBIKMaterial::IsMovieResidentInMemory()
  752. {
  753. if ( !m_pHBINK )
  754. return false;
  755. return ( ( m_nBinkFlags & ( BINKPRELOADALL | BINKFROMMEMORY ) ) != 0 );
  756. }
  757. static void ShutdownAndDeleteBinkMaterial( CBIKMaterial *pBIK )
  758. {
  759. if ( !pBIK->Shutdown() )
  760. {
  761. // WILL CRASH HERE
  762. DebuggerBreakIfDebugging();
  763. }
  764. delete pBIK;
  765. }
  766. bool CBIKMaterial::Shutdown( void )
  767. {
  768. m_bShutdown = true;
  769. AUTO_LOCK( m_BinkUpdateMutex );
  770. if ( m_nQueuedUpdateCount != 0 )
  771. {
  772. CMatRenderContextPtr pRenderContext( materials );
  773. if ( pRenderContext->GetCallQueue() )
  774. {
  775. pRenderContext->GetCallQueue()->QueueCall( &ShutdownAndDeleteBinkMaterial, this );
  776. return false;
  777. }
  778. }
  779. // If this isn't 0, then this zombie object is going to get called by the mat queue thread... badness!
  780. Assert( m_nQueuedUpdateCount == 0 );
  781. DestroyVideoStream();
  782. DestroyProceduralMaterial();
  783. DestroyProceduralTextures();
  784. if ( m_pHBINK )
  785. {
  786. if ( ENABLE_BIK_PERF_SPEW )
  787. {
  788. BINKSUMMARY summary;
  789. BinkGetSummary( m_pHBINK, &summary );
  790. Warning( "BINK PERF:\n" );
  791. Warning( "--------------------------\n" );
  792. Warning( "Height of frames: %u\n", summary.Height );
  793. Warning( "total time (ms): %u\n", summary.TotalTime );
  794. Warning( "file frame rate: %f\n", ( float )summary.FileFrameRate / ( float )summary.FileFrameRateDiv );
  795. Warning( "file frame rate: %u\n", summary.FileFrameRate );
  796. Warning( "file frame rate divisor: %u\n", summary.FileFrameRateDiv );
  797. Warning( "frame rate: %f\n", ( float )summary.FrameRate / ( float )summary.FrameRateDiv );
  798. Warning( "frame rate: %u\n", summary.FrameRate );
  799. Warning( "frame rate divisor: %u\n", summary.FrameRateDiv );
  800. Warning( "Time to open and prepare for decompression: %u\n", summary.TotalOpenTime );
  801. Warning( "Total Frames: %u\n", summary.TotalFrames );
  802. Warning( "Total Frames played: %u\n", summary.TotalPlayedFrames );
  803. Warning( "Total number of skipped frames: %u\n", summary.SkippedFrames );
  804. Warning( "Total number of skipped blits: %u\n", summary.SkippedBlits );
  805. Warning( "Total number of sound skips: %u\n", summary.SoundSkips );
  806. Warning( "Total time spent blitting: %u\n", summary.TotalBlitTime );
  807. Warning( "Total time spent reading: %u\n", summary.TotalReadTime );
  808. Warning( "Total time spent decompressing video: %u\n", summary.TotalVideoDecompTime );
  809. Warning( "Total time spent decompressing audio: %u\n", summary.TotalAudioDecompTime );
  810. Warning( "Total time spent reading while idle: %u\n", summary.TotalIdleReadTime );
  811. Warning( "Total time spent reading in background: %u\n", summary.TotalBackReadTime );
  812. Warning( "Total io speed (bytes/second): %u\n", summary.TotalReadSpeed );
  813. Warning( "Slowest single frame time (ms): %u\n", summary.SlowestFrameTime );
  814. Warning( "Second slowest single frame time (ms): %u\n", summary.Slowest2FrameTime );
  815. Warning( "Slowest single frame number: %u\n", summary.SlowestFrameNum );
  816. Warning( "Second slowest single frame number: %u\n", summary.Slowest2FrameNum );
  817. Warning( "Average data rate of the movie: %u\n", summary.AverageDataRate );
  818. Warning( "Average size of the frame: %u\n", summary.AverageFrameSize );
  819. Warning( "Highest amount of memory allocated: %u\n", summary.HighestMemAmount );
  820. Warning( "Total extra memory allocated: %u\n", summary.TotalIOMemory );
  821. Warning( "Highest extra memory actually used: %u\n", summary.HighestIOUsed );
  822. Warning( "Highest 1 second rate: %u\n", summary.Highest1SecRate );
  823. Warning( "Highest 1 second start frame: %u\n", summary.Highest1SecFrame );
  824. Warning( "--------------------------\n" );
  825. }
  826. BinkClose( m_pHBINK );
  827. m_pHBINK = NULL;
  828. }
  829. #if IsPlatformPS3()
  830. switch ( m_ResumeMode )
  831. {
  832. case PRM_NO_RESUME_NECESSARY:
  833. break;
  834. case PRM_RESUME_AT_END_OF_FIRST_FRAME:
  835. // This should not happen, as hopefully one frame at least occurred, but just in case let's do what is expected
  836. Assert( false );
  837. // Pass through...
  838. case PRM_RESUME_AT_END_OF_MOVIE:
  839. g_pFullFileSystem->ResumePrefetches( "Streaming of Bink movie is finished." );
  840. m_ResumeMode = PRM_NO_RESUME_NECESSARY; // Reset the state just in case.
  841. break;
  842. }
  843. #endif
  844. return true;
  845. }
  846. bool CBIKMaterial::IsVideoFinished()
  847. {
  848. AUTO_LOCK( m_BinkFrameCountMutex );
  849. return m_bShutdown || ( ( m_nCurrentFrame == m_nFrameCount ) && ( m_bLoops == false ) );
  850. }
  851. // Unless you like to Dine with Philosophers,
  852. // I don't recommend calling this function unless you already have the m_BinkUpdateMutex
  853. void CBIKMaterial::UpdateCurrentFrameIndex()
  854. {
  855. AUTO_LOCK( m_BinkUpdateMutex ); // If you already have this mutex, this is re-entrant safe and will early-out
  856. AUTO_LOCK( m_BinkFrameCountMutex );
  857. m_nCurrentFrame = m_pHBINK->FrameNum;
  858. }
  859. //-----------------------------------------------------------------------------
  860. // Purpose: Updates our scene
  861. // Output : Returns true on success, false on failure.
  862. //-----------------------------------------------------------------------------
  863. bool CBIKMaterial::Update( void )
  864. {
  865. // is the video done?
  866. if ( IsVideoFinished() )
  867. return false;
  868. // This gets decremented by UpdateInternal(), either right now (if not queueing) or when the work is done (if queueing)
  869. ThreadInterlockedIncrement( &m_nQueuedUpdateCount );
  870. CMatRenderContextPtr pRenderContext( materials );
  871. if ( pRenderContext->GetCallQueue() && bink_mat_queue_mode.GetBool() )
  872. {
  873. pRenderContext->GetCallQueue()->QueueCall( this, &CBIKMaterial::UpdateInternal );
  874. }
  875. else
  876. {
  877. UpdateInternal();
  878. if ( IsVideoFinished() )
  879. return false;
  880. }
  881. // When using mat_queue_mode with bink movies, the return value 'false' (which indicates that the movie is over) will be delayed by a frame
  882. return true;
  883. }
  884. void CBIKMaterial::UpdateInternal()
  885. {
  886. // If you crash in this function when called from the mat queue thread and the member variables appear to be junk,
  887. // it is likely that this bink material has been shutdown/deleted already.
  888. // That would be bad, because the call queue needs to be flushed before you can safely destroy this object.
  889. AUTO_LOCK( m_BinkUpdateMutex );
  890. ThreadInterlockedDecrement( &m_nQueuedUpdateCount );
  891. // If we're waiting, then go away
  892. if ( BinkWait( m_pHBINK ) )
  893. return;
  894. // Decompress this frame
  895. BinkDoFrame( m_pHBINK );
  896. // do we need to skip a frame?
  897. while ( BinkShouldSkip( m_pHBINK ) )
  898. {
  899. UpdateCurrentFrameIndex();
  900. // is the video done?
  901. if ( IsVideoFinished() )
  902. break;
  903. BinkNextFrame( m_pHBINK );
  904. BinkDoFrame( m_pHBINK );
  905. }
  906. // Regenerate our textures
  907. m_TextureY->Download();
  908. #ifdef SUPPORT_BINK_ALPHA
  909. m_TextureA->Download();
  910. #endif
  911. m_TextureCr->Download();
  912. m_TextureCb->Download();
  913. UpdateCurrentFrameIndex();
  914. // is the video done?
  915. if ( IsVideoFinished() )
  916. return;
  917. // Move on
  918. BinkNextFrame( m_pHBINK );
  919. UpdateCurrentFrameIndex();
  920. #if IsPlatformPS3()
  921. if ( m_ResumeMode == PRM_RESUME_AT_END_OF_FIRST_FRAME )
  922. {
  923. g_pFullFileSystem->ResumePrefetches( "Bink movie has been preloaded." );
  924. m_ResumeMode = PRM_NO_RESUME_NECESSARY;
  925. }
  926. #endif
  927. }
  928. // Call this in a loop that does nothing or something minor right before calling SwapBuffers.
  929. bool CBIKMaterial::ReadyForSwap( void )
  930. {
  931. AUTO_LOCK( m_BinkUpdateMutex );
  932. return !BinkWait( m_pHBINK );
  933. }
  934. //-----------------------------------------------------------------------------
  935. // Returns the material
  936. //-----------------------------------------------------------------------------
  937. IMaterial *CBIKMaterial::GetMaterial()
  938. {
  939. return m_Material;
  940. }
  941. //-----------------------------------------------------------------------------
  942. // Returns the texcoord range
  943. //-----------------------------------------------------------------------------
  944. void CBIKMaterial::GetTexCoordRange( float *pMaxU, float *pMaxV )
  945. {
  946. AUTO_LOCK( m_BinkUpdateMutex );
  947. // Must have a luminosity channel
  948. if ( m_TextureY == NULL )
  949. {
  950. *pMaxU = *pMaxV = 1.0f;
  951. return;
  952. }
  953. // YA texture is always larger than the CrCb texture, so always base our size on that
  954. int nTextureWidth = m_TextureY->GetActualWidth();
  955. int nTextureHeight = m_TextureY->GetActualHeight();
  956. if ( nTextureWidth )
  957. *pMaxU = (float)m_nBIKWidth / (float)nTextureWidth;
  958. else
  959. *pMaxU = 0.0f;
  960. if ( nTextureHeight )
  961. *pMaxV = (float)m_nBIKHeight / (float)nTextureHeight;
  962. else
  963. *pMaxV = 0.0f;
  964. }
  965. //-----------------------------------------------------------------------------
  966. // Returns the frame size of the BIK (stored in a subrect of the material itself)
  967. //-----------------------------------------------------------------------------
  968. void CBIKMaterial::GetFrameSize( int *pWidth, int *pHeight )
  969. {
  970. *pWidth = m_nBIKWidth;
  971. *pHeight = m_nBIKHeight;
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Initializes, shuts down the procedural texture
  975. //-----------------------------------------------------------------------------
  976. void CBIKMaterial::CreateProceduralTextures( const char *pTextureName )
  977. {
  978. int nWidth, nHeight;
  979. char textureName[MAX_PATH];
  980. Q_strncpy( textureName, pTextureName, MAX_PATH-1 );
  981. Q_StripExtension( textureName, textureName, sizeof( textureName ) );
  982. Q_strncat( textureName, "Y", MAX_PATH );
  983. unsigned int nTextureFlags = ( TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT | TEXTUREFLAGS_NOMIP | TEXTUREFLAGS_PROCEDURAL | TEXTUREFLAGS_SINGLECOPY | TEXTUREFLAGS_NOLOD );
  984. nWidth = m_nBIKWidth;
  985. nHeight = m_nBIKHeight;
  986. m_TextureY.InitProceduralTexture( textureName, "bik", nWidth, nHeight, BINK_SHADER_IMAGE_FORMAT, nTextureFlags );
  987. m_TextureY->SetTextureRegenerator( &m_YTextureRegenerator );
  988. #ifdef SUPPORT_BINK_ALPHA
  989. Q_strncpy( textureName, pTextureName, MAX_PATH-1 );
  990. Q_StripExtension( textureName, textureName, sizeof( textureName ) );
  991. Q_strncat( textureName, "A", MAX_PATH );
  992. m_TextureA.InitProceduralTexture( textureName, "bik", nWidth, nHeight, BINK_SHADER_IMAGE_FORMAT, nTextureFlags );
  993. m_TextureA->SetTextureRegenerator( &m_ATextureRegenerator );
  994. #endif
  995. Q_strncpy( textureName, pTextureName, MAX_PATH-1 );
  996. Q_StripExtension( textureName, textureName, sizeof( textureName ) );
  997. Q_strncat( textureName, "Cr", MAX_PATH );
  998. nWidth = m_nBIKWidth >> 1;
  999. nHeight = m_nBIKHeight >> 1;
  1000. m_TextureCr.InitProceduralTexture( textureName, "bik", nWidth, nHeight, BINK_SHADER_IMAGE_FORMAT, nTextureFlags );
  1001. m_TextureCr->SetTextureRegenerator( &m_CrTextureRegenerator );
  1002. Q_strncpy( textureName, pTextureName, MAX_PATH-1 );
  1003. Q_StripExtension( textureName, textureName, sizeof( textureName ) );
  1004. Q_strncat( textureName, "Cb", MAX_PATH );
  1005. m_TextureCb.InitProceduralTexture( textureName, "bik", nWidth, nHeight, BINK_SHADER_IMAGE_FORMAT, nTextureFlags );
  1006. m_TextureCb->SetTextureRegenerator( &m_CbTextureRegenerator );
  1007. // This pulls in way too many lib dependencies on the PC; on consoles it's in engine.dll
  1008. // It's also just a perf improvement and not as useful on PC.
  1009. #ifdef _GAMECONSOLE
  1010. Assert( !m_pScratchTexture );
  1011. m_pScratchTexture = CreateVTFTexture();
  1012. #endif // _GAMECONSOLE
  1013. }
  1014. void CBIKMaterial::DestroyProceduralTexture( CTextureReference &texture )
  1015. {
  1016. if( texture )
  1017. {
  1018. texture->SetTextureRegenerator( NULL );
  1019. texture.Shutdown( true );
  1020. }
  1021. }
  1022. void CBIKMaterial::DestroyProceduralTextures()
  1023. {
  1024. #ifdef _GAMECONSOLE
  1025. DestroyVTFTexture( m_pScratchTexture );
  1026. m_pScratchTexture = NULL;
  1027. #endif // GAMECONSOLE
  1028. DestroyProceduralTexture( m_TextureY );
  1029. #ifdef SUPPORT_BINK_ALPHA
  1030. DestroyProceduralTexture( m_TextureA );
  1031. #endif
  1032. DestroyProceduralTexture( m_TextureCr );
  1033. DestroyProceduralTexture( m_TextureCb );
  1034. }
  1035. //-----------------------------------------------------------------------------
  1036. // Initializes, shuts down the procedural material
  1037. //-----------------------------------------------------------------------------
  1038. void CBIKMaterial::CreateProceduralMaterial( const char *pMaterialName )
  1039. {
  1040. // FIXME: gak, this is backwards. Why doesn't the material just see that it has a funky basetexture?
  1041. char vmtfilename[ 512 ];
  1042. Q_strcpy( vmtfilename, pMaterialName );
  1043. Q_SetExtension( vmtfilename, ".vmt", sizeof( vmtfilename ) );
  1044. KeyValues *pVMTKeyValues = new KeyValues( "Bik" );
  1045. if ( bink_try_load_vmt.GetBool() && pVMTKeyValues->LoadFromFile( g_pFullFileSystem , vmtfilename, "GAME" ) )
  1046. {
  1047. // use VMT settings
  1048. }
  1049. else
  1050. {
  1051. pVMTKeyValues->SetString( "$ytexture", m_TextureY->GetName() );
  1052. #ifdef SUPPORT_BINK_ALPHA
  1053. pVMTKeyValues->SetString( "$atexture", m_TextureA->GetName() );
  1054. #endif
  1055. pVMTKeyValues->SetString( "$crtexture", m_TextureCr->GetName() );
  1056. pVMTKeyValues->SetString( "$cbtexture", m_TextureCb->GetName() );
  1057. pVMTKeyValues->SetInt( "$nofog", 1 );
  1058. pVMTKeyValues->SetInt( "$spriteorientation", 3 );
  1059. pVMTKeyValues->SetInt( "$translucent", 1 );
  1060. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  1061. pVMTKeyValues->SetInt( "$vertexalpha", 1 );
  1062. pVMTKeyValues->SetInt( "$nolod", 1 );
  1063. pVMTKeyValues->SetInt( "$nomip", 1 );
  1064. pVMTKeyValues->SetInt( "$nobasetexture", 1 );
  1065. }
  1066. m_Material.Init( pMaterialName, pVMTKeyValues );
  1067. m_Material->Refresh();
  1068. }
  1069. void CBIKMaterial::DestroyProceduralMaterial()
  1070. {
  1071. m_Material.Shutdown( true );
  1072. }
  1073. //-----------------------------------------------------------------------------
  1074. // Returns the frame rate of the BIK
  1075. //-----------------------------------------------------------------------------
  1076. int CBIKMaterial::GetFrameRate( )
  1077. {
  1078. return m_nFrameRate;
  1079. }
  1080. int CBIKMaterial::GetFrameCount( )
  1081. {
  1082. return m_nFrameCount;
  1083. }
  1084. //-----------------------------------------------------------------------------
  1085. // Sets the frame for an BIK material (use instead of SetTime)
  1086. //-----------------------------------------------------------------------------
  1087. void CBIKMaterial::SetFrame( float flFrame )
  1088. {
  1089. AUTO_LOCK( m_BinkUpdateMutex );
  1090. U32 nFrame = (U32)flFrame + 1;
  1091. CMatRenderContextPtr pRenderContext( materials );
  1092. if ( pRenderContext->GetCallQueue() && bink_mat_queue_mode.GetBool() )
  1093. {
  1094. pRenderContext->GetCallQueue()->QueueCall( this, &CBIKMaterial::SetFrameInternal, nFrame );
  1095. }
  1096. else
  1097. {
  1098. SetFrameInternal( nFrame );
  1099. }
  1100. }
  1101. void CBIKMaterial::SetFrameInternal( int nFrame )
  1102. {
  1103. AUTO_LOCK( m_BinkUpdateMutex );
  1104. if ( m_pHBINK->LastFrameNum != nFrame )
  1105. {
  1106. BinkGoto( m_pHBINK, nFrame, 0 );
  1107. m_TextureY->Download();
  1108. #ifdef SUPPORT_BINK_ALPHA
  1109. m_TextureA->Download();
  1110. #endif
  1111. m_TextureCr->Download();
  1112. m_TextureCb->Download();
  1113. }
  1114. UpdateCurrentFrameIndex();
  1115. }
  1116. //-----------------------------------------------------------------------------
  1117. // Initializes, shuts down the video stream
  1118. //-----------------------------------------------------------------------------
  1119. void CBIKMaterial::CreateVideoStream( )
  1120. {
  1121. // get the frame buffers info
  1122. BinkGetFrameBuffersInfo( m_pHBINK, &m_buffers );
  1123. // fixme: these should point to local buffers that the material system can splat
  1124. for ( int i = 0 ; i < m_buffers.TotalFrames ; i++ )
  1125. {
  1126. if ( m_buffers.Frames[ i ].YPlane.Allocate )
  1127. {
  1128. // calculate a good pitch
  1129. m_buffers.Frames[ i ].YPlane.BufferPitch = ( m_buffers.YABufferWidth + 15 ) & ~15;
  1130. // now allocate the pointer
  1131. m_buffers.Frames[ i ].YPlane.Buffer = MemAlloc_AllocAligned( m_buffers.Frames[ i ].YPlane.BufferPitch * m_buffers.YABufferHeight, 16 );
  1132. }
  1133. if ( m_buffers.Frames[ i ].cRPlane.Allocate )
  1134. {
  1135. // calculate a good pitch
  1136. m_buffers.Frames[ i ].cRPlane.BufferPitch = ( m_buffers.cRcBBufferWidth + 15 ) & ~15;
  1137. // now allocate the pointer
  1138. m_buffers.Frames[ i ].cRPlane.Buffer = MemAlloc_AllocAligned( m_buffers.Frames[ i ].cRPlane.BufferPitch * m_buffers.cRcBBufferHeight, 16 );
  1139. }
  1140. if ( m_buffers.Frames[ i ].cBPlane.Allocate )
  1141. {
  1142. // calculate a good pitch
  1143. m_buffers.Frames[ i ].cBPlane.BufferPitch = ( m_buffers.cRcBBufferWidth + 15 ) & ~15;
  1144. // now allocate the pointer
  1145. m_buffers.Frames[ i ].cBPlane.Buffer = MemAlloc_AllocAligned( m_buffers.Frames[ i ].cBPlane.BufferPitch * m_buffers.cRcBBufferHeight, 16 );
  1146. }
  1147. #ifdef SUPPORT_BINK_ALPHA
  1148. if ( m_buffers.Frames[ i ].APlane.Allocate )
  1149. { // calculate a good pitch
  1150. m_buffers.Frames[ i ].APlane.BufferPitch = ( m_buffers.YABufferWidth + 15 ) & ~15;
  1151. // now allocate the pointer
  1152. m_buffers.Frames[ i ].APlane.Buffer = MemAlloc_AllocAligned( m_buffers.Frames[ i ].APlane.BufferPitch * m_buffers.YABufferHeight, 16 );
  1153. }
  1154. #endif
  1155. }
  1156. // Now tell Bink to use these new planes
  1157. BinkRegisterFrameBuffers( m_pHBINK, &m_buffers );
  1158. }
  1159. //-----------------------------------------------------------------------------
  1160. // Purpose: Destroy the stream
  1161. //-----------------------------------------------------------------------------
  1162. void CBIKMaterial::DestroyVideoStream( )
  1163. {
  1164. // who free's this?
  1165. for ( int i = 0 ; i < m_buffers.TotalFrames ; i++ )
  1166. {
  1167. if ( m_buffers.Frames[ i ].YPlane.Allocate && m_buffers.Frames[ i ].YPlane.Buffer )
  1168. {
  1169. // now allocate the pointer
  1170. MemAlloc_FreeAligned( m_buffers.Frames[ i ].YPlane.Buffer );
  1171. m_buffers.Frames[ i ].YPlane.Buffer = NULL;
  1172. }
  1173. if ( m_buffers.Frames[ i ].cRPlane.Allocate && m_buffers.Frames[ i ].cRPlane.Buffer )
  1174. {
  1175. // now allocate the pointer
  1176. MemAlloc_FreeAligned( m_buffers.Frames[ i ].cRPlane.Buffer );
  1177. m_buffers.Frames[ i ].cRPlane.Buffer = NULL;
  1178. }
  1179. if ( m_buffers.Frames[ i ].cBPlane.Allocate && m_buffers.Frames[ i ].cBPlane.Buffer )
  1180. {
  1181. // now allocate the pointer
  1182. MemAlloc_FreeAligned( m_buffers.Frames[ i ].cBPlane.Buffer );
  1183. m_buffers.Frames[ i ].cBPlane.Buffer = NULL;
  1184. }
  1185. #ifdef SUPPORT_BINK_ALPHA
  1186. if ( m_buffers.Frames[ i ].APlane.Allocate && m_buffers.Frames[ i ].APlane.Buffer )
  1187. {
  1188. // now allocate the pointer
  1189. MemAlloc_FreeAligned( m_buffers.Frames[ i ].APlane.Buffer );
  1190. m_buffers.Frames[ i ].APlane.Buffer = NULL;
  1191. }
  1192. #endif
  1193. }
  1194. }
  1195. //-----------------------------------------------------------------------------
  1196. // Purpose: Returns the current frame number of the video
  1197. //-----------------------------------------------------------------------------
  1198. int CBIKMaterial::GetFrame( void )
  1199. {
  1200. AUTO_LOCK( m_BinkFrameCountMutex );
  1201. return m_nCurrentFrame;
  1202. }
  1203. //-----------------------------------------------------------------------------
  1204. // Purpose: Pause playback
  1205. //-----------------------------------------------------------------------------
  1206. void CBIKMaterial::Pause( void )
  1207. {
  1208. AUTO_LOCK( m_BinkUpdateMutex );
  1209. BinkPause( m_pHBINK, 1 );
  1210. }
  1211. //-----------------------------------------------------------------------------
  1212. // Purpose: Resume playback
  1213. //-----------------------------------------------------------------------------
  1214. void CBIKMaterial::Unpause( void )
  1215. {
  1216. AUTO_LOCK( m_BinkUpdateMutex );
  1217. BinkPause( m_pHBINK, 0 );
  1218. }
  1219. //-----------------------------------------------------------------------------
  1220. //
  1221. // Implementation of IAvi
  1222. //
  1223. //-----------------------------------------------------------------------------
  1224. class CBik : public CBaseAppSystem< IBik >
  1225. {
  1226. public:
  1227. CBik();
  1228. // Inherited from IAppSystem
  1229. virtual bool Connect( CreateInterfaceFn factory );
  1230. virtual void Disconnect();
  1231. virtual void *QueryInterface( const char *pInterfaceName );
  1232. virtual InitReturnVal_t Init();
  1233. virtual void Shutdown();
  1234. // Inherited from IBik
  1235. virtual BIKMaterial_t CreateMaterial( const char *pMaterialName, const char *pFileName, const char *pPathID, int flags );
  1236. virtual void DestroyMaterial( BIKMaterial_t hMaterial );
  1237. virtual bool Update( BIKMaterial_t hMaterial );
  1238. virtual bool ReadyForSwap( BIKMaterial_t hMaterial );
  1239. virtual IMaterial* GetMaterial( BIKMaterial_t hMaterial );
  1240. virtual void GetTexCoordRange( BIKMaterial_t hMaterial, float *pMaxU, float *pMaxV );
  1241. virtual void GetFrameSize( BIKMaterial_t hMaterial, int *pWidth, int *pHeight );
  1242. virtual int GetFrameRate( BIKMaterial_t hMaterial );
  1243. virtual int GetFrame( BIKMaterial_t hMaterial );
  1244. virtual void SetFrame( BIKMaterial_t hMaterial, float flFrame );
  1245. virtual int GetFrameCount( BIKMaterial_t hMaterial );
  1246. #ifdef WIN32
  1247. #if !defined( _X360 )
  1248. virtual bool SetDirectSoundDevice( void *pDevice );
  1249. virtual bool SetMilesSoundDevice( void *pDevice );
  1250. #else
  1251. virtual bool HookXAudio( void );
  1252. #endif
  1253. #endif
  1254. #if defined( _PS3 )
  1255. virtual bool SetPS3SoundDevice( int nChannelCount );
  1256. #endif
  1257. virtual void Pause( BIKMaterial_t hMaterial );
  1258. virtual void Unpause( BIKMaterial_t hMaterial );
  1259. virtual int GetGlobalMaterialAllocationNumber( void ) { return s_nMaterialAllocation; }
  1260. virtual bool PrecacheMovie( const char *pFileName, const char *pPathID );
  1261. virtual void *GetPrecachedMovie( const char *pFileName );
  1262. virtual void EvictPrecachedMovie( const char *pFileName );
  1263. virtual void EvictAllPrecachedMovies();
  1264. void DumpPrecachedMovieList();
  1265. virtual void UpdateVolume( BIKMaterial_t hMaterial );
  1266. virtual bool IsMovieResidentInMemory( BIKMaterial_t hMaterial );
  1267. private:
  1268. static void * RADLINK BinkMemAlloc( U32 bytes ) { return malloc( bytes ); };
  1269. static void RADLINK BinkMemFree( void PTR4* ptr ) { free( ptr ); };
  1270. // NOTE: Have to use pointers here since BIKMaterials inherit from ITextureRegenerator
  1271. // The realloc screws up the pointers held to ITextureRegenerators in the material system.
  1272. CUtlLinkedList< CBIKMaterial*, BIKMaterial_t > m_BIKMaterials;
  1273. static int s_nMaterialAllocation;
  1274. CUtlVector< PrecachedMovie_t > m_PrecachedMovies;
  1275. };
  1276. //-----------------------------------------------------------------------------
  1277. // Static variables
  1278. //-----------------------------------------------------------------------------
  1279. int CBik::s_nMaterialAllocation = 0;
  1280. //-----------------------------------------------------------------------------
  1281. // Singleton
  1282. //-----------------------------------------------------------------------------
  1283. static CBik g_BIK;
  1284. EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CBik, IBik, BIK_INTERFACE_VERSION, g_BIK );
  1285. //-----------------------------------------------------------------------------
  1286. // Constructor/destructor
  1287. //-----------------------------------------------------------------------------
  1288. CBik::CBik()
  1289. {
  1290. }
  1291. //-----------------------------------------------------------------------------
  1292. // Connect/disconnect
  1293. //-----------------------------------------------------------------------------
  1294. bool CBik::Connect( CreateInterfaceFn factory )
  1295. {
  1296. if ( IsGameConsole() )
  1297. {
  1298. return true;
  1299. }
  1300. ConnectTier1Libraries( &factory, 1 );
  1301. ConnectTier2Libraries( &factory, 1 );
  1302. if ( !( g_pFullFileSystem && materials ) )
  1303. {
  1304. Msg( "Bik failed to connect to a required system\n" );
  1305. }
  1306. return ( g_pFullFileSystem && materials );
  1307. }
  1308. //-----------------------------------------------------------------------------
  1309. // Connect/disconnect
  1310. //-----------------------------------------------------------------------------
  1311. void CBik::Disconnect( void )
  1312. {
  1313. }
  1314. //-----------------------------------------------------------------------------
  1315. // Query Interface
  1316. //-----------------------------------------------------------------------------
  1317. void *CBik::QueryInterface( const char *pInterfaceName )
  1318. {
  1319. if (!Q_strncmp( pInterfaceName, BIK_INTERFACE_VERSION, Q_strlen(BIK_INTERFACE_VERSION) + 1))
  1320. return (IBik*)this;
  1321. return NULL;
  1322. }
  1323. //-----------------------------------------------------------------------------
  1324. // Init/shutdown
  1325. //-----------------------------------------------------------------------------
  1326. InitReturnVal_t CBik::Init()
  1327. {
  1328. BinkSetMemory( BinkMemAlloc, BinkMemFree );
  1329. return INIT_OK;
  1330. }
  1331. void CBik::Shutdown()
  1332. {
  1333. #ifdef _PS3
  1334. BinkFreeGlobals();
  1335. #endif // _PS3
  1336. }
  1337. //-----------------------------------------------------------------------------
  1338. // Create/destroy an BIK material
  1339. //-----------------------------------------------------------------------------
  1340. BIKMaterial_t CBik::CreateMaterial( const char *pMaterialName, const char *pFileName, const char *pPathID, int flags )
  1341. {
  1342. // material names aren't filenames, they are expected to be adherent to forward slashes
  1343. char fixedMaterialName[MAX_PATH];
  1344. V_strncpy( fixedMaterialName, pMaterialName, sizeof( fixedMaterialName ) );
  1345. V_FixSlashes( fixedMaterialName, '/' );
  1346. BIKMaterial_t h = m_BIKMaterials.AddToTail();
  1347. m_BIKMaterials[h] = new CBIKMaterial;
  1348. if ( m_BIKMaterials[h]->Init( fixedMaterialName, pFileName, pPathID, flags ) == false )
  1349. {
  1350. delete m_BIKMaterials[h];
  1351. m_BIKMaterials.Remove( h );
  1352. return BIKMATERIAL_INVALID;
  1353. }
  1354. s_nMaterialAllocation++;
  1355. return h;
  1356. }
  1357. void CBik::DestroyMaterial( BIKMaterial_t h )
  1358. {
  1359. if ( h != BIKMATERIAL_INVALID )
  1360. {
  1361. if ( m_BIKMaterials[h]->Shutdown() )
  1362. {
  1363. delete m_BIKMaterials[h];
  1364. }
  1365. m_BIKMaterials.Remove( h );
  1366. }
  1367. }
  1368. //-----------------------------------------------------------------------------
  1369. // Purpose:
  1370. // Input : hMaterial -
  1371. // Output : Returns true on success, false on failure.
  1372. //-----------------------------------------------------------------------------
  1373. bool CBik::Update( BIKMaterial_t hMaterial )
  1374. {
  1375. if ( hMaterial == BIKMATERIAL_INVALID )
  1376. return false;
  1377. return m_BIKMaterials[hMaterial]->Update();
  1378. }
  1379. bool CBik::ReadyForSwap( BIKMaterial_t hMaterial )
  1380. {
  1381. Assert( hMaterial != BIKMATERIAL_INVALID );
  1382. if ( hMaterial == BIKMATERIAL_INVALID )
  1383. {
  1384. return true;
  1385. }
  1386. return m_BIKMaterials[hMaterial]->ReadyForSwap();
  1387. }
  1388. //-----------------------------------------------------------------------------
  1389. // Gets the IMaterial associated with an BIK material
  1390. //-----------------------------------------------------------------------------
  1391. IMaterial* CBik::GetMaterial( BIKMaterial_t h )
  1392. {
  1393. if ( h != BIKMATERIAL_INVALID )
  1394. return m_BIKMaterials[h]->GetMaterial();
  1395. return NULL;
  1396. }
  1397. //-----------------------------------------------------------------------------
  1398. // Returns the max texture coordinate of the BIK
  1399. //-----------------------------------------------------------------------------
  1400. void CBik::GetTexCoordRange( BIKMaterial_t h, float *pMaxU, float *pMaxV )
  1401. {
  1402. if ( h != BIKMATERIAL_INVALID )
  1403. {
  1404. m_BIKMaterials[h]->GetTexCoordRange( pMaxU, pMaxV );
  1405. }
  1406. else
  1407. {
  1408. *pMaxU = *pMaxV = 1.0f;
  1409. }
  1410. }
  1411. //-----------------------------------------------------------------------------
  1412. // Returns the frame size of the BIK (is a subrect of the material itself)
  1413. //-----------------------------------------------------------------------------
  1414. void CBik::GetFrameSize( BIKMaterial_t h, int *pWidth, int *pHeight )
  1415. {
  1416. if ( h != BIKMATERIAL_INVALID )
  1417. {
  1418. m_BIKMaterials[h]->GetFrameSize( pWidth, pHeight );
  1419. }
  1420. else
  1421. {
  1422. *pWidth = *pHeight = 1;
  1423. }
  1424. }
  1425. //-----------------------------------------------------------------------------
  1426. // Returns the frame size of the BIK (is a subrect of the material itself)
  1427. //-----------------------------------------------------------------------------
  1428. int CBik::GetFrameRate( BIKMaterial_t h )
  1429. {
  1430. if ( h == BIKMATERIAL_INVALID )
  1431. return -1;
  1432. return m_BIKMaterials[h]->GetFrameRate();
  1433. }
  1434. //-----------------------------------------------------------------------------
  1435. // Returns the frame rate of the BIK
  1436. //-----------------------------------------------------------------------------
  1437. int CBik::GetFrameCount( BIKMaterial_t h )
  1438. {
  1439. if ( h == BIKMATERIAL_INVALID )
  1440. return -1;
  1441. return m_BIKMaterials[h]->GetFrameCount();
  1442. }
  1443. //-----------------------------------------------------------------------------
  1444. // Sets the frame for an BIK material (use instead of SetTime)
  1445. //-----------------------------------------------------------------------------
  1446. void CBik::SetFrame( BIKMaterial_t h, float flFrame )
  1447. {
  1448. if ( h != BIKMATERIAL_INVALID )
  1449. {
  1450. m_BIKMaterials[h]->SetFrame( flFrame );
  1451. }
  1452. }
  1453. #if defined( WIN32 )
  1454. //-----------------------------------------------------------------------------
  1455. // Purpose:
  1456. // Input : pDevice -
  1457. // Output : Returns true on success, false on failure.
  1458. //-----------------------------------------------------------------------------
  1459. #if !defined( _X360 )
  1460. bool CBik::SetDirectSoundDevice( void *pDevice )
  1461. {
  1462. g_bDisableVolumeChanges = false;
  1463. return ( BinkSoundUseDirectSound( pDevice ) != 0 );
  1464. }
  1465. bool CBik::SetMilesSoundDevice( void *pDevice )
  1466. {
  1467. if ( !pDevice )
  1468. {
  1469. g_bDisableVolumeChanges = true;
  1470. return BinkSoundUseWaveOut() != 0;
  1471. }
  1472. g_bDisableVolumeChanges = false;
  1473. return ( BinkSoundUseMiles( pDevice ) != 0 );
  1474. }
  1475. #else
  1476. bool CBik::HookXAudio( void )
  1477. {
  1478. IXAudio2 *pXAudio2 = Audio_GetXAudio2();
  1479. if ( !pXAudio2 )
  1480. {
  1481. // it better be there, it was when th
  1482. Warning( "Bink playback not supported, init sequence of audio has been regressed." );
  1483. return false;
  1484. }
  1485. return ( BinkSoundUseXAudio2( pXAudio2 ) != 0 );
  1486. }
  1487. #endif
  1488. #endif // WIN32
  1489. #if defined( _PS3 )
  1490. bool CBik::SetPS3SoundDevice( int nChannelCount )
  1491. {
  1492. return BinkSoundUseLibAudio( nChannelCount );
  1493. }
  1494. #endif // _PS3
  1495. //-----------------------------------------------------------------------------
  1496. // Purpose: Gets the current frame from the Bink movie (for playback purposes)
  1497. //-----------------------------------------------------------------------------
  1498. int CBik::GetFrame( BIKMaterial_t hMaterial )
  1499. {
  1500. if ( hMaterial != BIKMATERIAL_INVALID )
  1501. {
  1502. return m_BIKMaterials[hMaterial]->GetFrame();
  1503. }
  1504. return -1;
  1505. }
  1506. //-----------------------------------------------------------------------------
  1507. // Purpose: Pause the movie playback
  1508. //-----------------------------------------------------------------------------
  1509. void CBik::Pause( BIKMaterial_t hMaterial )
  1510. {
  1511. if ( hMaterial != BIKMATERIAL_INVALID )
  1512. {
  1513. m_BIKMaterials[hMaterial]->Pause();
  1514. }
  1515. }
  1516. //-----------------------------------------------------------------------------
  1517. // Purpose: Resume movie playback
  1518. //-----------------------------------------------------------------------------
  1519. void CBik::Unpause( BIKMaterial_t hMaterial )
  1520. {
  1521. if ( hMaterial != BIKMATERIAL_INVALID )
  1522. {
  1523. m_BIKMaterials[hMaterial]->Unpause();
  1524. }
  1525. }
  1526. bool CBik::PrecacheMovie( const char *pFileName, const char *pPathID )
  1527. {
  1528. if ( GetPrecachedMovie( pFileName ) )
  1529. {
  1530. // alread precached
  1531. return true;
  1532. }
  1533. MEM_ALLOC_CREDIT();
  1534. // must deal in absolute paths to ensure zip cull (media files are external)
  1535. char pBIKFileName[ 512 ];
  1536. char pFullBIKFileName[ 512 ];
  1537. Q_snprintf( pBIKFileName, sizeof( pBIKFileName ), "%s", pFileName );
  1538. Q_DefaultExtension( pBIKFileName, ".bik", sizeof( pBIKFileName ) );
  1539. PathTypeQuery_t pathType;
  1540. if ( !g_pFullFileSystem->RelativePathToFullPath( pBIKFileName, pPathID, pFullBIKFileName, sizeof( pFullBIKFileName ), GetMoviePathFilter(), &pathType ) )
  1541. {
  1542. // A file by that name was not found
  1543. return false;
  1544. }
  1545. const char *pBaseName = V_UnqualifiedFileName( pFullBIKFileName );
  1546. int iIndex = m_PrecachedMovies.AddToTail();
  1547. m_PrecachedMovies[iIndex].m_BaseName = pBaseName;
  1548. if ( !g_pFullFileSystem->ReadFile( pFullBIKFileName, NULL, m_PrecachedMovies[iIndex].m_MemoryBuffer ) )
  1549. {
  1550. m_PrecachedMovies.Remove( iIndex );
  1551. return false;
  1552. }
  1553. #if defined( PLAT_BIG_ENDIAN )
  1554. // per Bink Docs
  1555. DWORD *pBase = (DWORD *)m_PrecachedMovies[iIndex].m_MemoryBuffer.Base();
  1556. int numDWords = m_PrecachedMovies[iIndex].m_MemoryBuffer.TellPut() / sizeof( DWORD );
  1557. for ( int i = 0; i < numDWords; i++ )
  1558. {
  1559. pBase[i] = DWordSwap( pBase[i] );
  1560. }
  1561. #endif
  1562. return true;
  1563. }
  1564. void *CBik::GetPrecachedMovie( const char *pFileName )
  1565. {
  1566. const char *pBaseName = V_UnqualifiedFileName( pFileName );
  1567. for ( int i = 0; i < m_PrecachedMovies.Count(); i++ )
  1568. {
  1569. if ( !V_stricmp( m_PrecachedMovies[i].m_BaseName.Get(), pBaseName ) )
  1570. {
  1571. return m_PrecachedMovies[i].m_MemoryBuffer.Base();
  1572. }
  1573. }
  1574. // not found
  1575. return NULL;
  1576. }
  1577. void CBik::EvictPrecachedMovie( const char *pFileName )
  1578. {
  1579. const char *pBaseName = V_UnqualifiedFileName( pFileName );
  1580. for ( int i = 0; i < m_PrecachedMovies.Count(); i++ )
  1581. {
  1582. if ( !V_stricmp( m_PrecachedMovies[i].m_BaseName.Get(), pBaseName ) )
  1583. {
  1584. m_PrecachedMovies.Remove( i );
  1585. break;
  1586. }
  1587. }
  1588. }
  1589. void CBik::EvictAllPrecachedMovies()
  1590. {
  1591. m_PrecachedMovies.Purge();
  1592. }
  1593. void CBik::UpdateVolume( BIKMaterial_t hMaterial )
  1594. {
  1595. if ( hMaterial != BIKMATERIAL_INVALID )
  1596. {
  1597. m_BIKMaterials[hMaterial]->UpdateVolume();
  1598. }
  1599. }
  1600. bool CBik::IsMovieResidentInMemory( BIKMaterial_t hMaterial )
  1601. {
  1602. if ( hMaterial != BIKMATERIAL_INVALID )
  1603. {
  1604. return m_BIKMaterials[hMaterial]->IsMovieResidentInMemory();
  1605. }
  1606. return false;
  1607. }
  1608. void CBik::DumpPrecachedMovieList()
  1609. {
  1610. Msg( "-- %d precached bink movies -- \n", m_PrecachedMovies.Count() );
  1611. for ( int i = 0; i < m_PrecachedMovies.Count(); ++ i )
  1612. {
  1613. Msg( "%d: %s, %d bytes\n", i, m_PrecachedMovies[i].m_BaseName.String(), m_PrecachedMovies[i].m_MemoryBuffer.Size() );
  1614. }
  1615. }
  1616. CON_COMMAND( bink_dump_precached_movies, "Dumps information about all precached Bink movies" )
  1617. {
  1618. g_BIK.DumpPrecachedMovieList();
  1619. }
  1620. #endif
  1621. #endif // BINK_VIDEO