jedi-academy/code/client/BinkVideo.cpp
2013-04-23 15:21:39 +10:00

389 lines
7.7 KiB
C++

/*
* This version of BinkVideo.cpp now ONLY works on Xbox.
* GCN support is hosed.
*/
#include "snd_local_console.h"
#include "../renderer/tr_local.h"
#include "BinkVideo.h"
#include "RAD.h"
char* binkSndMem = NULL;
static void PTR4* RADEXPLINK AllocWrapper(U32 size)
{
// Give bink pre-initialized sound mem on xbox
if(size == XBOX_BINK_SND_MEM) {
return binkSndMem;
}
return BinkVideo::Allocate(size);
}
static void RADEXPLINK FreeWrapper(void PTR4* ptr)
{
BinkVideo::Free(ptr);
}
/*********
BinkVideo
*********/
BinkVideo::BinkVideo()
{
bink = NULL;
buffer = NULL;
texture = 0;
x1 = 0.0f;
y1 = 0.0f;
x2 = 0.0f;
y2 = 0.0f;
w = 0.0f;
h = 0.0f;
status = NS_BV_STOPPED;
looping = false;
alpha = false;
#ifdef _XBOX
initialized = false;
#endif
}
/*********
~BinkVideo
*********/
BinkVideo::~BinkVideo()
{
Free(buffer);
BinkClose(bink);
}
/*********
AllocateXboxMem
Pre-Allocates sound memory for xbox to avoid fragmenting
*********/
void BinkVideo::AllocateXboxMem(void)
{
binkSndMem = (char*)Allocate(XBOX_BINK_SND_MEM);
initialized = true;
}
/*********
FreeXboxMem
*********/
void BinkVideo::FreeXboxMem(void)
{
initialized = false;
Z_Free(binkSndMem);
}
/*********
Start
Opens a bink file and gets it ready to play
*********/
bool BinkVideo::Start(const char *filename, float xOrigin, float yOrigin, float width, float height)
{
assert(initialized);
// Check to see if a video is being played.
if(status == NS_BV_PLAYING)
{
// stop
this->Stop();
}
// Set memory allocation wrapper
RADSetMemory(AllocWrapper,FreeWrapper);
// Set up sound for consoles
// We are on XBox, tell Bink to play all of the 5.1 tracks
U32 TrackIDsToPlay[ 4 ] = { 0, 1, 2, 3 };
BinkSetSoundTrack( 4, TrackIDsToPlay );
// Now route the sound tracks to the correct speaker
U32 bins[ 2 ];
bins[ 0 ] = DSMIXBIN_FRONT_LEFT;
bins[ 1 ] = DSMIXBIN_FRONT_RIGHT;
BinkSetMixBins( bink, 0, bins, 2 );
bins[ 0 ] = DSMIXBIN_FRONT_CENTER;
BinkSetMixBins( bink, 1, bins, 1 );
bins[ 0 ] = DSMIXBIN_LOW_FREQUENCY;
BinkSetMixBins( bink, 2, bins, 1 );
bins[ 0 ] = DSMIXBIN_BACK_LEFT;
bins[ 1 ] = DSMIXBIN_BACK_RIGHT;
BinkSetMixBins( bink, 3, bins, 2 );
// Try to open the Bink file.
bink = BinkOpen( filename, BINKSNDTRACK | BINKALPHA );
if(!bink)
{
return false;
}
assert(bink->Width <= MAX_WIDTH && bink->Height <=MAX_HEIGHT);
// allocate memory for the frame buffer
buffer = AllocWrapper(XBOX_BUFFER_SIZE);
// set the height, width, etc...
x1 = xOrigin;
y1 = yOrigin;
x2 = x1 + width;
y2 = y1 + height;
w = width;
h = height;
// Did the source .bik file have an alpha plane?
alpha = (bool)(bink->OpenFlags & BINKALPHA);
// flush any background sound reads
extern void S_DrainRawSoundData(void);
S_DrainRawSoundData();
// Create the video texture
GLuint tex = (GLuint)texture;
if (tex != 0)
qglDeleteTextures(1, &tex);
qglGenTextures(1, &tex);
qglBindTexture(GL_TEXTURE_2D, tex);
glState.currenttextures[glState.currenttmu] = tex;
qglTexImage2D(GL_TEXTURE_2D,
0,
alpha ? GL_LIN_RGBA8 : GL_LIN_RGB8,
bink->Width,
bink->Height,
0,
alpha ? GL_LIN_RGBA : GL_LIN_RGB,
GL_UNSIGNED_BYTE,
buffer);
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
qglTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
texture = (int)tex;
status = NS_BV_PLAYING;
return true;
}
/*********
Run
Decompresses a frame, renders it to the screen, and advances to
the next frame.
*********/
bool BinkVideo::Run(void)
{
if(status == NS_BV_STOPPED) // A movie can't be run if it's not started first
{
return false;
}
while(BinkWait(bink)); // Wait
DecompressFrame(); // Decompress
Draw(); // Render
if(status != NS_BV_PAUSED) // Only advance the frame is not paused
{
BinkNextFrame( bink );
}
if(bink->FrameNum == (bink->Frames - 1) && !looping) // The movie is done
{
Stop();
return false;
}
return true;
}
/*********
GetBinkData
Returns the buffer data for the next frame of the video
*********/
void* BinkVideo::GetBinkData(void)
{
//while(BinkWait(bink));
// This doesn't follow Bink guidelines. They suggest that you call BinkWait()
// very frequently, something like 4 to 5 times as fast as the framerate of
// the movie. We're technically coming close to that, but this code won't work
// if we have videoMap shaders with higher framerates than the planets (8).
if (!BinkWait(bink))
{
DecompressFrame();
BinkNextFrame(bink);
}
return buffer;
}
/********
Draw
Copies the decompressed frame to a texture to be rendered on
the screen.
********/
void BinkVideo::Draw(void)
{
if(buffer)
{
qglFlush();
extern void RB_SetGL2D (void);
RB_SetGL2D();
GL_SelectTexture(0);
// Update the video texture
qglBindTexture(GL_TEXTURE_2D, (GLuint)texture);
glState.currenttextures[glState.currenttmu] = texture;
qglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, bink->Width, bink->Height,
alpha ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, buffer );
// Clear the screen. We use triangles here (instead
// of glClear) because we want the back buffer to stick
// around... so we can get a nice, cheap fade on Gamecube
// reset.
qglColor3f(0.f, 0.f, 0.f);
#if defined (_XBOX) || (_GAMECUBE)
qglBeginEXT (GL_TRIANGLE_STRIP, 4, 0, 0, 4, 0);
#else
qglBegin(GL_TRIANGLE_STRIP);
#endif
qglTexCoord2f ( 0, 0 );
qglVertex2f (-10, -10);
qglTexCoord2f ( bink->Width , 0 );
qglVertex2f (650, -10);
qglTexCoord2f ( 0, bink->Height );
qglVertex2f (-10, 490);
qglTexCoord2f ( bink->Width, bink->Height );
qglVertex2f (650, 490);
qglEnd ();
// Draw the video
qglColor3f(1.f, 1.f, 1.f);
#if defined (_XBOX) || (_GAMECUBE)
qglBeginEXT (GL_TRIANGLE_STRIP, 4, 0, 0, 4, 0);
#else
qglBegin(GL_TRIANGLE_STRIP);
#endif
qglTexCoord2f ( 0, 0 );
qglVertex2f (x1, y1);
qglTexCoord2f ( bink->Width , 0 );
qglVertex2f (x2, y1);
qglTexCoord2f ( 0, bink->Height );
qglVertex2f (x1, y2);
qglTexCoord2f ( bink->Width, bink->Height );
qglVertex2f (x2, y2);
qglEnd ();
}
}
/*********
Stop
Stops the current movie, and clears it from memory
*********/
void BinkVideo::Stop(void)
{
if (bink)
BinkClose(bink);
bink = NULL;
if (buffer)
FreeWrapper(buffer);
buffer = NULL;
GLuint tex = (GLuint)texture;
if (tex != 0)
qglDeleteTextures(1, &tex);
texture = 0;
x1 = 0.0f;
y1 = 0.0f;
x2 = 0.0f;
y2 = 0.0f;
w = 0.0f;
h = 0.0f;
status = NS_BV_STOPPED;
}
/*********
Pause
Pauses the current movie. Only the current frame is rendered
*********/
void BinkVideo::Pause(void)
{
status = NS_BV_PAUSED;
}
/*********
SetExtents
Sets dimmension variables
*********/
void BinkVideo::SetExtents(float xOrigin, float yOrigin, float width, float height)
{
x1 = xOrigin;
y1 = yOrigin;
x2 = x1 + width;
y2 = y1 + height;
w = width;
h = height;
}
/*********
SetMasterVolume
Sets the volume of the specified track
*********/
void BinkVideo::SetMasterVolume(s32 volume)
{
int i;
for(i = 0; i < 4; i++)
{
BinkSetVolume(bink,i,volume);
}
}
/*********
DecompressFrame
Decompresses current frame and copies the data to
the buffer
*********/
S32 BinkVideo::DecompressFrame()
{
BinkDoFrame(bink);
S32 skip;
skip = BinkCopyToBuffer(
bink,
(void *)buffer,
NS_BV_DEFAULT_CIN_BPS * bink->Width, //pitch
bink->Height,
0,
0,
alpha ? BINKCOPYALL | BINKSURFACE32A : BINKCOPYALL | BINKSURFACE32);
return skip;
}
/*********
Allocate
Allocates memory for the frame buffer
*********/
void *BinkVideo::Allocate(U32 size)
{
return Z_Malloc(size, TAG_BINK, qfalse, 32);
}
/*********
FreeBuffer
Releases the frame buffer memory
*********/
void BinkVideo::Free(void* ptr)
{
Z_Free(ptr);
}