/*
 *
 *		Middleware MPEG Sofdec Player Sample
 *
 */

/***************************************************************************
 *      Include file
 ***************************************************************************/
#include <shinobi.h>
#include <sg_mw.h>
#include <sg_sd.h>


/***************************************************************************
 *      MACRO CONSTANT
 ***************************************************************************/
/*	Display mode	*/
#define SYS_MODE        KM_DSPMODE_NTSCI640x480
#define SYS_FRAME       KM_DSPBPP_ARGB8888
#define SYS_COUNT		1

/*	Vertex buffer size(2V latency mode is when a valiable is minus.)	*/
#define VB_OP			-500000
#define VB_OM			0
#define VB_TP			20000
#define VB_TM			0
#define VB_PT			0

#define AUDIO_SW		ON

/***************************************************************************
 *      Process MACRO
 ***************************************************************************/

/*	Turn over flag(ON/OFF)	*/
#define NOT_FLAG(flag)		(((flag) == OFF) ? ON : OFF)

/***************************************************************************
 *		Variable Declaration
 ***************************************************************************/

/*	The number of error	*/
Sint32 errcnt = 0;

/*	Pause status	*/
Sint32 pause = OFF;

/*	Flag for a show of character	*/
Sint32 disp_flag = ON;


/***************************************************************************
 *      Function Declaration
 ***************************************************************************/

/***
 *		Initialize display for movie without Ninja
 ***/

#if 0 // DjR 2/25/99
#define _SH4_
#define _CLX_
#define _FLAT_
#define _FLAT_MODEL_
#define _STRICT_UNION_
#endif

#include	"kamui.h"

KMSYSTEMCONFIGSTRUCT	sys_config;
KMSURFACEDESC			frmbuf_srfc0;
KMSURFACEDESC			frmbuf_srfc1;
PKMSURFACEDESC			srfc_array[2];

void WaitVsync(void)
{
    while (((*(volatile Uint32 *)0xa05f810c) & (Uint32)0x000001FF)!=0)
        ;
    while (((*(volatile Uint32 *)0xa05f810c) & (Uint32)0x000001FF)==0)
        ;
    return;
}

void InitSysConfig(KMVERTEXBUFFDESC *vb_desc)
{
	sys_config.dwSize = sizeof(KMSYSTEMCONFIGSTRUCT);
	sys_config.flags = KM_CONFIGFLAG_ENABLE_CLEAR_FRAMEBUFFER;
	srfc_array[0] = &frmbuf_srfc0;
	srfc_array[1] = &frmbuf_srfc1;
	sys_config.ppSurfaceDescArray = srfc_array;
	sys_config.nWidth = 0;
	sys_config.nHeight = 0;
	sys_config.nTextureMemorySize = 0x100000;

	sys_config.pBufferDesc = vb_desc;

	sys_config.pVertexBuffer = NULL;
	sys_config.nVertexBufferSize = 0;
	sys_config.fBufferSize[0] = 0.f;
	sys_config.fBufferSize[1] = 0.f;
	sys_config.fBufferSize[2] = 0.f;
	sys_config.fBufferSize[3] = 0.f;
	sys_config.fBufferSize[4] = 0.f;
	return;
}

void InitVertex(Sint32 op, Sint32 om, Sint32 tp, Sint32 tm ,Sint32 pt)
{
	Float	fvb_size;
	Uint32	vb_size;

	if( op < 0 ) {
		sys_config.flags = 0 | KM_CONFIGFLAG_ENABLE_2V_LATENCY;;
		sys_config.nVbufModel = KM_VERTEXBUFMODEL_NOBUF_OPAQUE;
		op = 100;
	}
	vb_size = op + om + tp + tm + pt;
	fvb_size = (Float)vb_size;
	sys_config.pVertexBuffer =
					(Uint32*)((Uint32)syMalloc((vb_size*4)+0x160)|0x20000000);
	sys_config.nVertexBufferSize = (vb_size+0x58);

	sys_config.fBufferSize[0] = (Float)op*100.f/fvb_size;
	sys_config.fBufferSize[1] = (Float)om*100.f/fvb_size;
	sys_config.fBufferSize[2] = (Float)tp*100.f/fvb_size;
	sys_config.fBufferSize[3] = (Float)tm*100.f/fvb_size;
	sys_config.fBufferSize[4] = (Float)pt*100.f/fvb_size;

	WaitVsync();

	kmSetSystemConfiguration(&sys_config);

	return;
}

/*	Load data to memory	*/
void *LoadFile(char *fname, long *len)
{
	GDFS			gdfs;
	long			fsize, nsct;
	void			*dat;

	gdfs = gdFsOpen(fname, NULL);
	if (gdfs == NULL) {
		for (;;) ;
	}
	gdFsGetFileSize(gdfs, &fsize);
	nsct = (fsize + 2047) / 2048;
	dat = syMalloc(nsct * 2048);
	if (dat == NULL) {
		for (;;) ;
	}
	gdFsRead(gdfs, nsct, dat);
	gdFsClose(gdfs);
	if (len != NULL) {
		*len = fsize;
	}

	return dat;
}

/*	サウンドドライバの転送・初期化					*/
/*	Initialize sound library and load sound driver	*/
void SoundInit(void *sndptr, void *mltptr)
{
	SDMEMBLK	memblk = NULL;

	/*	Initialize Sound library	 */
	sdLibInit(NULL, 0, 0);		/*	This api's argument is dummy now.  */

	/* 	Download and Initialize Sound driver.	 */
	/*	Create Memory block handle  */
	sdMemBlkCreate(&memblk);
	/*  Setting Memory block handle  */
	sdMemBlkSetPrm(memblk, sndptr, 0, SDD_MEMBLK_SYNC_FUNC, NULL);
	/*	Initialize Sound driver  */
	sdDrvInit(memblk);

	/*	Download and Initialize Multi unit	*/
	/*	Setting Memory block handle	*/
	sdMemBlkSetPrm(memblk, mltptr, 0, SDD_MEMBLK_SYNC_FUNC, NULL);
	sdDownloadMultiUnit(memblk);

	sdMemBlkDestroy(memblk);

	/*	Truemotion Only CPU mode	*/
#if	0
	/*	転送モードの設定		*/
	/*	Setting transfer mode	*/
	sdMemBlkSetTransferMode(SDE_MEMBLK_TRANSFER_MODE_DMA);
#endif

	return;
}

/***
 *			Playing middleware
 ***/

/*	Callback function when an error occur in middleware	*/
void UsrMwErrFunc(void *obj, char *ecode)
{
	errcnt++;

	return;
}

void play_main(MWPLY ply, char *fname)
{
	MWE_PLY_STAT			stat;
	const PDS_PERIPHERAL	*per;

	mwPlyEntryErrFunc((void *)UsrMwErrFunc, &ply);
	mwPlyPause(ply, pause);				/*	前回再生のポーズ状態を維持		*/
										/*	Keep the last time pause status	*/
	mwPlyStartFname(ply, (signed char *) fname);		/*	再生開始						*/
										/*	Start to play middleware		*/
	while (1) {
        //njWaitVSync();
        kmRender();
        kmFlipFrameBuffer();

		mwPlyStartFrame();
		per = pdGetPeripheral(PDD_PORT_A0);
		if (per->press & PDD_DGT_TA) {
			disp_flag = NOT_FLAG(disp_flag);
		}
		if (per->press & PDD_DGT_TX) {
			pause = ON;
			mwPlyPause(ply, ON);		/*	一時停止				*/
										/*	Pause					*/
		}
		if (per->press & PDD_DGT_TY) {
			pause = OFF;
			mwPlyPause(ply, OFF);		/*	一時停止解除			*/
										/*	Release pause status	*/
		}
		if (per->press & PDD_DGT_ST) {
			break;
		}
		stat = mwPlyGetStat(ply);
		if ((stat == MWE_PLY_STAT_PLAYEND) || (stat == MWE_PLY_STAT_ERROR)) {
			break;
		}
		mwPlyExecServer();
	}
	mwPlyStop(ply);						/*	再生停止 					*/
										/*	Stop to play middleware		*/
    //njWaitVSync();                      /*  パッドの状態取得のため      */
    kmRender();
    kmFlipFrameBuffer();
										/*	for getting status of PAD	*/
	mwPlyDestroy(ply);					/*	ハンドル消去				*/
										/*	Destroy handle				*/

	return;
}


/*	Playing SFD file	*/
void play_sfd(char *fname)
{
	MWPLY					ply;
	MWS_PLY_CPRM_SFD		cprm;

	/*	ハンドルの生成	*/
	/*	Create handle	*/
	memset(&cprm, 0, sizeof(cprm));	/*	予約メンバのゼロ設定のために必要	*/
									/*	To initialize reserved member		*/
	cprm.ftype			= MWD_PLY_FTYPE_SFD;
	cprm.dtype			= MWD_PLY_DTYPE_AUTO;
	cprm.max_bps = 450*1024*8;
	cprm.max_width = 320;
	cprm.max_height = 480;
	cprm.nfrm_pool_wk = 3;
	cprm.wksize = mwPlyCalcWorkSofdec(
								cprm.ftype,
								cprm.max_bps,
								cprm.max_width,
								cprm.max_height,
								cprm.nfrm_pool_wk);
	cprm.work = syMalloc(cprm.wksize);
	ply = mwPlyCreateSofdec(&cprm);
	if (ply == NULL) {
		for (;;) ;
	}
	mwPlySetAudioSw(ply, AUDIO_SW);
	play_main(ply, fname);
	syFree(cprm.work);

	return;
}

/***
 *		MAIN
 ***/

/*	Finalize application		*/
void UsrExit(void)
{
	/*	Finalize Middleware					*/
	mwPlyFinishSofdec();

	sbExitSystem();			/*	忍ライブラリの終了処理				*/
	syBtExit();				/*	シンプルプレイヤへジャンプ			*/
}

/*	Callback function when an error occur in GD file system	*/
void UsrGdErrFunc(void *obj, Sint32 errcode)
{
	if (errcode == GDD_ERR_TRAYOPEND || errcode == GDD_ERR_UNITATTENT) {
		UsrExit();					/*	アプリケーション終了処理	*/
									/*	Finalize application		*/
	}

	return;
}

/*	Callback function when V-sync interrupt	*/
void UsrVsyncFunc(void)
{
	Sint32 dstat;

    /*	サウンドライブラリのサーバ関数		*/
	/*	Server function of sound library	*/
	sdSysServer();

	/*	ドアオープンチェック	*/
	/*	Check door open			*/
	dstat = gdFsGetDrvStat();
	if (dstat == GDD_DRVSTAT_OPEN || dstat == GDD_DRVSTAT_BUSY) {
		gdFsReqDrvStat();
	}

	return;
}

void main(void)
{
	MWS_PLY_INIT_SFD		iprm;
	static KMVERTEXBUFFDESC	vb_desc;
	void 					*snddrv;
    void                    *mltfile;

#ifdef __GNUC__
	shinobi_workaround();
#endif
	/*	Initialize system for middleware(call before sbInitSystem)	*/
	mwPlyPreInitSofdec();

	/*	Initialize SHINOBI		*/
	sbInitSystem(SYS_MODE, SYS_FRAME, SYS_COUNT);

	InitSysConfig(&vb_desc);
	InitVertex(VB_OP, VB_OM, VB_TP, VB_TM, VB_PT);
	mwRnvSetVertexBuffer(&vb_desc);

	/*	Entry callback function of GD file system error	*/
	gdFsEntryErrFuncAll((void *)UsrGdErrFunc, NULL);

	/*	Prepare sound library		*/
	snddrv  = LoadFile("manatee.drv", NULL);
	mltfile = LoadFile("stream.mlt", NULL);
	SoundInit(snddrv, mltfile);

	/* install vertical blanking interrupt */
    //njSetVSyncFunction(UsrVsyncFunc);
    syChainAddHandler ( 0x0900, UsrVsyncFunc , 0x70 , NULL);

    /* The movie player needs to call some kmtexture functions, but without this useless
       bit of code, the linker will deadstrip these sections from our elf file. */
    {
        KMSURFACEDESC TexSurfaceDesc;
        kmCreateTextureSurface (&TexSurfaceDesc, 32, 32,
            (KM_TEXTURE_TWIDDLED | KM_TEXTURE_RGB565));
        kmFreeTexture (&TexSurfaceDesc);
    }

	/*	Initialize middleware			*/
	memset(&iprm, 0, sizeof(iprm));	/*	To initialize reserved member		*/
#if 0
	iprm.mode		= SYS_MODE;
	iprm.frame		= SYS_FRAME;
	iprm.count		= SYS_COUNT;
	iprm.latency	= MWD_PLY_LATENCY(VB_OP, VB_OM, VB_TP, VB_TM, VB_PT);
#endif
	mwPlyInitSofdec(&iprm);

	for (;;) {
        play_sfd ("SAMPLE.SFD");      /*  Playing animation   */
	}

	UsrExit();						/*	Finalize application		*/
}


/* end of file */