//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: VGUI panel which can play back video, in-engine // //============================================================================= #include "cbase.h" #include #include "vgui/IInput.h" #include #include "ienginevgui.h" #include "iclientmode.h" #include "vgui_video_player.h" #include "engine/IEngineSound.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" VideoPlayerPanel::VideoPlayerPanel( vgui::Panel *parent, const char *panelName, int nXpos, int nYpos, int nWidth, int nHeight, const char *pVideoFile ) : BaseClass( parent, panelName ), m_VideoMaterial( NULL ), m_VideoFileName( NULL ), m_VideoLoaded( false ), m_VideoPlaying( false ) { Assert( g_pVideo != NULL ); // init all the video realted member vars ClearVideo(); SetVisible( false ); SetKeyBoardInputEnabled( false ); SetMouseInputEnabled( false ); SetProportional( false ); SetPaintBackgroundEnabled( false ); SetPaintBorderEnabled( false ); // Set us up SetTall( nHeight ); SetWide( nWidth ); SetPos( nXpos, nYpos ); // use defaults for scheme and control settings for now // SetScheme( vgui::scheme()->LoadSchemeFromFile( "resource/VideoPlayerPanelScheme.res", "VideoPlayerPanelScheme")); //LoadControlSettings("resource/UI/VideoPlayerPanel.res"); // Assign video file if supplied SetVideo( pVideoFile ); SetVisible( true ); } //----------------------------------------------------------------------------- // Properly shutdown out materials //----------------------------------------------------------------------------- VideoPlayerPanel::~VideoPlayerPanel( void ) { SetParent( (vgui::Panel *) NULL ); StopVideo(); ClearVideo(); } bool VideoPlayerPanel::SetVideo( const char *pVideoFile ) { ClearVideo(); // clearing the video? if ( pVideoFile == NULL || pVideoFile[0] == 0x00 ) { return true; } // create the material m_VideoMaterial = g_pVideo->CreateVideoMaterial( "VideoPlayerMaterial", pVideoFile, "GAME", VideoPlaybackFlags::DEFAULT_MATERIAL_OPTIONS, VideoSystem::DETERMINE_FROM_FILE_EXTENSION, true ); if ( m_VideoMaterial == NULL ) { return false; } // save filename int sLen = V_strlen( pVideoFile ) + 1; m_VideoFileName = new char[ sLen ]; V_strncpy( m_VideoFileName, pVideoFile, sLen ); // compute Playback dimensions int nWidth, nHeight; m_VideoMaterial->GetVideoImageSize( &nWidth, &nHeight ); m_VideoMaterial->GetVideoTexCoordRange( &m_flU, &m_flV ); float flFrameRatio = ( (float) GetWide() / (float) GetTall() ); float flVideoRatio = ( (float) nWidth / (float) nHeight ); if ( flVideoRatio > flFrameRatio ) { m_nPlaybackWidth = GetWide(); m_nPlaybackHeight = ( GetWide() / flVideoRatio ); m_letterBox = 1; } else if ( flVideoRatio < flFrameRatio ) { m_nPlaybackWidth = ( GetTall() * flVideoRatio ); m_nPlaybackHeight = GetTall(); m_letterBox = 2; } else { m_nPlaybackWidth = GetWide(); m_nPlaybackHeight = GetTall(); m_letterBox = 0; } m_pMaterial = m_VideoMaterial->GetMaterial(); m_VideoDuration = m_VideoMaterial->GetVideoDuration(); m_VideoLoaded = true; return true; } void VideoPlayerPanel::ClearVideo() { if ( m_VideoPlaying ) { StopVideo(); } // Shut down this video, destroy the video material if ( g_pVideo != NULL && m_VideoMaterial != NULL ) { g_pVideo->DestroyVideoMaterial( m_VideoMaterial ); m_VideoMaterial = NULL; } if ( m_VideoFileName != NULL ) { delete[] m_VideoFileName; m_VideoFileName = NULL; } m_pMaterial = NULL; m_VideoLoaded = false; m_VideoPlaying = false; m_VideoPaused = false; m_nPlaybackHeight = 0; m_nPlaybackWidth = 0; m_letterBox = 0; m_flU = 0.0f; m_flV = 0.0f; m_VideoDuration = 0.0f; } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void VideoPlayerPanel::Activate( void ) { MoveToFront(); RequestFocus(); SetVisible( true ); SetEnabled( true ); vgui::surface()->SetMinimized( GetVPanel(), false ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void VideoPlayerPanel::OnClose( void ) { StopVideo(); // enginesound->NotifyEndMoviePlayback(); vgui::surface()->RestrictPaintToSinglePanel( NULL ); SetVisible( false ); MarkForDeletion(); } //----------------------------------------------------------------------------- // Purpose: Update and draw the frame //----------------------------------------------------------------------------- void VideoPlayerPanel::Paint( void ) { BaseClass::Paint(); // Get our dimensions int xpos = 0; int ypos = 0; vgui::ipanel()->GetAbsPos( GetVPanel(), xpos, ypos ); // GetPanelPos( xpos, ypos ); int width = GetWide(); int height = GetTall(); // Are we playing the video? Do we even have a video? if ( !m_VideoLoaded || !m_VideoPlaying ) { vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); vgui::surface()->DrawFilledRect( 0, 0, width, height ); return; } if ( m_VideoMaterial == NULL ) return; if ( m_VideoMaterial->Update() == false ) { StopVideo(); return; } // Black out the letterbox ares if we have them if ( m_letterBox != 0 ) { vgui::surface()->DrawSetColor( 0, 0, 0, 255 ); if ( m_letterBox == 1 ) // bars on top, bottom { int excess = ( height - m_nPlaybackHeight ); int top = excess /2; int bot = excess - top; vgui::surface()->DrawFilledRect( 0, 0, width, top ); vgui::surface()->DrawFilledRect( 0, height - bot, width, height ); } if ( m_letterBox == 2 ) // bars on left, right { int excess = ( width - m_nPlaybackWidth ); int left = excess /2; int right = excess - left; vgui::surface()->DrawFilledRect( 0, 0, left, height ); vgui::surface()->DrawFilledRect( width-right, 0, width, height ); } } // Draw the polys to draw this out CMatRenderContextPtr pRenderContext( materials ); pRenderContext->MatrixMode( MATERIAL_VIEW ); pRenderContext->PushMatrix(); pRenderContext->LoadIdentity(); pRenderContext->MatrixMode( MATERIAL_PROJECTION ); pRenderContext->PushMatrix(); pRenderContext->LoadIdentity(); pRenderContext->Bind( m_pMaterial, NULL ); CMeshBuilder meshBuilder; IMesh* pMesh = pRenderContext->GetDynamicMesh( true ); meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); float flLeftX = xpos; float flRightX = xpos + ( m_nPlaybackWidth-1 ); float flTopY = ypos; float flBottomY = ypos + ( m_nPlaybackHeight-1 ); // Map our UVs to cut out just the portion of the video we're interested in float flLeftU = 0.0f; float flTopV = 0.0f; // We need to subtract off a pixel to make sure we don't bleed float flRightU = m_flU - ( 1.0f / (float) m_nPlaybackWidth ); float flBottomV = m_flV - ( 1.0f / (float) m_nPlaybackHeight ); // Get the current viewport size int vx, vy, vw, vh; pRenderContext->GetViewport( vx, vy, vw, vh ); // map from screen pixel coords to -1..1 flRightX = FLerp( -1, 1, 0, vw, flRightX ); flLeftX = FLerp( -1, 1, 0, vw, flLeftX ); flTopY = FLerp( 1, -1, 0, vh ,flTopY ); flBottomY = FLerp( 1, -1, 0, vh, flBottomY ); float alpha = ((float)GetFgColor()[3]/255.0f); for ( int corner=0; corner<4; corner++ ) { bool bLeft = (corner==0) || (corner==3); meshBuilder.Position3f( (bLeft) ? flLeftX : flRightX, (corner & 2) ? flBottomY : flTopY, 0.0f ); meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f ); meshBuilder.TexCoord2f( 0, (bLeft) ? flLeftU : flRightU, (corner & 2) ? flBottomV : flTopV ); meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f ); meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f ); meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, alpha ); meshBuilder.AdvanceVertex(); } meshBuilder.End(); pMesh->Draw(); pRenderContext->MatrixMode( MATERIAL_VIEW ); pRenderContext->PopMatrix(); pRenderContext->MatrixMode( MATERIAL_PROJECTION ); pRenderContext->PopMatrix(); } bool VideoPlayerPanel::StartVideo() { if ( !m_VideoLoaded ) return false; // already playing? if ( m_VideoPlaying ) { // paused? if ( m_VideoPaused ) { return UnpauseVideo(); } return true; } m_VideoPlaying = m_VideoMaterial->StartVideo(); return m_VideoPlaying; } bool VideoPlayerPanel::StopVideo() { if ( !m_VideoLoaded || !m_VideoPlaying ) return false; m_VideoMaterial->StopVideo(); m_VideoPlaying = false; return true; } bool VideoPlayerPanel::PauseVideo() { if ( !m_VideoLoaded || !m_VideoPlaying ) return false; if ( !m_VideoPaused ) { m_VideoMaterial->SetPaused( true ); m_VideoPaused = true; } return true; } bool VideoPlayerPanel::UnpauseVideo() { if ( !m_VideoLoaded || !m_VideoPlaying ) return false; if ( m_VideoPaused ) { m_VideoMaterial->SetPaused( false ); m_VideoPaused = false; } return true; } float VideoPlayerPanel::GetCurrentPlaybackTime() { if ( !m_VideoLoaded ) { return 0.0f; } return m_VideoMaterial->GetCurrentVideoTime(); } bool VideoPlayerPanel::SetCurrentPlaybackTime( float newTime ) { if ( !m_VideoLoaded ) return false; if ( newTime < 0.0f || newTime > m_VideoDuration ) return false; return m_VideoMaterial->SetTime( newTime ); } bool VideoPlayerPanel::HasAudio() { if ( !m_VideoLoaded ) return false; return m_VideoMaterial->HasAudio(); } bool VideoPlayerPanel::IsMuted() { if ( !m_VideoLoaded ) return false; return m_VideoMaterial->IsMuted(); } bool VideoPlayerPanel::SetMute( bool muted ) { if ( !m_VideoLoaded ) return false; m_VideoMaterial->SetMuted( muted ); return true; } float VideoPlayerPanel::GetVolume() { if ( !m_VideoLoaded ) return 0.0f; return m_VideoMaterial->GetVolume(); } bool VideoPlayerPanel::SetVolume( float newVolume ) { if ( !m_VideoLoaded ) return false; return m_VideoMaterial->SetVolume( newVolume ); }