// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #include "stdafx.h" #ifdef DONTBUILDTHIS //#include <maxscrpt/maxobj.h> //#include <maxscrpt/value.h> #include <frantic/max3d/animation/serialize.hpp> #pragma warning( push ) #pragma warning( disable : 4512 ) #pragma warning( disable : 4100 ) #include <boost/archive/xml_iarchive.hpp> #include <boost/archive/xml_oarchive.hpp> #include <boost/serialization/map.hpp> #include <boost/serialization/nvp.hpp> #include <boost/serialization/string.hpp> #include <boost/serialization/vector.hpp> #pragma warning( pop ) namespace { TCHAR* toTCHAR( const frantic::tstring& str ) { const TCHAR* nameStr = str.c_str(); size_t len = wcslen( nameStr ) + 1; TCHAR* buffer = (TCHAR*)malloc( len ); memcpy( buffer, nameStr, len ); return buffer; } void insert_point3( Point3 point, std::map<std::string, float>& data, const std::string& name ) { data.insert( std::pair<std::string, float>( name + "_X", point.x ) ); data.insert( std::pair<std::string, float>( name + "_Y", point.y ) ); data.insert( std::pair<std::string, float>( name + "_Z", point.z ) ); } void insert_point4( Point4 point, std::map<std::string, float>& data, const std::string& name ) { data.insert( std::pair<std::string, float>( name + "_X", point.x ) ); data.insert( std::pair<std::string, float>( name + "_Y", point.y ) ); data.insert( std::pair<std::string, float>( name + "_Z", point.z ) ); data.insert( std::pair<std::string, float>( name + "_W", point.w ) ); } void insert_quat( Quat quat, std::map<std::string, float>& data, const std::string& name ) { data.insert( std::pair<std::string, float>( name + "_W", quat.w ) ); data.insert( std::pair<std::string, float>( name + "_X", quat.x ) ); data.insert( std::pair<std::string, float>( name + "_Y", quat.y ) ); data.insert( std::pair<std::string, float>( name + "_Z", quat.z ) ); } Point3 get_point3( std::map<std::string, float>& data, const std::string& name ) { float x = data.find( name + "_X" )->second; float y = data.find( name + "_Y" )->second; float z = data.find( name + "_Z" )->second; return Point3( x, y, z ); } Point4 get_point4( std::map<std::string, float>& data, const std::string& name ) { float x = data.find( name + "_X" )->second; float y = data.find( name + "_Y" )->second; float z = data.find( name + "_Z" )->second; float w = data.find( name + "_W" )->second; return Point4( x, y, z, w ); } Quat get_quat( std::map<std::string, float>& data, const std::string& name ) { float w = data.find( name + "_W" )->second; float x = data.find( name + "_X" )->second; float y = data.find( name + "_Y" )->second; float z = data.find( name + "_Z" )->second; return Quat( x, y, z, w ); } enum key_type { BEZ_FLOAT = 0, BEZ_POINT3, BEZ_SCALE, BEZ_POINT4, BEZ_QUAT, LIN_FLOAT, LIN_POINT3, LIN_ROT, LIN_SCALE, TCB_FLOAT, TCB_POINT3, TCB_ROT, TCB_SCALE, TCB_POINT4, UNKNOWN }; class key_serializer { int m_time; unsigned long m_flags; std::map<std::string, float> m_data; key_type m_type; private: void handle_bez_float( IBezFloatKey* key ) { m_data.insert( std::pair<std::string, float>( "Value", key->val ) ); m_data.insert( std::pair<std::string, float>( "InTan", key->intan ) ); m_data.insert( std::pair<std::string, float>( "OutTan", key->outtan ) ); m_data.insert( std::pair<std::string, float>( "InLength", key->inLength ) ); m_data.insert( std::pair<std::string, float>( "OutLength", key->outLength ) ); } void handle_bez_point3( IBezPoint3Key* key ) { insert_point3( key->val, m_data, "Value" ); insert_point3( key->intan, m_data, "InTan" ); insert_point3( key->outtan, m_data, "OutTan" ); insert_point3( key->inLength, m_data, "InLength" ); insert_point3( key->outLength, m_data, "OutLength" ); } void handle_bez_scale( IBezScaleKey* key ) { insert_point3( key->val.s, m_data, "Point" ); insert_quat( key->val.q, m_data, "Quat" ); insert_point3( key->intan, m_data, "InTan" ); insert_point3( key->outtan, m_data, "OutTan" ); insert_point3( key->inLength, m_data, "InLength" ); insert_point3( key->outLength, m_data, "OutLength" ); } void handle_bez_point4( IBezPoint4Key* key ) { insert_point4( key->val, m_data, "Value" ); insert_point4( key->intan, m_data, "InTan" ); insert_point4( key->outtan, m_data, "OutTan" ); insert_point4( key->inLength, m_data, "InLength" ); insert_point4( key->outLength, m_data, "OutLength" ); } void handle_bez_quat( IBezQuatKey* key ) { insert_quat( key->val, m_data, "Value" ); } void handle_lin_float( ILinFloatKey* key ) { m_data.insert( std::pair<std::string, float>( "Value", key->val ) ); } void handle_lin_point3( ILinPoint3Key* key ) { insert_point3( key->val, m_data, "Value" ); } void handle_lin_rot( ILinRotKey* key ) { insert_quat( key->val, m_data, "Value" ); } void handle_lin_scale( ILinScaleKey* key ) { insert_point3( key->val.s, m_data, "Point" ); insert_quat( key->val.q, m_data, "Quat" ); } void handle_tcb_base( ITCBKey* key ) { m_data.insert( std::pair<std::string, float>( "Tension", key->tens ) ); m_data.insert( std::pair<std::string, float>( "Cont", key->cont ) ); m_data.insert( std::pair<std::string, float>( "Bias", key->bias ) ); m_data.insert( std::pair<std::string, float>( "EaseIn", key->easeIn ) ); m_data.insert( std::pair<std::string, float>( "EaseOut", key->easeOut ) ); } void handle_tcb_float( ITCBFloatKey* key ) { handle_tcb_base( key ); m_data.insert( std::pair<std::string, float>( "Value", key->val ) ); } void handle_tcb_point3( ITCBPoint3Key* key ) { handle_tcb_base( key ); insert_point3( key->val, m_data, "Value" ); } void handle_tcb_rot( ITCBRotKey* key ) { handle_tcb_base( key ); insert_point3( key->val.axis, m_data, "Axis" ); m_data.insert( std::pair<std::string, float>( "Angle", key->val.angle ) ); } void handle_tcb_scale( ITCBScaleKey* key ) { handle_tcb_base( key ); insert_point3( key->val.s, m_data, "Point" ); insert_quat( key->val.q, m_data, "Quat" ); } void handle_tcb_point4( ITCBPoint4Key* key ) { handle_tcb_base( key ); insert_point4( key->val, m_data, "Value" ); } IBezFloatKey* get_bez_float() { IBezFloatKey* key = new IBezFloatKey(); key->val = m_data.find( "Value" )->second; key->intan = m_data.find( "InTan" )->second; key->outtan = m_data.find( "OutTan" )->second; key->inLength = m_data.find( "InLength" )->second; key->outLength = m_data.find( "OutLength" )->second; return key; } IBezPoint3Key* get_bez_point3() { IBezPoint3Key* key = new IBezPoint3Key(); key->val = get_point3( m_data, "Value" ); key->intan = get_point3( m_data, "InTan" ); key->outtan = get_point3( m_data, "OutTan" ); key->inLength = get_point3( m_data, "InLength" ); key->outLength = get_point3( m_data, "OutLength" ); return key; } IBezPoint4Key* get_bez_point4() { IBezPoint4Key* key = new IBezPoint4Key(); key->val = get_point4( m_data, "Value" ); key->intan = get_point4( m_data, "InTan" ); key->outtan = get_point4( m_data, "OutTan" ); key->inLength = get_point4( m_data, "InLength" ); key->outLength = get_point4( m_data, "OutLength" ); return key; } IBezScaleKey* get_bez_scale() { IBezScaleKey* key = new IBezScaleKey(); key->val.s = get_point3( m_data, "Point" ); key->val.q = get_quat( m_data, "Quat" ); key->intan = get_point3( m_data, "InTan" ); key->outtan = get_point3( m_data, "OutTan" ); key->inLength = get_point3( m_data, "InLength" ); key->outLength = get_point3( m_data, "OutLength" ); return key; } IBezQuatKey* get_bez_quat() { IBezQuatKey* key = new IBezQuatKey(); key->val = get_quat( m_data, "Value" ); return key; } ILinFloatKey* get_lin_float() { ILinFloatKey* key = new ILinFloatKey(); key->val = m_data.find( "Value" )->second; return key; } ILinPoint3Key* get_lin_point3() { ILinPoint3Key* key = new ILinPoint3Key(); key->val = get_point3( m_data, "Value" ); return key; } ILinRotKey* get_lin_rot() { ILinRotKey* key = new ILinRotKey(); key->val = get_quat( m_data, "Value" ); return key; } ILinScaleKey* get_lin_scale() { ILinScaleKey* key = new ILinScaleKey(); key->val.s = get_point3( m_data, "Point" ); key->val.q = get_quat( m_data, "Quat" ); return key; } void get_tcb_base( ITCBKey* key ) { key->tens = m_data.find( "Tension" )->second; key->cont = m_data.find( "Cont" )->second; key->bias = m_data.find( "Bias" )->second; key->easeIn = m_data.find( "EaseIn" )->second; key->easeOut = m_data.find( "EaseOut" )->second; } ITCBFloatKey* get_tcb_float() { ITCBFloatKey* key = new ITCBFloatKey(); get_tcb_base( key ); key->val = m_data.find( "Value" )->second; return key; } ITCBPoint3Key* get_tcb_point3() { ITCBPoint3Key* key = new ITCBPoint3Key(); get_tcb_base( key ); key->val = get_point3( m_data, "Value" ); return key; } ITCBRotKey* get_tcb_rot() { ITCBRotKey* key = new ITCBRotKey(); get_tcb_base( key ); key->val.axis = get_point3( m_data, "Axis" ); key->val.angle = m_data.find( "Angle" )->second; return key; } ITCBScaleKey* get_tcb_scale() { ITCBScaleKey* key = new ITCBScaleKey(); get_tcb_base( key ); key->val.s = get_point3( m_data, "Point" ); key->val.q = get_quat( m_data, "Quat" ); return key; } ITCBPoint4Key* get_tcb_point4() { ITCBPoint4Key* key = new ITCBPoint4Key(); get_tcb_base( key ); key->val = get_point4( m_data, "Value" ); return key; } public: key_serializer() : m_type( UNKNOWN ) {} key_serializer( IKey* key, unsigned long controller_class_id ) { m_time = key->time; m_flags = key->flags; switch( controller_class_id ) { case HYBRIDINTERP_FLOAT_CLASS_ID: handle_bez_float( (IBezFloatKey*)key ); m_type = BEZ_FLOAT; break; case HYBRIDINTERP_POINT3_CLASS_ID: case HYBRIDINTERP_POSITION_CLASS_ID: case HYBRIDINTERP_COLOR_CLASS_ID: handle_bez_point3( (IBezPoint3Key*)key ); m_type = BEZ_POINT3; break; case HYBRIDINTERP_ROTATION_CLASS_ID: handle_bez_quat( (IBezQuatKey*)key ); m_type = BEZ_QUAT; break; case HYBRIDINTERP_SCALE_CLASS_ID: handle_bez_scale( (IBezScaleKey*)key ); m_type = BEZ_SCALE; break; case HYBRIDINTERP_POINT4_CLASS_ID: case HYBRIDINTERP_FRGBA_CLASS_ID: handle_bez_point4( (IBezPoint4Key*)key ); m_type = BEZ_POINT4; break; case LININTERP_FLOAT_CLASS_ID: handle_lin_float( (ILinFloatKey*)key ); m_type = LIN_FLOAT; break; case LININTERP_POSITION_CLASS_ID: handle_lin_point3( (ILinPoint3Key*)key ); m_type = LIN_POINT3; break; case LININTERP_ROTATION_CLASS_ID: handle_lin_rot( (ILinRotKey*)key ); m_type = LIN_ROT; break; case LININTERP_SCALE_CLASS_ID: handle_lin_scale( (ILinScaleKey*)key ); m_type = LIN_SCALE; break; case TCBINTERP_FLOAT_CLASS_ID: handle_tcb_float( (ITCBFloatKey*)key ); m_type = TCB_FLOAT; break; case TCBINTERP_POINT3_CLASS_ID: case TCBINTERP_POSITION_CLASS_ID: handle_tcb_point3( (ITCBPoint3Key*)key ); m_type = TCB_POINT3; break; case TCBINTERP_ROTATION_CLASS_ID: handle_tcb_rot( (ITCBRotKey*)key ); m_type = TCB_ROT; break; case TCBINTERP_SCALE_CLASS_ID: handle_tcb_scale( (ITCBScaleKey*)key ); m_type = TCB_SCALE; break; case TCBINTERP_POINT4_CLASS_ID: handle_tcb_point4( (ITCBPoint4Key*)key ); m_type = TCB_POINT4; break; default: mprintf( _T( "Key Serializer Error : Unkown key type\n Parent Controller Class ID : %x\n" ), controller_class_id ); m_type = UNKNOWN; } } IKey* get_key() { IKey* key = 0; switch( m_type ) { case BEZ_FLOAT: key = get_bez_float(); break; case BEZ_POINT3: key = get_bez_point3(); break; case BEZ_QUAT: key = get_bez_quat(); break; case BEZ_SCALE: key = get_bez_scale(); break; case BEZ_POINT4: key = get_bez_point4(); break; case LIN_FLOAT: key = get_lin_float(); break; case LIN_POINT3: key = get_lin_point3(); break; case LIN_ROT: key = get_lin_rot(); break; case LIN_SCALE: key = get_lin_scale(); break; case TCB_FLOAT: key = get_tcb_float(); break; case TCB_POINT3: key = get_tcb_point3(); break; case TCB_ROT: key = get_tcb_rot(); break; case TCB_SCALE: key = get_tcb_scale(); break; case TCB_POINT4: key = get_tcb_point4(); break; default: mprintf( _T("Key Deserializer Error : Unkown key type\n" ) ); } if( key != 0 ) { key->time = m_time; key->flags = m_flags; } return key; } friend class boost::serialization::access; template <class archive> void serialize( archive& ar, const unsigned int /*version*/ ) { using boost::serialization::make_nvp; ar& make_nvp( "Type", m_type ); ar& make_nvp( "Time", m_time ); ar& make_nvp( "Flags", m_flags ); ar& make_nvp( "Data", m_data ); } }; class controller_serializer { std::vector<key_serializer> m_keyValues; std::vector<controller_serializer> m_subControllers; std::vector<controller_serializer> m_easeCurves; std::vector<controller_serializer> m_multCurves; unsigned long m_classIDA; unsigned long m_classIDB; unsigned long m_superClassID; public: controller_serializer() {} // As of know this only handles keyable interfaces //(If a keyable interface fails it class ID needs to be added in the key_serializer serialize / get_key functions) // Other controllers/ such as noise/ may not use keys // A special case will need to be created for each of these nodes if needed controller_serializer( Control* controller ) { m_classIDA = controller->ClassID().PartA(); m_classIDB = controller->ClassID().PartB(); m_superClassID = controller->SuperClassID(); // handle basic keyable controllers if( controller->IsKeyable() ) { IKeyControl* keyInterface = GetKeyControlInterface( controller ); if( keyInterface ) { // we need to create the key pointer like this since it can be different sizes AnyKey ak( keyInterface->GetKeySize() ); IKey* key = ak; for( int i = 0; i < keyInterface->GetNumKeys(); ++i ) { keyInterface->GetKey( i, key ); m_keyValues.push_back( key_serializer( key, m_classIDA ) ); } } } else { // put special cases here mprintf( _T( "Warning: Unhandled Unkeyable Controller. Class ID: %x_%x.\n" ), m_classIDA, m_classIDB ); } // if its a leaf check if there are any ease or mult curves if( controller->IsLeaf() ) { // it seems like there should be a better way to get at the mult/ease curves but I can't find it // using the GetEaseListInterface and GetMultListInterface macros just return null int numSubs = ( controller->NumEaseCurves() != 0 ) + ( controller->NumMultCurves() != 0 ); for( int i = 0; i < numSubs; ++i ) { Animatable* sub = controller->SubAnim( i ); if( sub->ClassID().PartA() == EASE_LIST_CLASS_ID ) { EaseCurveList* el = (EaseCurveList*)controller->SubAnim( i ); for( int j = 0; j < el->NumSubs(); ++j ) m_easeCurves.push_back( controller_serializer( (Control*)el->SubAnim( j ) ) ); } if( sub->ClassID().PartA() == MULT_LIST_CLASS_ID ) { MultCurveList* ml = (MultCurveList*)controller->SubAnim( i ); for( int j = 0; j < ml->NumSubs(); ++j ) m_multCurves.push_back( controller_serializer( (Control*)ml->SubAnim( j ) ) ); } } } // get the sub controllers else { for( int i = 0; i < controller->NumSubs(); ++i ) { Animatable* sub = controller->SubAnim( i ); if( sub ) { // some controllers may use parameter blocks // this currently is not handled if( sub->ClassID().PartA() != PARAMETER_BLOCK2_CLASS_ID ) m_subControllers.push_back( controller_serializer( (Control*)controller->SubAnim( i ) ) ); else mprintf( _T( "Warning: Cannot Serialize Parameter Block.\n" ) ); } } } } friend class boost::serialization::access; template <class archive> void serialize( archive& ar, const unsigned int /*version*/ ) { using boost::serialization::make_nvp; ar& make_nvp( "KeyValues", m_keyValues ); ar& make_nvp( "ClassIDA", m_classIDA ); ar& make_nvp( "ClassIDB", m_classIDB ); ar& make_nvp( "SuperClassID", m_superClassID ); ar& make_nvp( "SubControllers", m_subControllers ); ar& make_nvp( "EaseCurves", m_easeCurves ); ar& make_nvp( "MultCurves", m_multCurves ); } Control* get_controller() { Control* controller = 0; controller = (Control*)CreateInstance( m_superClassID, Class_ID( m_classIDA, m_classIDB ) ); if( controller ) { IKeyControl* keyInterface = GetKeyControlInterface( controller ); if( keyInterface ) { for( size_t i = 0; i < m_keyValues.size(); ++i ) { IKey* key = m_keyValues[i].get_key(); if( key ) keyInterface->AppendKey( key ); } } // go backwards to maintain order for( size_t i = m_easeCurves.size(); i > 0; --i ) { Control* c = m_easeCurves[i - 1].get_controller(); if( c ) controller->AppendEaseCurve( c ); } for( size_t i = m_multCurves.size(); i > 0; --i ) { Control* c = m_multCurves[i - 1].get_controller(); if( c ) controller->AppendMultCurve( c ); } for( size_t i = 0; i < m_subControllers.size(); ++i ) { Control* c = m_subControllers[i].get_controller(); if( c ) controller->AssignController( c, (int)i ); else // if we can not create a sub controller it can cause the parent to be invalid and max to crash return 0; } } else mprintf( _T( "Serialize Controller Error : Could not create controller with class id %x_%x and super class id %x\n" ), m_classIDA, m_classIDB, m_superClassID ); return controller; } }; class tvnode_serializer { std::vector<tvnode_serializer> m_subnodes; std::vector<controller_serializer> m_controllers; std::vector<frantic::tstring> m_controllerNames; std::vector<frantic::tstring> m_subnodeNames; public: tvnode_serializer() {} tvnode_serializer( ITrackViewNode* node ) { for( int i = 0; i < node->NumSubs(); ++i ) { Animatable* sub = node->SubAnim( i ); if( sub->ClassID() == TVNODE_CLASS_ID ) { tvnode_serializer tvns( (ITrackViewNode*)sub ); m_subnodes.push_back( tvns ); m_subnodeNames.push_back( node->GetName( i ) ); } else { Control* controller = (Control*)sub; controller_serializer cs( controller ); m_controllers.push_back( cs ); m_controllerNames.push_back( node->GetName( i ) ); } } } friend class boost::serialization::access; template <class archive> void serialize( archive& ar, const unsigned int /*version*/ ) { using boost::serialization::make_nvp; ar& make_nvp( "SubNodes", m_subnodes ); ar& make_nvp( "Controllers", m_controllers ); ar& make_nvp( "SubnodeNames", m_subnodeNames ); ar& make_nvp( "ControllerNames", m_controllerNames ); } void create_tvnode( ITrackViewNode* parent ) { for( size_t i = 0; i < m_subnodes.size(); ++i ) { TCHAR* nameStr = toTCHAR( m_subnodeNames[i] ); ITrackViewNode* newNode = CreateITrackViewNode(); parent->AddNode( newNode, nameStr, Class_ID( 0, 0 ) ); m_subnodes[i].create_tvnode( newNode ); } for( size_t i = 0; i < m_controllers.size(); ++i ) { Control* newCtrl = m_controllers[i].get_controller(); if( newCtrl ) { TCHAR* nameStr = toTCHAR( m_controllerNames[i] ); parent->AddController( newCtrl, nameStr, Class_ID( 0, 0 ) ); } } } }; } // end anonymous namespace serialization_interface::serialization_interface() { FFCreateDescriptor c( this, Interface_ID( 0x534847f5, 0xa5c298d ), _T( "FranticSerializer" ), 0 ); c.add_function( &serialization_interface::test, _T( "Test" ), _T( "Node" ) ); c.add_function( &serialization_interface::serialize_tvnode, _T( "Serialize_TVNode" ), _T( "TrackViewNode" ) ); c.add_function( &serialization_interface::deserialize_tvnode, _T( "Deserialize_TVNode" ), _T( "SerializedValueString" ), _T( "Parent" ) ); c.add_function( &serialization_interface::serialize_controller, _T( "Serialize_Controller" ), _T( "Controller" ) ); c.add_function( &serialization_interface::deserialize_controller, _T( "Deserialize_Controller" ), _T( "SerializedValueString" ) ); } std::string serialization_interface::serialize_tvnode( Value* tvnode ) { try { std::stringstream ss; tvnode_serializer tvns( tvnode->to_trackviewnode() ); boost::archive::xml_oarchive xml( ss ); xml << boost::serialization::make_nvp( "TVNode", tvns ); return ss.str(); } catch( const std::exception& e ) { mprintf( _T( "TVNode Serialization Error : %s\n" ), e.what() ); } return ""; } void serialization_interface::deserialize_tvnode( const std::string& serializedValueString, Value* parent ) { try { std::stringstream ss( serializedValueString ); tvnode_serializer tvns; boost::archive::xml_iarchive xml( ss ); xml >> boost::serialization::make_nvp( "TVNode", tvns ); tvns.create_tvnode( parent->to_trackviewnode() ); } catch( const std::exception& e ) { mprintf( _T( "TVNode Deserialization Error : %s\n" ), e.what() ); } } std::string serialization_interface::serialize_controller( Control* controller ) { std::stringstream ss; controller_serializer cs( controller ); boost::archive::xml_oarchive xml( ss ); xml << boost::serialization::make_nvp( "Controller", cs ); return ss.str(); } Control* serialization_interface::deserialize_controller( const std::string& serializedValueString ) { std::stringstream buffer( serializedValueString ); controller_serializer cs; boost::archive::xml_iarchive xml( buffer ); xml >> boost::serialization::make_nvp( "Controller", cs ); return cs.get_controller(); } std::string serialization_interface::test( Value* node ) { ITrackViewNode* tvnode = node->to_trackviewnode(); return frantic::strings::to_string( tvnode->GetName( 0 ) ); } void serialization_interface::initialize() {} static serialization_interface theSerializationInterface; void initialize_serialization_interface() { theSerializationInterface.initialize(); } #endif