/*========================================================================= fmv.cpp Author: A star studded cavalcade of everyone ever lumbered with doing the FMV on a climax game Created: Project: PRLSR PSX Purpose: Hacked up FMV player nicked from SBK && POP && Diablo && TPW. Duff. Copyright (c) 1998 / 1999 / 2000 Climax Development Ltd ===========================================================================*/ /*---------------------------------------------------------------------- Includes -------- */ #include "system\global.h" #include "fileio/fileio.h" #include "fileio/filetab.h" #include "gfx/prim.h" #include "system/vid.h" #include "utils/utils.h" /* Module Header File ------------------ */ #include "fmv/fmv.h" /* Std Lib ------- */ #include #include #include #include #include #include /* Other Libs ---------- */ #include "..\..\tools\vlc\include\vlc_bit.h" // #define FORCE_FMV 1 #if __FILE_SYSTEM__==CD | FORCE_FMV #define ENABLE_FMV #endif #if defined(__USER_CDBUILD__) #undef FORCE_FMV #endif /* Graphics -------- */ /*---------------------------------------------------------------------- Tyepdefs && Defines ------------------- */ #define FMVChannelL (1<<0) #define FMVChannelR (1<<1) #define FMVChannelLR (FMVChannelL|FMVChannelR) #define FMVWidth (320) #define FMVHeight (240) #define IS_RGB24 1 /* 0:RGB16, 1:RGB24 */ #if defined(__TERRITORY_USA__) #define TerrOfs (0) #else #define TerrOfs (28/2) #endif #if IS_RGB24==1 #define PPW 3/2 #define MODE 3 /* 24bit */ #else #define PPW 1 #define MODE 2 /* 16bit */ #endif #define RING_SIZE 32 #define CDMidVol 127 /*---------------------------------------------------------------------- Structure defintions -------------------- */ typedef struct FMVDATA { int m_filename; int m_numOfFrames; } FmvData; /* * Global movie decoding information */ typedef struct { u_long *vlcbuf[2]; int vlcid; u_short *imgbuf; RECT rect[2]; int rectid; RECT slice; int isdone; } DECENV; /*---------------------------------------------------------------------- Function Prototypes ------------------- */ extern "C" { void strCallback(); }; static void SetCDVolume(int val = CDMidVol); static void strInit(CdlLOC *loc); static int strNextVlc(DECENV *dec); static void strSync(DECENV *dec,int mode); static void strKickCD(CdlLOC *loc); static void strSetDefDecEnv(DECENV *dec,int Height); static u_long *strNext(DECENV *dec); /*---------------------------------------------------------------------- Vars ---- */ static FmvPerFrameFunc s_funcToCall; static DECENV dec; static int QuitFlag; static u_short *dcTab; static u16 AniNoFrames,LastFrame=0;; static u8 *PlaybackBuffer; static u_long *SectorBuffer; /*---------------------------------------------------------------------- Data ---- */ static const FmvData s_fmvData[MAX_FMVS]= { {FILEPOS_THQ_STR, 270-15 }, {FILEPOS_CLIMAX_STR, 243-15 }, {FILEPOS_INTRO_STR, 607-15 }, #if defined(__TERRITORY_EUR__) {FILEPOS_DEMO_STR, 909}, #endif }; /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ int FMV_play(int fmvNumber,FmvPerFrameFunc func) { #ifdef ENABLE_FMV CdlLOC loc; int startSector; DISPENV disp; DRAWENV draw; int YOfs; int frame = 0; int id; int Pad=0; RECT ClearRect={0,0,512,512}; #ifdef FORCE_FMV static int HasInit=0; if (!HasInit) { while (!CdInit()); CFileIO::FindAllFilePos(); HasInit=1; } #endif // Cos it uses prim pool, best check its big enough CdReadyCallback(0); // clear it in case XA is being naughty ASSERT(PRIMPOOL_SIZE>FMVWidth*(FMVHeight+1)); InitOTagR(OtPtr,MAX_OT); // Ensure no prims need the Prim Pool SYSTEM_DBGMSG("[FMV] Playing fmv %d ( fid:%d )",fmvNumber,s_fmvData[fmvNumber].m_filename); startSector=CFileIO::GetFilePos(s_fmvData[fmvNumber].m_filename); SYSTEM_DBGMSG("[FMV] Start sector %d",startSector); s_funcToCall=func; PlaybackBuffer=(unsigned char*)MemAlloc(320*(FMVHeight+1),"FmvPlay"); SectorBuffer=(u_long*)MemAlloc(RING_SIZE*2048,"FmvPlay"); // 65536 dcTab=(u_short*)MemAlloc(sizeof(DECDCTTAB),"FmvPlay"); DecDCTvlcBuild3(dcTab); DecDCTvlcSize3(320*FMVHeight); VSync(0); SetDispMask(0); ClearImage(&ClearRect,0,0,0); AniNoFrames = s_fmvData[fmvNumber].m_numOfFrames; LastFrame=0; SYSTEM_DBGMSG("[FMV] Number of frames is %d",AniNoFrames); SetCDVolume(); CdIntToPos(startSector,&loc); strSetDefDecEnv(&dec, FMVHeight); YOfs=((256-FMVHeight)+TerrOfs)/2; strInit(&loc); if (strNextVlc(&dec)!=-1) while(1) { DecDCTin(dec.vlcbuf[dec.vlcid], MODE); DecDCTout((u_long*)dec.imgbuf, dec.slice.w*dec.slice.h/2); if (strNextVlc(&dec)==-1) break; strSync(&dec, 0); VSync(0); id = dec.rectid? 0: 1; SetDefDispEnv(&disp, dec.rect[id].x, dec.rect[id].y,dec.rect[id].w, dec.rect[id].h); SetDefDrawEnv(&draw, dec.rect[id].x, dec.rect[id].y,dec.rect[id].w, dec.rect[id].h); disp.isrgb24 = IS_RGB24; #if IS_RGB24==1 disp.disp.w = disp.disp.w*2/3; #else disp.disp.w = disp.disp.w*2/2; #endif disp.screen.x = VidGetXOfs(); disp.screen.y = YOfs+VidGetYOfs(); disp.screen.h = FMVHeight-1; // update for PAL, to stop last row corruption, may work!! PutDispEnv(&disp); PutDrawEnv(&draw); SetDispMask(1); if (s_funcToCall) { if (s_funcToCall()) { SetCDVolumeOff(); Pad=true; break; } } if(QuitFlag) break; //do once only. } SetCDVolumeOff(); CdControlB(CdlPause,0,0); VSync(0); DrawSync(0); DecDCToutCallback(0); CdReadyCallback(0); DecDCTReset(0); VSync(0); DrawSync(0); StUnSetRing(); VSync(0); DrawSync(0); MemFree(dcTab); MemFree(SectorBuffer); MemFree(PlaybackBuffer); SetDispMask(0); ClearImage(&ClearRect,0,0,0); VSync(0); DrawSync(0); SetDispMask(1); // SetPrimCheck(); SYSTEM_DBGMSG("[FMV] Finished!"); return Pad; #else return (true); #endif } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ static void strSetDefDecEnv(DECENV *dec,int Height) { static u_long* vlcbuf0; static u_long* vlcbuf1; static u_short* imgbuf; int x0,y0,x1,y1; x0=0; y0=0; x1=0; y1=240; vlcbuf0 = (u_long*) MakePtr(PrimListStart,FMVWidth*(FMVHeight+1)*0); vlcbuf1 = (u_long*) MakePtr(PrimListStart,FMVWidth*(FMVHeight+1)*1); imgbuf = (u_short*) MakePtr(PlaybackBuffer,FMVWidth*(FMVHeight+1)*0); dec->vlcbuf[0] = vlcbuf0; dec->vlcbuf[1] = vlcbuf1; dec->vlcid = 0; dec->imgbuf = imgbuf; dec->rectid = 0; dec->isdone = 0; setRECT(&dec->rect[0], x0, y0, FMVWidth*PPW, FMVHeight); setRECT(&dec->rect[1], x1, y1, FMVWidth*PPW, FMVHeight); setRECT(&dec->slice, x0, y0, 16*PPW, FMVHeight); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ static void strInit(CdlLOC *loc) { DecDCTReset(0); QuitFlag = 0; DecDCToutCallback( strCallback ); StSetRing(SectorBuffer, RING_SIZE); StSetStream(IS_RGB24, 1, 0xffffffff, 0, 0); strKickCD(loc); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void strCallback() { #if IS_RGB24==1 extern long StCdIntrFlag; if(StCdIntrFlag) { StCdInterrupt(); StCdIntrFlag = 0; } #endif LoadImage(&dec.slice, (u_long *)dec.imgbuf); dec.slice.x += dec.slice.w; if (dec.slice.x < dec.rect[dec.rectid].x + dec.rect[dec.rectid].w) DecDCTout((u_long*)dec.imgbuf, dec.slice.w*dec.slice.h/2); else { 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; } } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ static int strNextVlc(DECENV *dec) { int cnt = 16;//WAIT_TIME; u_long *next; while ((next = strNext(dec)) == 0) { // if (--cnt == 0) return(-1); } dec->vlcid = dec->vlcid? 0: 1; /* swap ID */ DecDCTvlc3(next, dec->vlcbuf[dec->vlcid]/*,dcTab*/); /* VLC decode */ StFreeRing(next); /* free used frame */ return(0); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ static u_long *strNext(DECENV *dec) { RECT rect; u_long *addr; StHEADER *sector; int cnt = WAIT_TIME/8; static int width = 0; static int height = 0; while(StGetNext((u_long **)&addr,(u_long **)§or)) { if (--cnt == 0) return(0); } if (sector->frameCount >= AniNoFrames) QuitFlag = 1; if (sector->frameCountframeCount; if (width != sector->width || height != sector->height) { setRECT(&rect, 0, 0, FMVWidth, 480); ClearImage(&rect, 0, 0, 0); width = sector->width; height = sector->height; } dec->rect[0].w = dec->rect[1].w = width*PPW; dec->rect[0].h = dec->rect[1].h = height; dec->slice.h = height; return(addr); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ static void strSync(DECENV *dec,int mode) { volatile u_long cnt = WAIT_TIME; while (dec->isdone == 0) { if (--cnt == 0) { SYSTEM_DBGMSG("time out in decoding"); 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; } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ static void strKickCD(CdlLOC *loc) { while (CdControl(CdlSeekL, (u_char *)loc, 0) == 0); while(CdRead2(CdlModeStream|CdlModeSpeed|CdlModeRT) == 0); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SetCDVolumeOff() { SetCDVolume(0); SpuSetCommonCDMix(SPU_OFF); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SetCDVolumeOn() { SetCDVolume(); } /*---------------------------------------------------------------------- Function: Purpose: Params: Returns: ---------------------------------------------------------------------- */ void SetCDVolume(int val) { CdlATV Vol; int VolL,VolR; int Channel=FMVChannelLR; SpuCommonAttr Attr; VolL=val; VolR=val; Vol.val0 = VolL; // CdL -> SpuL Vol.val1 = VolL; // CdL -> SpuR Vol.val2 = VolR; // CdR -> SpuR Vol.val3 = VolR; // CdR -> SpuL CdMix(&Vol); Attr.mask = (SPU_COMMON_CDVOLL|SPU_COMMON_CDVOLR|SPU_COMMON_CDMIX); Attr.cd.volume.left =32000; Attr.cd.volume.right=32000; Attr.cd.mix=SPU_ON; SpuSetCommonAttr(&Attr); } /*=========================================================================== end */