mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 22:27:05 +00:00
348 lines
9.2 KiB
C++
348 lines
9.2 KiB
C++
|
//========= 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 );
|
||
|
}
|