2208 lines
53 KiB
C++
2208 lines
53 KiB
C++
#include "../idlib/precompiled.h"
|
|
#pragma hdrstop
|
|
|
|
#include "Game_local.h"
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idCamera
|
|
|
|
Base class for cameras
|
|
|
|
===============================================================================
|
|
*/
|
|
|
|
ABSTRACT_DECLARATION( idEntity, idCamera )
|
|
END_CLASS
|
|
|
|
/*
|
|
=====================
|
|
idCamera::Spawn
|
|
=====================
|
|
*/
|
|
void idCamera::Spawn( void ) {
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idCamera::GetRenderView
|
|
=====================
|
|
*/
|
|
renderView_t *idCamera::GetRenderView() {
|
|
renderView_t *rv = idEntity::GetRenderView();
|
|
GetViewParms( rv );
|
|
return rv;
|
|
}
|
|
|
|
/***********************************************************************
|
|
|
|
idCameraView
|
|
|
|
***********************************************************************/
|
|
const idEventDef EV_Camera_SetAttachments( "<getattachments>", NULL );
|
|
|
|
// RAVEN BEGIN
|
|
// bdube: added events
|
|
const idEventDef EV_SetFOV ( "setFOV", "f" );
|
|
const idEventDef EV_GetFOV ( "getFOV", NULL, 'f' );
|
|
const idEventDef EV_BlendFOV ( "blendFOV", "fff");
|
|
// RAVEN END
|
|
|
|
CLASS_DECLARATION( idCamera, idCameraView )
|
|
EVENT( EV_Activate, idCameraView::Event_Activate )
|
|
EVENT( EV_Camera_SetAttachments, idCameraView::Event_SetAttachments )
|
|
|
|
// RAVEN BEGIN
|
|
// bdube: added events
|
|
EVENT( EV_SetFOV, idCameraView::Event_SetFOV )
|
|
EVENT( EV_BlendFOV, idCameraView::Event_BlendFOV )
|
|
EVENT( EV_GetFOV, idCameraView::Event_GetFOV )
|
|
// RAVEN END
|
|
END_CLASS
|
|
|
|
/*
|
|
===============
|
|
idCameraView::idCameraView
|
|
================
|
|
*/
|
|
idCameraView::idCameraView() {
|
|
// RAVEN BEGIN
|
|
// bdube: interpolate fov
|
|
// scork: get it from the cvar, don't assume 90
|
|
fov.Init ( gameLocal.time, 0, g_fov.GetFloat(), g_fov.GetFloat() );
|
|
// RAVEN END
|
|
attachedTo = NULL;
|
|
attachedView = NULL;
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCameraView::Save
|
|
================
|
|
*/
|
|
void idCameraView::Save( idSaveGame *savefile ) const {
|
|
// RAVEN BEGIN
|
|
// bdube: fov interpolated now
|
|
savefile->WriteInt( fov.GetDuration() );
|
|
savefile->WriteInt( fov.GetStartTime() );
|
|
savefile->WriteFloat( fov.GetStartValue() );
|
|
savefile->WriteFloat( fov.GetEndValue() );
|
|
// RAVEN END
|
|
savefile->WriteObject( attachedTo );
|
|
savefile->WriteObject( attachedView );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCameraView::Restore
|
|
================
|
|
*/
|
|
void idCameraView::Restore( idRestoreGame *savefile ) {
|
|
// RAVEN BEGIN
|
|
// bdube: fov interpolated now
|
|
int set;
|
|
float setf;
|
|
savefile->ReadInt( set );
|
|
fov.SetDuration( set );
|
|
savefile->ReadInt( set );
|
|
fov.SetStartTime( set );
|
|
savefile->ReadFloat( setf );
|
|
fov.SetStartValue( setf );
|
|
savefile->ReadFloat( setf );
|
|
fov.SetEndValue( setf );
|
|
// RAVEN END
|
|
savefile->ReadObject( reinterpret_cast<idClass *&>( attachedTo ) );
|
|
savefile->ReadObject( reinterpret_cast<idClass *&>( attachedView ) );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCameraView::Event_SetAttachments
|
|
================
|
|
*/
|
|
void idCameraView::Event_SetAttachments( ) {
|
|
SetAttachment( &attachedTo, "attachedTo" );
|
|
SetAttachment( &attachedView, "attachedView" );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCameraView::Event_Activate
|
|
================
|
|
*/
|
|
void idCameraView::Event_Activate( idEntity *activator ) {
|
|
if (spawnArgs.GetBool("trigger")) {
|
|
if (gameLocal.GetCamera() != this) {
|
|
if ( g_debugCinematic.GetBool() ) {
|
|
gameLocal.Printf( "%d: '%s' start\n", gameLocal.framenum, GetName() );
|
|
}
|
|
|
|
gameLocal.SetCamera(this);
|
|
} else {
|
|
if ( g_debugCinematic.GetBool() ) {
|
|
gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() );
|
|
}
|
|
gameLocal.SetCamera(NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idCameraView::Stop
|
|
=====================
|
|
*/
|
|
void idCameraView::Stop( void ) {
|
|
if ( g_debugCinematic.GetBool() ) {
|
|
gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() );
|
|
}
|
|
gameLocal.SetCamera(NULL);
|
|
ActivateTargets( gameLocal.GetLocalPlayer() );
|
|
}
|
|
|
|
// RAVEN BEGIN
|
|
// bdube: added events
|
|
/*
|
|
=====================
|
|
idCameraView::Event_SetFOV
|
|
=====================
|
|
*/
|
|
void idCameraView::Event_SetFOV ( float newfov )
|
|
{
|
|
fov.Init ( gameLocal.time, 0, newfov, newfov );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idCameraView::Event_BlendFOV
|
|
=====================
|
|
*/
|
|
void idCameraView::Event_BlendFOV ( float beginFOV, float endFOV, float blendTime )
|
|
{
|
|
fov.Init ( gameLocal.time, SEC2MS(blendTime), beginFOV, endFOV );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idCameraView::Event_GetFOV
|
|
=====================
|
|
*/
|
|
void idCameraView::Event_GetFOV()
|
|
{
|
|
idThread::ReturnFloat(fov.GetCurrentValue(gameLocal.time));
|
|
}
|
|
// RAVEN END
|
|
|
|
/*
|
|
=====================
|
|
idCameraView::Spawn
|
|
=====================
|
|
*/
|
|
void idCameraView::SetAttachment( idEntity **e, const char *p ) {
|
|
const char *cam = spawnArgs.GetString( p );
|
|
if ( strlen ( cam ) ) {
|
|
*e = gameLocal.FindEntity( cam );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=====================
|
|
idCameraView::Spawn
|
|
=====================
|
|
*/
|
|
void idCameraView::Spawn( void ) {
|
|
// if no target specified use ourself
|
|
const char *cam = spawnArgs.GetString("cameraTarget");
|
|
if ( strlen ( cam ) == 0) {
|
|
spawnArgs.Set("cameraTarget", spawnArgs.GetString("name"));
|
|
}
|
|
// RAVEN BEGIN
|
|
// bdube: interpolate fov
|
|
// scork: ... but default from the cvar, not hardwired 90
|
|
fov.Init ( gameLocal.time, 0, spawnArgs.GetFloat("fov", va("%f",g_fov.GetFloat())), spawnArgs.GetFloat("fov", va("%f",g_fov.GetFloat())) );
|
|
// RAVEN END
|
|
|
|
PostEventMS( &EV_Camera_SetAttachments, 0 );
|
|
|
|
UpdateChangeableSpawnArgs(NULL);
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idCamera::RenderView
|
|
=====================
|
|
*/
|
|
void idCameraView::GetViewParms( renderView_t *view ) {
|
|
assert( view );
|
|
|
|
if (view == NULL) {
|
|
return;
|
|
}
|
|
|
|
idVec3 dir;
|
|
idEntity *ent;
|
|
|
|
if ( attachedTo ) {
|
|
ent = attachedTo;
|
|
} else {
|
|
ent = this;
|
|
}
|
|
|
|
view->vieworg = ent->GetPhysics()->GetOrigin();
|
|
if ( attachedView ) {
|
|
dir = attachedView->GetPhysics()->GetOrigin() - view->vieworg;
|
|
dir.Normalize();
|
|
view->viewaxis = dir.ToMat3();
|
|
} else {
|
|
view->viewaxis = ent->GetPhysics()->GetAxis();
|
|
}
|
|
|
|
// RAVEN BEGIN
|
|
// bdube: interpolate fov
|
|
gameLocal.CalcFov( fov.GetCurrentValue( gameLocal.time ), view->fov_x, view->fov_y );
|
|
// RAVEN END
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// RAVEN BEGIN
|
|
// rjohnson: camera is now contained in a def for frame commands
|
|
|
|
/***********************************************************************
|
|
|
|
rvCameraAnimation
|
|
|
|
***********************************************************************/
|
|
/*
|
|
=====================
|
|
rvCameraAnimation::rvCameraAnimation
|
|
=====================
|
|
*/
|
|
rvCameraAnimation::rvCameraAnimation( void ) {
|
|
frameRate = 0;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraAnimation::rvCameraAnimation
|
|
=====================
|
|
*/
|
|
rvCameraAnimation::rvCameraAnimation( const idDeclCameraDef *cameraDef, const rvCameraAnimation *anim ) {
|
|
cameraCuts = anim->cameraCuts;
|
|
camera = anim->camera;
|
|
frameLookup = anim->frameLookup;
|
|
frameCommands = anim->frameCommands;
|
|
frameRate = anim->frameRate;
|
|
name = anim->name;
|
|
realname = anim->realname;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraAnimation::~rvCameraAnimation
|
|
=====================
|
|
*/
|
|
rvCameraAnimation::~rvCameraAnimation( void ) {
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraAnimation::Name
|
|
=====================
|
|
*/
|
|
const char *rvCameraAnimation::Name( void ) const {
|
|
return name;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraAnimation::FullName
|
|
=====================
|
|
*/
|
|
const char *rvCameraAnimation::FullName( void ) const {
|
|
return realname;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraAnimation::NumFrames
|
|
=====================
|
|
*/
|
|
int rvCameraAnimation::NumFrames( void ) const {
|
|
return camera.Num();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraAnimation::NumCuts
|
|
=====================
|
|
*/
|
|
int rvCameraAnimation::NumCuts( void ) const {
|
|
return cameraCuts.Num();
|
|
}
|
|
|
|
void rvCameraAnimation::SetAnim( const idDeclCameraDef *cameraDef, const char *sourcename, const char *animname, idStr filename ) {
|
|
int version;
|
|
idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
|
|
idToken token;
|
|
int numFrames;
|
|
int numCuts;
|
|
int i;
|
|
|
|
filename.SetFileExtension( MD5_CAMERA_EXT );
|
|
if ( !parser.LoadFile( filename ) ) {
|
|
gameLocal.Error( "Unable to load '%s' on '%s'", filename.c_str(), name.c_str() );
|
|
}
|
|
|
|
cameraCuts.Clear();
|
|
cameraCuts.SetGranularity( 1 );
|
|
camera.Clear();
|
|
camera.SetGranularity( 1 );
|
|
|
|
parser.ExpectTokenString( MD5_VERSION_STRING );
|
|
version = parser.ParseInt();
|
|
if ( version != MD5_VERSION ) {
|
|
parser.Error( "Invalid version %d. Should be version %d\n", version, MD5_VERSION );
|
|
}
|
|
|
|
// skip the commandline
|
|
parser.ExpectTokenString( "commandline" );
|
|
parser.ReadToken( &token );
|
|
|
|
// parse num frames
|
|
parser.ExpectTokenString( "numFrames" );
|
|
numFrames = parser.ParseInt();
|
|
if ( numFrames <= 0 ) {
|
|
parser.Error( "Invalid number of frames: %d", numFrames );
|
|
}
|
|
|
|
// parse framerate
|
|
parser.ExpectTokenString( "frameRate" );
|
|
frameRate = parser.ParseInt();
|
|
if ( frameRate <= 0 ) {
|
|
parser.Error( "Invalid framerate: %d", frameRate );
|
|
}
|
|
|
|
// parse num cuts
|
|
parser.ExpectTokenString( "numCuts" );
|
|
numCuts = parser.ParseInt();
|
|
if ( ( numCuts < 0 ) || ( numCuts > numFrames ) ) {
|
|
parser.Error( "Invalid number of camera cuts: %d", numCuts );
|
|
}
|
|
|
|
// parse the camera cuts
|
|
parser.ExpectTokenString( "cuts" );
|
|
parser.ExpectTokenString( "{" );
|
|
cameraCuts.SetNum( numCuts );
|
|
for( i = 0; i < numCuts; i++ ) {
|
|
cameraCuts[ i ] = parser.ParseInt();
|
|
if ( ( cameraCuts[ i ] < 1 ) || ( cameraCuts[ i ] >= numFrames ) ) {
|
|
parser.Error( "Invalid camera cut" );
|
|
}
|
|
}
|
|
parser.ExpectTokenString( "}" );
|
|
|
|
// parse the camera frames
|
|
parser.ExpectTokenString( "camera" );
|
|
parser.ExpectTokenString( "{" );
|
|
camera.SetNum( numFrames );
|
|
for( i = 0; i < numFrames; i++ ) {
|
|
parser.Parse1DMatrix( 3, camera[ i ].t.ToFloatPtr() );
|
|
parser.Parse1DMatrix( 3, camera[ i ].q.ToFloatPtr() );
|
|
camera[ i ].fov = parser.ParseFloat();
|
|
}
|
|
parser.ExpectTokenString( "}" );
|
|
|
|
#if 0
|
|
if ( !gameLocal.GetLocalPlayer() ) {
|
|
return;
|
|
}
|
|
|
|
idDebugGraph gGraph;
|
|
idDebugGraph tGraph;
|
|
idDebugGraph qGraph;
|
|
idDebugGraph dtGraph;
|
|
idDebugGraph dqGraph;
|
|
gGraph.SetNumSamples( numFrames );
|
|
tGraph.SetNumSamples( numFrames );
|
|
qGraph.SetNumSamples( numFrames );
|
|
dtGraph.SetNumSamples( numFrames );
|
|
dqGraph.SetNumSamples( numFrames );
|
|
|
|
gameLocal.Printf( "\n\ndelta vec:\n" );
|
|
float diff_t, last_t, t;
|
|
float diff_q, last_q, q;
|
|
diff_t = last_t = 0.0f;
|
|
diff_q = last_q = 0.0f;
|
|
for( i = 1; i < numFrames; i++ ) {
|
|
t = ( camera[ i ].t - camera[ i - 1 ].t ).Length();
|
|
q = ( camera[ i ].q.ToQuat() - camera[ i - 1 ].q.ToQuat() ).Length();
|
|
diff_t = t - last_t;
|
|
diff_q = q - last_q;
|
|
gGraph.AddValue( ( i % 10 ) == 0 );
|
|
tGraph.AddValue( t );
|
|
qGraph.AddValue( q );
|
|
dtGraph.AddValue( diff_t );
|
|
dqGraph.AddValue( diff_q );
|
|
|
|
gameLocal.Printf( "%d: %.8f : %.8f, %.8f : %.8f\n", i, t, diff_t, q, diff_q );
|
|
last_t = t;
|
|
last_q = q;
|
|
}
|
|
|
|
gGraph.Draw( colorBlue, 300.0f );
|
|
tGraph.Draw( colorOrange, 60.0f );
|
|
dtGraph.Draw( colorYellow, 6000.0f );
|
|
qGraph.Draw( colorGreen, 60.0f );
|
|
dqGraph.Draw( colorCyan, 6000.0f );
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraAnimation::AddFrameCommand
|
|
|
|
Returns NULL if no error.
|
|
=====================
|
|
*/
|
|
const char *rvCameraAnimation::AddFrameCommand( const idDeclCameraDef *cameraDef, const idList<int>& frames, idLexer &src, const idDict *def ) {
|
|
int i;
|
|
int index;
|
|
idStr text;
|
|
idStr funcname;
|
|
frameCommand_t fc;
|
|
idToken token;
|
|
|
|
memset( &fc, 0, sizeof( fc ) );
|
|
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
|
|
if ( token == "call" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SCRIPTFUNCTION;
|
|
fc.function = gameLocal.program.FindFunction( token );
|
|
if ( !fc.function ) {
|
|
return va( "Function '%s' not found", token.c_str() );
|
|
}
|
|
} else if ( token == "object_call" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SCRIPTFUNCTIONOBJECT;
|
|
fc.string = new idStr( token );
|
|
} else if ( token == "event" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_EVENTFUNCTION;
|
|
const idEventDef *ev = idEventDef::FindEvent( token );
|
|
if ( !ev ) {
|
|
return va( "Event '%s' not found", token.c_str() );
|
|
}
|
|
if ( ev->GetNumArgs() != 0 ) {
|
|
return va( "Event '%s' has arguments", token.c_str() );
|
|
}
|
|
fc.string = new idStr( token );
|
|
}
|
|
// RAVEN BEGIN
|
|
// abahr:
|
|
else if( token == "eventArgs" ) {
|
|
src.ParseRestOfLine( token );
|
|
if( token.Length() <= 0 ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
|
|
fc.type = FC_EVENTFUNCTION_ARGS;
|
|
fc.parmList = new idList<idStr>();
|
|
token.Split( *fc.parmList, ' ' );
|
|
fc.event = idEventDef::FindEvent( (*fc.parmList)[0] );
|
|
if( !fc.event ) {
|
|
SAFE_DELETE_PTR( fc.parmList );
|
|
return va( "Event '%s' not found", (*fc.parmList)[0].c_str() );
|
|
}
|
|
|
|
fc.parmList->RemoveIndex( 0 );
|
|
}
|
|
// RAVEN END
|
|
else if ( token == "sound" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SOUND;
|
|
if ( !token.Cmpn( "snd_", 4 ) ) {
|
|
fc.string = new idStr( token );
|
|
} else {
|
|
fc.soundShader = declManager->FindSound( token );
|
|
if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
|
|
gameLocal.Warning( "Sound '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "sound_voice" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SOUND_VOICE;
|
|
if ( !token.Cmpn( "snd_", 4 ) ) {
|
|
fc.string = new idStr( token );
|
|
} else {
|
|
fc.soundShader = declManager->FindSound( token );
|
|
if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
|
|
gameLocal.Warning( "Sound '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "sound_voice2" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SOUND_VOICE2;
|
|
if ( !token.Cmpn( "snd_", 4 ) ) {
|
|
fc.string = new idStr( token );
|
|
} else {
|
|
fc.soundShader = declManager->FindSound( token );
|
|
if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
|
|
gameLocal.Warning( "Sound '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "sound_body" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SOUND_BODY;
|
|
if ( !token.Cmpn( "snd_", 4 ) ) {
|
|
fc.string = new idStr( token );
|
|
} else {
|
|
fc.soundShader = declManager->FindSound( token );
|
|
if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
|
|
gameLocal.Warning( "Sound '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "sound_body2" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SOUND_BODY2;
|
|
if ( !token.Cmpn( "snd_", 4 ) ) {
|
|
fc.string = new idStr( token );
|
|
} else {
|
|
fc.soundShader = declManager->FindSound( token );
|
|
if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
|
|
gameLocal.Warning( "Sound '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "sound_body3" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SOUND_BODY3;
|
|
if ( !token.Cmpn( "snd_", 4 ) ) {
|
|
fc.string = new idStr( token );
|
|
} else {
|
|
fc.soundShader = declManager->FindSound( token );
|
|
if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
|
|
gameLocal.Warning( "Sound '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "sound_weapon" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SOUND_WEAPON;
|
|
if ( !token.Cmpn( "snd_", 4 ) ) {
|
|
fc.string = new idStr( token );
|
|
} else {
|
|
fc.soundShader = declManager->FindSound( token );
|
|
if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
|
|
gameLocal.Warning( "Sound '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "sound_global" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SOUND_GLOBAL;
|
|
if ( !token.Cmpn( "snd_", 4 ) ) {
|
|
fc.string = new idStr( token );
|
|
} else {
|
|
fc.soundShader = declManager->FindSound( token );
|
|
if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
|
|
gameLocal.Warning( "Sound '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "sound_item" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SOUND_ITEM;
|
|
if ( !token.Cmpn( "snd_", 4 ) ) {
|
|
fc.string = new idStr( token );
|
|
} else {
|
|
fc.soundShader = declManager->FindSound( token );
|
|
if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
|
|
gameLocal.Warning( "Sound '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "sound_chatter" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SOUND_CHATTER;
|
|
if ( !token.Cmpn( "snd_", 4 ) ) {
|
|
fc.string = new idStr( token );
|
|
} else {
|
|
fc.soundShader = declManager->FindSound( token );
|
|
if ( fc.soundShader->GetState() == DS_DEFAULTED ) {
|
|
gameLocal.Warning( "Sound '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "skin" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_SKIN;
|
|
if ( token == "none" ) {
|
|
fc.skin = NULL;
|
|
} else {
|
|
fc.skin = declManager->FindSkin( token );
|
|
if ( !fc.skin ) {
|
|
return va( "Skin '%s' not found", token.c_str() );
|
|
}
|
|
}
|
|
} else if ( token == "fx" ) {
|
|
// RAVEN BEGIN
|
|
// bdube: use Raven effect system
|
|
fc.type = FC_FX;
|
|
|
|
// Get the effect name
|
|
if ( !src.ReadTokenOnLine( &token ) ) {
|
|
return va( "missing effect name" );
|
|
}
|
|
|
|
// Effect is indirect if it starts with fx_
|
|
if ( !idStr::Icmpn ( token, "fx_", 3 ) ) {
|
|
fc.string = new idStr ( token );
|
|
} else {
|
|
fc.effect = ( const idDecl * )declManager->FindEffect( token );
|
|
}
|
|
|
|
// Joint specified?
|
|
if ( src.ReadTokenOnLine ( &token ) ) {
|
|
fc.joint = new idStr ( token );
|
|
}
|
|
|
|
// End joint specified?
|
|
if ( src.ReadTokenOnLine ( &token ) ) {
|
|
fc.joint2 = new idStr ( token );
|
|
}
|
|
// RAVEN END
|
|
} else if ( token == "trigger" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_TRIGGER;
|
|
fc.string = new idStr( token );
|
|
// RAVEN BEGIN
|
|
// bdube: not using
|
|
/*
|
|
} else if ( token == "triggerSmokeParticle" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_TRIGGER_SMOKE_PARTICLE;
|
|
fc.string = new idStr( token );
|
|
*/
|
|
// RAVEN END
|
|
} else if ( token == "direct_damage" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_DIRECTDAMAGE;
|
|
if ( !gameLocal.FindEntityDef( token.c_str(), false ) ) {
|
|
return va( "Unknown entityDef '%s'", token.c_str() );
|
|
}
|
|
fc.string = new idStr( token );
|
|
} else if ( token == "muzzle_flash" ) {
|
|
/* if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
if ( ( token != "" ) && !modelDef->FindJoint( token ) ) {
|
|
return va( "Joint '%s' not found", token.c_str() );
|
|
}
|
|
fc.type = FC_MUZZLEFLASH;
|
|
fc.string = new idStr( token );*/
|
|
} else if ( token == "muzzle_flash" ) {
|
|
fc.type = FC_MUZZLEFLASH;
|
|
fc.string = new idStr( "" );
|
|
} else if ( token == "footstep" ) {
|
|
fc.type = FC_FOOTSTEP;
|
|
} else if ( token == "leftfoot" ) {
|
|
fc.type = FC_LEFTFOOT;
|
|
} else if ( token == "rightfoot" ) {
|
|
fc.type = FC_RIGHTFOOT;
|
|
} else if ( token == "enableEyeFocus" ) {
|
|
fc.type = FC_ENABLE_EYE_FOCUS;
|
|
} else if ( token == "disableEyeFocus" ) {
|
|
fc.type = FC_DISABLE_EYE_FOCUS;
|
|
} else if ( token == "disableGravity" ) {
|
|
fc.type = FC_DISABLE_GRAVITY;
|
|
} else if ( token == "enableGravity" ) {
|
|
fc.type = FC_ENABLE_GRAVITY;
|
|
} else if ( token == "jump" ) {
|
|
fc.type = FC_JUMP;
|
|
} else if ( token == "enableClip" ) {
|
|
fc.type = FC_ENABLE_CLIP;
|
|
} else if ( token == "disableClip" ) {
|
|
fc.type = FC_DISABLE_CLIP;
|
|
} else if ( token == "enableWalkIK" ) {
|
|
fc.type = FC_ENABLE_WALK_IK;
|
|
} else if ( token == "disableWalkIK" ) {
|
|
fc.type = FC_DISABLE_WALK_IK;
|
|
} else if ( token == "enableLegIK" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_ENABLE_LEG_IK;
|
|
fc.index = atoi( token );
|
|
} else if ( token == "disableLegIK" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line";
|
|
}
|
|
fc.type = FC_DISABLE_LEG_IK;
|
|
fc.index = atoi( token );
|
|
} else if ( token == "recordDemo" ) {
|
|
fc.type = FC_RECORDDEMO;
|
|
if( src.ReadTokenOnLine( &token ) ) {
|
|
fc.string = new idStr( token );
|
|
}
|
|
} else if ( token == "aviGame" ) {
|
|
fc.type = FC_AVIGAME;
|
|
if( src.ReadTokenOnLine( &token ) ) {
|
|
fc.string = new idStr( token );
|
|
}
|
|
// RAVEN BEGIN
|
|
// bdube: added script commands
|
|
} else if ( token == "ai_enablePain" ) {
|
|
fc.type = FC_AI_ENABLE_PAIN;
|
|
} else if ( token == "ai_disablePain" ) {
|
|
fc.type = FC_AI_DISABLE_PAIN;
|
|
} else if ( token == "ai_enableDamage" ) {
|
|
fc.type = FC_AI_ENABLE_DAMAGE;
|
|
} else if ( token == "ai_disableDamage" ) {
|
|
fc.type = FC_AI_DISABLE_DAMAGE;
|
|
} else if ( token == "ai_lockEnemyOrigin" ) {
|
|
fc.type = FC_AI_LOCKENEMYORIGIN;
|
|
} else if ( token == "ai_attack" ) {
|
|
fc.type = FC_AI_ATTACK;
|
|
|
|
// Name of attack
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line while looking for attack Name";
|
|
}
|
|
fc.string = new idStr( token );
|
|
|
|
// Joint to attack from
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line while looking for attack joint";
|
|
}
|
|
fc.joint = new idStr( token );
|
|
} else if ( token == "ai_attack_melee" ) {
|
|
if( !src.ReadTokenOnLine( &token ) ) {
|
|
return "Unexpected end of line while looking for melee attack name";
|
|
}
|
|
fc.type = FC_AI_ATTACK_MELEE;
|
|
fc.string = new idStr( token );
|
|
} else if ( token == "guievent" ) {
|
|
fc.type = FC_GUIEVENT;
|
|
if( src.ReadTokenOnLine( &token ) )
|
|
{
|
|
fc.string = new idStr( token );
|
|
}
|
|
} else if ( token == "speak" ) {
|
|
fc.type = FC_AI_SPEAK;
|
|
if( src.ReadTokenOnLine( &token ) ) {
|
|
fc.string = new idStr( token );
|
|
}
|
|
// RAVEN END
|
|
} else {
|
|
return va( "Unknown command '%s'", token.c_str() );
|
|
}
|
|
|
|
// check if we've initialized the frame loopup table
|
|
if ( !frameLookup.Num() ) {
|
|
// we haven't, so allocate the table and initialize it
|
|
frameLookup.SetGranularity( 1 );
|
|
frameLookup.SetNum( camera.Num() );
|
|
for( i = 0; i < frameLookup.Num(); i++ ) {
|
|
frameLookup[ i ].num = 0;
|
|
frameLookup[ i ].firstCommand = 0;
|
|
}
|
|
}
|
|
|
|
// RAVEN BEGIN
|
|
// bdube: support multiple frames
|
|
for ( int ii = 0; ii < frames.Num(); ii ++ ) {
|
|
int framenum = frames[ii];
|
|
|
|
// mekberg: error out of frame command is out of range.
|
|
// -1 because we don't want commands on the loop frame.
|
|
// If the anim doesn't loop they won't get handled.
|
|
if ( ( framenum < 1 ) || ( framenum > camera.Num() -1 ) ) {
|
|
gameLocal.Error("Frame command out of range: %d on anim '%s'. Max %d.", framenum, name.c_str(), camera.Num() -1 );
|
|
}
|
|
|
|
// Duplicate the frame info
|
|
if ( ii != 0 ) {
|
|
if ( fc.string ) {
|
|
fc.string = new idStr ( fc.string->c_str() );
|
|
}
|
|
if ( fc.joint ) {
|
|
fc.joint = new idStr ( fc.joint->c_str() );
|
|
}
|
|
if ( fc.joint2 ) {
|
|
fc.joint2 = new idStr ( fc.joint2->c_str() );
|
|
}
|
|
if ( fc.parmList ) {
|
|
fc.parmList = new idList<idStr>( *fc.parmList );
|
|
}
|
|
}
|
|
|
|
// frame numbers are 1 based in .def files, but 0 based internally
|
|
framenum--;
|
|
// RAVEN END
|
|
|
|
// allocate space for a new command
|
|
frameCommands.Alloc();
|
|
|
|
// calculate the index of the new command
|
|
index = frameLookup[ framenum ].firstCommand + frameLookup[ framenum ].num;
|
|
|
|
// move all commands from our index onward up one to give us space for our new command
|
|
for( i = frameCommands.Num() - 1; i > index; i-- ) {
|
|
frameCommands[ i ] = frameCommands[ i - 1 ];
|
|
}
|
|
|
|
// fix the indices of any later frames to account for the inserted command
|
|
for( i = framenum + 1; i < frameLookup.Num(); i++ ) {
|
|
frameLookup[ i ].firstCommand++;
|
|
}
|
|
|
|
// store the new command
|
|
frameCommands[ index ] = fc;
|
|
|
|
// increase the number of commands on this frame
|
|
frameLookup[ framenum ].num++;
|
|
|
|
// RAVEN BEGIN
|
|
// bdube: loop frame commands
|
|
}
|
|
// RAVEN END
|
|
|
|
// return with no error
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraAnimation::CallFrameCommandSound
|
|
=====================
|
|
*/
|
|
void rvCameraAnimation::CallFrameCommandSound ( const frameCommand_t& command, idEntity* ent, const s_channelType channel ) const {
|
|
|
|
int flags = 0;
|
|
if( channel == ( FC_SOUND_GLOBAL - FC_SOUND ) ) {
|
|
flags = SSF_PRIVATE_SOUND;
|
|
}
|
|
|
|
if ( command.string ) {
|
|
ent->StartSound ( command.string->c_str(), channel, flags, false, NULL );
|
|
} else {
|
|
ent->StartSoundShader( command.soundShader, channel, flags, false, NULL );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraAnimation::CallFrameCommands
|
|
=====================
|
|
*/
|
|
void rvCameraAnimation::CallFrameCommands( idEntity *ent, int from, int to ) const {
|
|
int index;
|
|
int end;
|
|
int frame;
|
|
int numframes;
|
|
|
|
if ( !frameLookup.Num() ) {
|
|
return;
|
|
}
|
|
|
|
numframes = NumFrames();
|
|
|
|
frame = from;
|
|
while( frame != to ) {
|
|
frame++;
|
|
if ( frame >= numframes ) {
|
|
frame = 0;
|
|
}
|
|
|
|
index = frameLookup[ frame ].firstCommand;
|
|
end = index + frameLookup[ frame ].num;
|
|
while( index < end ) {
|
|
const frameCommand_t &command = frameCommands[ index++ ];
|
|
|
|
// RAVEN BEGIN
|
|
// bdube: frame command debugging
|
|
if ( g_showFrameCmds.GetBool() ) {
|
|
idStr shortName;
|
|
shortName = name;
|
|
shortName.StripPath();
|
|
shortName.StripFileExtension ( );
|
|
gameLocal.Printf ( "Cameraframecmd: anim=%s frame=%d cmd=%s parm=%s\n",
|
|
shortName.c_str(),
|
|
frame + 1,
|
|
frameCommandInfo[command.type].name,
|
|
command.string?command.string->c_str():"???" );
|
|
}
|
|
// RAVEN END
|
|
|
|
switch( command.type ) {
|
|
case FC_SCRIPTFUNCTION: {
|
|
gameLocal.CallFrameCommand( ent, command.function );
|
|
break;
|
|
}
|
|
// RAVEN BEGIN
|
|
// bdube: rewrote
|
|
case FC_SCRIPTFUNCTIONOBJECT: {
|
|
ent->ProcessEvent ( &EV_CallFunction, command.string->c_str() );
|
|
break;
|
|
}
|
|
// RAVEN END
|
|
case FC_EVENTFUNCTION: {
|
|
const idEventDef *ev = idEventDef::FindEvent( command.string->c_str() );
|
|
ent->ProcessEvent( ev );
|
|
break;
|
|
}
|
|
// RAVEN BEGIN
|
|
// abahr:
|
|
case FC_EVENTFUNCTION_ARGS: {
|
|
assert( command.event );
|
|
ent->ProcessEvent( command.event, (int)command.parmList );
|
|
break;
|
|
}
|
|
// bdube: support indirection and simplify
|
|
case FC_SOUND:
|
|
case FC_SOUND_VOICE:
|
|
case FC_SOUND_VOICE2:
|
|
case FC_SOUND_BODY:
|
|
case FC_SOUND_BODY2:
|
|
case FC_SOUND_BODY3:
|
|
case FC_SOUND_WEAPON:
|
|
case FC_SOUND_ITEM:
|
|
case FC_SOUND_GLOBAL:
|
|
case FC_SOUND_CHATTER:
|
|
CallFrameCommandSound ( command, ent, (const s_channelType)(command.type - FC_SOUND) );
|
|
break;
|
|
// RAVEN END
|
|
|
|
case FC_FX: {
|
|
// RAVEN BEGIN
|
|
// bdube: use raven effect system
|
|
rvClientEffect* cent;
|
|
if ( command.string ) {
|
|
if ( command.joint ) {
|
|
cent = ent->PlayEffect ( command.string->c_str(), ent->GetAnimator()->GetJointHandle ( *command.joint ) );
|
|
} else {
|
|
cent = gameLocal.PlayEffect ( ent->spawnArgs, command.string->c_str(), ent->GetRenderEntity()->origin, ent->GetRenderEntity()->axis );
|
|
}
|
|
} else {
|
|
if ( command.joint ) {
|
|
cent = ent->PlayEffect ( command.effect, ent->GetAnimator()->GetJointHandle ( *command.joint ), vec3_origin, mat3_identity );
|
|
} else {
|
|
cent = gameLocal.PlayEffect ( command.effect, ent->GetRenderEntity()->origin, ent->GetRenderEntity()->axis );
|
|
}
|
|
}
|
|
// End origin bone specified?
|
|
// RAVEN BEGIN
|
|
// jnewquist: Use accessor for static class type
|
|
if ( cent && command.joint2 && ent->IsType ( idAnimatedEntity::GetClassType() ) ) {
|
|
// RAVEN END
|
|
cent->SetEndOrigin ( ent->GetAnimator()->GetJointHandle ( *command.joint2 ) );
|
|
}
|
|
// RAVEN END
|
|
break;
|
|
}
|
|
case FC_SKIN:
|
|
// ent->SetSkin( command.skin );
|
|
break;
|
|
|
|
case FC_TRIGGER: {
|
|
idEntity *target;
|
|
|
|
target = gameLocal.FindEntity( command.string->c_str() );
|
|
if ( target ) {
|
|
target->Signal( SIG_TRIGGER );
|
|
target->ProcessEvent( &EV_Activate, ent );
|
|
target->TriggerGuis();
|
|
} else {
|
|
gameLocal.Warning( "Framecommand 'trigger' on entity '%s', anim '%s', frame %d: Could not find entity '%s'",
|
|
ent->name.c_str(), FullName(), frame + 1, command.string->c_str() );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FC_DIRECTDAMAGE: {
|
|
ent->ProcessEvent( &AI_DirectDamage, command.string->c_str() );
|
|
break;
|
|
}
|
|
case FC_MUZZLEFLASH: {
|
|
break;
|
|
}
|
|
case FC_FOOTSTEP : {
|
|
// ent->ProcessEvent( &EV_Footstep );
|
|
break;
|
|
}
|
|
case FC_LEFTFOOT: {
|
|
// ent->ProcessEvent( &EV_FootstepLeft );
|
|
break;
|
|
}
|
|
case FC_RIGHTFOOT: {
|
|
// ent->ProcessEvent( &EV_FootstepRight );
|
|
break;
|
|
}
|
|
case FC_ENABLE_EYE_FOCUS: {
|
|
ent->ProcessEvent( &AI_EnableEyeFocus );
|
|
break;
|
|
}
|
|
case FC_DISABLE_EYE_FOCUS: {
|
|
ent->ProcessEvent( &AI_DisableEyeFocus );
|
|
break;
|
|
}
|
|
case FC_DISABLE_GRAVITY: {
|
|
ent->ProcessEvent( &AI_DisableGravity );
|
|
break;
|
|
}
|
|
case FC_ENABLE_GRAVITY: {
|
|
ent->ProcessEvent( &AI_EnableGravity );
|
|
break;
|
|
}
|
|
case FC_JUMP: {
|
|
ent->ProcessEvent( &AI_JumpFrame );
|
|
break;
|
|
}
|
|
case FC_ENABLE_CLIP: {
|
|
ent->ProcessEvent( &AI_EnableClip );
|
|
break;
|
|
}
|
|
case FC_DISABLE_CLIP: {
|
|
ent->ProcessEvent( &AI_DisableClip );
|
|
break;
|
|
}
|
|
case FC_ENABLE_WALK_IK: {
|
|
// ent->ProcessEvent( &EV_EnableWalkIK );
|
|
break;
|
|
}
|
|
case FC_DISABLE_WALK_IK: {
|
|
// ent->ProcessEvent( &EV_DisableWalkIK );
|
|
break;
|
|
}
|
|
case FC_ENABLE_LEG_IK: {
|
|
// ent->ProcessEvent( &EV_EnableLegIK, command.index );
|
|
break;
|
|
}
|
|
case FC_DISABLE_LEG_IK: {
|
|
// ent->ProcessEvent( &EV_DisableLegIK, command.index );
|
|
break;
|
|
}
|
|
case FC_RECORDDEMO: {
|
|
if ( command.string ) {
|
|
cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "recordDemo %s", command.string->c_str() ) );
|
|
} else {
|
|
cmdSystem->BufferCommandText( CMD_EXEC_NOW, "stoprecording" );
|
|
}
|
|
break;
|
|
}
|
|
case FC_AVIGAME: {
|
|
if ( command.string ) {
|
|
cmdSystem->BufferCommandText( CMD_EXEC_NOW, va( "aviGame %s", command.string->c_str() ) );
|
|
} else {
|
|
cmdSystem->BufferCommandText( CMD_EXEC_NOW, "aviGame" );
|
|
}
|
|
break;
|
|
}
|
|
|
|
case FC_AI_ENABLE_PAIN:
|
|
// ent->ProcessEvent ( &AI_EnablePain );
|
|
break;
|
|
|
|
case FC_AI_DISABLE_PAIN:
|
|
// ent->ProcessEvent ( &AI_DisablePain );
|
|
break;
|
|
|
|
case FC_AI_ENABLE_DAMAGE:
|
|
// ent->ProcessEvent ( &AI_EnableDamage );
|
|
break;
|
|
|
|
case FC_AI_LOCKENEMYORIGIN:
|
|
// ent->ProcessEvent ( &AI_LockEnemyOrigin );
|
|
break;
|
|
|
|
case FC_AI_ATTACK:
|
|
// ent->ProcessEvent ( &AI_Attack, command.string->c_str(), command.joint->c_str() );
|
|
break;
|
|
|
|
case FC_AI_DISABLE_DAMAGE:
|
|
// ent->ProcessEvent ( &AI_DisableDamage );
|
|
break;
|
|
|
|
case FC_AI_SPEAK:
|
|
// ent->ProcessEvent( &AI_Speak, command.string->c_str() );
|
|
break;
|
|
|
|
case FC_ACT_ATTACH_HIDE:
|
|
/*
|
|
if ( ent->IsType(idActor::GetClassType()) )
|
|
{
|
|
static_cast<idActor*>(ent)->HideAttachment( command.string->c_str() );
|
|
}
|
|
*/
|
|
break;
|
|
|
|
case FC_ACT_ATTACH_SHOW:
|
|
/*
|
|
if ( ent->IsType(idActor::GetClassType()) )
|
|
{
|
|
static_cast<idActor*>(ent)->ShowAttachment( command.string->c_str() );
|
|
}
|
|
*/
|
|
break;
|
|
|
|
case FC_AI_ATTACK_MELEE:
|
|
// ent->ProcessEvent( &AI_AttackMelee, command.string->c_str() );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
idDeclCameraDef
|
|
|
|
***********************************************************************/
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::idDeclCameraDef
|
|
=====================
|
|
*/
|
|
idDeclCameraDef::idDeclCameraDef() {
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::~idDeclCameraDef
|
|
=====================
|
|
*/
|
|
idDeclCameraDef::~idDeclCameraDef() {
|
|
FreeData();
|
|
}
|
|
|
|
// RAVEN BEGIN
|
|
// jsinger: Added to support serialization/deserialization of binary decls
|
|
#ifdef RV_BINARYDECLS
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::idDeclCameraDef( SerialInputStream &stream )
|
|
=====================
|
|
*/
|
|
idDeclCameraDef::idDeclCameraDef( SerialInputStream &stream )
|
|
{
|
|
// not supported yet
|
|
assert(false);
|
|
}
|
|
|
|
void idDeclCameraDef::Write( SerialOutputStream &stream ) const
|
|
{
|
|
// not supported yet
|
|
assert(false);
|
|
}
|
|
|
|
void idDeclCameraDef::AddReferences() const
|
|
{
|
|
// not supported yet
|
|
assert(false);
|
|
}
|
|
#endif
|
|
// RAVEN END
|
|
/*
|
|
=================
|
|
idDeclCameraDef::Size
|
|
=================
|
|
*/
|
|
// RAVEN BEGIN
|
|
// jscott: made more accurate
|
|
size_t idDeclCameraDef::Size( void ) const {
|
|
|
|
size_t size;
|
|
|
|
size = sizeof( idDeclCameraDef );
|
|
size += anims.Allocated();
|
|
|
|
return( size );
|
|
}
|
|
// RAVEN END
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::CopyDecl
|
|
=====================
|
|
*/
|
|
void idDeclCameraDef::CopyDecl( const idDeclCameraDef *decl ) {
|
|
int i;
|
|
|
|
FreeData();
|
|
|
|
anims.SetNum( decl->anims.Num() );
|
|
for( i = 0; i < anims.Num(); i++ ) {
|
|
anims[ i ] = new rvCameraAnimation( this, decl->anims[ i ] );
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::FreeData
|
|
=====================
|
|
*/
|
|
void idDeclCameraDef::FreeData( void ) {
|
|
anims.DeleteContents( true );
|
|
}
|
|
|
|
/*
|
|
================
|
|
idDeclCameraDef::DefaultDefinition
|
|
================
|
|
*/
|
|
const char *idDeclCameraDef::DefaultDefinition( void ) const {
|
|
return "{ }";
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::Touch
|
|
=====================
|
|
*/
|
|
void idDeclCameraDef::Touch( void ) const {
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::ParseAnim
|
|
=====================
|
|
*/
|
|
bool idDeclCameraDef::ParseAnim( idLexer &src, int numDefaultAnims ) {
|
|
int i;
|
|
int len;
|
|
rvCameraAnimation *anim;
|
|
idStr alias;
|
|
idToken realname;
|
|
idToken token;
|
|
int numAnims;
|
|
|
|
numAnims = 0;
|
|
|
|
if( !src.ReadToken( &realname ) ) {
|
|
src.Warning( "Unexpected end of file" );
|
|
MakeDefault();
|
|
return false;
|
|
}
|
|
alias = realname;
|
|
|
|
for( i = 0; i < anims.Num(); i++ ) {
|
|
if ( !idStr::Cmp( anims[ i ]->FullName(), realname ) ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( ( i < anims.Num() ) && ( i >= numDefaultAnims ) ) {
|
|
src.Warning( "Duplicate anim '%s'", realname.c_str() );
|
|
MakeDefault();
|
|
return false;
|
|
}
|
|
|
|
if ( i < numDefaultAnims ) {
|
|
anim = anims[ i ];
|
|
} else {
|
|
// create the alias associated with this animation
|
|
anim = new rvCameraAnimation();
|
|
anims.Append( anim );
|
|
}
|
|
|
|
// random anims end with a number. find the numeric suffix of the animation.
|
|
len = alias.Length();
|
|
for( i = len - 1; i > 0; i-- ) {
|
|
if ( !isdigit( alias[ i ] ) ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// check for zero length name, or a purely numeric name
|
|
if ( i <= 0 ) {
|
|
src.Warning( "Invalid animation name '%s'", alias.c_str() );
|
|
MakeDefault();
|
|
return false;
|
|
}
|
|
|
|
// remove the numeric suffix
|
|
alias.CapLength( i + 1 );
|
|
|
|
// parse the anims from the string
|
|
if( !src.ReadToken( &token ) ) {
|
|
src.Warning( "Unexpected end of file" );
|
|
MakeDefault();
|
|
return false;
|
|
}
|
|
|
|
anim->SetAnim( this, realname, alias, token );
|
|
|
|
// parse any frame commands or animflags
|
|
if ( src.CheckTokenString( "{" ) ) {
|
|
while( 1 ) {
|
|
if( !src.ReadToken( &token ) ) {
|
|
src.Warning( "Unexpected end of file" );
|
|
MakeDefault();
|
|
return false;
|
|
}
|
|
if ( token == "}" ) {
|
|
break;
|
|
} else if ( token == "frame" ) {
|
|
// create a frame command
|
|
// RAVEN BEGIN
|
|
// bdube: Support a list of frame numbers
|
|
// int framenum;
|
|
const char *err;
|
|
idList<int> frameList;
|
|
|
|
do
|
|
{
|
|
// RAVEN END
|
|
// make sure we don't have any line breaks while reading the frame command so the error line # will be correct
|
|
if ( !src.ReadTokenOnLine( &token ) ) {
|
|
src.Warning( "Missing frame # after 'frame'" );
|
|
MakeDefault();
|
|
return false;
|
|
}
|
|
if ( token.type == TT_PUNCTUATION && token == "-" ) {
|
|
src.Warning( "Invalid frame # after 'frame'" );
|
|
MakeDefault();
|
|
return false;
|
|
} else if ( token.type != TT_NUMBER || token.subtype == TT_FLOAT ) {
|
|
src.Error( "expected integer value, found '%s'", token.c_str() );
|
|
}
|
|
// RAVEN BEGIN
|
|
// bdube: multiple frames
|
|
frameList.Append ( token.GetIntValue() );
|
|
|
|
} while ( src.CheckTokenString ( "," ) );
|
|
// RAVEN END
|
|
|
|
// put the command on the specified frame of the animation
|
|
// RAVEN BEGIN
|
|
// bdube: Support a list of frame numbers
|
|
err = anim->AddFrameCommand( this, frameList, src, NULL );
|
|
// RAVEN END
|
|
if ( err ) {
|
|
src.Warning( "%s", err );
|
|
MakeDefault();
|
|
return false;
|
|
}
|
|
} else {
|
|
src.Warning( "Unknown command '%s'", token.c_str() );
|
|
MakeDefault();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
================
|
|
idDeclCameraDef::Parse
|
|
================
|
|
*/
|
|
bool idDeclCameraDef::Parse( const char *text, const int textLength, bool noCaching ) {
|
|
idStr filename;
|
|
idStr extension;
|
|
idLexer src;
|
|
idToken token;
|
|
idToken token2;
|
|
int numDefaultAnims;
|
|
|
|
TIME_THIS_SCOPE( __FUNCLINE__);
|
|
|
|
src.LoadMemory( text, textLength, GetFileName(), GetLineNum() );
|
|
src.SetFlags( DECL_LEXER_FLAGS );
|
|
src.SkipUntilString( "{" );
|
|
|
|
numDefaultAnims = 0;
|
|
while( 1 ) {
|
|
if ( !src.ReadToken( &token ) ) {
|
|
break;
|
|
}
|
|
|
|
if ( !token.Icmp( "}" ) ) {
|
|
break;
|
|
}
|
|
else if ( token == "anim" ) {
|
|
if ( !ParseAnim( src, numDefaultAnims ) ) {
|
|
MakeDefault();
|
|
return false;
|
|
}
|
|
} else {
|
|
src.Warning( "unknown token '%s'", token.c_str() );
|
|
MakeDefault();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// shrink the anim list down to save space
|
|
anims.SetGranularity( 1 );
|
|
anims.SetNum( anims.Num() );
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::Validate
|
|
=====================
|
|
*/
|
|
bool idDeclCameraDef::Validate( const char *psText, int iTextLength, idStr &strReportTo ) const {
|
|
idDeclCameraDef *pSelf = (idDeclCameraDef*) declManager->AllocateDecl( DECL_MODELDEF );
|
|
bool bOk = pSelf->Parse( psText, iTextLength, false );
|
|
pSelf->FreeData();
|
|
delete pSelf->base;
|
|
delete pSelf;
|
|
|
|
return bOk;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::HasAnim
|
|
=====================
|
|
*/
|
|
bool idDeclCameraDef::HasAnim( const char *name ) const {
|
|
int i;
|
|
|
|
// find any animations with same name
|
|
for( i = 0; i < anims.Num(); i++ ) {
|
|
if ( !idStr::Cmp( anims[ i ]->Name(), name ) ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::NumAnims
|
|
=====================
|
|
*/
|
|
int idDeclCameraDef::NumAnims( void ) const {
|
|
return anims.Num() + 1;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::GetSpecificAnim
|
|
|
|
Gets the exact anim for the name, without randomization.
|
|
=====================
|
|
*/
|
|
int idDeclCameraDef::GetSpecificAnim( const char *name ) const {
|
|
int i;
|
|
|
|
// find a specific animation
|
|
for( i = 0; i < anims.Num(); i++ ) {
|
|
if ( !idStr::Cmp( anims[ i ]->FullName(), name ) ) {
|
|
return i + 1;
|
|
}
|
|
}
|
|
|
|
// didn't find it
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idDeclCameraDef::GetAnim
|
|
=====================
|
|
*/
|
|
int idDeclCameraDef::GetAnim( const char *name ) const {
|
|
int i;
|
|
int which;
|
|
const int MAX_ANIMS = 64;
|
|
int animList[ MAX_ANIMS ];
|
|
int numAnims;
|
|
int len;
|
|
|
|
len = strlen( name );
|
|
if ( len && idStr::CharIsNumeric( name[ len - 1 ] ) ) {
|
|
// find a specific animation
|
|
return GetSpecificAnim( name );
|
|
}
|
|
|
|
// find all animations with same name
|
|
numAnims = 0;
|
|
for( i = 0; i < anims.Num(); i++ ) {
|
|
if ( !idStr::Cmp( anims[ i ]->Name(), name ) ) {
|
|
animList[ numAnims++ ] = i;
|
|
if ( numAnims >= MAX_ANIMS ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !numAnims ) {
|
|
return 0;
|
|
}
|
|
|
|
// get a random anim
|
|
//FIXME: don't access gameLocal here?
|
|
which = gameLocal.random.RandomInt( numAnims );
|
|
return animList[ which ] + 1;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
===============================================================================
|
|
|
|
idCameraAnim
|
|
|
|
===============================================================================
|
|
*/
|
|
const idEventDef EV_Camera_Start( "start", NULL );
|
|
const idEventDef EV_Camera_Stop( "stop", NULL );
|
|
|
|
// RAVEN BEGIN
|
|
// mekberg: wait support
|
|
const idEventDef EV_Camera_IsActive( "isActive", "", 'd' );
|
|
// RAVEN END
|
|
|
|
CLASS_DECLARATION( idCamera, idCameraAnim )
|
|
EVENT( EV_Thread_SetCallback, idCameraAnim::Event_SetCallback )
|
|
EVENT( EV_Camera_Stop, idCameraAnim::Event_Stop )
|
|
EVENT( EV_Camera_Start, idCameraAnim::Event_Start )
|
|
EVENT( EV_Activate, idCameraAnim::Event_Activate )
|
|
|
|
// RAVEN BEGIN
|
|
// mekberg: wait support
|
|
EVENT( EV_IsActive, idCameraAnim::Event_IsActive )
|
|
// RAVEN END
|
|
END_CLASS
|
|
|
|
|
|
/*
|
|
=====================
|
|
idCameraAnim::idCameraAnim
|
|
=====================
|
|
*/
|
|
idCameraAnim::idCameraAnim() {
|
|
threadNum = 0;
|
|
offset.Zero();
|
|
cycle = 1;
|
|
starttime = 0;
|
|
activator = NULL;
|
|
lastFrame = -1;
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idCameraAnim::~idCameraAnim
|
|
=====================
|
|
*/
|
|
idCameraAnim::~idCameraAnim() {
|
|
if ( gameLocal.GetCamera() == this ) {
|
|
gameLocal.SetCamera( NULL );
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCameraAnim::Save
|
|
================
|
|
*/
|
|
void idCameraAnim::Save( idSaveGame *savefile ) const {
|
|
savefile->WriteInt( threadNum );
|
|
savefile->WriteVec3( offset );
|
|
savefile->WriteInt( starttime );
|
|
savefile->WriteInt( cycle );
|
|
savefile->WriteInt( lastFrame ); // cnicholson: Added unsaved var
|
|
|
|
activator.Save( savefile );
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCameraAnim::Restore
|
|
================
|
|
*/
|
|
void idCameraAnim::Restore( idRestoreGame *savefile ) {
|
|
savefile->ReadInt( threadNum );
|
|
savefile->ReadVec3( offset );
|
|
savefile->ReadInt( starttime );
|
|
savefile->ReadInt( cycle );
|
|
savefile->ReadInt( lastFrame ); // cnicholson: Added unread var
|
|
|
|
activator.Restore( savefile );
|
|
|
|
LoadAnim();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idCameraAnim::Spawn
|
|
=====================
|
|
*/
|
|
void idCameraAnim::Spawn( void ) {
|
|
if ( spawnArgs.GetVector( "old_origin", "0 0 0", offset ) ) {
|
|
offset = GetPhysics()->GetOrigin() - offset;
|
|
} else {
|
|
offset.Zero();
|
|
}
|
|
|
|
// always think during cinematics
|
|
cinematic = true;
|
|
|
|
LoadAnim();
|
|
|
|
// RAVEN BEGIN
|
|
#ifndef _CONSOLE
|
|
// touch the cinematic streaming command file during build
|
|
if ( cvarSystem->GetCVarBool("com_makingBuild") && cvarSystem->GetCVarBool("com_Bundler") )
|
|
{
|
|
idFile *file;
|
|
idStr filename = "cinematics/";
|
|
filename += gameLocal.mapFileNameStripped;
|
|
filename += "_";
|
|
filename += name;
|
|
filename += ".cincmd";
|
|
file = fileSystem->OpenFileRead( filename );
|
|
fileSystem->CloseFile( file );
|
|
}
|
|
#endif
|
|
// RAVEN END
|
|
}
|
|
|
|
/*
|
|
================
|
|
idCameraAnim::Load
|
|
================
|
|
*/
|
|
void idCameraAnim::LoadAnim( void ) {
|
|
idLexer parser( LEXFL_ALLOWPATHNAMES | LEXFL_NOSTRINGESCAPECHARS | LEXFL_NOSTRINGCONCAT );
|
|
idToken token;
|
|
idStr filename;
|
|
const char *key;
|
|
|
|
key = spawnArgs.GetString( "camera" );
|
|
const idDecl *mapDecl = declManager->FindType( DECL_CAMERADEF, key, false );
|
|
cameraDef = static_cast<const idDeclCameraDef *>( mapDecl );
|
|
|
|
key = spawnArgs.GetString( "anim" );
|
|
if ( !key ) {
|
|
gameLocal.Error( "Missing 'anim' key on '%s'", name.c_str() );
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCameraAnim::Start
|
|
================
|
|
*/
|
|
void idCameraAnim::Start( void ) {
|
|
cycle = spawnArgs.GetInt( "cycle" );
|
|
if ( !cycle ) {
|
|
cycle = 1;
|
|
}
|
|
|
|
if ( g_debugCinematic.GetBool() ) {
|
|
gameLocal.Printf( "%d: '%s' start\n", gameLocal.framenum, GetName() );
|
|
}
|
|
|
|
lastFrame = -1;
|
|
starttime = gameLocal.time;
|
|
gameLocal.SetCamera( this );
|
|
BecomeActive( TH_THINK );
|
|
|
|
// RAVEN BEGIN
|
|
// jnewquist: Track texture usage during cinematics for streaming purposes
|
|
#ifndef _CONSOLE
|
|
renderSystem->TrackTextureUsage( idRenderSystem::TEXTURE_TRACK_BEGIN, cameraDef->GetAnim(1)->GetFrameRate(), GetName() );
|
|
#endif
|
|
// RAVEN END
|
|
|
|
// if the player has already created the renderview for this frame, have him update it again so that the camera starts this frame
|
|
// RAVEN BEGIN
|
|
// mekberg: make sure render view is valid.
|
|
if ( gameLocal.GetLocalPlayer( )->GetRenderView( ) && gameLocal.GetLocalPlayer()->GetRenderView()->time == gameLocal.time ) {
|
|
// RAVEN END
|
|
gameLocal.GetLocalPlayer()->CalculateRenderView();
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idCameraAnim::Stop
|
|
=====================
|
|
*/
|
|
void idCameraAnim::Stop( void ) {
|
|
if ( gameLocal.GetCamera() == this ) {
|
|
if ( g_debugCinematic.GetBool() ) {
|
|
gameLocal.Printf( "%d: '%s' stop\n", gameLocal.framenum, GetName() );
|
|
}
|
|
|
|
BecomeInactive( TH_THINK );
|
|
gameLocal.SetCamera( NULL );
|
|
if ( threadNum ) {
|
|
idThread::ObjectMoveDone( threadNum, this );
|
|
threadNum = 0;
|
|
}
|
|
ActivateTargets( activator.GetEntity() );
|
|
|
|
// RAVEN BEGIN
|
|
// jnewquist: Track texture usage during cinematics for streaming purposes
|
|
#ifndef _CONSOLE
|
|
renderSystem->TrackTextureUsage( idRenderSystem::TEXTURE_TRACK_END, cameraDef->GetAnim(1)->GetFrameRate() );
|
|
#endif
|
|
// RAVEN END
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idCameraAnim::Think
|
|
=====================
|
|
*/
|
|
void idCameraAnim::Think( void ) {
|
|
int frame;
|
|
int frameTime;
|
|
|
|
if ( thinkFlags & TH_THINK ) {
|
|
// check if we're done in the Think function when the cinematic is being skipped (idCameraAnim::GetViewParms isn't called when skipping cinematics).
|
|
// RAVEN BEGIN
|
|
// abahr: removed '!'
|
|
if ( gameLocal.skipCinematic ) {
|
|
// RAVEN END
|
|
return;
|
|
}
|
|
|
|
if ( cameraDef->GetAnim(1)->NumFrames() < 2 ) {
|
|
// 1 frame anims never end
|
|
return;
|
|
}
|
|
|
|
if ( cameraDef->GetAnim(1)->GetFrameRate() == gameLocal.GetMHz() ) {
|
|
frameTime = gameLocal.time - starttime;
|
|
frame = frameTime / gameLocal.msec;
|
|
} else {
|
|
frameTime = ( gameLocal.time - starttime ) * cameraDef->GetAnim(1)->GetFrameRate();
|
|
frame = frameTime / 1000;
|
|
}
|
|
|
|
if ( frame > cameraDef->GetAnim(1)->NumFrames() + cameraDef->GetAnim(1)->NumCuts() - 2 ) {
|
|
if ( cycle > 0 ) {
|
|
cycle--;
|
|
}
|
|
lastFrame = -1;
|
|
|
|
if ( cycle != 0 ) {
|
|
// advance start time so that we loop
|
|
starttime += ( ( cameraDef->GetAnim(1)->NumFrames() - cameraDef->GetAnim(1)->NumCuts() ) * 1000 ) / cameraDef->GetAnim(1)->GetFrameRate();
|
|
} else {
|
|
Stop();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
idCameraAnim::GetViewParms
|
|
=====================
|
|
*/
|
|
void idCameraAnim::GetViewParms( renderView_t *view ) {
|
|
int realFrame;
|
|
int frame;
|
|
int frameTime;
|
|
float lerp;
|
|
float invlerp;
|
|
const cameraFrame_t *camFrame;
|
|
int i;
|
|
int cut;
|
|
idQuat q1, q2, q3;
|
|
|
|
assert( view );
|
|
if ( !view ) {
|
|
return;
|
|
}
|
|
//RAVEN BEGIN
|
|
//jshepard: safety first
|
|
if( !cameraDef ) {
|
|
gameLocal.Warning("Invalid cameraDef in GetViewParms");
|
|
return;
|
|
}
|
|
//RAVEN END
|
|
if ( !cameraDef->GetAnim(1) ) {
|
|
return;
|
|
}
|
|
|
|
if ( cameraDef->GetAnim(1)->NumFrames() == 0 ) {
|
|
// we most likely are in the middle of a restore
|
|
// FIXME: it would be better to fix it so this doesn't get called during a restore
|
|
return;
|
|
}
|
|
|
|
if ( cameraDef->GetAnim(1)->GetFrameRate() == gameLocal.GetMHz() ) {
|
|
frameTime = gameLocal.time - starttime;
|
|
frame = frameTime / gameLocal.msec;
|
|
lerp = 0.0f;
|
|
} else {
|
|
frameTime = ( gameLocal.time - starttime ) * cameraDef->GetAnim(1)->GetFrameRate();
|
|
frame = frameTime / 1000;
|
|
lerp = ( frameTime % 1000 ) * 0.001f;
|
|
}
|
|
|
|
// skip any frames where camera cuts occur
|
|
realFrame = frame;
|
|
cut = 0;
|
|
for( i = 0; i < cameraDef->GetAnim(1)->NumCuts(); i++ ) {
|
|
if ( frame < cameraDef->GetAnim(1)->GetCut( i ) ) {
|
|
break;
|
|
}
|
|
frame++;
|
|
cut++;
|
|
}
|
|
if ( lastFrame != frame ) {
|
|
cameraDef->GetAnim(1)->CallFrameCommands( this, lastFrame, frame );
|
|
lastFrame = frame;
|
|
}
|
|
|
|
if ( g_debugCinematic.GetBool() ) {
|
|
int prevFrameTime = ( gameLocal.time - starttime - gameLocal.msec ) * cameraDef->GetAnim(1)->GetFrameRate();
|
|
int prevFrame = prevFrameTime / 1000;
|
|
int prevCut;
|
|
|
|
prevCut = 0;
|
|
for( i = 0; i < cameraDef->GetAnim(1)->NumCuts(); i++ ) {
|
|
if ( prevFrame < cameraDef->GetAnim(1)->GetCut( i ) ) {
|
|
break;
|
|
}
|
|
prevFrame++;
|
|
prevCut++;
|
|
}
|
|
|
|
if ( prevCut != cut ) {
|
|
gameLocal.Printf( "%d: '%s' cut %d\n", gameLocal.framenum, GetName(), cut );
|
|
}
|
|
}
|
|
|
|
// clamp to the first frame. also check if this is a one frame anim. one frame anims would end immediately,
|
|
// but since they're mainly used for static cams anyway, just stay on it infinitely.
|
|
if ( ( frame < 0 ) || ( cameraDef->GetAnim(1)->NumFrames() < 2 ) ) {
|
|
view->viewaxis = cameraDef->GetAnim(1)->GetAnim( 0 )->q.ToQuat().ToMat3();
|
|
view->vieworg = cameraDef->GetAnim(1)->GetAnim( 0 )->t + offset;
|
|
view->fov_x = cameraDef->GetAnim(1)->GetAnim( 0 )->fov;
|
|
} else if ( frame > cameraDef->GetAnim(1)->NumFrames() - 2 ) {
|
|
if ( cycle > 0 ) {
|
|
cycle--;
|
|
}
|
|
|
|
if ( cycle != 0 ) {
|
|
// advance start time so that we loop
|
|
starttime += ( ( cameraDef->GetAnim(1)->NumFrames() - cameraDef->GetAnim(1)->NumCuts() ) * 1000 ) / cameraDef->GetAnim(1)->GetFrameRate();
|
|
GetViewParms( view );
|
|
return;
|
|
}
|
|
|
|
Stop();
|
|
if ( gameLocal.GetCamera() != NULL ) {
|
|
// we activated another camera when we stopped, so get it's viewparms instead
|
|
gameLocal.GetCamera()->GetViewParms( view );
|
|
return;
|
|
} else {
|
|
// just use our last frame
|
|
camFrame = cameraDef->GetAnim(1)->GetAnim( cameraDef->GetAnim(1)->NumFrames() - 1 );
|
|
view->viewaxis = camFrame->q.ToQuat().ToMat3();
|
|
view->vieworg = camFrame->t + offset;
|
|
view->fov_x = camFrame->fov;
|
|
}
|
|
} else if ( lerp == 0.0f ) {
|
|
camFrame = cameraDef->GetAnim(1)->GetAnim( frame );
|
|
view->viewaxis = camFrame[ 0 ].q.ToMat3();
|
|
view->vieworg = camFrame[ 0 ].t + offset;
|
|
view->fov_x = camFrame[ 0 ].fov;
|
|
} else {
|
|
camFrame = cameraDef->GetAnim(1)->GetAnim( frame );
|
|
invlerp = 1.0f - lerp;
|
|
q1 = camFrame[ 0 ].q.ToQuat();
|
|
q2 = camFrame[ 1 ].q.ToQuat();
|
|
q3.Slerp( q1, q2, lerp );
|
|
view->viewaxis = q3.ToMat3();
|
|
view->vieworg = camFrame[ 0 ].t * invlerp + camFrame[ 1 ].t * lerp + offset;
|
|
view->fov_x = camFrame[ 0 ].fov * invlerp + camFrame[ 1 ].fov * lerp;
|
|
}
|
|
|
|
gameLocal.CalcFov( view->fov_x, view->fov_x, view->fov_y );
|
|
|
|
// setup the pvs for this frame
|
|
UpdatePVSAreas( view->vieworg );
|
|
|
|
#if 0
|
|
static int lastFrame = 0;
|
|
static idVec3 lastFrameVec( 0.0f, 0.0f, 0.0f );
|
|
if ( gameLocal.time != lastFrame ) {
|
|
gameRenderWorld->DebugBounds( colorCyan, idBounds( view->vieworg ).Expand( 16.0f ), vec3_origin, gameLocal.msec );
|
|
gameRenderWorld->DebugLine( colorRed, view->vieworg, view->vieworg + idVec3( 0.0f, 0.0f, 2.0f ), 10000, false );
|
|
gameRenderWorld->DebugLine( colorCyan, lastFrameVec, view->vieworg, 10000, false );
|
|
gameRenderWorld->DebugLine( colorYellow, view->vieworg + view->viewaxis[ 0 ] * 64.0f, view->vieworg + view->viewaxis[ 0 ] * 66.0f, 10000, false );
|
|
gameRenderWorld->DebugLine( colorOrange, view->vieworg + view->viewaxis[ 0 ] * 64.0f, view->vieworg + view->viewaxis[ 0 ] * 64.0f + idVec3( 0.0f, 0.0f, 2.0f ), 10000, false );
|
|
lastFrameVec = view->vieworg;
|
|
lastFrame = gameLocal.time;
|
|
}
|
|
#endif
|
|
|
|
if ( g_showcamerainfo.GetBool() ) {
|
|
gameLocal.Printf( "^5Frame: ^7%d/%d\n\n\n", realFrame + 1, cameraDef->GetAnim(1)->NumFrames() - cameraDef->GetAnim(1)->NumCuts() );
|
|
}
|
|
// jnewquist: Track texture usage during cinematics for streaming purposes
|
|
#ifndef _CONSOLE
|
|
renderSystem->TrackTextureUsage( idRenderSystem::TEXTURE_TRACK_UPDATE, realFrame );
|
|
#endif
|
|
}
|
|
// RAVEN END
|
|
|
|
/*
|
|
===============
|
|
idCameraAnim::Event_Activate
|
|
================
|
|
*/
|
|
void idCameraAnim::Event_Activate( idEntity *_activator ) {
|
|
activator = _activator;
|
|
if ( thinkFlags & TH_THINK ) {
|
|
Stop();
|
|
} else {
|
|
Start();
|
|
}
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCameraAnim::Event_Start
|
|
================
|
|
*/
|
|
void idCameraAnim::Event_Start( void ) {
|
|
Start();
|
|
}
|
|
|
|
/*
|
|
===============
|
|
idCameraAnim::Event_Stop
|
|
================
|
|
*/
|
|
void idCameraAnim::Event_Stop( void ) {
|
|
Stop();
|
|
}
|
|
|
|
/*
|
|
================
|
|
idCameraAnim::Event_SetCallback
|
|
================
|
|
*/
|
|
void idCameraAnim::Event_SetCallback( void ) {
|
|
if ( ( gameLocal.GetCamera() == this ) && !threadNum ) {
|
|
threadNum = idThread::CurrentThreadNum();
|
|
idThread::ReturnInt( true );
|
|
} else {
|
|
idThread::ReturnInt( false );
|
|
}
|
|
}
|
|
|
|
// RAVEN BEGIN
|
|
// mekberg: wait support
|
|
/*
|
|
================
|
|
idCameraAnim::Event_IsActive
|
|
================
|
|
*/
|
|
void idCameraAnim::Event_IsActive( void ) {
|
|
idThread::ReturnFloat( gameLocal.GetCamera( ) ? 1.0f : 0.0f );
|
|
}
|
|
|
|
// RAVEN END
|
|
|
|
// RAVEN BEGIN
|
|
// jscott: portal sky support
|
|
|
|
/***********************************************************************
|
|
|
|
rvCameraPortalSky
|
|
|
|
***********************************************************************/
|
|
|
|
CLASS_DECLARATION( idCamera, rvCameraPortalSky )
|
|
END_CLASS
|
|
|
|
/*
|
|
===============
|
|
rvCameraPortalSky::Save
|
|
================
|
|
*/
|
|
void rvCameraPortalSky::Save( idSaveGame *savefile ) const
|
|
{
|
|
}
|
|
|
|
/*
|
|
===============
|
|
rvCameraPortalSky::Restore
|
|
================
|
|
*/
|
|
void rvCameraPortalSky::Restore( idRestoreGame *savefile )
|
|
{
|
|
// Run spawn to set default values
|
|
Spawn();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraPortalSky::Spawn
|
|
=====================
|
|
*/
|
|
void rvCameraPortalSky::Spawn( void )
|
|
{
|
|
if( gameLocal.GetPortalSky() )
|
|
{
|
|
gameLocal.Error( "Only one portal sky camera allowed" );
|
|
}
|
|
gameLocal.SetPortalSky( this );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraPortalSky::GetViewParms
|
|
=====================
|
|
*/
|
|
void rvCameraPortalSky::GetViewParms( renderView_t *view )
|
|
{
|
|
assert( view );
|
|
if( view )
|
|
{
|
|
view->vieworg = GetPhysics()->GetOrigin();
|
|
view->viewID = -1;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
rvCameraPlayback
|
|
|
|
***********************************************************************/
|
|
|
|
CLASS_DECLARATION( idCamera, rvCameraPlayback )
|
|
END_CLASS
|
|
|
|
/*
|
|
===============
|
|
rvCameraPlayback::Save
|
|
================
|
|
*/
|
|
void rvCameraPlayback::Save( idSaveGame *savefile ) const
|
|
{
|
|
}
|
|
|
|
/*
|
|
===============
|
|
rvCameraPlayback::Restore
|
|
================
|
|
*/
|
|
void rvCameraPlayback::Restore( idRestoreGame *savefile )
|
|
{
|
|
// Run spawn to set default values
|
|
Spawn();
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraPlayback::Spawn
|
|
=====================
|
|
*/
|
|
void rvCameraPlayback::Spawn( void )
|
|
{
|
|
startTime = gameLocal.time;
|
|
playback = declManager->PlaybackByIndex( g_currentPlayback.GetInteger() );
|
|
}
|
|
|
|
/*
|
|
=====================
|
|
rvCameraPlayback::GetViewParms
|
|
=====================
|
|
*/
|
|
void rvCameraPlayback::GetViewParms( renderView_t *view )
|
|
{
|
|
rvDeclPlaybackData pbd;
|
|
|
|
assert( view );
|
|
if( view )
|
|
{
|
|
pbd.Init();
|
|
if( declManager->GetPlaybackData( playback, PBFL_GET_POSITION | PBFL_GET_ANGLES_FROM_VEL, gameLocal.time - startTime, gameLocal.time - startTime, &pbd ) )
|
|
{
|
|
startTime = gameLocal.time;
|
|
}
|
|
|
|
view->vieworg = pbd.GetPosition();
|
|
view->viewaxis = pbd.GetAngles().ToMat3();
|
|
|
|
// field of view
|
|
// RAVEN BEGIN
|
|
// jshepard: fov as a float for smoove transitions
|
|
gameLocal.CalcFov ( g_fov.GetFloat(), view->fov_x, view->fov_y );
|
|
|
|
// RAVEN END
|
|
}
|
|
}
|
|
|
|
// RAVEN END
|