SBSPSS/source/fmv/fmv.cpp
2001-09-06 19:03:11 +00:00

538 lines
11 KiB
C++

/*=========================================================================
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 <sys/types.h>
#include <libgte.h>
#include <libgpu.h>
#include <libpress.h>
#include <libcd.h>
#include <libetc.h>
/* 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 **)&sector))
{
if (--cnt == 0) return(0);
}
if (sector->frameCount >= AniNoFrames) QuitFlag = 1;
if (sector->frameCount<LastFrame) QuitFlag=1; // Fix for nasty over-run bug
LastFrame=sector->frameCount;
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 */