/*
 *
 *			Middleware MPEG Sofdec Playing Sample
 *
 *			Chainging location, size, depth, video output sw
 *
 */

/***************************************************************************
 *      インクルードファイル
 *      Include file
 ***************************************************************************/
#include <shinobi.h>
#include <nindows.h>
#include <sg_sd.h>
#include <sg_mw.h>


/***************************************************************************
 *      定数マクロ
 *      MACRO CONSTANT
 ***************************************************************************/
/*
 * 表示モード
 *   CPU時間配分の優先度は、Sofdecよりアプリケーション(ポリゴン処理)が高い。
 *   ポリゴン処理負荷を減らせば、SofdecのCPU時間が増加する。
 *   1V毎にポリゴン処理をするより、2V毎の表示更新(インタレース)の方が、
 *   動画のコマ落ちの危険は小さい。
 * Display mode
 *   CPU time distribution of the application(poligon operation) takes 
 *   precedence over Sofdec decoder. CPU time of Sofdec increases when you 
 *   reduce poligon operation.
 */
#define SYS_MODE		NJD_RESOLUTION_640x480_NTSCI
#define SYS_FRAME		NJD_FRAMEBUFFER_MODE_ARGB8888
#define SYS_COUNT		1

/* 頂点登録用バッファサイズ(1つをマイナスにすると2Vレーテンシモード)	*/
/*	Vertex buffer size(2V latency mode is when a valiable is minus.)	*/
#define VB_OP			-800000
#define VB_OM			0
#define VB_TP			200000
#define VB_TM			0
#define VB_PT			0

/*
 * 音声再生の指定
 *   ON   :音声あり動画ファイルならば音声再生を行う。デフォルト。
 *   OFF  :音声再生を抑止する。音声あり動画ファイルでも映像だけを再生。
 * Setting play audio
 *   ON   :Play audio when the animation file is interleaved audio(default)
 *   OFF  :Not play audio
 */
#define AUDIO_SW		ON

/*	エラーメッセージ長		*/
/*	Length of error message	*/
#define ERRMSG_LEN		256

/*	Teapotオブジェクト	*/
/*	Teapot object		*/
#define OBJECT			object_tea_Teapot1_Teapot1


/***************************************************************************
 *      処理マクロ
 *      Process MACRO
 ***************************************************************************/

/*	フラグON/OFFの反転		*/
/*	Turn over flag(ON/OFF)	*/
#define NOT_FLAG(flag)		(((flag) == OFF) ? ON : OFF)

/*	再生ファイル番号の前進	*/
/*	Renew file number		*/
#define NEXT_FILE_NO(file_no, nfiles) \
			(((file_no) <= ((nfiles) - 2)) ? (file_no) + 1 : 0)


/***************************************************************************
 *      変数定義
 *		Variable Declaration
 ***************************************************************************/

/*	Teapot関連外部変数					*/
/*	Global variable for display Teapot	*/
extern NJS_OBJECT		OBJECT[];
extern Uint16			T009[];
extern NJS_MATRIX		matrix[8];
extern NJS_VERTEX_BUF	vbuf[4096];


/*	エラー発生回数		*/
/*	The number of error	*/
Sint32 errcnt = 0;

/*	エラーメッセージ	*/
/*	Error message		*/
char errmsg[ERRMSG_LEN] = "(OK)";

/*	Teapot表示フラグ		*/
/*	Flag for display Teapot	*/
Sint32 disp_flag = ON;

/*	ポーズ状態		*/
/*	Pause status	*/
Sint32 pause = OFF;

/*	ハンドル生成パラメータ		*/
/*	Parameter for handle create	*/
MWS_PLY_CPRM_SFD cprm;

/*	ミドルウェア再生ハンドル	*/
/*	Middleware playing handle	*/
MWPLY ply = NULL;

/*	Teapot関連変数				*/
/*	Variable for display Teapot	*/
NJS_TEXNAME			texname[1];
NJS_TEXLIST			tlist1 = {texname, 1};
NJS_TEXINFO			info;
NJS_TEXMEMLIST		tex[10];
NJS_VIEW			view;
NJS_LIGHT			light;

/*	V割込みカウンタ	*/
/*	V-Int counter	*/
Uint32 vcount = 0;

/*	マトリクスの各軸の回転角度	*/
/*	Revolving angles of matrix	*/
Sint32 xx, yy, zz = 0;

/*	再生ファイル名リスト (ファイル名を追加できる)	*/
/*	File name list(You can add other file.)			*/
char *fname[] = {
	"SAMPLE.SFD",
};

/*	再生ファイル番号	*/
/*	File number			*/
long file_no = 0;

/*	再生ファイル数		*/
/*	The number of file	*/
long nfiles = sizeof(fname) / sizeof(char *);

/*	ムービーのサイズ・位置・奥行き	*/
/*	location, size, Z of Movie		*/
long mv_lx=100, mv_ly=100, mv_sx=320, mv_sy=240;
float mv_lz=10.0;
/*	delta of location, size, Z 	*/
long mv_vlx=4, mv_vly=5, mv_vsx=2, mv_vsy=3;
float mv_vlz=0.1;

/*	ムービー表示フラグ		*/
/*	Flag for display Movie	*/
Sint32 mv_video_output_flag = ON;

/***************************************************************************
 *      関数定義
 *      Function Declaration
 ***************************************************************************/

/***
 *		サウンド環境の初期化
 *		Initialize sound section
 ***/

/*	サウンドドライバの転送・初期化					*/
/*	Initialize sound library and load sound driver	*/
Void SoundInit(Void *ptr)
{
	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 Memoby block handle  */
	sdMemBlkSetPrm(memblk, ptr, 0, SDD_MEMBLK_SYNC_FUNC, NULL);
	/*	Initialize Sound driver  */
	sdDrvInit(memblk);
	sdMemBlkDestroy(memblk);

	/*	転送モードの設定		*/
	/*	Setting transfer mode	*/
	sdMemBlkSetTransferMode(SDE_MEMBLK_TRANSFER_MODE_DMA);

	return;
}

/***
 *			ユーティリティ関数
 *			Utility function
 ***/

/*	データの読み込み	*/
/*	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;
}

/***
 *		メイン処理
 *		MAIN
 ***/

/*	ミドルウェアのエラー発生時に起動する関数			*/
/*	Callback function when an error occur in middleware	*/
void UsrMwErrFunc(void *obj, char *ecode)
{
	errcnt++;
	strncpy(errmsg, ecode, ERRMSG_LEN);

	return;
}

/*	GDファイルシステムのエラー発生時に起動する関数			*/
/*	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) {
		njUserExit();
	}

	return;
}

/*	ユーザがV-SYNC割り込みに登録する関数	*/
/*	Callback function when V-sync interrupt	*/
void UsrVsyncFunc(void)
{
	Sint32 dstat;

    vcount++;

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

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

	return;
}


void njUserInit(void)
{
	void *snddrv;
	MWS_PLY_INIT_SFD	iprm;

	/*	ミドルウェアのためのシステム初期化 (sbInitSystemの前に置く)	*/
	/*	Initialize system for middleware(call before sbInitSystem)	*/
	mwPlyPreInitSofdec();

	/*	忍ライブラリの初期化	*/
	/*	Initialize SHINOBI		*/
	njSetBorderColor(0x00000000);
	sbInitSystem(SYS_MODE, SYS_FRAME, SYS_COUNT);
	njInitVertexBuffer(VB_OP, VB_OM, VB_TP, VB_TM, VB_PT);
	njInitPrint(NULL, 0, 0);
	njInitMatrix(matrix, 8 , 0);
	njInit3D(vbuf, 4096);
	njInitView(&view);
	njCreateLight(&light, NJD_PHONG_DIR);
	njSetLightIntensity(&light, 1.5f, 1.0f, 0.7f);
	njSetLightAngle(&light, NJM_RAD_ANG(NJD_PI / 30.f),
							NJM_RAD_ANG(NJD_PI /  4.f));
	njSetLightDirection(&light, 0, 0.707f, -0.707f);
	njSetView(&view);
	njInitTexture(tex, 10);
	nwInitSystem(10,NJD_PORT_A0);
	njSetTextureInfo(&info,
						T009,NJD_TEXFMT_RGB_565|NJD_TEXFMT_TWIDDLED,128,128);
	njSetTextureName(&texname[0],&info, 0, 
							NJD_TEXATTR_TYPE_MEMORY|NJD_TEXATTR_GLOBALINDEX);
	njLoadTexture(&tlist1);
	njSetTexture(&tlist1);
	njControl3D(NJD_CONTROL_3D_CONSTANT_ATTR);
	njSetConstantAttr(0xffffffff,
				NJD_FLAG_USE_TEXTURE | NJD_FLAG_USE_ENV|NJD_FILTER_BILINEAR);
	njPrintSize(16);

	/*	GDファイルシステムエラーコールバック関数の登録	*/
	/*	Entry callback function of GD file system error	*/
	gdFsEntryErrFuncAll((void *)UsrGdErrFunc, NULL);

	/*	サウンドライブラリの準備	*/
	/*	Prepare sound library		*/
	snddrv = LoadFile("manatee.drv", NULL);
	SoundInit(snddrv);

	njSetVSyncFunction(UsrVsyncFunc);

	/*	ミドルウェアライブラリ初期化	*/
	/*	Initialize middleware			*/
	memset(&iprm, 0, sizeof(iprm));	/*	予約メンバのゼロ設定のために必要	*/
									/*	To initialize reserved member		*/
	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);
	mwPlyInitSofdec(&iprm);

	/*	ハンドルの生成	*/
	/*	Create handle	*/
	memset(&cprm, 0, sizeof(cprm));	/*	予約メンバのゼロ設定のために必要	*/
									/*	To initialize reserved member		*/
	cprm.ftype			= MWD_PLY_FTYPE_SFD;
	cprm.dtype			= MWD_PLY_DTYPE_AUTO;	/*	AUTOの方が画質が良い	*/
												/*	Quality is good in case 
												 *	of specified 'AUTO'.	*/
	cprm.max_bps = 450*1024*8;		/*	最大ビットストリーム量(bit/sec)
									 *	実際よりも少なくすることも可能。
									 *	ムービーが途中でフリーズするときは
									 *	この値を増やしてください。			*/
									/*	Maximum number of bit per second
									 *	You can reduce it than a fact.
									 *	Increase this value when the movie
									 *	stops on the way.					*/
	cprm.max_width = 320;			/*	再生画像サイズの最大幅				*/
									/*	Maximum width of video stream		*/
	cprm.max_height = 480;			/*	再生画像サイズの最大高さ			*/
									/*	Maximum height of video stream		*/
	cprm.nfrm_pool_wk = 3;			/*	システム領域のフレームプール数
									 *	標準的には３で良いが、処理負荷の
									 *	変動によりコマ落ちが発生する場合は
									 *	増やしてください。					*/
									/*	Size of working area
									 *	It is good with 3 normally. But please
									 *	increase it when frame drop occurs by
									 *	processing load change.				*/
	cprm.wksize = mwPlyCalcWorkSofdec(	/*	作業領域の大きさの計算			*/
										/*	Calculation of working area size*/
								cprm.ftype,
								cprm.max_bps,
								cprm.max_width,
								cprm.max_height,
								cprm.nfrm_pool_wk);
	cprm.work = syMalloc(cprm.wksize);	/*	作業領域の確保					*/
										/*	Allocation of working area		*/
	ply = mwPlyCreateSofdec(&cprm);
	if (ply == NULL) {
		for (;;) ;
	}

	mwPlyEntryErrFunc((void *)UsrMwErrFunc, &ply);
	mwPlySetAudioSw(ply, AUDIO_SW);
	mwPlyPause(ply, pause);				/*	前回再生のポーズ状態を維持		*/
										/*	Keep the last time pause status	*/
	mwPlyStartFname(ply, fname[file_no]);	/*	再生開始					*/
											/*	Start to play middleware	*/

	return;
}

/*	次のファイルの再生	*/
/*	Play the next file	*/
void playNext(void)
{
	file_no = NEXT_FILE_NO(file_no, nfiles);
	mwPlyStop(ply);
	mwPlyDestroy(ply);
	ply = mwPlyCreateSofdec(&cprm);
	if (ply == NULL) {
		for (;;) ;
	}

	mwPlyEntryErrFunc((void *)UsrMwErrFunc, &ply);
	mwPlySetAudioSw(ply, AUDIO_SW);
	mwPlyPause(ply, pause);				/*	前回再生のポーズ状態を維持		*/
										/*	Keep the last time pause status	*/
	mwPlySetVideoSw(ply, mv_video_output_flag);
	mwPlyStartFname(ply, fname[file_no]);

	return;
}

Sint32 njUserMain(void)
{
	const PDS_PERIPHERAL	*per;
	MWE_PLY_STAT			stat;

	mwPlyStartFrame();
	/*	位置・サイズ・奥行きの設定	*/
	mwPlySetDispPos(ply, mv_lx, mv_ly);
	mwPlySetDispSize(ply, mv_sx, mv_sy);
	mwPlySetDispZ(ply, mv_lz);
	if ( mv_lx  >= 320 || mv_lx <= 0 )
		mv_vlx *= -1;
	if ( mv_ly  >= 240 || mv_ly <= 0 )
		mv_vly *= -1;
	if ( mv_sx <= 160 || mv_sx >= 480 )
		mv_vsx *= -1;
	if ( mv_sy <= 120 || mv_sy >= 360 )
		mv_vsy *= -1;
	if ( mv_lz <= 6.0 || mv_lz >= 14.0 )
		mv_vlz *= -1.0;
	mv_lx += mv_vlx, mv_ly += mv_vly, mv_lz += mv_vlz;
	mv_sx += mv_vsx, mv_sy += mv_vsy;

	per = pdGetPeripheral(PDD_PORT_A0);
	if (per->press & PDD_DGT_ST) {
		playNext();
	}
	if (per->press & PDD_DGT_TA) {
		disp_flag = NOT_FLAG(disp_flag);
	}
	if (per->press & PDD_DGT_TB) {
		mv_video_output_flag = NOT_FLAG(mv_video_output_flag);
		mwPlySetVideoSw(ply, mv_video_output_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	*/
	}

	/*	再生終了のチェック	*/
	/*	Check end of play	*/
	stat = mwPlyGetStat(ply);
	if ((stat == MWE_PLY_STAT_PLAYEND) || (stat == MWE_PLY_STAT_ERROR)) {
		playNext();
	}

	/*	Teapotの表示処理			*/
	/*	Operation of display Teapot	*/
	njClearMatrix();
	njTranslate( NULL, 0.f, 0.f, -12.f );
	njRotateXYZ( NULL, xx, yy, zz );
	if (disp_flag) {
		njDrawObject(OBJECT);
	}
	xx += 257;
	yy += 179;
	zz += 193;
	njPrintD(NJM_LOCATION(2,3), vcount, 8);

	mwPlyExecServer();

	return nwExecute();
}

void njUserExit(void)
{
	mwPlyFinishSofdec();	/*	ライブラリ終了処理					*/
							/*	Finalize Middleware					*/
	nwExitSystem();
	njExitPrint();
	njExitTexture();

	sbExitSystem();			/*	忍ライブラリの終了処理				*/
							/*	Finalize SHINOBI					*/
	syBtExit();				/*	シンプルプレイヤへジャンプ			*/
							/*	Jump to Simple player				*/

	return;
}


/* end of file */
