  
#include "glover.h"



UBYTE disablequitvideo=0;

#define SCR_WIDTH   320
#define SCR_HEIGHT  256
/*
 *  16bit/pixel mode or 24 bit/pixel mode :
 */
#define IS_RGB24    0   /* 0:RGB16, 1:RGB24 */
#define PPW 1       // pixel/short word :
#define DCT_MODE    2   /* 16 bit decode : 16bit モードでデコード */

// time out parameter for strNextVlc() and strNext() : strNext(),strNextVlc()
#define MOVIE_WAIT 2000

typedef struct {
    u_long  *vlcbuf[2]; // VLC buffer 
    int vlcid;      // current decode buffer id :
    u_short *imgbuf[2]; // decode image buffer 
    int imgid;      // corrently use buffer id :
    RECT    rect[2];    // double buffer orign(upper left point) address   on the VRAM (double buffer) :
    int rectid;     // currently translating buffer id :	 
    RECT    slice;      // the region decoded by once DecDCTout() :
    int isdone;     // the flag of decoding whole frame :
} DECENV;
static DECENV   dec;        /* instance of DECENV : デコード環境の実体 */

/*  Ring buffer for STREAMING
 *  minmum size is two frame :
 */
#define RING_SIZE   32      /* 32 sectors : 単位はセクタ */
//static u_long   Ring_Buff[RING_SIZE*SECTOR_SIZE];
ULONG *Ring_Buff=0;
//static u_long   Ring_Buff[RING_SIZE*SECTOR_SIZE];

/*  VLC table
 *  memory area for vlc parameters
 *  DecDCTvlcBuild() expands compressed data to that area
 *  compressed size is about 3kbyte and decompressed size is about 64kbyte :
 */
//DECDCTTAB  vlc_table;
//DECDCTTAB  *vlc_table_ptr;
u_short *vlc_table_ptr;
 
/*  VLC buffer(double buffer)
 *  stock the result of VLC decode :
 */
#define VLC_BUFF_SIZE 320/2*256     // not correct value :
//static u_long   vlcbuf0[VLC_BUFF_SIZE];
//static u_long   vlcbuf1[VLC_BUFF_SIZE];
static ULONG*   vlcbuf0=0;
static ULONG*   vlcbuf1=0;

/*  image buffer(double buffer)
 *  stock the result of MDEC
 *  rectangle of 16(width) by XX(height) :
 */
#define SLICE_IMG_SIZE 16*PPW*SCR_HEIGHT
//static u_short  imgbuf0[SLICE_IMG_SIZE];
//static u_short  imgbuf1[SLICE_IMG_SIZE];
USHORT *imgbuf0=0;
USHORT *imgbuf1=0;
    
static int  StrWidth  = 0;  // resolution of movie :
static int  StrHeight = 0;  
static int  Rewind_Switch;  // the end flag set after last frame :

/*
 *  prototypes :
 */
//static int anim();
static void strSetDefDecEnv(DECENV *dec, int x0, int y0, int x1, int y1);
static void strInit(CdlLOC *loc, void (*callback)());
static void strCallback();
static int  strNextVlc(DECENV *dec);
static void strSync(DECENV *dec, int mode);
static u_long *strNext(DECENV *dec);
static void strKickCD(CdlLOC *loc);

/**************************************
*          DECLARE VARIABLES          *
**************************************/

#define VIDEO_TIMEOUT (4000)
UBYTE	displayBufferInd=0;

//*********************************************************************************	
void 
Init_Sys(void) {		// System initialisation. 
//RECT	vram;

//	CdInit(); //cant use, takes too long!
//	CdReset();
	VSync(0);
	CdDataCallback(0);                
    CdReadCallback(0);               
    CdSyncCallback(0);               
    CdReadyCallback((void*)0);               
	ResetCallback();
//	CD_initvol(); //this re-enables normal chip sound as well!
//	Pause_Music();
//	CdDeMute();
	DrawSync(0);
	DecDCTReset(0); 
    DecDCToutCallback(0);             
	DrawSyncCallback(0);
//	printf("MDEC initialisation OK\n");
}

//*********************************************************************************	
/***************************************************************************************************************************/
/***************************************************************************************************************************/


#if DEMODISC==YES
UBYTE *videoroot={"\\GLOVER\\VIDEO\\"}; 
#else
UBYTE *videoroot={"\\VIDEO\\"}; 
#endif

SPRITE *mgmframesprpointer=0;
ULONG clipnum=0;
ULONG framenum=0;
ULONG	lastframe=0;
UBYTE videofilename[64];	// why is this a global... have we got a temp workblock somewhere for this kinda thing?

UBYTE newvideo(UBYTE *name,ULONG len)
{
    CdlFILE file;
    CdlLOC  save_loc;		// retry location :    
    int frame_no;		// retry frame no : 
//	ULONG lionrgb=0;
	int res_store = resolution;
	RECT rc = {0,0,512,256};

//	LONG lastframe=0;
//    ResetCallback();
	CDctrl.trackrequested=0;
//    CdInit();
//   	CdSetDebug(1);
//    ResetGraph(0);
//    SetGraphDebug(0);

	VSync(0);
//	Clear_Video_Memory(1024);

	clipnum=0;
    sprintf(videofilename,"%s%s;1",videoroot,name);
	Init_Sys();

	rc.w = resolution;
	ClearImage(&rc,0,0,0);
	DrawSync(0);
	rc.y=256;
   	ClearImage(&rc,0,0,0);
	DrawSync(0);

	Cls();
   	resolution=320;
  	Set_Up_Display();
	
	(UBYTE*)Ring_Buff=MALLOC(RING_SIZE*SECTOR_SIZE*4,"VIDEO BUFFER");
	(UBYTE*)vlcbuf0=MALLOC(VLC_BUFF_SIZE*4,"VLC BUFFER0");
	(UBYTE*)vlcbuf1=MALLOC(VLC_BUFF_SIZE*4,"VLC BUFFER1");
	(UBYTE*)imgbuf0=MALLOC(SLICE_IMG_SIZE*2,"SLICE0");
	(UBYTE*)imgbuf1=MALLOC(SLICE_IMG_SIZE*2,"SLICE1");


    /* search file チ */
	PRINTF("video load %s\n",videofilename);
    if (CdSearchFile(&file,videofilename) == 0)       printf("file not found\n");

   // strSetDefDecEnv(&dec, POS_X, POS_Y, POS_X, POS_Y+SCR_HEIGHT);    // set the position of vram 
	StrWidth=320;
	StrHeight=192; //240;
	resolution=320;
    strSetDefDecEnv(&dec, 0,PALMODE*8+24, 0,PALMODE*8+256+24); // set the position of video on screen 

    strInit(&file.pos, strCallback);     // init streaming system & kick cd : 

	vlc_table_ptr = MALLOC(sizeof(DECDCTTAB),"video table");
    DecDCTvlcBuild(&vlc_table_ptr[0]);	    // expand compressed vlc parameter data :
//    DecDCTvlcBuild(vlc_table);	    // expand compressed vlc parameter data :
    
    while(strNextVlc(&dec)== -1){    // VLC decode the first frame
		printf("time out in strNext()");
		save_loc = file.pos; // start position 
		strKickCD(&save_loc);
     }
    
       SetDispMask(1);     // display enable 
    Rewind_Switch = 0;
    Cls();
    clscol.r=254;
	frame=0;

        Start_Loop();
        End_Loop(-1);
//  		GsInitGraph(320,256,4,1,0);	//N.B. can change style between Dithered & Non-dithered!


//					printf(">>> During Vid\n");
//					memoryShow();


    while (clipnum<3) //frame<len)
     {
//		PRINTF("v");
    
		if (disablequitvideo!=YES)
		{

/*			
#define PAD_LEFT		(1<<7)			// Pad digital buttons
#define PAD_RIGHT		(1<<5)
#define PAD_UP			(1<<4)
#define PAD_DOWN		(1<<6)
#define PAD_CROSS		(1<<14)
#define PAD_CIRCLE		(1<<13)
#define PAD_TRIANGLE	(1<<12)
#define PAD_SQUARE		(1<<15)
#define PAD_L1			(1<<10)
#define PAD_L2			(1<<8)
#define PAD_R1			(1<<11)
#define PAD_R2			(1<<9)
#define PAD_SELECT		(1<<0)
#define PAD_START		(1<<3)
*/
			
//			if (pad[0]&PADstart)break;
			if (debounce[0] & (PAD_START | PAD_SELECT | PAD_CROSS | PAD_CIRCLE))
				break;
        }
        //DrawSync(0);
        DecDCTin(dec.vlcbuf[dec.vlcid], DCT_MODE);	// start DCT decoding the result of VLC decoded data :
        
        // prepare for recieving the result of DCT decode :
        // next DecDCTout is called in DecDCToutCallback :
        DecDCTout((u_long *)dec.imgbuf[dec.imgid], dec.slice.w*dec.slice.h/2);
        
        // decode the next frame's VLC data :
		while(strNextVlc(&dec)== -1)
			{
		    frame_no = StGetBackloc(&save_loc);	// get current location 
	   		printf("time out in strNext() %d\n",frame_no);
	  //	  	if(frame_no>END_FRAME || frame_no<=0) // invalid frame no 
	  //  		  save_loc = file.pos; // start position 
		    strKickCD(&save_loc);
		  	}
        
        strSync(&dec, 0);         // wait for whole decode process per 1 frame :
        
	   	endpoly();
        Start_Loop();
 			if (framenum>(len-3))break;
	  //	VSync(0);
        End_Loop(-1);
         // stop button pressed exit animation routine :
		//if (pad)     break;
    }

//	PRINTF("Video End\n");
 	endpoly();
    VSync(0);
   		CDSETVOLUME(&(CDctrl.sAttenuationVol),0); //cdgamevolume);		
   
   
//    VSync(30);
	SCREENOFF;
//	Cls();
    // post processing of animation routine :
    DecDCToutCallback(0);
    StUnSetRing();
    CdControlB(CdlPause,0,0);

//	PRINTF("Video Free\n");

//	FREE((UBYTE**)&Ring_Buff);
//	FREE((UBYTE**)&vlcbuf0);
//	FREE((UBYTE**)&vlcbuf1);
//	FREE((UBYTE**)&imgbuf0);
//	FREE((UBYTE**)&imgbuf1);

// the pointers were mallocced, not flexed
// (& memory.c, at the moment, only frees efficiently if blocks at the high end are freed in reverse order)

	FREE(vlc_table_ptr);
	FREE((UBYTE*)imgbuf1);
	FREE((UBYTE*)imgbuf0);
	FREE((UBYTE*)vlcbuf1);
	FREE((UBYTE*)vlcbuf0);
	FREE((UBYTE*)Ring_Buff);

//    StopCallback();

	PRINTF("Video Fin\n");

	CDctrl.caCtrlParams[0] = CdlStatStandby; //CdlModeRept|CdlModeDA;
	CdControl(CdlSetmode, (CDctrl.caCtrlParams) , 0);
    DecDCTReset(0);

//    CdInit();
//   	CdSetDebug(1);
	if (resolution==320)
	{
		rc.w = res_store;

		resolution=res_store;	//640;
		Set_Up_Display();
//	    Cls();
		rc.y=0;
		ClearImage(&rc,0,0,0);
		DrawSync(0);
		rc.y=256;
	   	ClearImage(&rc,0,0,0);
		DrawSync(0);
		SetDispMask(1);     // display enable 
	}
	CDctrl.Volume=128;		  
   	CDSETVOLUME(&(CDctrl.sAttenuationVol),CDctrl.Volume); //cdgamevolume);		
	return 1;
}
/************************************************************************************************************************/

/*
 * init DECENV    buffer0(x0,y0),buffer1(x1,y1) :
 */
static void strSetDefDecEnv(DECENV *dec, int x0, int y0, int x1, int y1)
{

    dec->vlcbuf[0] = vlcbuf0;
    dec->vlcbuf[1] = vlcbuf1;
    dec->vlcid     = 0;

    dec->imgbuf[0] = imgbuf0;
    dec->imgbuf[1] = imgbuf1;
    dec->imgid     = 0;

    // width and height of rect[] are set dynamicaly according to STR data :
    dec->rect[0].x = x0;
    dec->rect[0].y = y0;
    dec->rect[1].x = x1;
    dec->rect[1].y = y1;
    dec->rectid    = 0;

    dec->slice.x = x0;
    dec->slice.y = y0;
    dec->slice.w = 16*PPW;

    dec->isdone    = 0;
}

/******************************************************************************/
/*
 * init the streaming environment and start the cdrom :
 */
static void strInit(CdlLOC *loc, void (*callback)())
{
    DecDCTReset(0);				    	// cold reset mdec : 
    
    DecDCToutCallback(callback);	   // set the callback after 1 block MDEC decoding :
    
    StSetRing(Ring_Buff, RING_SIZE);    // set the ring buffer : 
    
    StSetStream(IS_RGB24, 1, 0xffffffff, 0, 0);   // init the streaming library : end frame is set endless
    
    strKickCD(loc);							      // start the cdrom : 
}

/**************************************************************************************************************/
/*
 *  back ground process
 *  callback of DecDCTout() :
 */
static void strCallback()
{
  RECT snap_rect;
  int  id;
  
  id = dec.imgid;
  snap_rect = dec.slice;
  
    // switch the id of decoding buffer : */
    dec.imgid = dec.imgid? 0:1;

    // update slice(rectangle) position :
    dec.slice.x += dec.slice.w;
    
    // remaining slice ? 
    if (dec.slice.x < dec.rect[dec.rectid].x + dec.rect[dec.rectid].w) {
        // prepare for next slice 
        DecDCTout((u_long *)dec.imgbuf[dec.imgid], dec.slice.w*dec.slice.h/2);
    }
    // last slice ; end of 1 frame
    else {
        // set the decoding done flag
        dec.isdone = 1;
        // update the position on VRAM 
        dec.rectid = dec.rectid? 0: 1;
        dec.slice.x = dec.rect[dec.rectid].x;
        dec.slice.y = dec.rect[dec.rectid].y;
    }
  
  // transfer the decoded data to VRAM :
  LoadImage(&snap_rect, (u_long *)dec.imgbuf[id]);
}
/**************************************************************************************************************/

 /*
 *  execute VLC decoding
 *  the decoding data is the next frame's
 *  if time out in strNext() return -1 :
 */
u_long *strNext();
static int strNextVlc(DECENV *dec)
{
    int cnt = MOVIE_WAIT;
    u_long  *next;
    // get the 1 frame streaming data
    while ((next = strNext(dec)) == 0) {
        if (--cnt == 0)          return -1;
    }
    
    // switch the decoding area 
    dec->vlcid = dec->vlcid? 0: 1;
    
//    DecDCTvlc2(next, dec->vlcbuf[dec->vlcid],vlc_table);	 // VLC decode
    DecDCTvlc2(next, dec->vlcbuf[dec->vlcid],&vlc_table_ptr[0]);	 // VLC decode
    
    // free the ring buffer
    StFreeRing(next);
    return 0;
}

/**************************************************************************************************************/
/*
 *  get the 1 frame streaming data
 *  return vale     normal end -> top address of 1 frame streaming data
 *                  error      -> NULL :
 */
static u_long *strNext(DECENV *dec)
{
    u_long      *addr;
    StHEADER    *sector;
    int     cnt = MOVIE_WAIT;
    // get the 1 frame streaming data withe TIME-OUT :
    //if (sector->frameCount<400)
    lastframe=framenum;
    while(StGetNext((u_long **)&addr,(u_long **)&sector)) {
        if (--cnt == 0)        return(0);
    }
    // if the frame number greater than the end frame, set the end switch :
//    if((sector->frameCount >= END_FRAME)||(sector->frameCount<lastframe)) {
//     if((sector->frameCount >= END_FRAME)) {
//        Rewind_Switch = 1;
//    }
    framenum=sector->frameCount;
   	
   	if ((framenum<10)&&(lastframe>20)){
		clipnum++;
	 //	printf("next clip\n");
	}
   	
   	//printf("%d,%d:",sector->frameCount,lastframe);
    
    // if the resolution is differ to previous frame, clear frame buffer :
    if(StrWidth != sector->width || StrHeight != sector->height) {
        
        RECT    rect;
   //		printf("new width & height= %d,%d\n",sector->width,sector->height);
        setRECT(&rect, 0, 0, SCR_WIDTH * PPW, SCR_HEIGHT*2);
      //  ClearImage(&rect, 0, 0, 0);
        
        StrWidth  = sector->width;
        StrHeight = sector->height;
	    dec->slice.x = dec->rect[0].x; //x0;
 
    }
    
    // set DECENV according to the data on the STR format :
    dec->rect[0].w = dec->rect[1].w = StrWidth*PPW;
    dec->rect[0].h = dec->rect[1].h = StrHeight;
    dec->slice.h   = StrHeight;
    
//	printf("w,h=%d,%d\n",dec->rect[0].w,dec->rect[0].h);
    return(addr);
}
/**************************************************************************************************************/
//  wait for finish decodeing 1 frame with TIME-OUT :
static void strSync(DECENV *dec, int mode /* VOID */){
    volatile u_long cnt = WAIT_TIME;

    // wait for the decod is done flag set by background process :
    while (dec->isdone == 0) {
        if (--cnt == 0) {
            // if timeout force to switch buffer
            printf("time out in decoding !\n");
            dec->isdone = 1;
            dec->rectid = dec->rectid? 0: 1;
            dec->slice.x = dec->rect[dec->rectid].x;
            dec->slice.y = dec->rect[dec->rectid].y;
        }
    }
    dec->isdone = 0;
}
/**************************************************************************************************************/
static void strKickCD(CdlLOC *loc)
{
u_char param;
param = CdlModeSpeed;
  
 loop:
  // seek to the destination 
  while (CdControl(CdlSetloc, (u_char *)loc, 0) == 0);
  while (CdControl(CdlSetmode, &param, 0) == 0);
#ifdef APD_LOAD
	APDSetCnt(VSync(3));
#else
  VSync(3);  // wait for 3 VSync when changing the speed :
#endif
    // out the read command with streaming mode :
  if(CdRead2(CdlModeStream2|CdlModeSpeed|CdlModeRT) == 0)
    goto loop;
}
