jediacademy/codemp/client/BinkVideo.cpp
2013-04-04 17:35:38 -05:00

524 lines
10 KiB
C++

#include "snd_local_console.h"
#include "../renderer/tr_local.h"
#include "BinkVideo.h"
#include "RAD.h"
bool bvUseGCTexMem = true;
#ifdef _XBOX
int memMarker = 0;
char* binkXboxStartAddr = NULL;
char* binkXboxCurrentAddr = NULL;
char* binkXboxNextAddr = NULL;
#endif
static void PTR4* RADEXPLINK AllocWrapper(U32 size)
{
// Give bink pre-initialized mem on xbox
#ifdef _XBOX
switch(memMarker)
{
case 0:
memMarker++;
binkXboxCurrentAddr = binkXboxStartAddr;
binkXboxNextAddr = binkXboxCurrentAddr + size;
return (void *)binkXboxStartAddr;
case 1: case 2: case 3: case 4: case 5: case 6: case 7:
memMarker++;
binkXboxCurrentAddr = binkXboxNextAddr;
binkXboxNextAddr = binkXboxCurrentAddr + size;
return (void *)binkXboxCurrentAddr;
case 8:
memMarker = -1;
binkXboxCurrentAddr = binkXboxNextAddr;
binkXboxNextAddr = binkXboxStartAddr;
return (void *)binkXboxCurrentAddr;
default:
return BinkVideo::Allocate(size);
}
#endif
return BinkVideo::Allocate(size);
}
static void RADEXPLINK FreeWrapper(void PTR4* ptr)
{
// Don't free the preinitialized mem
#ifdef _XBOX
if(memMarker < 6)
{
memMarker++;
return;
}
else if(memMarker == 6)
{
memMarker = 1;
binkXboxNextAddr = binkXboxStartAddr + XBOX_MEM_STAGE_1;
return;
}
#endif
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;
#ifdef _XBOX
initialized = false;
#endif
}
/*********
~BinkVideo
*********/
BinkVideo::~BinkVideo()
{
Free(buffer);
BinkClose(bink);
}
/*********
AllocateXboxMem
Pre-Allocates memory for xbox
*********/
#ifdef _XBOX
void BinkVideo::AllocateXboxMem(void)
{
u32 memToAllocate = XBOX_MEM_STAGE_1 +
XBOX_MEM_STAGE_2 +
XBOX_MEM_STAGE_3 +
XBOX_MEM_STAGE_4 +
XBOX_MEM_STAGE_5 +
XBOX_MEM_STAGE_6 +
XBOX_MEM_STAGE_7 +
XBOX_MEM_STAGE_8 +
XBOX_BUFFER_SIZE;
binkXboxStartAddr = (char*)Allocate(memToAllocate);
memMarker = 0;
initialized = true;
}
/*********
FreeXboxMem
*********/
void BinkVideo::FreeXboxMem(void)
{
initialized = false;
Z_Free(binkXboxStartAddr);
memMarker = 0;
}
#endif
/*********
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)
{
#ifdef _XBOX
assert(initialized);
#endif
// 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
#if defined(_XBOX)
// If 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 );
#elif defined(_GAMECUBE)
BinkSoundUseNGCSound();
RADMEMALLOC a;
alGeti(AL_MEMORY_ALLOCATOR, (ALint*)&a);
RADMEMFREE f;
alGeti(AL_MEMORY_DEALLOCATOR, (ALint*)&f);
RADSetAudioMemory(a, f);
#endif
// Try to open the Bink file.
#ifdef _XBOX
bink = BinkOpen( filename, BINKSNDTRACK );
if(!bink)
{
return false;
}
#elif defined _GAMECUBE
if(bvUseGCTexMem)
{
extern void GLW_TexCacheLock(void);
GLW_TexCacheLock();
}
bink = BinkOpen( filename, 0);
if(!bink)
{
extern void GLW_TexCacheUnlock(void);
GLW_TexCacheUnlock();
return false;
}
#endif
assert(bink->Width <= MAX_WIDTH && bink->Height <=MAX_HEIGHT);
// allocate memory for the frame buffer
#ifdef _XBOX
buffer = AllocWrapper(XBOX_BUFFER_SIZE);
#elif _GAMECUBE
buffer = Allocate(XBOX_BUFFER_SIZE);
#endif
// set the height, width, etc...
x1 = xOrigin;
y1 = yOrigin;
x2 = x1 + width;
y2 = y1 + height;
w = width;
h = height;
// flush any background sound reads
#if defined (_XBOX)|| (_GAMECUBE)
extern void S_DrainRawSoundData(void);
S_DrainRawSoundData();
#endif
// 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, GL_RGB5, bink->Width, bink->Height, 0,
GL_RGB_SWIZZLE_EXT, 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));
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,
GL_RGB_SWIZZLE_EXT, 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 ( 1 , 0 );
qglVertex2f (650, -10);
qglTexCoord2f ( 0, 1 );
qglVertex2f (-10, 490);
qglTexCoord2f ( 1, 1 );
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 ( 1 , 0 );
qglVertex2f (x2, y1);
qglTexCoord2f ( 0, 1 );
qglVertex2f (x1, y2);
qglTexCoord2f ( 1, 1 );
qglVertex2f (x2, y2);
qglEnd ();
}
}
/*********
Stop
Stops the current movie, and clears it from memory
*********/
void BinkVideo::Stop(void)
{
BinkClose(bink);
bink = NULL;
#ifdef _XBOX
FreeWrapper(buffer);
#elif _GAMECUBE
Free(buffer);
#endif
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;
#ifdef _XBOX
memMarker = 0;
#endif
#ifdef _GAMECUBE
extern void GLW_TexCacheUnlock(void);
GLW_TexCacheUnlock();
#endif
}
/*********
Pause
Pauses the current movie. Only the current frame is rendered
*********/
void BinkVideo::Pause(void)
{
status = NS_BV_PAUSED;
}
/*********
SetExtends
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)
{
#ifdef _XBOX
int i;
for(i = 0; i < 4; i++)
{
BinkSetVolume(bink,i,volume);
}
#else
BinkSetVolume(bink,0,volume);
#endif
}
/*********
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,
BINKCOPYALL | BINKSURFACE565);
return skip;
}
/*********
Allocate
Allocates memory for the frame buffer
*********/
void *BinkVideo::Allocate(U32 size)
{
size = RoundUp(size + 32, 32);
char* ptr = NULL;
#ifdef _GAMECUBE
if (bvUseGCTexMem)
{
// Try allocating from texture cache
extern void* GLW_TexCacheAllocRaw(int size);
ptr = (char*)GLW_TexCacheAllocRaw(size);
}
#endif
if (!ptr)
{
// Did not allocate texture cache memory, fall
// back to main memory..
ptr = (char*)Z_Malloc(size, TAG_BINK, qfalse, 32);
ptr[0] = 'z';
}
else
{
// Allocated memory from the texture cache
ptr[0] = 't';
}
return (void*)(ptr + 32);
}
/*********
FreeBuffer
Releases the frame buffer memory
*********/
void BinkVideo::Free(void* ptr)
{
char* base = (char*)ptr - 32;
switch (*base)
{
#ifdef _GAMECUBE
case 't':
{
// Free texture cache memory
extern void GLW_TexCacheFreeRaw(void* ptr);
GLW_TexCacheFreeRaw(base);
break;
}
#endif
case 'z':
// Free main memory
Z_Free(base);
break;
default:
assert(false);
}
}