//========= 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( 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( "combo" ); control.m_bIsMulti = pControl->GetValue( "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 = ""; } 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( "defaultValue" ) ); } else { float flValue, flBalance, flLeft, flRight; flValue = pControl->GetValue( "defaultValue", 0.0f ); flBalance = pControl->GetValue( "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( "defaultMultilevel" ) ); } continue; } if ( !control.m_bIsStereo ) { buf.Printf( "%.5f\t1.000\t", pControlValue->GetValue( "value" ) ); } else { float flValue, flBalance, flLeft, flRight; flValue = pControlValue->GetValue( "value" ); flBalance = pControlValue->GetValue( "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( "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( "value" ); pFlexWeights->influence = 1.0f; pFlexWeights++; } else { float flValue, flBalance, flLeft, flRight; flValue = pControlValue->GetValue( "value" ); flBalance = pControlValue->GetValue( "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( "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 = ""; } 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( 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 ); } } }