@ -23,6 +23,7 @@
# include <MCore/Source/AttributeFactory.h>
# include <MCore/Source/AzCoreConversions.h>
# include <MCore/Source/Distance.h>
# include <MCore/Source/File.h>
# include <MCore/Source/ReflectionSerializer.h>
# include <MCore/Source/StringConversions.h>
# include <MCore/Source/MCoreSystem.h>
@ -53,7 +54,6 @@
# include "../AnimGraphTransitionCondition.h"
# include "../MCore/Source/Endian.h"
# include "../NodeMap.h"
# include "LegacyAnimGraphNodeParser.h"
# include <EMotionFX/Source/Importer/ActorFileFormat.h>
# include <EMotionFX/Source/TwoStringEventData.h>
@ -245,14 +245,10 @@ namespace EMotionFX
{
mFileHighVersion = 1 ;
mFileLowVersion = 0 ;
mIsUnicodeFile = true ;
// allocate the string buffer used for reading in variable sized strings
mStringStorageSize = 256 ;
mStringStorage = ( char * ) MCore : : Allocate ( mStringStorageSize , EMFX_MEMCATEGORY_IMPORTER ) ;
mBlendNodes . SetMemoryCategory ( EMFX_MEMCATEGORY_IMPORTER ) ;
mBlendNodes . Reserve ( 1024 ) ;
//mConvertString.Reserve( 256 );
}
@ -281,57 +277,8 @@ namespace EMotionFX
mStringStorage = nullptr ;
mStringStorageSize = 0 ;
//mConvertString.Clear();
// get rid of the blend nodes array
mBlendNodes . Clear ( ) ;
m_entryNodeIndexToStateMachineIdLookupTable . clear ( ) ;
}
// check if the strings in the file are encoded using unicode or multi-byte
bool SharedHelperData : : GetIsUnicodeFile ( const char * dateString , MCore : : Array < SharedData * > * sharedData )
{
// find the helper data
SharedData * data = Importer : : FindSharedData ( sharedData , SharedHelperData : : TYPE_ID ) ;
SharedHelperData * helperData = static_cast < SharedHelperData * > ( data ) ;
AZStd : : vector < AZStd : : string > dateParts ;
AzFramework : : StringFunc : : Tokenize ( dateString , dateParts , MCore : : CharacterConstants : : space , false /* keep empty strings */ , true /* keep space strings */ ) ;
// decode the month
int32 month = 0 ;
const AZStd : : string & monthString = dateParts [ 0 ] ;
const char * monthStrings [ 12 ] = { " Jan " , " Feb " , " Mar " , " Apr " , " May " , " Jun " , " Jul " , " Aug " , " Sep " , " Oct " , " Nov " , " Dec " } ;
for ( int32 i = 0 ; i < 12 ; + + i )
{
if ( monthString = = monthStrings [ i ] )
{
month = i + 1 ;
break ;
}
}
//int32 day = dateParts[1].ToInt();
int32 year ;
if ( ! AzFramework : : StringFunc : : LooksLikeInt ( dateParts [ 2 ] . c_str ( ) , & year ) )
{
return false ;
}
// set if the file contains unicode strings or not based on the compilcation date
if ( year < 2012 | | ( year = = 2012 & & month < 11 ) )
{
helperData - > mIsUnicodeFile = false ;
}
//LogInfo( "String: '%s', Decoded: %i.%i.%i - isUnicode=%i", dateString, day, month, year, helperData->mIsUnicodeFile );
return helperData - > mIsUnicodeFile ;
}
const char * SharedHelperData : : ReadString ( MCore : : Stream * file , MCore : : Array < SharedData * > * sharedData , MCore : : Endian : : EEndianType endianType )
{
MCORE_ASSERT ( file ) ;
@ -366,25 +313,6 @@ namespace EMotionFX
return helperData - > mStringStorage ;
}
// get the array of anim graph nodes
MCore : : Array < AnimGraphNode * > & SharedHelperData : : GetBlendNodes ( MCore : : Array < SharedData * > * sharedData )
{
// find the helper data
SharedData * data = Importer : : FindSharedData ( sharedData , SharedHelperData : : TYPE_ID ) ;
SharedHelperData * helperData = static_cast < SharedHelperData * > ( data ) ;
return helperData - > mBlendNodes ;
}
// Get the table of entry state indices to state machines IDs
AZStd : : map < AZ : : u64 , uint32 > & SharedHelperData : : GetEntryStateToStateMachineTable ( MCore : : Array < SharedData * > * sharedData )
{
// Find the helper data
SharedData * data = Importer : : FindSharedData ( sharedData , SharedHelperData : : TYPE_ID ) ;
SharedHelperData * helperData = static_cast < SharedHelperData * > ( data ) ;
return helperData - > m_entryNodeIndexToStateMachineIdLookupTable ;
}
//-----------------------------------------------------------------------------
// constructor
@ -1999,7 +1927,6 @@ namespace EMotionFX
//----------------------------------------------------------------------------------------------------------
//
bool ChunkProcessorActorAttachmentNodes : : Process ( MCore : : File * file , Importer : : ImportParameters & importParams )
{
const MCore : : Endian : : EEndianType endianType = importParams . mEndianType ;
@ -2055,866 +1982,6 @@ namespace EMotionFX
return true ;
}
//----------------------------------------------------------------------------------------------------------
// animGraph state transitions
bool ChunkProcessorAnimGraphStateTransitions : : Process ( MCore : : File * file , Importer : : ImportParameters & importParams )
{
// read the number of transitions to follow
uint32 numTransitions ;
file - > Read ( & numTransitions , sizeof ( uint32 ) ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & numTransitions , importParams . mEndianType ) ;
// read the state machine index
uint32 stateMachineIndex ;
file - > Read ( & stateMachineIndex , sizeof ( uint32 ) ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & stateMachineIndex , importParams . mEndianType ) ;
// get the loaded anim graph nodes
MCore : : Array < AnimGraphNode * > & blendNodes = SharedHelperData : : GetBlendNodes ( importParams . mSharedData ) ;
if ( stateMachineIndex > = blendNodes . GetLength ( ) )
{
if ( GetLogging ( ) )
{
AZ_Error ( " EMotionFX " , false , " State machine refers to invalid blend node, state machine index: %d, amount of blend node: %d " , stateMachineIndex , blendNodes . GetLength ( ) ) ;
}
return false ;
}
AZ_Assert ( azrtti_typeid ( blendNodes [ stateMachineIndex ] ) = = azrtti_typeid < AnimGraphStateMachine > ( ) , " ChunkProcessorAnimGraphStateTransitions::Process : Unexpected node type expected AnimGraphStateMachine. Found %u instead " , azrtti_typeid ( blendNodes [ stateMachineIndex ] ) ) ;
AnimGraphStateMachine * stateMachine = static_cast < AnimGraphStateMachine * > ( blendNodes [ stateMachineIndex ] ) ;
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Num transitions for state machine '%s' = %d " , blendNodes [ stateMachineIndex ] - > GetName ( ) , numTransitions ) ;
}
stateMachine - > ReserveTransitions ( numTransitions ) ;
// read the transitions
FileFormat : : AnimGraph_StateTransition transition ;
for ( uint32 i = 0 ; i < numTransitions ; + + i )
{
// read the transition
file - > Read ( & transition , sizeof ( FileFormat : : AnimGraph_StateTransition ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & transition . mSourceNode , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & transition . mDestNode , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & transition . mNumConditions , importParams . mEndianType ) ;
MCore : : Endian : : ConvertSignedInt32 ( & transition . mStartOffsetX , importParams . mEndianType ) ;
MCore : : Endian : : ConvertSignedInt32 ( & transition . mStartOffsetY , importParams . mEndianType ) ;
MCore : : Endian : : ConvertSignedInt32 ( & transition . mEndOffsetX , importParams . mEndianType ) ;
MCore : : Endian : : ConvertSignedInt32 ( & transition . mEndOffsetY , importParams . mEndianType ) ;
//----------------------------------------------
// read the node header
FileFormat : : AnimGraph_NodeHeader nodeHeader ;
file - > Read ( & nodeHeader , sizeof ( FileFormat : : AnimGraph_NodeHeader ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mTypeID , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mParentIndex , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mVersion , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mNumCustomDataBytes , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mNumChildNodes , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mNumAttributes , importParams . mEndianType ) ;
MCore : : Endian : : ConvertSignedInt32 ( & nodeHeader . mVisualPosX , importParams . mEndianType ) ;
MCore : : Endian : : ConvertSignedInt32 ( & nodeHeader . mVisualPosY , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mVisualizeColor , importParams . mEndianType ) ;
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - State Transition Node: " ) ;
MCore : : LogDetailedInfo ( " + Type = %d " , nodeHeader . mTypeID ) ;
MCore : : LogDetailedInfo ( " + Version = %d " , nodeHeader . mVersion ) ;
MCore : : LogDetailedInfo ( " + Num data bytes = %d " , nodeHeader . mNumCustomDataBytes ) ;
MCore : : LogDetailedInfo ( " + Num attributes = %d " , nodeHeader . mNumAttributes ) ;
MCore : : LogDetailedInfo ( " + Num conditions = %d " , transition . mNumConditions ) ;
MCore : : LogDetailedInfo ( " + Source node = %d " , transition . mSourceNode ) ;
MCore : : LogDetailedInfo ( " + Dest node = %d " , transition . mDestNode ) ;
}
// create the transition object
AnimGraphStateTransition * emfxTransition = nullptr ;
if ( GetNewTypeIdByOldNodeTypeId ( nodeHeader . mTypeID ) = = azrtti_typeid < AnimGraphStateTransition > ( ) )
{
emfxTransition = aznew AnimGraphStateTransition ( ) ;
}
if ( emfxTransition )
{
if ( transition . mDestNode > = blendNodes . GetLength ( ) )
{
if ( GetLogging ( ) )
{
AZ_Error ( " EMotionFX " , false , " State machine transition refers to invalid destination blend node, transition index %d, blend node: %d " , i , transition . mDestNode ) ;
}
delete emfxTransition ;
emfxTransition = nullptr ;
}
// A source node index of MCORE_INVALIDINDEX32 indicates that the transition is a wildcard transition. Don't go into error state in this case.
else if ( transition . mSourceNode ! = MCORE_INVALIDINDEX32 & & transition . mSourceNode > = blendNodes . GetLength ( ) )
{
if ( GetLogging ( ) )
{
AZ_Error ( " EMotionFX " , false , " State machine transition refers to invalid source blend node, transition index %d, blend node: %d " , i , transition . mSourceNode ) ;
}
delete emfxTransition ;
emfxTransition = nullptr ;
}
else
{
AnimGraphNode * targetNode = blendNodes [ transition . mDestNode ] ;
if ( targetNode = = nullptr )
{
delete emfxTransition ;
emfxTransition = nullptr ;
}
else
{
AZ_Assert ( azrtti_istypeof < AnimGraphStateTransition > ( emfxTransition ) , " ChunkProcessorAnimGraphStateTransitions::Process : Unexpected node type expected AnimGraphStateTransition. Found %u instead " , azrtti_typeid ( blendNodes [ stateMachineIndex ] ) ) ;
// Now apply the transition settings
// Check if we are dealing with a wildcard transition
if ( transition . mSourceNode = = MCORE_INVALIDINDEX32 )
{
emfxTransition - > SetSourceNode ( nullptr ) ;
emfxTransition - > SetIsWildcardTransition ( true ) ;
}
else
{
// set the source node
emfxTransition - > SetSourceNode ( blendNodes [ transition . mSourceNode ] ) ;
}
// set the destination node
emfxTransition - > SetTargetNode ( targetNode ) ;
emfxTransition - > SetVisualOffsets ( transition . mStartOffsetX , transition . mStartOffsetY , transition . mEndOffsetX , transition . mEndOffsetY ) ;
// now read the attributes
if ( ! LegacyAnimGraphNodeParser : : ParseLegacyAttributes < AnimGraphStateTransition > ( file , nodeHeader . mNumAttributes , importParams . mEndianType , importParams , * emfxTransition ) )
{
delete emfxTransition ;
emfxTransition = nullptr ;
AZ_Error ( " EMotionFX " , false , " Unable to parse state transition " ) ;
return false ;
}
// add the transition to the state machine
stateMachine - > AddTransition ( emfxTransition ) ;
}
}
}
if ( emfxTransition )
{
// iterate through all conditions
for ( uint32 c = 0 ; c < transition . mNumConditions ; + + c )
{
// read the condition node header
FileFormat : : AnimGraph_NodeHeader conditionHeader ;
file - > Read ( & conditionHeader , sizeof ( FileFormat : : AnimGraph_NodeHeader ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & conditionHeader . mTypeID , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & conditionHeader . mVersion , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & conditionHeader . mNumCustomDataBytes , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & conditionHeader . mNumAttributes , importParams . mEndianType ) ;
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Transition Condition: " ) ;
MCore : : LogDetailedInfo ( " + Type = %d " , conditionHeader . mTypeID ) ;
MCore : : LogDetailedInfo ( " + Version = %d " , conditionHeader . mVersion ) ;
MCore : : LogDetailedInfo ( " + Num data bytes = %d " , conditionHeader . mNumCustomDataBytes ) ;
MCore : : LogDetailedInfo ( " + Num attributes = %d " , conditionHeader . mNumAttributes ) ;
}
AnimGraphTransitionCondition * emfxCondition = nullptr ;
if ( ! LegacyAnimGraphNodeParser : : ParseTransitionConditionChunk ( file , importParams , conditionHeader , emfxCondition ) )
{
AZ_Error ( " EMotionFX " , false , " Unable to parse Transition condition of type %u in legacy file " , azrtti_typeid ( emfxCondition ) ) ;
delete emfxCondition ;
emfxCondition = nullptr ;
return false ;
}
// add the condition to the transition
emfxTransition - > AddCondition ( emfxCondition ) ;
}
//emfxTransition->Init( animGraph );
}
// something went wrong with creating the transition
else
{
MCore : : LogWarning ( " Cannot load and instantiate state transition. State transition from %d to %d will be skipped. " , transition . mSourceNode , transition . mDestNode ) ;
// skip reading the attributes
if ( ! ForwardAttributes ( file , importParams . mEndianType , nodeHeader . mNumAttributes ) )
{
return false ;
}
// skip reading the node custom data
if ( file - > Forward ( nodeHeader . mNumCustomDataBytes ) = = false )
{
return false ;
}
// iterate through all conditions and skip them as well
for ( uint32 c = 0 ; c < transition . mNumConditions ; + + c )
{
// read the condition node header
FileFormat : : AnimGraph_NodeHeader conditionHeader ;
file - > Read ( & conditionHeader , sizeof ( FileFormat : : AnimGraph_NodeHeader ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & conditionHeader . mTypeID , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & conditionHeader . mVersion , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & conditionHeader . mNumCustomDataBytes , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & conditionHeader . mNumAttributes , importParams . mEndianType ) ;
// skip reading the attributes
if ( ! ForwardAttributes ( file , importParams . mEndianType , conditionHeader . mNumAttributes ) )
{
return false ;
}
// skip reading the node custom data
if ( file - > Forward ( conditionHeader . mNumCustomDataBytes ) = = false )
{
return false ;
}
}
}
}
return true ;
}
//----------------------------------------------------------------------------------------------------------
// animGraph state transitions
bool ChunkProcessorAnimGraphAdditionalInfo : : Process ( MCore : : File * file , Importer : : ImportParameters & /*importParams*/ )
{
return file - > Forward ( sizeof ( FileFormat : : AnimGraph_AdditionalInfo ) ) ;
}
//----------------------------------------------------------------------------------------------------------
// animGraph node connections
bool ChunkProcessorAnimGraphNodeConnections : : Process ( MCore : : File * file , Importer : : ImportParameters & importParams )
{
// read the number of transitions to follow
uint32 numConnections ;
file - > Read ( & numConnections , sizeof ( uint32 ) ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & numConnections , importParams . mEndianType ) ;
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Num node connections = %d " , numConnections ) ;
}
// get the array of currently loaded nodes
MCore : : Array < AnimGraphNode * > & blendNodes = SharedHelperData : : GetBlendNodes ( importParams . mSharedData ) ;
// read the connections
FileFormat : : AnimGraph_NodeConnection connection ;
for ( uint32 i = 0 ; i < numConnections ; + + i )
{
// read the transition
file - > Read ( & connection , sizeof ( FileFormat : : AnimGraph_NodeConnection ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & connection . mSourceNode , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & connection . mTargetNode , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt16 ( & connection . mSourceNodePort , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt16 ( & connection . mTargetNodePort , importParams . mEndianType ) ;
// log details
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " + Connection #%d = From node %d (port id %d) into node %d (port id %d) " , i , connection . mSourceNode , connection . mSourceNodePort , connection . mTargetNode , connection . mTargetNodePort ) ;
}
// get the source and the target node and check if they are valid
AnimGraphNode * sourceNode = blendNodes [ connection . mSourceNode ] ;
AnimGraphNode * targetNode = blendNodes [ connection . mTargetNode ] ;
if ( sourceNode = = nullptr | | targetNode = = nullptr )
{
MCore : : LogWarning ( " EMotionFX::ChunkProcessorAnimGraphNodeConnections() - Connection cannot be created because the source or target node is invalid! (sourcePortID=%d targetPortID=%d sourceNode=%d targetNode=%d) " , connection . mSourceNodePort , connection . mTargetNodePort , connection . mSourceNode , connection . mTargetNode ) ;
continue ;
}
// create the connection
const uint32 sourcePort = blendNodes [ connection . mSourceNode ] - > FindOutputPortByID ( connection . mSourceNodePort ) ;
const uint32 targetPort = blendNodes [ connection . mTargetNode ] - > FindInputPortByID ( connection . mTargetNodePort ) ;
if ( sourcePort ! = MCORE_INVALIDINDEX32 & & targetPort ! = MCORE_INVALIDINDEX32 )
{
blendNodes [ connection . mTargetNode ] - > AddConnection ( blendNodes [ connection . mSourceNode ] , static_cast < uint16 > ( sourcePort ) , static_cast < uint16 > ( targetPort ) ) ;
}
else
{
MCore : : LogWarning ( " EMotionFX::ChunkProcessorAnimGraphNodeConnections() - Connection cannot be created because the source or target port doesn't exist! (sourcePortID=%d targetPortID=%d sourceNode='%s' targetNode=%s') " , connection . mSourceNodePort , connection . mTargetNodePort , blendNodes [ connection . mSourceNode ] - > GetName ( ) , blendNodes [ connection . mTargetNode ] - > GetName ( ) ) ;
}
}
return true ;
}
//----------------------------------------------------------------------------------------------------------
// animGraph node
bool ChunkProcessorAnimGraphNode : : Process ( MCore : : File * file , Importer : : ImportParameters & importParams )
{
AnimGraph * animGraph = importParams . mAnimGraph ;
MCORE_ASSERT ( animGraph ) ;
// read the node header
FileFormat : : AnimGraph_NodeHeader nodeHeader ;
file - > Read ( & nodeHeader , sizeof ( FileFormat : : AnimGraph_NodeHeader ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mTypeID , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mParentIndex , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mVersion , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mNumCustomDataBytes , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mNumChildNodes , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mNumAttributes , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeHeader . mVisualizeColor , importParams . mEndianType ) ;
MCore : : Endian : : ConvertSignedInt32 ( & nodeHeader . mVisualPosX , importParams . mEndianType ) ;
MCore : : Endian : : ConvertSignedInt32 ( & nodeHeader . mVisualPosY , importParams . mEndianType ) ;
const char * nodeName = SharedHelperData : : ReadString ( file , importParams . mSharedData , importParams . mEndianType ) ;
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Blend Node: " ) ;
MCore : : LogDetailedInfo ( " + Name = %s " , nodeName ) ;
MCore : : LogDetailedInfo ( " + Parent index = %d " , nodeHeader . mParentIndex ) ;
MCore : : LogDetailedInfo ( " + Type = %d " , nodeHeader . mTypeID ) ;
MCore : : LogDetailedInfo ( " + Version = %d " , nodeHeader . mVersion ) ;
MCore : : LogDetailedInfo ( " + Num data bytes = %d " , nodeHeader . mNumCustomDataBytes ) ;
MCore : : LogDetailedInfo ( " + Num child nodes = %d " , nodeHeader . mNumChildNodes ) ;
MCore : : LogDetailedInfo ( " + Num attributes = %d " , nodeHeader . mNumAttributes ) ;
MCore : : LogDetailedInfo ( " + Visualize Color = %d, %d, %d " , MCore : : ExtractRed ( nodeHeader . mVisualizeColor ) , MCore : : ExtractGreen ( nodeHeader . mVisualizeColor ) , MCore : : ExtractBlue ( nodeHeader . mVisualizeColor ) ) ;
MCore : : LogDetailedInfo ( " + Visual pos = (%d, %d) " , nodeHeader . mVisualPosX , nodeHeader . mVisualPosY ) ;
MCore : : LogDetailedInfo ( " + Collapsed = %s " , ( nodeHeader . mFlags & FileFormat : : ANIMGRAPH_NODEFLAG_COLLAPSED ) ? " Yes " : " No " ) ;
MCore : : LogDetailedInfo ( " + Visualized = %s " , ( nodeHeader . mFlags & FileFormat : : ANIMGRAPH_NODEFLAG_VISUALIZED ) ? " Yes " : " No " ) ;
MCore : : LogDetailedInfo ( " + Disabled = %s " , ( nodeHeader . mFlags & FileFormat : : ANIMGRAPH_NODEFLAG_DISABLED ) ? " Yes " : " No " ) ;
MCore : : LogDetailedInfo ( " + Virtual FinalOut= %s " , ( nodeHeader . mFlags & FileFormat : : ANIMGRAPH_NODEFLAG_VIRTUALFINALOUTPUT ) ? " Yes " : " No " ) ;
}
AnimGraphNode * node = nullptr ;
if ( ! LegacyAnimGraphNodeParser : : ParseAnimGraphNodeChunk ( file
, importParams
, nodeName
, nodeHeader
, node ) )
{
if ( importParams . mAnimGraph - > GetRootStateMachine ( ) = = node )
{
importParams . mAnimGraph - > SetRootStateMachine ( nullptr ) ;
}
if ( node )
{
AnimGraphNode * parentNode = node - > GetParentNode ( ) ;
if ( parentNode )
{
parentNode - > RemoveChildNodeByPointer ( node , false ) ;
}
}
delete node ;
node = nullptr ;
return false ;
}
EMotionFX : : GetEventManager ( ) . OnCreatedNode ( animGraph , node ) ;
return true ;
}
//----------------------------------------------------------------------------------------------------------
// animGraph parameters
bool ChunkProcessorAnimGraphParameters : : Process ( MCore : : File * file , Importer : : ImportParameters & importParams )
{
AnimGraph * animGraph = importParams . mAnimGraph ;
MCORE_ASSERT ( animGraph ) ;
// read the number of parameters
uint32 numParams ;
file - > Read ( & numParams , sizeof ( uint32 ) ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & numParams , importParams . mEndianType ) ;
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Num parameters = %d " , numParams ) ;
}
// read all parameters
for ( uint32 p = 0 ; p < numParams ; + + p )
{
// read the parameter info header
FileFormat : : AnimGraph_ParameterInfo paramInfo ;
file - > Read ( & paramInfo , sizeof ( FileFormat : : AnimGraph_ParameterInfo ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & paramInfo . mNumComboValues , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & paramInfo . mInterfaceType , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & paramInfo . mAttributeType , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt16 ( & paramInfo . mFlags , importParams . mEndianType ) ;
// check the attribute type
const uint32 attribType = paramInfo . mAttributeType ;
if ( attribType = = 0 )
{
MCore : : LogError ( " EMotionFX::ChunkProcessorAnimGraphParameters::Process() - Failed to convert interface type %d to an attribute type. " , attribType ) ;
return false ;
}
const AZ : : TypeId parameterTypeId = EMotionFX : : FileFormat : : GetParameterTypeIdForInterfaceType ( paramInfo . mInterfaceType ) ;
const AZStd : : string name = SharedHelperData : : ReadString ( file , importParams . mSharedData , importParams . mEndianType ) ;
AZStd : : unique_ptr < EMotionFX : : Parameter > newParam ( EMotionFX : : ParameterFactory : : Create ( parameterTypeId ) ) ;
AZ_Assert ( azrtti_istypeof < EMotionFX : : ValueParameter > ( newParam . get ( ) ) , " Expected a value parameter " ) ;
if ( ! newParam )
{
MCore : : LogError ( " EMotionFX::ChunkProcessorAnimGraphParameters::Process() - Failed to create parameter: '%s'. " , name . c_str ( ) ) ;
return false ;
}
// read the strings
newParam - > SetName ( name ) ;
SharedHelperData : : ReadString ( file , importParams . mSharedData , importParams . mEndianType ) ; // We dont use internal name anymore
newParam - > SetDescription ( SharedHelperData : : ReadString ( file , importParams . mSharedData , importParams . mEndianType ) ) ;
// log the details
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Parameter #%d: " , p ) ;
MCore : : LogDetailedInfo ( " + Name = %s " , newParam - > GetName ( ) . c_str ( ) ) ;
MCore : : LogDetailedInfo ( " + Description = %s " , newParam - > GetDescription ( ) . c_str ( ) ) ;
MCore : : LogDetailedInfo ( " + type = %s " , newParam - > RTTI_GetTypeName ( ) ) ;
MCore : : LogDetailedInfo ( " + Attribute type = %d " , paramInfo . mAttributeType ) ;
MCore : : LogDetailedInfo ( " + Has MinMax = %d " , paramInfo . mHasMinMax ) ;
MCore : : LogDetailedInfo ( " + Flags = %d " , paramInfo . mFlags ) ;
}
MCore : : Attribute * attr ( MCore : : GetAttributeFactory ( ) . CreateAttributeByType ( attribType ) ) ;
EMotionFX : : ValueParameter * valueParameter = static_cast < EMotionFX : : ValueParameter * > ( newParam . get ( ) ) ;
// create the min, max and default value attributes
if ( paramInfo . mHasMinMax = = 1 )
{
// min value
attr - > Read ( file , importParams . mEndianType ) ;
valueParameter - > SetMinValueFromAttribute ( attr ) ;
// max value
attr - > Read ( file , importParams . mEndianType ) ;
valueParameter - > SetMaxValueFromAttribute ( attr ) ;
}
// default value
attr - > Read ( file , importParams . mEndianType ) ;
valueParameter - > SetDefaultValueFromAttribute ( attr ) ;
delete attr ;
// Parameters were previously stored in "AttributeSettings". The calss supported
// multiple values, however, the UI did not, so this ended up not being used.
// Support for multiple values in parameters is possible, however we dont need it now.
// Leaving this code as reference
for ( uint32 i = 0 ; i < paramInfo . mNumComboValues ; + + i )
{
SharedHelperData : : ReadString ( file , importParams . mSharedData , importParams . mEndianType ) ;
}
if ( ! animGraph - > AddParameter ( newParam . get ( ) ) )
{
MCore : : LogError ( " EMotionFX::ChunkProcessorAnimGraphParameters::Process() - Failed to add parameter: '%s'. " , name . c_str ( ) ) ;
return false ;
}
newParam . release ( ) ; // ownership moved to animGraph
}
return true ;
}
// animGraph node groups
bool ChunkProcessorAnimGraphNodeGroups : : Process ( MCore : : File * file , Importer : : ImportParameters & importParams )
{
AnimGraph * animGraph = importParams . mAnimGraph ;
MCORE_ASSERT ( animGraph ) ;
// read the number of node groups
uint32 numNodeGroups ;
file - > Read ( & numNodeGroups , sizeof ( uint32 ) ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & numNodeGroups , importParams . mEndianType ) ;
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Num Node Groups = %d " , numNodeGroups ) ;
}
// read all node groups
for ( uint32 g = 0 ; g < numNodeGroups ; + + g )
{
// read the node group header
FileFormat : : AnimGraph_NodeGroup nodeGroupChunk ;
file - > Read ( & nodeGroupChunk , sizeof ( FileFormat : : AnimGraph_NodeGroup ) ) ;
MCore : : RGBAColor emfxColor ( nodeGroupChunk . mColor . mR , nodeGroupChunk . mColor . mG , nodeGroupChunk . mColor . mB , nodeGroupChunk . mColor . mA ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeGroupChunk . mNumNodes , importParams . mEndianType ) ;
MCore : : Endian : : ConvertRGBAColor ( & emfxColor , importParams . mEndianType ) ;
const AZ : : Color color128 = MCore : : EmfxColorToAzColor ( emfxColor ) ;
const AZ : : u32 color32 = color128 . ToU32 ( ) ;
const char * groupName = SharedHelperData : : ReadString ( file , importParams . mSharedData , importParams . mEndianType ) ;
const uint32 numNodes = nodeGroupChunk . mNumNodes ;
// create and fill the new node group
AnimGraphNodeGroup * nodeGroup = aznew AnimGraphNodeGroup ( groupName ) ;
animGraph - > AddNodeGroup ( nodeGroup ) ;
nodeGroup - > SetIsVisible ( nodeGroupChunk . mIsVisible ! = 0 ) ;
nodeGroup - > SetColor ( color32 ) ;
// set the nodes of the node group
MCore : : Array < AnimGraphNode * > & blendNodes = SharedHelperData : : GetBlendNodes ( importParams . mSharedData ) ;
nodeGroup - > SetNumNodes ( numNodes ) ;
for ( uint32 i = 0 ; i < numNodes ; + + i )
{
// read the node index of the current node inside the group
uint32 nodeNr ;
file - > Read ( & nodeNr , sizeof ( uint32 ) ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & nodeNr , importParams . mEndianType ) ;
MCORE_ASSERT ( nodeNr ! = MCORE_INVALIDINDEX32 ) ;
// set the id of the given node to the group
if ( nodeNr ! = MCORE_INVALIDINDEX32 & & blendNodes [ nodeNr ] )
{
nodeGroup - > SetNode ( i , blendNodes [ nodeNr ] - > GetId ( ) ) ;
}
else
{
nodeGroup - > SetNode ( i , AnimGraphNodeId : : InvalidId ) ;
}
}
// log the details
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Node Group #%d: " , g ) ;
MCore : : LogDetailedInfo ( " + Name = %s " , nodeGroup - > GetName ( ) ) ;
MCore : : LogDetailedInfo ( " + Color = (%.2f, %.2f, %.2f, %.2f) " , static_cast < float > ( color128 . GetR ( ) ) , static_cast < float > ( color128 . GetG ( ) ) , static_cast < float > ( color128 . GetB ( ) ) , static_cast < float > ( color128 . GetA ( ) ) ) ;
MCore : : LogDetailedInfo ( " + Num Nodes = %i " , nodeGroup - > GetNumNodes ( ) ) ;
}
}
return true ;
}
// animGraph group parameters
bool ChunkProcessorAnimGraphGroupParameters : : Process ( MCore : : File * file , Importer : : ImportParameters & importParams )
{
AnimGraph * animGraph = importParams . mAnimGraph ;
MCORE_ASSERT ( animGraph ) ;
// read the number of group parameters
uint32 numGroupParameters ;
file - > Read ( & numGroupParameters , sizeof ( uint32 ) ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & numGroupParameters , importParams . mEndianType ) ;
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Num group parameters = %d " , numGroupParameters ) ;
}
// Group parameters is going to re-shuffle the value parameter indices, therefore we
// need to update the connections downstream of parameter nodes.
EMotionFX : : ValueParameterVector valueParametersBeforeChange = animGraph - > RecursivelyGetValueParameters ( ) ;
// Since relocating a parameter to another parent changes its index, we are going to
// compute all the relationships leaving the value parameters at the root, then relocate
// them.
AZStd : : vector < AZStd : : pair < const EMotionFX : : GroupParameter * , EMotionFX : : ParameterVector > > parametersByGroup ;
// read all group parameters
for ( uint32 g = 0 ; g < numGroupParameters ; + + g )
{
// read the group parameter header
FileFormat : : AnimGraph_GroupParameter groupChunk ;
file - > Read ( & groupChunk , sizeof ( FileFormat : : AnimGraph_GroupParameter ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & groupChunk . mNumParameters , importParams . mEndianType ) ;
const char * groupName = SharedHelperData : : ReadString ( file , importParams . mSharedData , importParams . mEndianType ) ;
const uint32 numParameters = groupChunk . mNumParameters ;
// create and fill the new group parameter
AZStd : : unique_ptr < EMotionFX : : Parameter > parameter ( EMotionFX : : ParameterFactory : : Create ( azrtti_typeid < EMotionFX : : GroupParameter > ( ) ) ) ;
parameter - > SetName ( groupName ) ;
// Previously collapsed/expanded state in group parameters was stored in the animgraph file. However, that
// would require to check out the animgraph file if you expand/collapse a group. Because this change was not
// done through commands, the dirty state was not properly restored.
// Collapsing state should be more of a setting per-user than something saved in the animgraph
//groupParameter->SetIsCollapsed(groupChunk.mCollapsed != 0);
if ( ! animGraph - > AddParameter ( parameter . get ( ) ) )
{
continue ;
}
const EMotionFX : : GroupParameter * groupParameter = static_cast < EMotionFX : : GroupParameter * > ( parameter . release ( ) ) ;
parametersByGroup . emplace_back ( groupParameter , EMotionFX : : ParameterVector ( ) ) ;
AZStd : : vector < EMotionFX : : Parameter * > & parametersInGroup = parametersByGroup . back ( ) . second ;
// set the parameters of the group parameter
for ( uint32 i = 0 ; i < numParameters ; + + i )
{
// read the parameter index
uint32 parameterIndex ;
file - > Read ( & parameterIndex , sizeof ( uint32 ) ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & parameterIndex , importParams . mEndianType ) ;
MCORE_ASSERT ( parameterIndex ! = MCORE_INVALIDINDEX32 ) ;
if ( parameterIndex ! = MCORE_INVALIDINDEX32 )
{
const EMotionFX : : Parameter * childParameter = animGraph - > FindValueParameter ( parameterIndex ) ;
parametersInGroup . emplace_back ( const_cast < EMotionFX : : Parameter * > ( childParameter ) ) ;
}
}
// log the details
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Group parameter #%d: " , g ) ;
MCore : : LogDetailedInfo ( " + Name = %s " , groupParameter - > GetName ( ) . c_str ( ) ) ;
MCore : : LogDetailedInfo ( " + Num Parameters = %i " , groupParameter - > GetNumParameters ( ) ) ;
}
}
// Now move the parameters to their groups
for ( const AZStd : : pair < const EMotionFX : : GroupParameter * , EMotionFX : : ParameterVector > & groupAndParameters : parametersByGroup )
{
const EMotionFX : : GroupParameter * groupParameter = groupAndParameters . first ;
for ( EMotionFX : : Parameter * parameter : groupAndParameters . second )
{
animGraph - > TakeParameterFromParent ( parameter ) ;
animGraph - > AddParameter ( const_cast < EMotionFX : : Parameter * > ( parameter ) , groupParameter ) ;
}
}
const EMotionFX : : ValueParameterVector valueParametersAfterChange = animGraph - > RecursivelyGetValueParameters ( ) ;
AZStd : : vector < EMotionFX : : AnimGraphObject * > affectedObjects ;
animGraph - > RecursiveCollectObjectsOfType ( azrtti_typeid < EMotionFX : : ObjectAffectedByParameterChanges > ( ) , affectedObjects ) ;
for ( EMotionFX : : AnimGraphObject * affectedObject : affectedObjects )
{
EMotionFX : : ObjectAffectedByParameterChanges * affectedObjectByParameterChanges = azdynamic_cast < EMotionFX : : ObjectAffectedByParameterChanges * > ( affectedObject ) ;
affectedObjectByParameterChanges - > ParameterOrderChanged ( valueParametersBeforeChange , valueParametersAfterChange ) ;
}
return true ;
}
// animGraph game controller settings
bool ChunkProcessorAnimGraphGameControllerSettings : : Process ( MCore : : File * file , Importer : : ImportParameters & importParams )
{
uint32 i ;
AnimGraph * animGraph = importParams . mAnimGraph ;
MCORE_ASSERT ( animGraph ) ;
// get the game controller settings for the anim graph and clear it
AnimGraphGameControllerSettings & gameControllerSettings = animGraph - > GetGameControllerSettings ( ) ;
gameControllerSettings . Clear ( ) ;
// read the number of presets and the active preset index
uint32 activePresetIndex , numPresets ;
file - > Read ( & activePresetIndex , sizeof ( uint32 ) ) ;
file - > Read ( & numPresets , sizeof ( uint32 ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & activePresetIndex , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & numPresets , importParams . mEndianType ) ;
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Game Controller Settings (NumPresets=%d, ActivePreset=%d) " , numPresets , activePresetIndex ) ;
}
// preallocate memory for the presets
gameControllerSettings . SetNumPresets ( numPresets ) ;
// read all presets
for ( uint32 p = 0 ; p < numPresets ; + + p )
{
// read the preset chunk
FileFormat : : AnimGraph_GameControllerPreset presetChunk ;
file - > Read ( & presetChunk , sizeof ( FileFormat : : AnimGraph_GameControllerPreset ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & presetChunk . mNumParameterInfos , importParams . mEndianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & presetChunk . mNumButtonInfos , importParams . mEndianType ) ;
// read the preset name and get the number of parameter and button infos
const char * presetName = SharedHelperData : : ReadString ( file , importParams . mSharedData , importParams . mEndianType ) ;
const uint32 numParamInfos = presetChunk . mNumParameterInfos ;
const uint32 numButtonInfos = presetChunk . mNumButtonInfos ;
// create and fill the new preset
AnimGraphGameControllerSettings : : Preset * preset = aznew AnimGraphGameControllerSettings : : Preset ( presetName ) ;
gameControllerSettings . SetPreset ( p , preset ) ;
// read the parameter infos
preset - > SetNumParamInfos ( numParamInfos ) ;
for ( i = 0 ; i < numParamInfos ; + + i )
{
// read the parameter info chunk
FileFormat : : AnimGraph_GameControllerParameterInfo paramInfoChunk ;
file - > Read ( & paramInfoChunk , sizeof ( FileFormat : : AnimGraph_GameControllerParameterInfo ) ) ;
// read the parameter name
const char * parameterName = SharedHelperData : : ReadString ( file , importParams . mSharedData , importParams . mEndianType ) ;
// construct and fill the parameter info
AnimGraphGameControllerSettings : : ParameterInfo * parameterInfo = aznew AnimGraphGameControllerSettings : : ParameterInfo ( parameterName ) ;
parameterInfo - > m_axis = paramInfoChunk . mAxis ;
parameterInfo - > m_invert = ( paramInfoChunk . mInvert ! = 0 ) ;
parameterInfo - > m_mode = ( AnimGraphGameControllerSettings : : ParameterMode ) paramInfoChunk . mMode ;
preset - > SetParamInfo ( i , parameterInfo ) ;
}
// read the button infos
preset - > SetNumButtonInfos ( numButtonInfos ) ;
for ( i = 0 ; i < numButtonInfos ; + + i )
{
// read the button info chunk
FileFormat : : AnimGraph_GameControllerButtonInfo buttonInfoChunk ;
file - > Read ( & buttonInfoChunk , sizeof ( FileFormat : : AnimGraph_GameControllerButtonInfo ) ) ;
// read the button string
const char * buttonString = SharedHelperData : : ReadString ( file , importParams . mSharedData , importParams . mEndianType ) ;
// construct and fill the button info
AnimGraphGameControllerSettings : : ButtonInfo * buttonInfo = aznew AnimGraphGameControllerSettings : : ButtonInfo ( buttonInfoChunk . mButtonIndex ) ;
buttonInfo - > m_mode = ( AnimGraphGameControllerSettings : : ButtonMode ) buttonInfoChunk . mMode ;
buttonInfo - > m_string = buttonString ;
preset - > SetButtonInfo ( i , buttonInfo ) ;
}
// log the details
if ( GetLogging ( ) )
{
MCore : : LogDetailedInfo ( " - Preset '%s': " , preset - > GetName ( ) ) ;
MCore : : LogDetailedInfo ( " + Num Param Infos = %d " , preset - > GetNumParamInfos ( ) ) ;
MCore : : LogDetailedInfo ( " + Num Button Infos = %d " , preset - > GetNumButtonInfos ( ) ) ;
}
}
// set the active preset
if ( activePresetIndex ! = MCORE_INVALIDINDEX32 )
{
AnimGraphGameControllerSettings : : Preset * activePreset = gameControllerSettings . GetPreset ( activePresetIndex ) ;
gameControllerSettings . SetActivePreset ( activePreset ) ;
}
return true ;
}
//----------------------------------------------------------------------------------------------------------
// MotionSet
//----------------------------------------------------------------------------------------------------------
// all submotions in one chunk
bool ChunkProcessorMotionSet : : Process ( MCore : : File * file , Importer : : ImportParameters & importParams )
{
const MCore : : Endian : : EEndianType endianType = importParams . mEndianType ;
FileFormat : : MotionSetsChunk motionSetsChunk ;
file - > Read ( & motionSetsChunk , sizeof ( FileFormat : : MotionSetsChunk ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & motionSetsChunk . mNumSets , endianType ) ;
// get the number of motion sets and iterate through them
const uint32 numMotionSets = motionSetsChunk . mNumSets ;
for ( uint32 i = 0 ; i < numMotionSets ; + + i )
{
FileFormat : : MotionSetChunk motionSetChunk ;
file - > Read ( & motionSetChunk , sizeof ( FileFormat : : MotionSetChunk ) ) ;
// convert endian
MCore : : Endian : : ConvertUnsignedInt32 ( & motionSetChunk . mNumChildSets , endianType ) ;
MCore : : Endian : : ConvertUnsignedInt32 ( & motionSetChunk . mNumMotionEntries , endianType ) ;
// get the parent set
const char * parentSetName = SharedHelperData : : ReadString ( file , importParams . mSharedData , endianType ) ;
GetMotionManager ( ) . Lock ( ) ;
MotionSet * parentSet = GetMotionManager ( ) . FindMotionSetByName ( parentSetName , importParams . m_isOwnedByRuntime ) ;
GetMotionManager ( ) . Unlock ( ) ;
// read the motion set name and create our new motion set
const char * motionSetName = SharedHelperData : : ReadString ( file , importParams . mSharedData , endianType ) ;
MotionSet * motionSet = aznew MotionSet ( motionSetName , parentSet ) ;
motionSet - > SetIsOwnedByRuntime ( importParams . m_isOwnedByRuntime ) ;
// set the root motion set to the importer params motion set, this will be returned by the Importer::LoadMotionSet() function
if ( parentSet = = nullptr )
{
assert ( importParams . mMotionSet = = nullptr ) ;
importParams . mMotionSet = motionSet ;
}
// read the filename and set it
/*const char* motionSetFileName = */ SharedHelperData : : ReadString ( file , importParams . mSharedData , endianType ) ;
//motionSet->SetFileName( motionSetFileName );
// in case this is not a root motion set add the new motion set as child set to the parent set
if ( parentSet )
{
parentSet - > AddChildSet ( motionSet ) ;
}
// Read all motion entries.
const uint32 numMotionEntries = motionSetChunk . mNumMotionEntries ;
motionSet - > ReserveMotionEntries ( numMotionEntries ) ;
AZStd : : string nativeMotionFileName ;
for ( uint32 j = 0 ; j < numMotionEntries ; + + j )
{
// read the motion entry
const char * motionFileName = SharedHelperData : : ReadString ( file , importParams . mSharedData , endianType ) ;
nativeMotionFileName = motionFileName ;
// read the string id and set it
const char * motionStringID = SharedHelperData : : ReadString ( file , importParams . mSharedData , endianType ) ;
// add the motion entry to the motion set
MotionSet : : MotionEntry * motionEntry = aznew MotionSet : : MotionEntry ( nativeMotionFileName . c_str ( ) , motionStringID ) ;
motionSet - > AddMotionEntry ( motionEntry ) ;
}
}
return true ;
}
//----------------------------------------------------------------------------------------------------------
// NodeMap
//----------------------------------------------------------------------------------------------------------