diff options
Diffstat (limited to 'movieobjects/dmeanimationset.cpp')
| -rw-r--r-- | movieobjects/dmeanimationset.cpp | 1407 |
1 files changed, 1407 insertions, 0 deletions
diff --git a/movieobjects/dmeanimationset.cpp b/movieobjects/dmeanimationset.cpp new file mode 100644 index 0000000..926de45 --- /dev/null +++ b/movieobjects/dmeanimationset.cpp @@ -0,0 +1,1407 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= +#include "movieobjects/dmeanimationset.h" +#include "movieobjects/dmebookmark.h" +#include "movieobjects/dmegamemodel.h" +#include "movieobjects/dmecombinationoperator.h" +#include "datamodel/dmelementfactoryhelper.h" +#include "datamodel/dmehandle.h" +#include "phonemeconverter.h" +#include "tier1/utlstringmap.h" +#include "tier2/tier2.h" +#include "filesystem.h" +#include "studio.h" +#include "tier3/tier3.h" +#include "tier1/utlbuffer.h" + +//----------------------------------------------------------------------------- +// CDmePresetGroup - container for animation set info +//----------------------------------------------------------------------------- +IMPLEMENT_ELEMENT_FACTORY( DmePreset, CDmePreset ); + +void CDmePreset::OnConstruction() +{ + m_ControlValues.Init( this, "controlValues" ); + m_nProceduralType.InitAndSet( this, "procedural", PROCEDURAL_PRESET_NOT ); +} + +void CDmePreset::OnDestruction() +{ +} + +CDmaElementArray< CDmElement > &CDmePreset::GetControlValues() +{ + return m_ControlValues; +} + +const CDmaElementArray< CDmElement > &CDmePreset::GetControlValues() const +{ + return m_ControlValues; +} + +int CDmePreset::FindControlValueIndex( const char *pControlName ) +{ + int c = m_ControlValues.Count(); + for ( int i = 0; i < c; ++i ) + { + CDmElement *e = m_ControlValues.Get( i ); + if ( !Q_stricmp( e->GetName(), pControlName ) ) + return i; + } + return -1; +} + +CDmElement *CDmePreset::FindControlValue( const char *pControlName ) +{ + int i = FindControlValueIndex( pControlName ); + if ( i >= 0 ) + return m_ControlValues.Get(i); + return NULL; +} + +CDmElement *CDmePreset::FindOrAddControlValue( const char *pControlName ) +{ + CDmElement *pControlValues = FindControlValue( pControlName ); + if ( !pControlValues ) + { + // Create the default groups in order + pControlValues = CreateElement< CDmElement >( pControlName, GetFileId() ); + m_ControlValues.AddToTail( pControlValues ); + } + return pControlValues; +} + +void CDmePreset::RemoveControlValue( const char *pControlName ) +{ + int i = FindControlValueIndex( pControlName ); + if ( i >= 0 ) + { + m_ControlValues.Remove( i ); + } +} + + +//----------------------------------------------------------------------------- +// Is the preset read-only? +//----------------------------------------------------------------------------- +bool CDmePreset::IsReadOnly() +{ + DmAttributeReferenceIterator_t h = g_pDataModel->FirstAttributeReferencingElement( GetHandle() ); + while ( h != DMATTRIBUTE_REFERENCE_ITERATOR_INVALID ) + { + CDmAttribute *pAttribute = g_pDataModel->GetAttribute( h ); + CDmePresetGroup *pOwner = CastElement<CDmePresetGroup>( pAttribute->GetOwner() ); + if ( pOwner && pOwner->m_bIsReadOnly ) + return true; + h = g_pDataModel->NextAttributeReferencingElement( h ); + } + return false; +} + + +//----------------------------------------------------------------------------- +// Copies control values +//----------------------------------------------------------------------------- +void CDmePreset::CopyControlValuesFrom( CDmePreset *pSource ) +{ + m_ControlValues.RemoveAll(); + + const CDmaElementArray< CDmElement > &sourceValues = pSource->GetControlValues(); + int nCount = sourceValues.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmElement *pCopy = sourceValues[i]->Copy( ); + m_ControlValues.AddToTail( pCopy ); + } +} + +void CDmePreset::SetProceduralPresetType( int nType ) +{ + Assert( nType >= 0 && nType < NUM_PROCEDURAL_PRESET_TYPES ); + m_nProceduralType = nType; +} + +bool CDmePreset::IsProcedural() const +{ + return m_nProceduralType != PROCEDURAL_PRESET_NOT; +} + +int CDmePreset::GetProceduralPresetType() const +{ + return m_nProceduralType; +} + +IMPLEMENT_ELEMENT_FACTORY( DmeProceduralPresetSettings, CDmeProceduralPresetSettings ); + +void CDmeProceduralPresetSettings::OnConstruction() +{ + m_flJitterScale.InitAndSet( this, "jitterscale", 1.0f ); + m_flSmoothScale.InitAndSet( this, "smoothscale", 1.0f ); + m_flSharpenScale.InitAndSet( this, "sharpenscale", 1.0f ); + m_flSoftenScale.InitAndSet( this, "softenscale", 1.0f ); + + m_nJitterIterations.InitAndSet( this, "jitteriterations", 5 ); + m_nSmoothIterations.InitAndSet( this, "smoothiterations", 5 ); + m_nSharpenIterations.InitAndSet( this, "sharpeniterations", 1 ); + m_nSoftenIterations.InitAndSet( this, "softeniterations", 1 ); + + // 1/12 second now ( 833 ten thousandths ) + m_nStaggerInterval.InitAndSet( this, "staggerinterval", 10000 / 12 ); +} + +void CDmeProceduralPresetSettings::OnDestruction() +{ +} + +//----------------------------------------------------------------------------- +// CDmePresetRemap - copies presets from one group to another +//----------------------------------------------------------------------------- +IMPLEMENT_ELEMENT_FACTORY( DmePresetRemap, CDmePresetRemap ); + +void CDmePresetRemap::OnConstruction() +{ + m_SourcePresetGroup.Init( this, "sourcePresetGroup" ); + m_SrcPresets.Init( this, "srcPresets" ); + m_DestPresets.Init( this, "destPresets" ); +} + +void CDmePresetRemap::OnDestruction() +{ +} + + +const char *CDmePresetRemap::FindSourcePreset( const char *pDestPresetName ) +{ + int nCount = m_DestPresets.Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( !Q_stricmp( pDestPresetName, m_DestPresets[i] ) ) + return m_SrcPresets[i]; + } + return NULL; +} + +void CDmePresetRemap::AddRemap( const char *pSourcePresetName, const char *pDestPresetName ) +{ + m_SrcPresets.AddToTail( pSourcePresetName ); + m_DestPresets.AddToTail( pDestPresetName ); +} + +void CDmePresetRemap::RemoveAll() +{ + m_SrcPresets.RemoveAll(); + m_DestPresets.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Iteration +//----------------------------------------------------------------------------- +int CDmePresetRemap::GetRemapCount() +{ + return m_SrcPresets.Count(); +} + +const char *CDmePresetRemap::GetRemapSource( int i ) +{ + return m_SrcPresets[i]; +} + +const char *CDmePresetRemap::GetRemapDest( int i ) +{ + return m_DestPresets[i]; +} + + +//----------------------------------------------------------------------------- +// CDmePresetGroup - container for animation set info +//----------------------------------------------------------------------------- +IMPLEMENT_ELEMENT_FACTORY( DmePresetGroup, CDmePresetGroup ); + +void CDmePresetGroup::OnConstruction() +{ + m_Presets.Init( this, "presets" ); + m_bIsVisible.InitAndSet( this, "visible", true ); + m_bIsReadOnly.Init( this, "readonly" ); +} + +void CDmePresetGroup::OnDestruction() +{ +} + +CDmaElementArray< CDmePreset > &CDmePresetGroup::GetPresets() +{ + return m_Presets; +} + +const CDmaElementArray< CDmePreset > &CDmePresetGroup::GetPresets() const +{ + return m_Presets; +} + +//----------------------------------------------------------------------------- +// Finds the index of a particular preset group +//----------------------------------------------------------------------------- +int CDmePresetGroup::FindPresetIndex( CDmePreset *pPreset ) +{ + int c = m_Presets.Count(); + for ( int i = 0; i < c; ++i ) + { + CDmePreset *e = m_Presets.Get( i ); + if ( pPreset == e ) + return i; + } + return -1; +} + + +CDmePreset *CDmePresetGroup::FindPreset( const char *pPresetName ) +{ + int i; + int c = m_Presets.Count(); + for ( i = 0; i < c; ++i ) + { + CDmePreset *e = m_Presets.Get( i ); + if ( !Q_stricmp( e->GetName(), pPresetName ) ) + return e; + } + return NULL; +} + +CDmePreset *CDmePresetGroup::FindOrAddPreset( const char *pPresetName, int nType /*=PROCEDURAL_PRESET_NOT*/ ) +{ + CDmePreset *pPreset = FindPreset( pPresetName ); + if ( !pPreset ) + { + // Create the default groups in order + pPreset = CreateElement< CDmePreset >( pPresetName, GetFileId() ); + pPreset->SetProceduralPresetType( nType ); + m_Presets.AddToTail( pPreset ); + } + return pPreset; +} + +bool CDmePresetGroup::RemovePreset( CDmePreset *pPreset ) +{ + int i = FindPresetIndex( pPreset ); + if ( i >= 0 ) + { + m_Presets.Remove( i ); + return true; + } + return false; +} + +void CDmePresetGroup::MovePresetUp( CDmePreset *pPreset ) +{ + int i = FindPresetIndex( pPreset ); + if ( i >= 1 ) + { + m_Presets.Swap( i, i-1 ); + } +} + +void CDmePresetGroup::MovePresetDown( CDmePreset *pPreset ) +{ + int i = FindPresetIndex( pPreset ); + if ( i >= 0 && i < m_Presets.Count() - 1 ) + { + m_Presets.Swap( i, i+1 ); + } +} + + +//----------------------------------------------------------------------------- +// Reorder presets +//----------------------------------------------------------------------------- +void CDmePresetGroup::MovePresetInFrontOf( CDmePreset *pPreset, CDmePreset *pInFrontOf ) +{ + if ( pPreset == pInFrontOf ) + return; + + int nEnd = pInFrontOf ? FindPresetIndex( pInFrontOf ) : m_Presets.Count(); + Assert( nEnd >= 0 ); + + RemovePreset( pPreset ); + if ( nEnd > m_Presets.Count() ) + { + nEnd = m_Presets.Count(); + } + m_Presets.InsertBefore( nEnd, pPreset ); +} + + +//----------------------------------------------------------------------------- +// The preset remap +//----------------------------------------------------------------------------- +CDmePresetRemap *CDmePresetGroup::GetPresetRemap() +{ + return GetValueElement< CDmePresetRemap >( "presetRemap" ); +} + +CDmePresetRemap *CDmePresetGroup::GetOrAddPresetRemap() +{ + CDmePresetRemap *pPresetRemap = GetPresetRemap(); + if ( !pPresetRemap ) + { + pPresetRemap = CreateElement< CDmePresetRemap >( "PresetRemap", GetFileId() ); + SetValue( "presetRemap", pPresetRemap ); + } + return pPresetRemap; +} + + + +//----------------------------------------------------------------------------- +// Finds a control index +//----------------------------------------------------------------------------- +struct ExportedControl_t +{ + CUtlString m_Name; + bool m_bIsStereo; + bool m_bIsMulti; + int m_nFirstIndex; +}; + + +//----------------------------------------------------------------------------- +// Builds a unique list of controls found in the presets +//----------------------------------------------------------------------------- +static int FindExportedControlIndex( const char *pControlName, CUtlVector< ExportedControl_t > &uniqueControls ) +{ + int nCount = uniqueControls.Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( !Q_stricmp( pControlName, uniqueControls[i].m_Name ) ) + return i; + } + return -1; +} + + +//----------------------------------------------------------------------------- +// Builds a unique list of controls found in the presets +//----------------------------------------------------------------------------- +static int BuildExportedControlList( CDmeAnimationSet *pAnimationSet, const CDmePresetGroup *pPresetGroup, CUtlVector< ExportedControl_t > &uniqueControls ) +{ + int nGlobalIndex = 0; + const CDmrElementArrayConst< CDmePreset > &presets = pPresetGroup->GetPresets(); + int nPresetCount = presets.Count(); + for ( int iPreset = 0; iPreset < nPresetCount; ++iPreset ) + { + CDmePreset *pPreset = presets[iPreset]; + const CDmrElementArray< CDmElement > &controls = pPreset->GetControlValues(); + + int nControlCount = controls.Count(); + for ( int i = 0; i < nControlCount; ++i ) + { + const char *pControlName = controls[i]->GetName(); + int nIndex = FindExportedControlIndex( pControlName, uniqueControls ); + if ( nIndex >= 0 ) + continue; + CDmAttribute *pValueAttribute = controls[i]->GetAttribute( "value" ); + if ( !pValueAttribute || pValueAttribute->GetType() != AT_FLOAT ) + continue; + + if ( pAnimationSet ) + { + + CDmElement *pControl = pAnimationSet->FindControl( pControlName ); + if ( !pControl ) + continue; + + int j = uniqueControls.AddToTail(); + ExportedControl_t &control = uniqueControls[j]; + control.m_Name = pControlName; + control.m_bIsStereo = pControl->GetValue<bool>( "combo" ); + control.m_bIsMulti = pControl->GetValue<bool>( "multi" ); + control.m_nFirstIndex = nGlobalIndex; + nGlobalIndex += 1 + control.m_bIsStereo + control.m_bIsMulti; + } + else + { + int j = uniqueControls.AddToTail(); + ExportedControl_t &control = uniqueControls[j]; + control.m_Name = pControlName; + // this isn't quite as reliable as querying the animation set but if we don't have one... + control.m_bIsStereo = controls[ i ]->GetAttribute( "balance" ) ? true : false; + control.m_bIsMulti = controls[ i ]->GetAttribute( "multilevel" ) ? true : false; + control.m_nFirstIndex = nGlobalIndex; + nGlobalIndex += 1 + control.m_bIsStereo + control.m_bIsMulti; + } + } + } + return nGlobalIndex; +} + + +//----------------------------------------------------------------------------- +// Exports this preset group to a faceposer .txt expression file +// Either an animation set or a combination operator are required so that +// the default value for unspecified +//----------------------------------------------------------------------------- +bool CDmePresetGroup::ExportToTXT( const char *pFileName, CDmeAnimationSet *pAnimationSet /* = NULL */, CDmeCombinationOperator *pComboOp /* = NULL */ ) const +{ + const CDmePresetGroup *pPresetGroup = this; + + // find all used controls + CUtlVector< ExportedControl_t > exportedControls; + BuildExportedControlList( pAnimationSet, pPresetGroup, exportedControls ); + + CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER ); + + // Output the unique keys + buf.Printf( "$keys " ); + int nExportedControlCount = exportedControls.Count(); + for ( int i = 0; i < nExportedControlCount; ++i ) + { + char pTempBuf[MAX_PATH]; + + ExportedControl_t &control = exportedControls[i]; + if ( !control.m_bIsStereo ) + { + buf.Printf("%s ", control.m_Name.Get() ); + } + else + { + Q_snprintf( pTempBuf, sizeof(pTempBuf), "right_%s", control.m_Name.Get() ); + buf.Printf("%s ", pTempBuf ); + Q_snprintf( pTempBuf, sizeof(pTempBuf), "left_%s", control.m_Name.Get() ); + buf.Printf("%s ", pTempBuf ); + } + + if ( control.m_bIsMulti ) + { + Q_snprintf( pTempBuf, sizeof(pTempBuf), "multi_%s", control.m_Name.Get() ); + buf.Printf("%s ", pTempBuf ); + } + } + buf.Printf( "\n" ); + buf.Printf( "$hasweighting\n" ); + buf.Printf( "$normalized\n" ); + + // Output all presets + const CDmrElementArrayConst< CDmePreset > &presets = pPresetGroup->GetPresets(); + int nPresetCount = presets.Count(); + for ( int iPreset = 0; iPreset < nPresetCount; ++iPreset ) + { + CDmePreset *pPreset = presets[iPreset]; + const char *pPresetName = pPreset->GetName(); + + // Hack for 'silence' and for p_ naming scheme + if ( !Q_stricmp( pPresetName, "p_silence" ) ) + { + pPresetName = "<sil>"; + } + if ( pPresetName[0] == 'p' && pPresetName[1] == '_' ) + { + pPresetName = &pPresetName[2]; + } + + buf.Printf( "\"%s\" \t", pPresetName ); + + int nPhonemeIndex = TextToPhonemeIndex( pPresetName ); + int nCode = CodeForPhonemeByIndex( nPhonemeIndex ); + if ( nCode < 128 ) + { + buf.Printf( "\"%c\" \t", nCode ); + } + else + { + buf.Printf( "\"0x%x\"\t", nCode ); + } + + for ( int i = 0; i < nExportedControlCount; ++i ) + { + ExportedControl_t &control = exportedControls[i]; + CDmElement *pControlValue = pPreset->FindControlValue( control.m_Name ); + if ( !pControlValue ) + { + CDmElement *pControl = pAnimationSet ? pAnimationSet->FindControl( control.m_Name ) : NULL; + if ( !pControl ) + { + const ControlIndex_t nIndex = pComboOp ? pComboOp->FindControlIndex( control.m_Name ) : -1; + if ( nIndex >= 0 ) + { + buf.Printf( "%.5f\t0.000\t", pComboOp->GetControlDefaultValue( nIndex ) ); + if ( control.m_bIsStereo ) + { + buf.Printf( "%.5f\t0.000\t", pComboOp->GetControlDefaultValue( nIndex ) ); + } + if ( control.m_bIsMulti ) + { + buf.Printf( "%.5f\t0.000\t", pComboOp->GetControlDefaultValue( nIndex ) ); + } + } + else + { + buf.Printf( "0.000\t0.000\t" ); + if ( control.m_bIsStereo ) + { + buf.Printf( "0.000\t0.000\t" ); + } + if ( control.m_bIsMulti ) + { + buf.Printf( "0.000\t0.000\t" ); + } + } + + continue; + } + + if ( !control.m_bIsStereo ) + { + buf.Printf( "%.5f\t1.000\t", pControl->GetValue<float>( "defaultValue" ) ); + } + else + { + float flValue, flBalance, flLeft, flRight; + flValue = pControl->GetValue<float>( "defaultValue", 0.0f ); + flBalance = pControl->GetValue<float>( "defaultBalance", 0.5f ); + ValueBalanceToLeftRight( &flLeft, &flRight, flValue, flBalance ); + buf.Printf( "%.5f\t1.000\t", flRight ); + buf.Printf( "%.5f\t1.000\t", flLeft ); + } + + if ( control.m_bIsMulti ) + { + buf.Printf( "%.5f\t1.000\t", pControl->GetValue<float>( "defaultMultilevel" ) ); + } + continue; + } + + if ( !control.m_bIsStereo ) + { + buf.Printf( "%.5f\t1.000\t", pControlValue->GetValue<float>( "value" ) ); + } + else + { + float flValue, flBalance, flLeft, flRight; + flValue = pControlValue->GetValue<float>( "value" ); + flBalance = pControlValue->GetValue<float>( "balance" ); + ValueBalanceToLeftRight( &flLeft, &flRight, flValue, flBalance ); + buf.Printf( "%.5f\t1.000\t", flRight ); + buf.Printf( "%.5f\t1.000\t", flLeft ); + } + + if ( control.m_bIsMulti ) + { + buf.Printf( "%.5f\t1.000\t", pControlValue->GetValue<float>( "multilevel" ) ); + } + } + const char *pDesc = DescForPhonemeByIndex( nPhonemeIndex ); + buf.Printf( "\"%s\"\n", pDesc ? pDesc : pPresetName ); + } + + return g_pFullFileSystem->WriteFile( pFileName, NULL, buf ); +} + +#ifdef ALIGN4 +#undef ALIGN4 +#endif // #ifdef ALIGN4 +#define ALIGN4( a ) a = (byte *)((int)((byte *)a + 3) & ~ 3) + + +//----------------------------------------------------------------------------- +// Exports this preset group to a faceposer .vfe expression file +//----------------------------------------------------------------------------- +bool CDmePresetGroup::ExportToVFE( const char *pFileName, CDmeAnimationSet *pAnimationSet /* = NULL */, CDmeCombinationOperator *pComboOp /* = NULL */ ) const +{ + const CDmePresetGroup *pPresetGroup = this; + + int i; + const CDmrElementArrayConst< CDmePreset > &presets = pPresetGroup->GetPresets(); + + // find all used controls + CUtlVector< ExportedControl_t > exportedControls; + int nTotalControlCount = BuildExportedControlList( pAnimationSet, pPresetGroup, exportedControls ); + const int nExportedControlCount = exportedControls.Count(); + + byte *pData = (byte *)calloc( 1024 * 1024, 1 ); + byte *pDataStart = pData; + + flexsettinghdr_t *fhdr = (flexsettinghdr_t *)pData; + + fhdr->id = ('V' << 16) + ('F' << 8) + ('E'); + fhdr->version = 0; + if ( !g_pFullFileSystem->FullPathToRelativePathEx( pFileName, "GAME", fhdr->name, sizeof(fhdr->name) ) ) + { + Q_strncpy( fhdr->name, pFileName, sizeof(fhdr->name) ); + } + + // allocate room for header + pData += sizeof( flexsettinghdr_t ); + ALIGN4( pData ); + + // store flex settings + flexsetting_t *pSetting = (flexsetting_t *)pData; + fhdr->numflexsettings = presets.Count(); + fhdr->flexsettingindex = pData - pDataStart; + pData += sizeof( flexsetting_t ) * fhdr->numflexsettings; + ALIGN4( pData ); + for ( i = 0; i < fhdr->numflexsettings; i++ ) + { + CDmePreset *pPreset = presets[i]; + Assert( pPreset ); + + pSetting[i].index = i; + pSetting[i].settingindex = pData - (byte *)(&pSetting[i]); + + flexweight_t *pFlexWeights = (flexweight_t *)pData; + + for ( int j = 0; j < nExportedControlCount; j++ ) + { + ExportedControl_t &control = exportedControls[ j ]; + CDmElement *pControlValue = pPreset->FindControlValue( control.m_Name ); + if ( !pControlValue ) + { + const ControlIndex_t nIndex = pComboOp ? pComboOp->FindControlIndex( control.m_Name ) : -1; + if ( nIndex >= 0 ) + { + if ( !control.m_bIsStereo ) + { + pSetting[i].numsettings++; + pFlexWeights->key = control.m_nFirstIndex; + pFlexWeights->weight = pComboOp->GetControlDefaultValue( nIndex ); + pFlexWeights->influence = 1.0f; + pFlexWeights++; + } + else + { + float flValue, flBalance, flLeft, flRight; + flValue = pComboOp->GetControlDefaultValue( nIndex ); + flBalance = 0.5; + ValueBalanceToLeftRight( &flLeft, &flRight, flValue, flBalance ); + + pSetting[i].numsettings += 2; + pFlexWeights->key = control.m_nFirstIndex; + pFlexWeights->weight = flRight; + pFlexWeights->influence = 1.0f; + pFlexWeights++; + pFlexWeights->key = control.m_nFirstIndex + 1; + pFlexWeights->weight = flLeft; + pFlexWeights->influence = 1.0f; + pFlexWeights++; + } + + if ( control.m_bIsMulti ) + { + pSetting[i].numsettings++; + pFlexWeights->key = control.m_nFirstIndex + 1 + control.m_bIsStereo; + pFlexWeights->weight = 0.5f; + pFlexWeights->influence = 1.0f; + pFlexWeights++; + } + } + else + { + pSetting[i].numsettings++; + pFlexWeights->key = control.m_nFirstIndex; + pFlexWeights->weight = 0.0f; + pFlexWeights->influence = 0.0f; + pFlexWeights++; + + if ( control.m_bIsStereo ) + { + pSetting[i].numsettings++; + pFlexWeights->key = control.m_nFirstIndex + 1; + pFlexWeights->weight = 0.0f; + pFlexWeights->influence = 0.0f; + pFlexWeights++; + } + + if ( control.m_bIsMulti ) + { + pSetting[i].numsettings++; + pFlexWeights->key = control.m_nFirstIndex + 1 + control.m_bIsStereo; + pFlexWeights->weight = 0.5f; + pFlexWeights->influence = 0.0f; + pFlexWeights++; + } + } + + continue; + } + + if ( !control.m_bIsStereo ) + { + pSetting[i].numsettings++; + pFlexWeights->key = control.m_nFirstIndex; + pFlexWeights->weight = pControlValue->GetValue<float>( "value" ); + pFlexWeights->influence = 1.0f; + pFlexWeights++; + } + else + { + float flValue, flBalance, flLeft, flRight; + flValue = pControlValue->GetValue<float>( "value" ); + flBalance = pControlValue->GetValue<float>( "balance" ); + ValueBalanceToLeftRight( &flLeft, &flRight, flValue, flBalance ); + + pSetting[i].numsettings += 2; + pFlexWeights->key = control.m_nFirstIndex; + pFlexWeights->weight = flRight; + pFlexWeights->influence = 1.0f; + pFlexWeights++; + pFlexWeights->key = control.m_nFirstIndex + 1; + pFlexWeights->weight = flLeft; + pFlexWeights->influence = 1.0f; + pFlexWeights++; + } + + if ( control.m_bIsMulti ) + { + pSetting[i].numsettings++; + pFlexWeights->key = control.m_nFirstIndex + 1 + control.m_bIsStereo; + pFlexWeights->weight = pControlValue->GetValue<float>( "multilevel" ); + pFlexWeights->influence = 1.0f; + pFlexWeights++; + } + } + + pData = (byte *)pFlexWeights; + ALIGN4( pData ); + } + + int numindexes = 1; + for (i = 0; i < fhdr->numflexsettings; i++) + { + if ( pSetting[i].index >= numindexes ) + { + numindexes = pSetting[i].index + 1; + } + } + + // store indexed table + int *pIndex = (int *)pData; + fhdr->numindexes = numindexes; + fhdr->indexindex = pData - pDataStart; + pData += sizeof( int ) * numindexes; + ALIGN4( pData ); + for (i = 0; i < numindexes; i++) + { + pIndex[i] = -1; + } + for (i = 0; i < fhdr->numflexsettings; i++) + { + pIndex[pSetting[i].index] = i; + } + + // store flex setting names + for (i = 0; i < fhdr->numflexsettings; i++) + { + CDmePreset *pPreset = presets[i]; + const char *pPresetName = pPreset->GetName(); + + // Hack for 'silence' and for p_ naming scheme + if ( pPresetName[0] == 'p' && pPresetName[1] == '_' ) + { + pPresetName = &pPresetName[2]; + } + if ( !Q_stricmp( pPresetName, "silence" ) ) + { + pPresetName = "<sil>"; + } + + pSetting[i].nameindex = pData - (byte *)(&pSetting[i]); + strcpy( (char *)pData, pPresetName ); + pData += Q_strlen( pPresetName ) + 1; + } + ALIGN4( pData ); + + // store key names + char **pKeynames = (char **)pData; + fhdr->numkeys = nTotalControlCount; + fhdr->keynameindex = pData - pDataStart; + pData += sizeof(char *) * nTotalControlCount; + int j = 0; + for ( i = 0; i < nExportedControlCount; ++i ) + { + char pTempBuf[MAX_PATH]; + + ExportedControl_t &control = exportedControls[i]; + if ( !control.m_bIsStereo ) + { + pKeynames[j++] = (char *)(pData - pDataStart); + strcpy( (char *)pData, control.m_Name ); + pData += Q_strlen( control.m_Name ) + 1; + } + else + { + pKeynames[j++] = (char *)(pData - pDataStart); + Q_snprintf( pTempBuf, sizeof(pTempBuf), "right_%s", control.m_Name.Get() ); + strcpy( (char *)pData, pTempBuf ); + pData += Q_strlen( pTempBuf ) + 1; + + pKeynames[j++] = (char *)(pData - pDataStart); + Q_snprintf( pTempBuf, sizeof(pTempBuf), "left_%s", control.m_Name.Get() ); + strcpy( (char *)pData, pTempBuf ); + pData += Q_strlen( pTempBuf ) + 1; + } + + if ( control.m_bIsMulti ) + { + pKeynames[j++] = (char *)(pData - pDataStart); + Q_snprintf( pTempBuf, sizeof(pTempBuf), "multi_%s", control.m_Name.Get() ); + strcpy( (char *)pData, pTempBuf ); + pData += Q_strlen( pTempBuf ) + 1; + } + } + Assert( j == nTotalControlCount ); + ALIGN4( pData ); + + // allocate room for remapping + int *keymapping = (int *)pData; + fhdr->keymappingindex = pData - pDataStart; + pData += sizeof( int ) * nTotalControlCount; + for (i = 0; i < nTotalControlCount; i++) + { + keymapping[i] = -1; + } + ALIGN4( pData ); + + fhdr->length = pData - pDataStart; + + FileHandle_t fh = g_pFullFileSystem->Open( pFileName, "wb" ); + if ( !fh ) + { + ConWarning( "Unable to write to %s (read-only?)\n", pFileName ); + free( pDataStart ); + return false; + } + + g_pFullFileSystem->Write( pDataStart, fhdr->length, fh ); + g_pFullFileSystem->Close( fh ); + free( pDataStart ); + return true; +} + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// CDmeAnimationSet - container for animation set info +//----------------------------------------------------------------------------- +IMPLEMENT_ELEMENT_FACTORY( DmeAnimationSet, CDmeAnimationSet ); + +void CDmeAnimationSet::OnConstruction() +{ + m_Controls.Init( this, "controls" ); + m_PresetGroups.Init( this, "presetGroups" ); + m_SelectionGroups.Init( this, "selectionGroups" ); + m_PhonemeMap.Init( this, "phonememap" ); + m_Operators.Init( this, "operators" ); + m_Bookmarks.Init( this, "bookmarks" ); +} + +void CDmeAnimationSet::OnDestruction() +{ +} + +CDmaElementArray< CDmElement > &CDmeAnimationSet::GetControls() +{ + return m_Controls; +} + +CDmaElementArray< CDmePresetGroup > &CDmeAnimationSet::GetPresetGroups() +{ + return m_PresetGroups; +} + +CDmaElementArray< CDmeOperator > &CDmeAnimationSet::GetOperators() +{ + return m_Operators; +} + +void CDmeAnimationSet::AddOperator( CDmeOperator *pOperator ) +{ + m_Operators.AddToTail( pOperator ); +} + +void CDmeAnimationSet::RemoveOperator( CDmeOperator *pOperator ) +{ + int nCount = m_Operators.Count(); + for ( int i = 0; i < nCount; ++i ) + { + if ( m_Operators[i] == pOperator ) + { + m_Operators.Remove(i); + break; + } + } +} + +//----------------------------------------------------------------------------- +// Finds the index of a particular preset group +//----------------------------------------------------------------------------- +void CDmeAnimationSet::OnElementUnserialized() +{ + BaseClass::OnElementUnserialized(); + + CDmeGameModel *pGameModel = GetValueElement< CDmeGameModel >( "gameModel" ); + if ( pGameModel ) + { + // NOTE: The model preset manager can't possibly have the right + // file id at this point; it's up to the preset group manager to queue + // application requests until it gets one + g_pModelPresetGroupMgr->ApplyModelPresets( pGameModel->GetModelName(), this ); + } +} + + +//----------------------------------------------------------------------------- +// Finds the index of a particular preset group +//----------------------------------------------------------------------------- +int CDmeAnimationSet::FindPresetGroupIndex( CDmePresetGroup *pPresetGroup ) +{ + int c = m_PresetGroups.Count(); + for ( int i = 0; i < c; ++i ) + { + CDmePresetGroup *e = m_PresetGroups.Get( i ); + if ( pPresetGroup == e ) + return i; + } + return -1; +} + +int CDmeAnimationSet::FindPresetGroupIndex( const char *pGroupName ) +{ + int c = m_PresetGroups.Count(); + for ( int i = 0; i < c; ++i ) + { + CDmePresetGroup *e = m_PresetGroups.Get( i ); + if ( e && !Q_stricmp( e->GetName(), pGroupName ) ) + return i; + } + return -1; +} + + +//----------------------------------------------------------------------------- +// Find by name +//----------------------------------------------------------------------------- +CDmePresetGroup *CDmeAnimationSet::FindPresetGroup( const char *pGroupName ) +{ + int nIndex = FindPresetGroupIndex( pGroupName ); + if ( nIndex >= 0 ) + return m_PresetGroups[nIndex]; + return NULL; +} + + +//----------------------------------------------------------------------------- +// Find or add by name +//----------------------------------------------------------------------------- +CDmePresetGroup *CDmeAnimationSet::FindOrAddPresetGroup( const char *pGroupName ) +{ + CDmePresetGroup *pPresetGroup = FindPresetGroup( pGroupName ); + if ( !pPresetGroup ) + { + // Create the default groups in order + pPresetGroup = CreateElement< CDmePresetGroup >( pGroupName, GetFileId() ); + m_PresetGroups.AddToTail( pPresetGroup ); + } + return pPresetGroup; +} + + +//----------------------------------------------------------------------------- +// Remove preset group +//----------------------------------------------------------------------------- +bool CDmeAnimationSet::RemovePresetGroup( CDmePresetGroup *pPresetGroup ) +{ + int i = FindPresetGroupIndex( pPresetGroup ); + if ( i >= 0 ) + { + m_PresetGroups.Remove( i ); + return true; + } + return false; +} + + +//----------------------------------------------------------------------------- +// Move preset group up/down in the list +//----------------------------------------------------------------------------- +void CDmeAnimationSet::MovePresetGroupUp( CDmePresetGroup *pPresetGroup ) +{ + int i = FindPresetGroupIndex( pPresetGroup ); + if ( i >= 1 ) + { + m_PresetGroups.Swap( i, i-1 ); + } +} + +void CDmeAnimationSet::MovePresetGroupDown( CDmePresetGroup *pPresetGroup ) +{ + int i = FindPresetGroupIndex( pPresetGroup ); + if ( i >= 0 && i < m_PresetGroups.Count() - 1 ) + { + m_PresetGroups.Swap( i, i+1 ); + } +} + + +//----------------------------------------------------------------------------- +// Reorder preset groups +//----------------------------------------------------------------------------- +void CDmeAnimationSet::MovePresetGroupInFrontOf( CDmePresetGroup *pPresetGroup, CDmePresetGroup *pInFrontOf ) +{ + if ( pPresetGroup == pInFrontOf ) + return; + +#ifdef DBGFLAG_ASSERT + int nStart = FindPresetGroupIndex( pPresetGroup ); +#endif + + int nEnd = pInFrontOf ? FindPresetGroupIndex( pInFrontOf ) : m_PresetGroups.Count(); + Assert( nStart >= 0 && nEnd >= 0 ); + + RemovePresetGroup( pPresetGroup ); + if ( nEnd > m_PresetGroups.Count() ) + { + nEnd = m_PresetGroups.Count(); + } + m_PresetGroups.InsertBefore( nEnd, pPresetGroup ); +} + + +CDmePreset *CDmeAnimationSet::FindOrAddPreset( const char *pGroupName, const char *pPresetName, int nType /*=PROCEDURAL_PRESET_NOT*/ ) +{ + CDmePresetGroup *pPresetGroup = FindOrAddPresetGroup( pGroupName ); + return pPresetGroup->FindOrAddPreset( pPresetName, nType ); +} + +bool CDmeAnimationSet::RemovePreset( CDmePreset *pPreset ) +{ + int c = m_PresetGroups.Count(); + for ( int i = 0; i < c; ++i ) + { + if ( m_PresetGroups[i]->RemovePreset( pPreset ) ) + return true; + } + return false; +} + + +const CDmaElementArray< CDmeBookmark > &CDmeAnimationSet::GetBookmarks() const +{ + return m_Bookmarks; +} + +CDmaElementArray< CDmeBookmark > &CDmeAnimationSet::GetBookmarks() +{ + return m_Bookmarks; +} + + +CDmaElementArray< CDmElement > &CDmeAnimationSet::GetSelectionGroups() +{ + return m_SelectionGroups; +} + +CDmaElementArray< CDmePhonemeMapping > &CDmeAnimationSet::GetPhonemeMap() +{ + return m_PhonemeMap; +} + +void CDmeAnimationSet::RestoreDefaultPhonemeMap() +{ + CUndoScopeGuard guard( "RestoreDefaultPhonemeMap" ); + + int i; + int c = m_PhonemeMap.Count(); + for ( i = 0; i < c; ++i ) + { + g_pDataModel->DestroyElement( m_PhonemeMap[ i ]->GetHandle() ); + } + m_PhonemeMap.Purge(); + + int phonemeCount = NumPhonemes(); + for ( i = 0; i < phonemeCount; ++i ) + { + const char *pName = NameForPhonemeByIndex( i ); + CDmePhonemeMapping *mapping = CreateElement< CDmePhonemeMapping >( pName, GetFileId() ); + char presetName[ 256 ]; + Q_snprintf( presetName, sizeof( presetName ), "p_%s", pName ); + mapping->m_Preset = presetName; + mapping->m_Weight = 1.0f; + + m_PhonemeMap.AddToTail( mapping ); + } +} + +CDmePhonemeMapping *CDmeAnimationSet::FindMapping( const char *pRawPhoneme ) +{ + int c = m_PhonemeMap.Count(); + for ( int i = 0; i < c; ++i ) + { + CDmePhonemeMapping *e = m_PhonemeMap.Get( i ); + Assert( e ); + if ( !e ) + continue; + + if ( !Q_stricmp( e->GetName(), pRawPhoneme ) ) + return e; + } + return NULL; +} + + +//----------------------------------------------------------------------------- +// Finds a control +//----------------------------------------------------------------------------- +CDmElement *CDmeAnimationSet::FindControl( const char *pControlName ) +{ + int c = m_Controls.Count(); + for ( int i = 0; i < c; ++i ) + { + CDmElement *e = m_Controls.Get( i ); + if ( !Q_stricmp( e->GetName(), pControlName ) ) + return e; + } + return NULL; +} + + +//----------------------------------------------------------------------------- +// Finds or adds a control +//----------------------------------------------------------------------------- +CDmElement *CDmeAnimationSet::FindOrAddControl( const char *pControlName ) +{ + CDmElement *pControl = FindControl( pControlName ); + if ( !pControl ) + { + // If not, then create one + pControl = CreateElement< CDmElement >( pControlName, GetFileId() ); + m_Controls.AddToTail( pControl ); + } + return pControl; +} + + +CDmElement *CDmeAnimationSet::FindSelectionGroup( const char *pSelectionGroupName ) +{ + int c = m_SelectionGroups.Count(); + for ( int i = 0; i < c; ++i ) + { + CDmElement *e = m_SelectionGroups.Get( i ); + if ( !Q_stricmp( e->GetName(), pSelectionGroupName ) ) + return e; + } + return NULL; +} + +CDmElement *CDmeAnimationSet::FindOrAddSelectionGroup( const char *pSelectionGroupName ) +{ + CDmElement *pSelectionGroup = FindSelectionGroup( pSelectionGroupName ); + if ( !pSelectionGroup ) + { + // Create the default groups in order + pSelectionGroup = CreateElement< CDmElement >( pSelectionGroupName, GetFileId() ); + pSelectionGroup->AddAttribute( "selectedControls", AT_STRING_ARRAY ); + m_SelectionGroups.AddToTail( pSelectionGroup ); + } + return pSelectionGroup; +} + +void CDmeAnimationSet::CollectOperators( CUtlVector< DmElementHandle_t > &operators ) +{ + int numOperators = m_Operators.Count(); + for ( int i = 0; i < numOperators; ++i ) + { + DmElementHandle_t h = m_Operators.GetHandle( i ); + if ( h != DMELEMENT_HANDLE_INVALID ) + { + operators.AddToTail( h ); + } + } +} + +struct PPType_t +{ + int type; + char const *name; +}; + +static PPType_t g_PresetNames[ NUM_PROCEDURAL_PRESET_TYPES ] = +{ + { PROCEDURAL_PRESET_NOT, "NotProcedural!!!" }, + { PROCEDURAL_PRESET_IN_CROSSFADE, "In" }, + { PROCEDURAL_PRESET_OUT_CROSSFADE, "Out" }, + { PROCEDURAL_PRESET_REVEAL, "Reveal" }, + { PROCEDURAL_PRESET_PASTE, "Paste" }, + { PROCEDURAL_PRESET_JITTER, "Jitter" }, + { PROCEDURAL_PRESET_SMOOTH, "Smooth" }, + { PROCEDURAL_PRESET_SHARPEN, "Sharpen" }, + { PROCEDURAL_PRESET_SOFTEN, "Soften" }, + { PROCEDURAL_PRESET_STAGGER, "Stagger" }, +}; + +void CDmeAnimationSet::EnsureProceduralPresets() +{ + // Note: Starts at index 1 to skip the PROCEDURAL_PRESET_NOT case + for ( int i = 1; i < NUM_PROCEDURAL_PRESET_TYPES; ++i ) + { + FindOrAddPreset( "Procedural", g_PresetNames[ i ].name, g_PresetNames[ i ].type ); + } +} + +//----------------------------------------------------------------------------- +// A cache of preset groups to be associated with specific models +//----------------------------------------------------------------------------- +class CModelPresetGroupManager : public IModelPresetGroupManager +{ +public: + CModelPresetGroupManager(); + virtual void AssociatePresetsWithFile( DmFileId_t fileId ); + virtual void ApplyModelPresets( const char *pModelName, CDmeAnimationSet *pAnimationSet ); + +private: + struct QueuedPresetRequest_t + { + CUtlString m_ModelName; + CDmeHandle< CDmeAnimationSet > m_hAnimationSet; + }; + + typedef CUtlVector< CDmeHandle< CDmePresetGroup, true > > PresetGroupList_t; + + // Loads model presets from .pre files matching the model name + void LoadModelPresets( const char *pModelName, PresetGroupList_t &list ); + + CUtlStringMap< PresetGroupList_t > m_Lookup; + DmFileId_t m_FileId; + CUtlVector< QueuedPresetRequest_t > m_QueuedPresetRequest; +}; + + +//----------------------------------------------------------------------------- +// Singleton +//----------------------------------------------------------------------------- +static CModelPresetGroupManager s_ModelPresetGroupManager; +IModelPresetGroupManager *g_pModelPresetGroupMgr = &s_ModelPresetGroupManager; + + +//----------------------------------------------------------------------------- +// Constructor +//----------------------------------------------------------------------------- +CModelPresetGroupManager::CModelPresetGroupManager() +{ + m_FileId = DMFILEID_INVALID; +} + + +//----------------------------------------------------------------------------- +// Associates presets in the cache with a particular file +//----------------------------------------------------------------------------- +void CModelPresetGroupManager::AssociatePresetsWithFile( DmFileId_t fileId ) +{ + m_FileId = fileId; + m_Lookup.Clear(); + if ( m_FileId != DMFILEID_INVALID ) + { + int nCount = m_QueuedPresetRequest.Count(); + for ( int i = 0; i < nCount; ++i ) + { + QueuedPresetRequest_t &request = m_QueuedPresetRequest[i]; + if ( request.m_hAnimationSet.Get() ) + { + ApplyModelPresets( request.m_ModelName, request.m_hAnimationSet.Get() ); + } + } + m_QueuedPresetRequest.Purge(); + } +} + + +//----------------------------------------------------------------------------- +// Loads model presets from .pre files matching the model name +//----------------------------------------------------------------------------- +void CModelPresetGroupManager::LoadModelPresets( const char *pModelName, PresetGroupList_t &list ) +{ + list.RemoveAll(); + + char pPresetPath[MAX_PATH]; + Q_ExtractFilePath( pModelName, pPresetPath, sizeof(pPresetPath) ); + + char pPresetNameBuf[MAX_PATH]; + Q_StripExtension( pModelName, pPresetNameBuf, sizeof(pPresetNameBuf) ); + int nLen = Q_strlen( pPresetNameBuf ); + Q_snprintf( &pPresetNameBuf[nLen], MAX_PATH - nLen, "*.pre" ); + + CDisableUndoScopeGuard sg; + + FileFindHandle_t fh; + const char *pFileName = g_pFullFileSystem->FindFirstEx( pPresetNameBuf, "GAME", &fh ); + for ( ; pFileName; pFileName = g_pFullFileSystem->FindNext( fh ) ) + { + char pRelativePresetPath[MAX_PATH]; + Q_ComposeFileName(pPresetPath, pFileName, pRelativePresetPath, sizeof(pRelativePresetPath) ); + + CDmElement* pRoot = NULL; + DmFileId_t fileid = g_pDataModel->RestoreFromFile( pRelativePresetPath, "GAME", NULL, &pRoot, CR_FORCE_COPY ); + if ( fileid == DMFILEID_INVALID || !pRoot ) + continue; + + CDmePresetGroup *pPresetGroup = CastElement<CDmePresetGroup>( pRoot ); + if ( !pPresetGroup ) + { + if ( pRoot ) + { + g_pDataModel->RemoveFileId( pRoot->GetFileId() ); + } + continue; + } + + pPresetGroup->SetFileId( m_FileId, TD_DEEP ); + + // Presets used through the model preset manager must be read only + shared + pPresetGroup->m_bIsReadOnly = true; + pPresetGroup->SetShared( true ); + + int i = list.AddToTail(); + list[i] = pPresetGroup; + } + g_pFullFileSystem->FindClose( fh ); +} + + +//----------------------------------------------------------------------------- +// Applies model presets associated with a particular model to an animation set +//----------------------------------------------------------------------------- +void CModelPresetGroupManager::ApplyModelPresets( const char *pModelName, CDmeAnimationSet *pAnimationSet ) +{ + if ( m_FileId == DMFILEID_INVALID ) + { + int i = m_QueuedPresetRequest.AddToTail(); + m_QueuedPresetRequest[i].m_ModelName = pModelName; + m_QueuedPresetRequest[i].m_hAnimationSet = pAnimationSet; + return; + } + + if ( !m_Lookup.Defined( pModelName ) ) + { + LoadModelPresets( pModelName, m_Lookup[pModelName] ); + } + + PresetGroupList_t &list = m_Lookup[pModelName]; + int nCount = list.Count(); + for ( int i = 0; i < nCount; ++i ) + { + CDmePresetGroup *pPresetGroup = list[i]; + int nIndex = pAnimationSet->FindPresetGroupIndex( pPresetGroup->GetName() ); + if ( nIndex >= 0 ) + { + pAnimationSet->GetPresetGroups().Set( nIndex, pPresetGroup ); + } + else + { + pAnimationSet->GetPresetGroups().AddToTail( pPresetGroup ); + } + } +} |