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.
527 lines
15 KiB
527 lines
15 KiB
//========= Copyright � 1996-2009, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//=====================================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "c_vguiscreen.h"
|
|
#include "vgui_controls/ImagePanel.h"
|
|
#include <vgui/IVGui.h>
|
|
#include "ienginevgui.h"
|
|
#include "fmtstr.h"
|
|
#include "vgui_controls/ImagePanel.h"
|
|
#include <vgui/ISurface.h>
|
|
#include "avi/ibik.h"
|
|
#include "engine/IEngineSound.h"
|
|
#include "VGuiMatSurface/IMatSystemSurface.h"
|
|
#include "c_movie_display.h"
|
|
|
|
// NOTE: This has to be the last file included!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
using namespace vgui;
|
|
|
|
struct VideoPlaybackInfo_t
|
|
{
|
|
VideoPlaybackInfo_t( void ) :
|
|
m_pMaterial ( NULL ),
|
|
m_nSourceHeight(0), m_nSourceWidth(0),
|
|
m_flU(0.0f),m_flV(0.0f) {}
|
|
|
|
IMaterial *m_pMaterial;
|
|
int m_nSourceHeight, m_nSourceWidth; // Source movie's dimensions
|
|
float m_flU, m_flV; // U,V ranges for video on its sheet
|
|
};
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Control screen
|
|
//-----------------------------------------------------------------------------
|
|
class CMovieDisplayScreen : public CVGuiScreenPanel
|
|
{
|
|
DECLARE_CLASS( CMovieDisplayScreen, CVGuiScreenPanel );
|
|
|
|
public:
|
|
CMovieDisplayScreen( vgui::Panel *parent, const char *panelName );
|
|
~CMovieDisplayScreen( void );
|
|
|
|
virtual void ApplySchemeSettings( IScheme *pScheme );
|
|
|
|
virtual bool Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData );
|
|
virtual void OnTick( void );
|
|
virtual void Paint( void );
|
|
|
|
private:
|
|
bool IsActive( void );
|
|
bool IsAGroupPeer( CMovieDisplayScreen* pScreen );
|
|
|
|
void SetupMovie( void );
|
|
void UpdateMovie( void );
|
|
bool BeginPlayback( const char *pFilename );
|
|
void CalculatePlaybackDimensions( int nSrcWidth, int nSrcHeight );
|
|
|
|
void TakeOverAsMaster();
|
|
|
|
inline void GetPanelPos( int &xpos, int &ypos )
|
|
{
|
|
xpos = ( (float) ( GetWide() - m_nPlaybackWidth ) / 2 );
|
|
ypos = ( (float) ( GetTall() - m_nPlaybackHeight ) / 2 );
|
|
}
|
|
|
|
private:
|
|
|
|
// BINK playback info
|
|
BIKMaterial_t m_BIKHandle;
|
|
VideoPlaybackInfo_t m_playbackInfo;
|
|
CHandle<C_VGuiScreen> m_hVGUIScreen;
|
|
CHandle<C_MovieDisplay> m_hScreenEntity;
|
|
|
|
int m_nTextureId;
|
|
int m_nPlaybackHeight; // Playback dimensions (proper ration adjustments)
|
|
int m_nPlaybackWidth;
|
|
bool m_bBlackBackground;
|
|
bool m_bSlaved;
|
|
bool m_bInitialized;
|
|
|
|
bool m_bLastActiveState; // HACK: I'd rather get a real callback...
|
|
|
|
// VGUI specifics
|
|
ImagePanel *m_pScanLineImage;
|
|
|
|
bool bIsAlreadyVisible;
|
|
};
|
|
|
|
DECLARE_VGUI_SCREEN_FACTORY( CMovieDisplayScreen, "movie_display_screen" );
|
|
|
|
CUtlVector <CMovieDisplayScreen *> g_MovieDisplays;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Constructor:
|
|
//-----------------------------------------------------------------------------
|
|
CMovieDisplayScreen::CMovieDisplayScreen( vgui::Panel *parent, const char *panelName )
|
|
: BaseClass( parent, "CMovieDisplayScreen" )
|
|
{
|
|
m_pScanLineImage = new vgui::ImagePanel( this, "ScanLines");
|
|
m_pScanLineImage->SetImage( "elevator_video_lines" );
|
|
|
|
m_BIKHandle = BIKHANDLE_INVALID;
|
|
m_nTextureId = -1;
|
|
m_bBlackBackground = true;
|
|
m_bSlaved = false;
|
|
m_bInitialized = false;
|
|
|
|
// Add ourselves to the global list of movie displays
|
|
g_MovieDisplays.AddToTail( this );
|
|
|
|
m_bLastActiveState = IsActive();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Clean up the movie
|
|
//-----------------------------------------------------------------------------
|
|
CMovieDisplayScreen::~CMovieDisplayScreen( void )
|
|
{
|
|
if ( m_BIKHandle != BIKHANDLE_INVALID )
|
|
{
|
|
if ( bik )
|
|
bik->DestroyMaterial( m_BIKHandle );
|
|
m_BIKHandle = BIKHANDLE_INVALID;
|
|
}
|
|
|
|
// Clean up our texture reference
|
|
if ( m_nTextureId != -1 )
|
|
{
|
|
g_pMatSystemSurface->DestroyTextureID( m_nTextureId );
|
|
m_nTextureId = -1;
|
|
}
|
|
|
|
// Remove ourselves from the global list of movie displays
|
|
g_MovieDisplays.FindAndRemove( this );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Setup our scheme
|
|
//-----------------------------------------------------------------------------
|
|
void CMovieDisplayScreen::ApplySchemeSettings( IScheme *pScheme )
|
|
{
|
|
assert( pScheme );
|
|
|
|
BaseClass::ApplySchemeSettings(pScheme);
|
|
|
|
m_pScanLineImage->SetShouldScaleImage( true );
|
|
int wide, tall;
|
|
this->GetSize( wide, tall );
|
|
m_pScanLineImage->SetSize( wide, tall );
|
|
m_pScanLineImage->SetDrawColor( Color( 100, 100, 100, 255 ) );
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Initialization
|
|
//-----------------------------------------------------------------------------
|
|
bool CMovieDisplayScreen::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
|
|
{
|
|
// Make sure we get ticked...
|
|
vgui::ivgui()->AddTickSignal( GetVPanel() );
|
|
|
|
if ( !BaseClass::Init( pKeyValues, pInitData ) )
|
|
return false;
|
|
|
|
// Save this for simplicity later on
|
|
m_hVGUIScreen = dynamic_cast<C_VGuiScreen *>( GetEntity() );
|
|
if ( m_hVGUIScreen != NULL )
|
|
{
|
|
// Also get the associated entity
|
|
m_hScreenEntity = dynamic_cast<C_MovieDisplay *>(m_hVGUIScreen->GetOwnerEntity());
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Helper function to check our active state
|
|
//-----------------------------------------------------------------------------
|
|
bool CMovieDisplayScreen::IsActive( void )
|
|
{
|
|
bool bScreenActive = false;
|
|
if ( m_hVGUIScreen != NULL )
|
|
{
|
|
bScreenActive = m_hVGUIScreen->IsActive();
|
|
}
|
|
|
|
return bScreenActive;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Either become the master of a group of screens, or become a slave to another
|
|
//-----------------------------------------------------------------------------
|
|
void CMovieDisplayScreen::SetupMovie( void )
|
|
{
|
|
// Only bother if we haven't been setup yet
|
|
if ( m_bInitialized || !IsActive() )
|
|
return;
|
|
|
|
#if defined( _GAMECONSOLE )
|
|
Assert( bik );
|
|
#endif
|
|
|
|
if ( !bik )
|
|
return;
|
|
|
|
CMovieDisplayScreen *pMasterScreen = NULL;
|
|
for ( int i = 0; i < g_MovieDisplays.Count(); i++ )
|
|
{
|
|
// Must be a valid peer and not be us
|
|
if ( !IsAGroupPeer( g_MovieDisplays[i] ) || g_MovieDisplays[i] == this )
|
|
continue;
|
|
|
|
// See if we've found a master display
|
|
if ( g_MovieDisplays[i]->m_bInitialized && g_MovieDisplays[i]->m_bSlaved == false )
|
|
{
|
|
m_bSlaved = true;
|
|
|
|
// Share the info from the master
|
|
m_playbackInfo = g_MovieDisplays[i]->m_playbackInfo;
|
|
|
|
// We need to calculate our own playback dimensions as we may be a different size than our parent
|
|
CalculatePlaybackDimensions( m_playbackInfo.m_nSourceWidth, m_playbackInfo.m_nSourceHeight );
|
|
|
|
// Bind our texture
|
|
m_nTextureId = surface()->CreateNewTextureID( true );
|
|
g_pMatSystemSurface->DrawSetTextureMaterial( m_nTextureId, m_playbackInfo.m_pMaterial );
|
|
|
|
// Hold this as the master screen
|
|
pMasterScreen = g_MovieDisplays[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// We need to try again, we have no screen entity!
|
|
if ( m_hScreenEntity == NULL )
|
|
return;
|
|
|
|
// No master found, become one
|
|
if ( pMasterScreen == NULL && !m_hScreenEntity->IsForcedSlave() )
|
|
{
|
|
const char *szFilename = m_hScreenEntity->GetMovieFilename();
|
|
BeginPlayback( szFilename );
|
|
m_bSlaved = false;
|
|
m_bInitialized = true; // we are the new master - we are done
|
|
}
|
|
else if ( pMasterScreen != NULL ) // we are a slave then we are done.
|
|
{
|
|
m_bInitialized = true;
|
|
}
|
|
}
|
|
|
|
bool CMovieDisplayScreen::IsAGroupPeer( CMovieDisplayScreen* pScreen )
|
|
{
|
|
// Must be valid
|
|
if ( pScreen == NULL )
|
|
return false;
|
|
|
|
// Must have an associated movie entity
|
|
if ( pScreen->m_hScreenEntity == NULL )
|
|
return false;
|
|
|
|
// Must have a group name to care
|
|
const char *szGroupName = m_hScreenEntity->GetGroupName();
|
|
if ( szGroupName[0] == NULL )
|
|
return false;
|
|
|
|
// Group names must match!
|
|
// FIXME: Use an ID instead?
|
|
const char *szTestGroupName = pScreen->m_hScreenEntity->GetGroupName();
|
|
if ( Q_strnicmp( szTestGroupName, szGroupName, 128 ) )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Try to take over as the master for playback.
|
|
//-----------------------------------------------------------------------------
|
|
void CMovieDisplayScreen::TakeOverAsMaster( void )
|
|
{
|
|
// Tell all of the screens that are peers to us that they need to be set up again
|
|
for ( int i = 0; i < g_MovieDisplays.Count(); i++ )
|
|
{
|
|
if ( IsAGroupPeer( g_MovieDisplays[i] ) )
|
|
{
|
|
if ( g_MovieDisplays[i]->m_nTextureId != -1 )
|
|
{
|
|
g_pMatSystemSurface->DestroyTextureID( g_MovieDisplays[i]->m_nTextureId );
|
|
g_MovieDisplays[i]->m_nTextureId = -1;
|
|
}
|
|
|
|
// make it so we will reinitialize ourselves.
|
|
g_MovieDisplays[i]->m_bInitialized = false;
|
|
}
|
|
}
|
|
|
|
// Even if we don't become the master we should stop trying
|
|
m_hScreenEntity->SetMasterAttempted();
|
|
|
|
SetupMovie();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Deal with the details of the video playback
|
|
//-----------------------------------------------------------------------------
|
|
void CMovieDisplayScreen::UpdateMovie( void )
|
|
{
|
|
// Only the master in a group updates the bink file
|
|
if ( m_bSlaved )
|
|
return;
|
|
|
|
// Must have a movie to play
|
|
if ( m_BIKHandle == BIKHANDLE_INVALID )
|
|
return;
|
|
|
|
// Get the current activity state of the screen
|
|
bool bScreenActive = IsActive();
|
|
|
|
// Pause if the game has paused
|
|
bool bPaused = ( engine->IsPaused() || engine->Con_IsVisible() );
|
|
if ( bPaused )
|
|
{
|
|
bScreenActive = false;
|
|
}
|
|
|
|
// See if we've changed our activity state
|
|
if ( bik && bScreenActive != m_bLastActiveState )
|
|
{
|
|
if ( bScreenActive )
|
|
{
|
|
if ( /*m_bRestartOnResume*/ 1 && !bPaused )
|
|
{
|
|
bik->SetFrame( m_BIKHandle, 1.0f );
|
|
}
|
|
|
|
bik->Unpause( m_BIKHandle );
|
|
}
|
|
else
|
|
{
|
|
bik->Pause( m_BIKHandle );
|
|
}
|
|
}
|
|
|
|
// Updated
|
|
m_bLastActiveState = bScreenActive;
|
|
|
|
// Update the frame if we're currently enabled
|
|
if ( bScreenActive )
|
|
{
|
|
// Update our frame
|
|
if ( bik && bik->Update( m_BIKHandle ) == false )
|
|
{
|
|
// Issue a close command
|
|
// OnVideoOver();
|
|
// StopPlayback();
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Update the display string
|
|
//-----------------------------------------------------------------------------
|
|
void CMovieDisplayScreen::OnTick()
|
|
{
|
|
BaseClass::OnTick();
|
|
|
|
if( m_hScreenEntity && m_hScreenEntity->GetWantsToBeMaster() )
|
|
{
|
|
TakeOverAsMaster();
|
|
}
|
|
|
|
// Create our playback or slave to another screen already playing
|
|
SetupMovie();
|
|
|
|
// Now update the movie
|
|
UpdateMovie();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Adjust the playback dimensions to properly account for our screen dimensions
|
|
//-----------------------------------------------------------------------------
|
|
void CMovieDisplayScreen::CalculatePlaybackDimensions( int nSrcWidth, int nSrcHeight )
|
|
{
|
|
// Change our stretching type
|
|
if ( m_hScreenEntity && m_hScreenEntity->IsStretchingToFill() )
|
|
{
|
|
m_nPlaybackWidth = GetWide();
|
|
m_nPlaybackHeight = GetTall();
|
|
return;
|
|
}
|
|
|
|
float flFrameRatio = ( (float) GetWide() / (float) GetTall() );
|
|
float flVideoRatio = ( (float) nSrcWidth / (float) nSrcHeight );
|
|
|
|
if ( flVideoRatio > flFrameRatio )
|
|
{
|
|
m_nPlaybackWidth = GetWide();
|
|
m_nPlaybackHeight = ( GetWide() / flVideoRatio );
|
|
}
|
|
else if ( flVideoRatio < flFrameRatio )
|
|
{
|
|
m_nPlaybackWidth = ( GetTall() * flVideoRatio );
|
|
m_nPlaybackHeight = GetTall();
|
|
}
|
|
else
|
|
{
|
|
m_nPlaybackWidth = GetWide();
|
|
m_nPlaybackHeight = GetTall();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Begins playback of a movie
|
|
// Output : Returns true on success, false on failure.
|
|
//-----------------------------------------------------------------------------
|
|
bool CMovieDisplayScreen::BeginPlayback( const char *pFilename )
|
|
{
|
|
#if defined( _GAMECONSOLE )
|
|
Assert( bik );
|
|
#endif
|
|
|
|
if ( !bik )
|
|
return false;
|
|
|
|
if ( m_BIKHandle == BIKHANDLE_INVALID )
|
|
{
|
|
// Create a globally unique name for this material
|
|
char szMaterialName[256];
|
|
|
|
// Append our group name if we have one
|
|
const char *szGroupName = m_hScreenEntity->GetGroupName();
|
|
if ( szGroupName[0] != NULL )
|
|
{
|
|
Q_snprintf( szMaterialName, sizeof(szMaterialName), "%s_%s", pFilename, szGroupName );
|
|
}
|
|
else
|
|
{
|
|
Q_strncpy( szMaterialName, pFilename, sizeof(szMaterialName) );
|
|
}
|
|
|
|
// Load and create our BINK video
|
|
int nFlags = BIK_NO_AUDIO; // FIXME: Allow?
|
|
|
|
nFlags |= BIK_PRELOAD;
|
|
if ( m_hScreenEntity->IsLooping() )
|
|
{
|
|
nFlags |= BIK_LOOP;
|
|
}
|
|
|
|
if ( bik )
|
|
m_BIKHandle = bik->CreateMaterial( szMaterialName, pFilename, "GAME", nFlags );
|
|
if ( m_BIKHandle == BIKHANDLE_INVALID )
|
|
return false;
|
|
}
|
|
|
|
// NOTE: This class shouldn't turn off all sounds (Bank)
|
|
//if ( ( nFlags & BIK_NO_AUDIO ) != 0 )
|
|
//{
|
|
// // We want to be the sole audio source
|
|
// enginesound->NotifyBeginMoviePlayback();
|
|
//}
|
|
|
|
// Get our basic info from the movie
|
|
bik->GetFrameSize( m_BIKHandle, &m_playbackInfo.m_nSourceWidth, &m_playbackInfo.m_nSourceHeight );
|
|
bik->GetTexCoordRange( m_BIKHandle, &m_playbackInfo.m_flU, &m_playbackInfo.m_flV );
|
|
m_playbackInfo.m_pMaterial = bik->GetMaterial( m_BIKHandle );
|
|
|
|
// Get our playback dimensions
|
|
CalculatePlaybackDimensions( m_playbackInfo.m_nSourceWidth, m_playbackInfo.m_nSourceHeight );
|
|
|
|
// Bind our texture
|
|
m_nTextureId = surface()->CreateNewTextureID( true );
|
|
g_pMatSystemSurface->DrawSetTextureMaterial( m_nTextureId, m_playbackInfo.m_pMaterial );
|
|
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Update and draw the frame
|
|
//-----------------------------------------------------------------------------
|
|
void CMovieDisplayScreen::Paint( void )
|
|
{
|
|
// Masters must keep the video updated
|
|
if ( m_bSlaved == false && m_BIKHandle == BIKHANDLE_INVALID )
|
|
{
|
|
BaseClass::Paint();
|
|
return;
|
|
}
|
|
|
|
// Sit in the "center"
|
|
int xpos, ypos;
|
|
GetPanelPos( xpos, ypos );
|
|
|
|
bool bStretchToFill = ( m_hScreenEntity != NULL ) ? m_hScreenEntity->IsStretchingToFill() : false;
|
|
bool bUsingCustomUVs = ( m_hScreenEntity != NULL ) ? m_hScreenEntity->IsUsingCustomUVs() : false;
|
|
|
|
// Black out the background (we could omit drawing under the video surface, but this is straight-forward)
|
|
if ( m_bBlackBackground && !bStretchToFill )
|
|
{
|
|
surface()->DrawSetColor( 0, 0, 0, 255 );
|
|
surface()->DrawFilledRect( 0, 0, GetWide(), GetTall() );
|
|
}
|
|
|
|
// Draw it
|
|
surface()->DrawSetTexture( m_nTextureId );
|
|
surface()->DrawSetColor( 255, 255, 255, 255 );
|
|
|
|
if ( bUsingCustomUVs )
|
|
{
|
|
surface()->DrawTexturedSubRect( xpos, ypos, xpos+m_nPlaybackWidth, ypos+m_nPlaybackHeight,
|
|
m_hScreenEntity->GetUMin(),
|
|
m_hScreenEntity->GetVMin(),
|
|
m_hScreenEntity->GetUMax(),
|
|
m_hScreenEntity->GetVMax() );
|
|
}
|
|
else
|
|
{
|
|
surface()->DrawTexturedSubRect( xpos, ypos, xpos+m_nPlaybackWidth, ypos+m_nPlaybackHeight, 0.f, 0.f, m_playbackInfo.m_flU, m_playbackInfo.m_flV );
|
|
}
|
|
|
|
// Parent's turn
|
|
BaseClass::Paint();
|
|
}
|