text: //========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose: VGUI panel which can play back video, in-engine
  //
  //=============================================================================
  
  #include "cbase.h"
  #include <vgui/IVGui.h>
  #include "vgui/IInput.h"
  #include <vgui/ISurface.h>
  #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);
  }
  