/********************************************************************
 *
 *   Author:			Robert Karlsson
 *
 *   Module:			Movie.cpp
 *
 *   $Workfile: $
 *   $Revision: 1.2 $
 *   $Date: 2000/11/18 18:23:42 $
 *
 *   Description:		Implementation of the Movie class.
 *
 *   Usage:				>>!! DONT FORGET TO LINK WITH amstrmid.lib !!<<
 *
 *                   1. Create an instance of the class
 *							2. Invoke Create() with filename of movie and with pointer to CDXSurface
 *								that the movie will render to. It will also scale the movie to fit the
 *								size of the CDXSurface. Remember to create CDXSurface first!
 *							3. Invoke Play()
 *							4. In your main game loop, call Update() and then draw the surface to the screen.
 *							5. You can stop the movie by calling Stop(), or wait until Update() returns false(movie done.)
 *							6. Invoke Destroy()
 *							7. Delete instance.
 *
 *   Dependencies:
 *
 ********************************************************************/

/*** Include files **************************************************/
#include "Movie.h"

#include <cdx.h>
#include <cdxsurface.h>
#include "mmstream.h"
#include "amstream.h"
#include "ddstream.h"

/*** Defines ********************************************************/

/*** Macros *********************************************************/

/*** Data types definitions and typedefs ****************************/

/*** Global variables ***********************************************/

/********************************************************************/
/*** Class constructor/destructor ***********************************/
/********************************************************************/
/*********************************************************************
 *
 *   Purpose:
 *
 *   Inparameters:
 *
 *   Outparameters:
 *
 *   Return value:
 *
 *   Note:
 *
 */
Movie::Movie(CDXScreen* pScreen)
{
	m_pScreen = pScreen;
}

/*********************************************************************
 *
 *   Purpose:
 *
 *   Inparameters:
 *
 *   Outparameters:
 *
 *   Return value:
 *
 *   Note:
 *
 */
Movie::~Movie()
{

}

/********************************************************************/
/*** Public Member Functions ****************************************/
/********************************************************************/
/*********************************************************************
 *
 *   Purpose:
 *
 *   Inparameters:	szFilename			Filename of the movie.
 *							pSurface				Surface to render movie on.
 *
 *   Outparameters:
 *
 *   Return value:	bool					true or false
 *
 *   Note:
 *
 */
bool Movie::Create(char *szFilename, CDXSurface *pSurface)
{
	CoInitialize( NULL );		// Initialize COM
	m_pSurface = pSurface;

	return OpenMMStream(szFilename);
}

/*********************************************************************
 *
 *   Purpose:
 *
 *   Inparameters:
 *
 *   Outparameters:
 *
 *   Return value:
 *
 *   Note:
 *
 */
bool Movie::Play()
{
	HRESULT rval;

   rval = m_pMMStream->GetMediaStream(MSPID_PrimaryVideo, &m_pPrimaryVidStream);
	if(FAILED(rval)) { return false; } //DDError(rval, NULL, __FILE__, __LINE__);

   rval = m_pPrimaryVidStream->QueryInterface(IID_IDirectDrawMediaStream, (void **)&m_pDDStream);
	if(FAILED(rval)) { return false; } //DDError(rval, NULL, __FILE__, __LINE__);

   rval = m_pDDStream->CreateSample(NULL, NULL, 0, &m_pDDStreamSample);
	if(FAILED(rval)) { return false; } //DDError(rval, NULL, __FILE__, __LINE__);

   rval = m_pDDStreamSample->GetSurface(&m_pDDSurface, &m_rectClipping);
	if(FAILED(rval)) { return false; } //DDError(rval, NULL, __FILE__, __LINE__);
   rval = m_pMMStream->SetState(STREAMSTATE_RUN);
	if(FAILED(rval)) { return false; } //DDError(rval, NULL, __FILE__, __LINE__);

	return true;
}

/*********************************************************************
 *
 *   Purpose:			Actual drawing to the surface must be done somewhere, right? :-)
 *
 *   Inparameters:
 *
 *   Outparameters:
 *
 *   Return value:	bool				true or false. true if movie done, else false.
 *
 *   Note:				Casting an IDirectDrawSurface to an IDirectDrawSurface4, might cause problems?
 *
 */
bool Movie::Update()
{
	HRESULT rval;

	if (m_pDDStreamSample->Update(0, NULL, NULL, 0) != S_OK)
	{
	    return false;
	}
	else
	{

		rval = m_pSurface->GetDDS()->Blt(NULL, // Destination rect, NULL = whole surface
	#ifndef NTDX3
										 (IDirectDrawSurface7*)
	#endif
										 m_pDDSurface,
										 &m_rectClipping,
										 DDBLT_WAIT,
										 NULL);

		if(FAILED(rval)) { return false; } //DDError(rval, NULL, __FILE__, __LINE__);

		return true;
    }
}

/*********************************************************************
 *
 *   Purpose:			Clean up
 *
 *   Inparameters:
 *
 *   Outparameters:
 *
 *   Return value:
 *
 *   Note:
 *
 */
bool Movie::Destroy()
{
	RELEASE(m_pMMStream);
	RELEASE(m_pPrimaryVidStream);
	RELEASE(m_pDDStream);
	RELEASE(m_pDDSurface);
	RELEASE(m_pDDStreamSample);

	CoUninitialize();

	return true;
}


/*********************************************************************
 *
 *   Purpose:			Guess!
 *
 *   Inparameters:
 *
 *   Outparameters:
 *
 *   Return value:
 *
 *   Note:
 *
 */
bool Movie::Stop()
{
	HRESULT rval;

	rval = m_pMMStream->SetState(STREAMSTATE_STOP);

	if(FAILED(rval)) { return false; } //DDError(rval, NULL, __FILE__, __LINE__);

	return true;


}

/********************************************************************/
/*** Protected Member Functions *************************************/
/********************************************************************/

/********************************************************************/
/*** Private Member Functions ***************************************/
/********************************************************************/
/*********************************************************************
 *
 *   Purpose:
 *
 *   Inparameters:
 *
 *   Outparameters:
 *
 *   Return value:
 *
 *   Note:
 *
 */
bool Movie::OpenMMStream(char* szFilename)
{
	HRESULT					rval;
   IAMMultiMediaStream*	pAMStream;
   WCHAR	   				wPath[MAX_PATH];


	// Create COM object
	rval = CoCreateInstance(CLSID_AMMultiMediaStream,
									NULL,
									CLSCTX_INPROC_SERVER,
			  						IID_IAMMultiMediaStream,
									(void **)&pAMStream
									);

	if(FAILED(rval)) { DDError(rval, NULL, __FILE__, __LINE__); return false; } //DDError(rval, NULL, __FILE__, __LINE__);

	rval = pAMStream->Initialize(STREAMTYPE_READ, 0, NULL);
	if(FAILED(rval)) { DDError(rval, NULL, __FILE__, __LINE__);return false; } //DDError(rval, NULL, __FILE__, __LINE__);

	rval = pAMStream->AddMediaStream(m_pScreen->GetDD(), &MSPID_PrimaryVideo, 0, NULL);
	if(FAILED(rval)) { DDError(rval, NULL, __FILE__, __LINE__);return false; } //DDError(rval, NULL, __FILE__, __LINE__);

	rval = pAMStream->AddMediaStream(NULL, &MSPID_PrimaryAudio, AMMSF_ADDDEFAULTRENDERER, NULL);
	if(FAILED(rval)) { DDError(rval, NULL, __FILE__, __LINE__);return false; } //DDError(rval, NULL, __FILE__, __LINE__);

   if(0 == MultiByteToWideChar(CP_ACP, 0, szFilename, -1, wPath, sizeof(wPath)/sizeof(wPath[0])))
	{
		return false;
	}

   rval = pAMStream->OpenFile(wPath, 0);
	if(FAILED(rval)) { DDError(rval, NULL, __FILE__, __LINE__);return false; } //DDError(rval, NULL, __FILE__, __LINE__);

   m_pMMStream = pAMStream;

	// These two lines are unnecessary? Looks like that to me
   pAMStream->AddRef();
	RELEASE(pAMStream);

	return true;
}
/*
 * $History: $
 *
 */

/* EOF */





