source-engine/tier3/choreoutils.cpp

348 lines
9.2 KiB
C++
Raw Permalink Normal View History

2020-04-22 16:56:21 +00:00
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Helper methods + classes for file access
//
//===========================================================================//
#include "tier3/choreoutils.h"
#include "tier3/tier3.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
#include "studio.h"
#include "../game/shared/choreoscene.h"
#include "../game/shared/choreoevent.h"
#include "tier1/KeyValues.h"
#include "bone_setup.h"
#include "soundchars.h"
//-----------------------------------------------------------------------------
// Find sequence by name
//-----------------------------------------------------------------------------
static int LookupSequence( CStudioHdr *pStudioHdr, const char *pSequenceName )
{
for ( int i = 0; i < pStudioHdr->GetNumSeq(); i++ )
{
if ( !Q_stricmp( pSequenceName, pStudioHdr->pSeqdesc( i ).pszLabel() ) )
return i;
}
return -1;
}
//-----------------------------------------------------------------------------
// Returns sequence flags
//-----------------------------------------------------------------------------
static int GetSequenceFlags( CStudioHdr *pStudioHdr, int nSequence )
{
if ( !pStudioHdr || nSequence < 0 || nSequence >= pStudioHdr->GetNumSeq() )
return 0;
mstudioseqdesc_t &seqdesc = pStudioHdr->pSeqdesc( nSequence );
return seqdesc.flags;
}
//-----------------------------------------------------------------------------
// Does a sequence loop?
//-----------------------------------------------------------------------------
static bool DoesSequenceLoop( CStudioHdr *pStudioHdr, int nSequence )
{
int nFlags = GetSequenceFlags( pStudioHdr, nSequence );
bool bLooping = ( nFlags & STUDIO_LOOPING ) ? true : false;
return bLooping;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool AutoAddGestureKeys( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly )
{
int iSequence = LookupSequence( pStudioHdr, e->GetParameters() );
if ( iSequence < 0 )
return false;
KeyValues *pSeqKeyValues = new KeyValues( "" );
if ( !pSeqKeyValues->LoadFromBuffer( pStudioHdr->pszName(), Studio_GetKeyValueText( pStudioHdr, iSequence ) ) )
{
pSeqKeyValues->deleteThis();
return false;
}
// Do we have a build point section?
KeyValues *pKVAllFaceposer = pSeqKeyValues->FindKey("faceposer");
if ( !pKVAllFaceposer )
{
pSeqKeyValues->deleteThis();
return false;
}
int nMaxFrame = Studio_MaxFrame( pStudioHdr, iSequence, pPoseParameters ) - 1;
// Start grabbing the sounds and slotting them in
KeyValues *pkvFaceposer;
char szStartLoop[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "loop" };
char szEndLoop[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "end" };
char szEntry[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "apex" };
char szExit[CEventAbsoluteTag::MAX_EVENTTAG_LENGTH] = { "end" };
for ( pkvFaceposer = pKVAllFaceposer->GetFirstSubKey(); pkvFaceposer; pkvFaceposer = pkvFaceposer->GetNextKey() )
{
if ( !Q_stricmp( pkvFaceposer->GetName(), "startloop" ) )
{
Q_strncpy( szStartLoop, pkvFaceposer->GetString(), sizeof(szStartLoop) );
continue;
}
if ( !Q_stricmp( pkvFaceposer->GetName(), "endloop" ) )
{
Q_strncpy( szEndLoop, pkvFaceposer->GetString(), sizeof(szEndLoop) );
continue;
}
if ( !Q_stricmp( pkvFaceposer->GetName(), "entrytag" ) )
{
Q_strncpy( szEntry, pkvFaceposer->GetString(), sizeof(szEntry) );
continue;
}
if ( !Q_stricmp( pkvFaceposer->GetName(), "exittag" ) )
{
Q_strncpy( szExit, pkvFaceposer->GetString(), sizeof(szExit) );
continue;
}
if ( !Q_stricmp( pkvFaceposer->GetName(), "tags" ) )
{
if ( nMaxFrame <= 0 )
continue;
KeyValues *pkvTags;
for ( pkvTags = pkvFaceposer->GetFirstSubKey(); pkvTags; pkvTags = pkvTags->GetNextKey() )
{
float flPercentage = (float)pkvTags->GetInt() / nMaxFrame;
CEventAbsoluteTag *ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, pkvTags->GetName() );
if (ptag)
{
// reposition tag
ptag->SetPercentage( flPercentage );
}
else
{
e->AddAbsoluteTag( CChoreoEvent::ORIGINAL, pkvTags->GetName(), flPercentage );
e->AddAbsoluteTag( CChoreoEvent::PLAYBACK, pkvTags->GetName(), flPercentage );
}
// lock the original tags so they can't be edited
ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, pkvTags->GetName() );
Assert( ptag );
ptag->SetLocked( true );
}
e->VerifyTagOrder();
e->PreventTagOverlap();
continue;
}
}
// FIXME: lookup linear tags in sequence data
{
CEventAbsoluteTag *ptag;
ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szStartLoop );
if (ptag)
{
ptag->SetLinear( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szStartLoop );
if (ptag)
{
ptag->SetLinear( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szEndLoop );
if (ptag)
{
ptag->SetLinear( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szEndLoop );
if (ptag)
{
ptag->SetLinear( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szEntry );
if (ptag)
{
ptag->SetEntry( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szEntry );
if (ptag)
{
ptag->SetEntry( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::ORIGINAL, szExit );
if (ptag)
{
ptag->SetExit( true );
}
ptag = e->FindAbsoluteTag( CChoreoEvent::PLAYBACK, szExit );
if (ptag)
{
ptag->SetExit( true );
}
}
pSeqKeyValues->deleteThis();
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool UpdateGestureLength( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly )
{
Assert( e );
if ( !e )
return false;
if ( e->GetType() != CChoreoEvent::GESTURE )
return false;
int iSequence = LookupSequence( pStudioHdr, e->GetParameters() );
if ( iSequence < 0 )
return false;
bool bChanged = false;
float flSeqDuration = Studio_Duration( pStudioHdr, iSequence, pPoseParameters );
float flCurDuration;
e->GetGestureSequenceDuration( flCurDuration );
if ( flSeqDuration != 0.0f && flSeqDuration != flCurDuration )
{
bChanged = true;
if ( !bCheckOnly )
{
e->SetGestureSequenceDuration( flSeqDuration );
}
}
return bChanged;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool UpdateSequenceLength( CChoreoEvent *e, CStudioHdr *pStudioHdr, float *pPoseParameters, bool bCheckOnly, bool bVerbose )
{
Assert( e );
if ( !e )
return false;
if ( e->GetType() != CChoreoEvent::SEQUENCE )
{
if ( bVerbose )
{
ConMsg( "UpdateSequenceLength: called on non-SEQUENCE event %s\n", e->GetName() );
}
return false;
}
int iSequence = LookupSequence( pStudioHdr, e->GetParameters() );
if ( iSequence < 0 )
return false;
bool bChanged = false;
bool bLooping = DoesSequenceLoop( pStudioHdr, iSequence );
float flSeqDuration = Studio_Duration( pStudioHdr, iSequence, pPoseParameters );
if ( bLooping )
{
if ( e->IsFixedLength() )
{
if ( bCheckOnly )
return true;
if ( bVerbose )
{
ConMsg( "UpdateSequenceLength: %s is looping, removing fixed length flag\n", e->GetName() );
}
bChanged = true;
}
e->SetFixedLength( false );
if ( !e->HasEndTime() )
{
if ( bCheckOnly )
return true;
if ( bVerbose )
{
ConMsg( "CheckSequenceLength: %s is looping, setting default end time\n", e->GetName() );
}
e->SetEndTime( e->GetStartTime() + flSeqDuration );
bChanged = true;
}
return bChanged;
}
if ( !e->IsFixedLength() )
{
if ( bCheckOnly )
return true;
if ( bVerbose )
{
ConMsg( "CheckSequenceLength: %s is fixed length, removing looping flag\n", e->GetName() );
}
bChanged = true;
}
e->SetFixedLength( true );
if ( e->HasEndTime() )
{
float dt = e->GetDuration();
if ( fabs( dt - flSeqDuration ) > 0.01f )
{
if ( bCheckOnly )
return true;
if ( bVerbose )
{
ConMsg( "CheckSequenceLength: %s has wrong duration, changing length from %f to %f seconds\n",
e->GetName(), dt, flSeqDuration );
}
bChanged = true;
}
}
else
{
if ( bCheckOnly )
return true;
if ( bVerbose )
{
ConMsg( "CheckSequenceLength: %s has wrong duration, changing length to %f seconds\n",
e->GetName(), flSeqDuration );
}
bChanged = true;
}
if ( !bCheckOnly )
{
e->SetEndTime( e->GetStartTime() + flSeqDuration );
}
return bChanged;
}
//-----------------------------------------------------------------------------
// Finds sound files associated with events
//-----------------------------------------------------------------------------
const char *GetSoundForEvent( CChoreoEvent *pEvent, CStudioHdr *pStudioHdr )
{
const char *pSoundName = pEvent->GetParameters();
if ( Q_stristr( pSoundName, ".wav" ) )
return PSkipSoundChars( pSoundName );
const char *pFileName = g_pSoundEmitterSystem->GetWavFileForSound( pSoundName, ( pStudioHdr && pStudioHdr->IsValid() ) ? pStudioHdr->pszName() : NULL );
return PSkipSoundChars( pFileName );
}