230 lines
5.9 KiB
C++
230 lines
5.9 KiB
C++
/*
|
|
gl_movie.cpp - draw screen movie surfaces
|
|
Copyright (C) 2011 Uncle Mike
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
*/
|
|
|
|
#include "hud.h"
|
|
#include "cl_util.h"
|
|
#include "gl_local.h"
|
|
#include "gl_world.h"
|
|
#include "mathlib.h"
|
|
#include "event_api.h"
|
|
#include <stringlib.h>
|
|
|
|
int R_PrecacheCinematic( const char *cinname )
|
|
{
|
|
int load_sound = 0;
|
|
|
|
if( !cinname || !*cinname )
|
|
return -1;
|
|
|
|
if( *cinname == '*' )
|
|
{
|
|
if( g_iXashEngineBuildNumber >= 4256 )
|
|
load_sound = 1;
|
|
cinname++;
|
|
}
|
|
|
|
// not AVI file
|
|
if( Q_stricmp( UTIL_FileExtension( cinname ), "avi" ))
|
|
return -1;
|
|
|
|
// first check for co-existing
|
|
for( int i = 0; i < MAX_MOVIES; i++ )
|
|
{
|
|
if( !Q_stricmp( tr.cinematics[i].name, cinname ))
|
|
{
|
|
// already existed
|
|
return i;
|
|
}
|
|
}
|
|
|
|
// found an empty slot
|
|
for( i = 0; i < MAX_MOVIES; i++ )
|
|
{
|
|
if( !tr.cinematics[i].name[0] )
|
|
break;
|
|
}
|
|
|
|
if( i == MAX_MOVIES )
|
|
{
|
|
ALERT( at_error, "R_PrecacheCinematic: cinematic list limit exceeded\n" );
|
|
return -1;
|
|
}
|
|
|
|
// register new cinematic
|
|
Q_strncpy( tr.cinematics[i].name, cinname, sizeof( tr.cinematics[0].name ));
|
|
if( tr.cinematics[i].state )
|
|
{
|
|
ALERT( at_warning, "Reused cin state %i with %s\n", i, tr.cinematics[i].name );
|
|
FREE_CINEMATIC( tr.cinematics[i].state );
|
|
}
|
|
|
|
ALERT( at_console, "Loading cinematic %s [%s]\n", cinname, load_sound ? "sound" : "muted" );
|
|
tr.cinematics[i].state = OPEN_CINEMATIC( tr.cinematics[i].name, load_sound );
|
|
|
|
// grab info about movie
|
|
if( tr.cinematics[i].state != NULL )
|
|
CIN_GET_VIDEO_INFO( tr.cinematics[i].state, &tr.cinematics[i].xres, &tr.cinematics[i].yres, &tr.cinematics[i].length );
|
|
|
|
return i;
|
|
}
|
|
|
|
void R_InitCinematics( void )
|
|
{
|
|
const char *name, *ext;
|
|
|
|
// make sure what we have texture to draw cinematics
|
|
if( !FBitSet( world->features, WORLD_HAS_MOVIES ))
|
|
return;
|
|
|
|
for( int i = 1; i < 1024; i++ )
|
|
{
|
|
name = gRenderfuncs.GetFileByIndex( i );
|
|
|
|
if( !name || !*name ) break; // end of files array
|
|
|
|
ext = UTIL_FileExtension( name );
|
|
if( Q_stricmp( ext, "avi" )) continue; // not AVI
|
|
|
|
if( R_PrecacheCinematic( name ) == -1 )
|
|
break; // full
|
|
}
|
|
}
|
|
|
|
void R_FreeCinematics( void )
|
|
{
|
|
for( int i = 0; i < MAX_MOVIES; i++ )
|
|
{
|
|
if( tr.cinematics[i].state )
|
|
{
|
|
ALERT( at_notice, "release cinematic %s\n", tr.cinematics[i].name );
|
|
FREE_CINEMATIC( tr.cinematics[i].state );
|
|
}
|
|
}
|
|
|
|
memset( tr.cinematics, 0, sizeof( tr.cinematics ));
|
|
|
|
for( i = 0; i < MAX_MOVIE_TEXTURES; i++ )
|
|
{
|
|
if( !tr.cinTextures[i] ) break;
|
|
FREE_TEXTURE( tr.cinTextures[i] );
|
|
}
|
|
|
|
memset( tr.cinTextures, 0, sizeof( tr.cinTextures ));
|
|
}
|
|
|
|
int R_AllocateCinematicTexture( unsigned int txFlags )
|
|
{
|
|
int i = tr.num_cin_used;
|
|
|
|
if( i >= MAX_MOVIE_TEXTURES )
|
|
{
|
|
ALERT( at_error, "R_AllocateCinematicTexture: cine textures limit exceeded!\n" );
|
|
return 0; // disable
|
|
}
|
|
tr.num_cin_used++;
|
|
|
|
if( !tr.cinTextures[i] )
|
|
{
|
|
char txName[16];
|
|
|
|
Q_snprintf( txName, sizeof( txName ), "*cinematic%i", i );
|
|
|
|
// create new cinematic texture
|
|
// NOTE: dimension of texture is no matter because CIN_UPLOAD_FRAME will be rescale texture
|
|
tr.cinTextures[i] = CREATE_TEXTURE( txName, 256, 256, NULL, txFlags );
|
|
}
|
|
|
|
return (i+1);
|
|
}
|
|
|
|
void R_UpdateCinematic( const msurface_t *surf )
|
|
{
|
|
if( !RI->currententity->curstate.body )
|
|
return; // just disabled
|
|
|
|
// draw the cinematic
|
|
mextrasurf_t *es = surf->info;
|
|
|
|
// found the corresponding cinstate
|
|
const char *cinname = gRenderfuncs.GetFileByIndex( RI->currententity->curstate.sequence );
|
|
int cinhandle = R_PrecacheCinematic( cinname );
|
|
|
|
if( cinhandle >= 0 && es->cintexturenum <= 0 )
|
|
es->cintexturenum = R_AllocateCinematicTexture( TF_NOMIPMAP );
|
|
|
|
if( cinhandle == -1 || es->cintexturenum <= 0 || CIN_IS_ACTIVE( tr.cinematics[cinhandle].state ) == false )
|
|
{
|
|
// cinematic textures limit exceeded, so remove SURF_MOVIE flag
|
|
((msurface_t *)surf)->flags &= ~SURF_MOVIE;
|
|
return;
|
|
}
|
|
|
|
gl_movie_t *cin = &tr.cinematics[cinhandle];
|
|
float cin_time;
|
|
|
|
if( FBitSet( RI->currententity->curstate.iuser1, CF_LOOPED_MOVIE ))
|
|
{
|
|
// advances cinematic time
|
|
cin_time = fmod( RI->currententity->curstate.fuser2, cin->length );
|
|
}
|
|
else
|
|
{
|
|
cin_time = RI->currententity->curstate.fuser2;
|
|
}
|
|
|
|
// read the next frame
|
|
int cin_frame = CIN_GET_FRAME_NUMBER( cin->state, cin_time );
|
|
|
|
// upload the new frame
|
|
if( cin_frame != es->checkcount )
|
|
{
|
|
GL_SelectTexture( GL_TEXTURE0 ); // doesn't matter. select 0-th unit just as default
|
|
byte *raw = CIN_GET_FRAMEDATA( cin->state, cin_frame );
|
|
CIN_UPLOAD_FRAME( tr.cinTextures[es->cintexturenum-1], cin->xres, cin->yres, cin->xres, cin->yres, raw );
|
|
es->checkcount = cin_frame;
|
|
}
|
|
}
|
|
|
|
void R_UpdateCinSound( cl_entity_t *e )
|
|
{
|
|
if( g_iXashEngineBuildNumber < 4256 )
|
|
return; // too old for this feature
|
|
|
|
if( !e->curstate.body || !FBitSet( e->curstate.iuser1, CF_MOVIE_SOUND ))
|
|
return; // just disabled
|
|
|
|
// found the corresponding cinstate
|
|
const char *cinname = gRenderfuncs.GetFileByIndex( e->curstate.sequence );
|
|
int cinhandle = R_PrecacheCinematic( cinname );
|
|
|
|
if( cinhandle == -1 || CIN_IS_ACTIVE( tr.cinematics[cinhandle].state ) == false )
|
|
return;
|
|
|
|
gl_movie_t *cin = &tr.cinematics[cinhandle];
|
|
float cin_time;
|
|
|
|
if( FBitSet( e->curstate.iuser1, CF_LOOPED_MOVIE ))
|
|
{
|
|
// advances cinematic time
|
|
cin_time = fmod( e->curstate.fuser2, cin->length );
|
|
}
|
|
else
|
|
{
|
|
cin_time = e->curstate.fuser2;
|
|
}
|
|
|
|
// stream avi sound
|
|
CIN_UPDATE_SOUND( cin->state, e->index, VOL_NORM, ATTN_IDLE, cin_time );
|
|
} |