//-----------------------------------------------------------------------------
// File: XMVPlayer.cpp
//
// Desc: Example use of playing XMV content
//
// Hist: 2.7.03 - Created
//
//          XMV playback has a few principle variations:
//              Playing to a texture or to the overlay planes
//              Using the packet interface to read the file, using packets to copy from
//              memory, or letting XMV do the reading.
//              Using Play() to play the entire movie, or GetNextFrame
//              Unpacking to an RGB or YUV texture
//              Playing full screen or on just part of the screen
//
//          If these could be combined arbitrarily this would give us dozens of combinations.
//          A few of the combinations don't make sense - overlay planes are always YUV,
//          Play() always uses the overlay planes, etc.
//
//          Many of these variations - such as using CreateDecoderForFile versus
//          CreateDecoderForPackets - do not affect other aspects of playback, so the
//          different variations can be mixed without difficulty.
//
//          This sample tries to show all sensible combinations of these possibilities
//
//          When playing to an overlay plane this sample also demonstrates placing other
//          graphics above the movie being played.
//
//          The playback logic is encapsulated in the XMVHelper class, so the actual
//          playback process is pretty simple.
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------


#include <XBApp.h>
#include <XBFont.h>
#include <XBHelp.h>
#include <xgraphics.h>
#include <string>
using namespace std;

#include <xmv.h>
#include "XMVHelper.h"
float fLeft=1127.939941;
float fRight=1639.070068;
float fTop=269.890015;
float fBottom=660.219971;
float fLeftMenu=1127.939941;
float fRightMenu=1639.070068;
float fTopMenu=269.890015;
float fBottomMenu=660.219971;
float fDualLeft=1127.939941;
float fDualRight=1639.070068;
float fDualTop=269.890015;
float fDualBottom=660.219971;
extern string activeMovie;
//FLOAT fLeftMM   = 10+100;//fOriginX;
//FLOAT fRightMM  = 266+100;//fOriginX + ( fSizeY * fMovieWidth) / fMovieHeight;
//FLOAT fTopMM    = 10+100;//fOriginY;
//FLOAT fBottomMM = 266+100;//fOriginY + fSizeY;

extern IDirect3DDevice8 *Device;
extern int GUIState;
extern int OptionGUIImageSelected;
extern IDirect3DTexture8 *TexPreview;

//-----------------------------------------------------------------------------
// Name: g_colorKey
// Desc: Used when color keying is enabled
//-----------------------------------------------------------------------------
const D3DCOLOR g_colorKey = D3DCOLOR_ARGB( 0xFF, 0x3F, 0x00, 0x3F );

//-----------------------------------------------------------------------------
// Name: g_fullScreenRect and g_partialScreenRect
// Desc: Rectangles to use when playing movies full or partial screen.
//-----------------------------------------------------------------------------
const RECT g_fullScreenRect = { 0, 0, 640, 480 };
const RECT g_partialScreenRect = { 160, 120, 480, 360 };


//extern "C" int dprintf(char *format, ...);

//-----------------------------------------------------------------------------
// Name: class CXMVBoxSample
// Desc: Main class to run this application. Most functionality is inherited
//       from the CXBApplication base class.
//-----------------------------------------------------------------------------

class CXMVBoxSample 
{
public:
    enum READ_METHOD
    {
        READ_FROM_FILE,     // Read from a file using CreateDecoderForFile
        READ_FROM_PACKETS,  // Read from a file using CreateDecoderForPackets
        READ_FROM_MEMORY,   // Read from a block of memory
        READ_METHOD_COUNT   // Number of READ_METHOD enums
    };

    CXBFont         m_Font;                 // Font object
    CXMVPlayer      m_player;               // Movie player object
    READ_METHOD     m_readMethod;           // Controls how the movie data is read.
    BOOL            m_bYUV;                 // Unpack to a YUV or RGB texture - using an overlay requires YUV
    BOOL            m_bUseTextures;         // Render to a texture or an overlay - using Play() requires an overlay
    BOOL            m_bUsePlay;             // Use the Play() or GetNextFrame() method to play the movie
    BOOL            m_bUseColorKey;         // Use a colorkey - requires an overlay
    BOOL            m_bFullScreen;          // Should we play full screen or just partial?

    HRESULT PlayVideoWithPlay( const CHAR* strFilename );
    HRESULT PlayVideoWithGetNextFrame( const CHAR* strFilename );
    BOOL    PlayVideoFrame();           // Play a frame from a video, if one is playing.
    HRESULT OpenMovie( const CHAR* strFilename, D3DFORMAT format, BOOL allocateTextures );

public:
    virtual HRESULT Render();
    virtual HRESULT Init(char*);

    CXMVBoxSample();
};



//-----------------------------------------------------------------------------
// Name: CXMVBoxSample
// Desc: Constructor for CXMVBoxSample class
//-----------------------------------------------------------------------------
CXMVBoxSample::CXMVBoxSample() 
         
{
    m_bFullScreen =         FALSE;
    m_readMethod =          READ_FROM_PACKETS;
    m_bYUV =                TRUE;
    m_bUseTextures =        TRUE;
    m_bUsePlay =            FALSE;
    m_bUseColorKey =        FALSE;
}


//-----------------------------------------------------------------------------
// Name: FrameMove
// Desc: Performs per-frame updates
//-----------------------------------------------------------------------------
HRESULT CXMVBoxSample::Init(char* name)
{
	const char* strMovieName = name;//"D:\\Media\\Videos\\Test.xmv";

	if ( m_player.IsPlaying() )
	{
		// Halt movie playback
		m_player.Destroy();
	}
	
	return PlayVideoWithGetNextFrame( strMovieName );
}




//-----------------------------------------------------------------------------
// Name: Render
// Desc: Renders the scene
//-----------------------------------------------------------------------------
HRESULT CXMVBoxSample::Render()
{
    PlayVideoFrame();
    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: OpenMovie()
// Desc: Open a movie file in one of the three supported ways.
//-----------------------------------------------------------------------------
HRESULT CXMVBoxSample::OpenMovie( const CHAR* strFilename, D3DFORMAT format, BOOL bAllocateTextures )
{
	bAllocateTextures = TRUE;
    HRESULT hr = E_FAIL;
    switch ( m_readMethod )
    {
        case READ_FROM_FILE:
            hr = m_player.OpenFile( strFilename, format, Device, bAllocateTextures );
            break;
        case READ_FROM_PACKETS:
            hr = m_player.OpenFileForPackets( strFilename, format, Device, bAllocateTextures  );
            break;
        case READ_FROM_MEMORY:
            hr = m_player.OpenMovieFromMemory( strFilename, format, Device, bAllocateTextures  );
            break;
    }
    return hr;
}




//-----------------------------------------------------------------------------
// Name: MoviePlayerThread()
// Desc: This function is used in a separate thread so that the main thread can
// do other tasks, such as loading data, or just checking for the user to press A.
// Alternately the movie can be played in the main thread, with a sub-thread
// to check for button presses.
//-----------------------------------------------------------------------------
DWORD __stdcall MoviePlayerThread( void* pMovieData )
{
    assert( pMovieData );
    CXMVPlayer *pPlayer = ( CXMVPlayer* )pMovieData;

    // Play the movie
    // Can also be played in a subrectangle by specifying a rectangle, but that
    // rarely makes sense with the Play() interface.
    pPlayer->Play( XMVFLAG_NONE, 0 );

    return 0;
}




//-----------------------------------------------------------------------------
// Name: SimplePlayVideo()
// Desc: Plays specified video file.
//-----------------------------------------------------------------------------
HRESULT CXMVBoxSample::PlayVideoWithPlay( const CHAR* strFilename )
{
    // When using Play(), which uses overlays, we have to use D3DFMT_YUY2
    D3DFORMAT format = D3DFMT_YUY2;

    // We can use the file or memory or packet interface - it doesn't matter.
    HRESULT hr = OpenMovie( strFilename, format, FALSE );
    if ( FAILED( hr ) )
        return hr;

    // Start the movie stopping thread - this should always succeed.
    HANDLE hThread = CreateThread( 0, 0, &MoviePlayerThread, &m_player, 0, 0 );

    // Loop waiting for the user to press A or the movie to exit.
    // Resource loading or other activity can be placed here.
    for ( ;; )
    {
        // Wait a little while, or until the movie thread exits.
        // Can do useful work here.
        DWORD waitResult = WaitForSingleObject( hThread, 1000 / 60 );

        // WAIT_OBJECT_0 means the thread exited and we should exit.
        if ( waitResult == WAIT_OBJECT_0 )
            break;

        // Refresh the input data.
        XBInput_GetInput( g_Gamepads );

        // See if the user has pressed A on any of the controllers.
        for ( int i = 0; i < ( sizeof( g_Gamepads ) / sizeof( g_Gamepads[0] ) ); ++i )
        {
            if( g_Gamepads[i].bPressedAnalogButtons[XINPUT_GAMEPAD_A] )
            {
                // If the user presses A, terminate the currently playing movie.
                // This may take a few hundred milliseconds.
                m_player.TerminatePlayback();
                goto exit;
            }
        }
    }

exit:
    // We have to make sure the thread is terminated *before* we close the movie
    // decoder, to make sure it has stopped referencing the movie player object.

    // Wait for the thread to terminate.
    WaitForSingleObject( hThread, INFINITE );

    // Clean up our thread handles to free all thread resources.
    // This has to be done after we finish waiting on the handle.
    CloseHandle( hThread );

    // Free all movie playback resources.
    m_player.Destroy();

    return hr;
}




//-----------------------------------------------------------------------------
// Name: TexturePlayVideo()
// Desc: Plays specified video file on a texture.
//-----------------------------------------------------------------------------
HRESULT CXMVBoxSample::PlayVideoWithGetNextFrame( const CHAR* strFilename )
{
    assert( !m_player.IsPlaying() );

    // If we're not currently playing a movie then start playing one.
    D3DFORMAT format = D3DFMT_YUY2;
   
    if ( !m_bYUV )
    {
        // The only non-YUV formats allowed are D3DFMT_LIN_A8R8G8B8 and D3DFMT_LIN_X8R8G8B8
        format = D3DFMT_LIN_A8R8G8B8;
    }
   
    // We can use the file or memory or packet interface - it doesn't matter.
    HRESULT hr = OpenMovie( strFilename, format, TRUE );

    return hr;
}




//-----------------------------------------------------------------------------
// Name: PlayVideoFrame()
// Desc: Plays one frame of video if a movie is currently open and if there is
// a frame available. This function is safe to call at any time.
//-----------------------------------------------------------------------------
BOOL CXMVBoxSample::PlayVideoFrame()
{
	if ( !m_player.IsPlaying() ) {
			
			m_player.Destroy();
			Init((char*)activeMovie.c_str());//(char*)a.c_str());
			return FALSE;
	}

	const FLOAT fMovieWidth = FLOAT( m_player.GetWidth() );
	const FLOAT fMovieHeight = FLOAT( m_player.GetHeight() );

	// Move to the next frame.
	LPDIRECT3DTEXTURE8 movieTexture = 0;
	movieTexture = m_player.AdvanceFrameForTexturing( Device );

	// See if the movie is over now.
	if ( !m_player.IsPlaying() )
	{
		// Clean up the movie, then return.
		m_player.Destroy();
		//if(screenResizeMV == 1) Init("D:\\media\\preview.xmv");
		//if(screenOptionsM == 1) {
			m_player.Destroy();
			
			Init((char*)activeMovie.c_str());//Init((char*)a.c_str());
		//}

		//if(vgplaying == 1) 
		//	resumeVGMusic();
		//else 
		//	resumeMusic();

		return FALSE;
	}

	// If no texture is ready, return TRUE to indicate that a movie is playing,
	// but don't render anything yet.
	if ( !movieTexture )
		return TRUE;


	// Have the texture start small and scale up, just to prove it's on
	// a texture.
	const DWORD FRAMES_TO_EASE_IN = 40;
	FLOAT fRatio = 1.0;
	if ( m_player.GetCurrentFrame() < FRAMES_TO_EASE_IN )
		fRatio = FLOAT( m_player.GetCurrentFrame() ) / FRAMES_TO_EASE_IN;



	// Draw the texture.
	Device->SetRenderState( D3DRS_FILLMODE,         D3DFILL_SOLID );
	Device->SetRenderState( D3DRS_CULLMODE,         D3DCULL_CCW );
	Device->SetRenderState( D3DRS_ZENABLE,          FALSE );

	// Draw the texture as a quad.
	Device->SetTexture( 0, movieTexture );
	Device->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );
	Device->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );

	// Wrapping isn't allowed on linear textures.
	Device->SetTextureStageState( 0, D3DTSS_ADDRESSU,  D3DTADDRESS_CLAMP );
	Device->SetTextureStageState( 0, D3DTSS_ADDRESSV,  D3DTADDRESS_CLAMP );

	// If we're unpacking to a YUV surface we have to tell the hardware that we
	// are rendering from a YUV surface.
	if ( m_bYUV )
		Device->SetRenderState( D3DRS_YUVENABLE, TRUE );

	

	// On linear textures the texture coordinate range is from 0,0 to width,height, instead
	// of 0,0 to 1,1.
	Device->SetVertexShader( D3DFVF_XYZRHW|D3DFVF_TEX1 );
	Device->Begin( D3DPT_QUADLIST );
	
	
	if(GUIState == 0 || GUIState == 31) { // || screenResizeMV_MM == 1) {
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, fMovieHeight );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fLeftMenu,  fBottomMenu, 0.0f, 1.0f );
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, 0 );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fLeftMenu,  fTopMenu,    0.0f, 1.0f );
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, 0 );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fRightMenu, fTopMenu,    0.0f, 1.0f );
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, fMovieHeight );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fRightMenu, fBottomMenu, 0.0f, 1.0f );
	}

	if(GUIState == 30 || GUIState == 34) { //30
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, fMovieHeight );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fLeft,  fBottom, 0.0f, 1.0f );
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, 0 );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fLeft,  fTop,    0.0f, 1.0f );
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, 0 );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fRight, fTop,    0.0f, 1.0f );
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, fMovieHeight );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fRight, fBottom, 0.0f, 1.0f );
	}

	if(GUIState == 56 || GUIState == 57 || GUIState == 28 || GUIState == 32 || GUIState == 44 || GUIState == 45) {
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, fMovieHeight );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fDualLeft,  fDualBottom, 0.0f, 1.0f );
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, 0 );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fDualLeft,  fDualTop,    0.0f, 1.0f );
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, 0 );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fDualRight, fDualTop,    0.0f, 1.0f );
		Device->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, fMovieHeight );
		Device->SetVertexData4f( D3DVSDE_VERTEX, fDualRight, fDualBottom, 0.0f, 1.0f );
	}

	if(GUIState == 1 || GUIState == 2) {
		if(TexPreview) {
			Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, fMovieHeight );
			Device->SetVertexData4f( D3DVSDE_VERTEX, fDualLeft,  fDualBottom, 0.0f, 1.0f );
			Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, 0 );
			Device->SetVertexData4f( D3DVSDE_VERTEX, fDualLeft,  fDualTop,    0.0f, 1.0f );
			Device->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, 0 );
			Device->SetVertexData4f( D3DVSDE_VERTEX, fDualRight, fDualTop,    0.0f, 1.0f );
			Device->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, fMovieHeight );
			Device->SetVertexData4f( D3DVSDE_VERTEX, fDualRight, fDualBottom, 0.0f, 1.0f );
		}
		else {
			Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, fMovieHeight );
			Device->SetVertexData4f( D3DVSDE_VERTEX, fLeft,  fBottom, 0.0f, 1.0f );
			Device->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, 0 );
			Device->SetVertexData4f( D3DVSDE_VERTEX, fLeft,  fTop,    0.0f, 1.0f );
			Device->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, 0 );
			Device->SetVertexData4f( D3DVSDE_VERTEX, fRight, fTop,    0.0f, 1.0f );
			Device->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, fMovieHeight );
			Device->SetVertexData4f( D3DVSDE_VERTEX, fRight, fBottom, 0.0f, 1.0f );
		}
	}

	Device->End();

	// If we switched to YUV texturing then we need to switch back.
	if ( m_bYUV )
		Device->SetRenderState( D3DRS_YUVENABLE, FALSE );

	return TRUE;
}

CXMVBoxSample moviePlayer;
extern bool videoRender;
//extern int inGame;
//extern bool videoRender;
//extern int vgplaying;
//extern void pauseVGMusic();
//extern void pauseMusic();
//extern void resumeVGMusic();
//extern void resumeMusic();
extern "C" int dprintf(char *format, ...);
bool initMovie(char* name) {
	dprintf("Start Movie: %s\n", name);
	if(FAILED(moviePlayer.Init(name))) {
		videoRender = false;
		activeMovie = "";
		/*
		activeMovie = "D:\\Preview.xmv";

		if(vgplaying == 1) {
			resumeVGMusic();
		}
		else {
			resumeMusic();
		}*/
		return false;
	}
	videoRender = true;
	activeMovie = name;
	return true;
}

void drawMovie() {

	moviePlayer.Render();
}

bool getPlaying() {
	return moviePlayer.m_player.IsPlaying();
}


void stopMovie() {
	videoRender = false;
	if ( moviePlayer.m_player.IsPlaying() )
	{
		moviePlayer.m_player.Destroy();
	}	
}
