You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
347 lines
9.2 KiB
347 lines
9.2 KiB
//========= 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 ); |
|
}
|
|
|