//====== Copyright © 1996-2006, Valve Corporation, All rights reserved. ======= // // Purpose: // //============================================================================= #include "dmserializers.h" #include "dmebaseimporter.h" #include "datamodel/idatamodel.h" #include "datamodel/dmattribute.h" #include "datamodel/dmelement.h" #include "datamodel/dmattributevar.h" #include //----------------------------------------------------------------------------- // Format converter //----------------------------------------------------------------------------- class CImportSFMV1 : public CSFMBaseImporter { typedef CSFMBaseImporter BaseClass; public: CImportSFMV1( char const *formatName, char const *nextFormatName ); private: virtual bool DoFixup( CDmElement *pSourceRoot ); // Fixes up a single time attribute - converting from float seconds to int tenths-of-a-millisecond void ConvertTimeAttribute( CDmElement *pElementInternal, const char *pOldName, const char *pNewName ); // Fixes up a single timeframe void FixupTimeframe( CDmElement *pElementInternal ); // Fixes up a single log - converting from int milliseconds to int tenths-of-a-millisecond void FixupLog( CDmElement *pElementInternal ); CUtlRBTree< CDmElement*, int > m_fixedElements; }; //----------------------------------------------------------------------------- // Singleton instance //----------------------------------------------------------------------------- static CImportSFMV1 s_ImportDmxV1( "sfm_v1", "sfm_v2" ); void InstallSFMV1Importer( IDataModel *pFactory ) { pFactory->AddLegacyUpdater( &s_ImportDmxV1 ); } //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- CImportSFMV1::CImportSFMV1( char const *formatName, char const *nextFormatName ) : BaseClass( formatName, nextFormatName ) { m_fixedElements.SetLessFunc( DefLessFunc( CDmElement * ) ); } //----------------------------------------------------------------------------- // Fixes up all elements //----------------------------------------------------------------------------- bool CImportSFMV1::DoFixup( CDmElement *pElementInternal ) { if ( !pElementInternal ) return true; if ( m_fixedElements.Find( pElementInternal ) != m_fixedElements.InvalidIndex() ) return true; m_fixedElements.Insert( pElementInternal ); const char *pType = pElementInternal->GetTypeString(); if ( !Q_strcmp( pType, "DmeTimeFrame" ) ) { FixupTimeframe( pElementInternal ); } else if ( !Q_strcmp( pType, "DmeLog" ) || !Q_strcmp( pType, "DmeIntLog" ) || !Q_strcmp( pType, "DmeFloatLog" ) || !Q_strcmp( pType, "DmeBoolLog" ) || !Q_strcmp( pType, "DmeColorLog" ) || !Q_strcmp( pType, "DmeVector2Log" ) || !Q_strcmp( pType, "DmeVector3Log" ) || !Q_strcmp( pType, "DmeVector4Log" ) || !Q_strcmp( pType, "DmeQAngleLog" ) || !Q_strcmp( pType, "DmeQuaternionLog" ) || !Q_strcmp( pType, "DmeVMatrixLog" ) ) { FixupLog( pElementInternal ); } for ( CDmAttribute *pAttribute = pElementInternal->FirstAttribute(); pAttribute; pAttribute = pAttribute->NextAttribute() ) { if ( pAttribute->GetType() == AT_ELEMENT ) { CDmElement *pElement = pAttribute->GetValueElement( ); DoFixup( pElement ); continue; } if ( pAttribute->GetType() == AT_ELEMENT_ARRAY ) { CDmrElementArray<> array( pAttribute ); int nCount = array.Count(); for ( int i = 0; i < nCount; ++i ) { CDmElement *pChild = array[ i ]; DoFixup( pChild ); } continue; } } return true; } //----------------------------------------------------------------------------- // Fixes up a single time attribute - converting from float seconds to int tenths-of-a-millisecond //----------------------------------------------------------------------------- void CImportSFMV1::ConvertTimeAttribute( CDmElement *pElementInternal, const char *pOldName, const char *pNewName ) { float time = 0.0f; CDmAttribute *pOldAttr = pElementInternal->GetAttribute( pOldName ); if ( !pOldAttr ) { Warning( "*** Problem in file encountered!\n" ); Warning( "*** TimeFrame \"%s\" is missing attribute \"%s\"!\n", pElementInternal->GetName(), pOldName ); Warning( "*** Setting new attribute \"%s\" to 0\n", pNewName ); } else if ( pOldAttr->GetType() != AT_FLOAT ) { Warning( "*** Problem in file encountered!\n" ); Warning( "*** TimeFrame \"%s\" has attribute \"%s\" with an unexpected type (expected float)!\n", pElementInternal->GetName(), pOldName ); } else { time = pOldAttr->GetValue< float >(); pElementInternal->RemoveAttribute( pOldName ); } CDmAttribute *pNewAttr = NULL; // this is disabled because even dmxconvert installs *some* movieobjects factories, when it probably shouldn't // the method of installing movieobjects factories will change at some point in the future, and we can turn on this safety check then #if 0 int i = g_pDataModel->GetFirstFactory(); if ( g_pDataModel->IsValidFactory( i ) ) { // factories installed - most likely from within movieobjects.lib // ie there may be different ways of allocating attributes, so it's not safe to add them here pNewAttr = pElementInternal->GetAttribute( pNewName ); if ( !pNewAttr || pNewAttr->GetType() != AT_INT ) { Assert( 0 ); Warning( "*** Converter error - expected element \"%s\" to contain int attribute \"%s\"!\n", pElementInternal->GetName(), pNewName ); Warning( "*** - if you get this error, the converter is out of sync with the element library!\n" ); return; } } else { #endif // no factories installed - most likely from within dmxconvert.exe // ie we're just working with CDmElement subclasses, so it's safe to add attributes pNewAttr = pElementInternal->AddAttribute( pNewName, AT_INT ); if ( !pNewAttr ) { Assert( 0 ); Warning( "*** Converter error - element \"%s\" already has a non-int attribute \"%s\"!\n", pElementInternal->GetName(), pNewName ); return; } #if 0 } #endif pNewAttr->SetValue< int >( floor( time * 10000 + 0.5f ) ); } //----------------------------------------------------------------------------- // Fixes up a single timeframe //----------------------------------------------------------------------------- void CImportSFMV1::FixupTimeframe( CDmElement *pElementInternal ) { ConvertTimeAttribute( pElementInternal, "start", "startTime" ); ConvertTimeAttribute( pElementInternal, "duration", "durationTime" ); ConvertTimeAttribute( pElementInternal, "offset", "offsetTime" ); } //----------------------------------------------------------------------------- // Fixes up a single log - converting from int milliseconds to int tenths-of-a-millisecond //----------------------------------------------------------------------------- void CImportSFMV1::FixupLog( CDmElement *pElementInternal ) { CDmAttribute *pAttr = pElementInternal->GetAttribute( "times" ); if ( !pAttr ) { Warning( "*** Problem in file encountered!\n" ); Warning( "*** Log \"%s\" is missing attribute \"%s\"!\n", pElementInternal->GetName(), "times" ); return; } if ( pAttr->GetType() != AT_INT_ARRAY ) { Warning( "*** Problem in file encountered!\n" ); Warning( "*** Log \"%s\" has attribute \"%s\" with an unexpected type (expected int array)!\n", pElementInternal->GetName(), "times" ); return; } CDmrArray array( pAttr ); int c = array.Count(); for ( int i = 0; i < c; ++i ) { // convert all log times from int milliseconds to int tenths-of-a-millisecond array.Set( i, 10 * array[i] ); } }