// Copyright Epic Games, Inc. All Rights Reserved. #include "AddSolverDeformerNode.h" #include "GroomSolverComponent.h" #include "Dataflow/DataflowConnection.h" #include "OptimusDataTypeRegistry.h" #include "OptimusVariableDescription.h" #include "OptimusDeformer.h" #include "OptimusDeformerInstance.h" #include "OptimusDeformerDynamicInstanceManager.h" #include "Dataflow/DataflowSimulationManager.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(AddSolverDeformerNode) namespace UE::Groom::Private { template FORCEINLINE UE::Dataflow::TConnectionReference GetConnectionReference(const TArray& DataflowInputs, int32 InputIndex) { return { &DataflowInputs[InputIndex], InputIndex, &DataflowInputs }; } template FORCEINLINE void RegisterArrayConnection(const TArray& DataflowInputs, FDataflowNode& DataflowNode) { if(!DataflowInputs.IsEmpty()) { for(int32 InputIndex = 0; InputIndex < DataflowInputs.Num(); ++InputIndex) { DataflowNode.FindOrRegisterInputArrayConnection(GetConnectionReference(DataflowInputs, InputIndex)); } } } template FORCEINLINE void UnregisterArrayConnection(TArray& DataflowInputs, FDataflowNode& DataflowNode) { TArray NodeInputs = DataflowNode.GetInputs(); int32 NumRegisteredInputs = 0; for (FDataflowInput* NodeInput: NodeInputs) { if(PolicyType::SupportsTypeStatic(NodeInput->GetType())) { NumRegisteredInputs++; } } const int32 NumDataflowInputs = DataflowInputs.Num(); if(NumRegisteredInputs > NumDataflowInputs) { DataflowInputs.SetNum(NumRegisteredInputs); for (int32 InputIndex = NumDataflowInputs; InputIndex < NumRegisteredInputs; ++InputIndex) { DataflowNode.UnregisterInputConnection(GetConnectionReference(DataflowInputs, InputIndex)); } DataflowInputs.SetNum(NumDataflowInputs); } } template FORCEINLINE void RemoveOptionPin(TArray& DataflowInputs, const FDataflowNode& DataflowNode, const UE::Dataflow::FPin& Pin) { if(!DataflowInputs.IsEmpty() && (Pin.Direction == UE::Dataflow::FPin::EDirection::INPUT)) { for(int32 InputIndex = 0; InputIndex < DataflowInputs.Num(); ++InputIndex) { if (const FDataflowInput* const DeformerInput = DataflowNode.FindInput(GetConnectionReference(DataflowInputs, InputIndex))) { if(Pin.Type == DeformerInput->GetType() && Pin.Name == DeformerInput->GetName() ) { DataflowInputs.RemoveAt(InputIndex); break; } } } } } template FORCEINLINE void GatherOptionPins(const TArray& DataflowInputs, const FDataflowNode& DataflowNode, TArray& Pins) { for(int32 InputIndex = DataflowInputs.Num()-1; InputIndex >= 0; --InputIndex) { if (const FDataflowInput* const DeformerInput = DataflowNode.FindInput(GetConnectionReference(DataflowInputs, InputIndex))) { Pins.Emplace(UE::Dataflow::FPin{ UE::Dataflow::FPin::EDirection::INPUT, DeformerInput->GetType(), DeformerInput->GetName() }); } } } template FORCEINLINE void AddOptionPin(TArray& DataflowInputs, FDataflowNode& DataflowNode, const FName& PinName, TArray& Pins) { const uint32 InputIndex = DataflowInputs.AddDefaulted(); FDataflowInput& DeformerInput = DataflowNode.RegisterInputArrayConnection(GetConnectionReference(DataflowInputs, InputIndex) ); DeformerInput.SetName(PinName); DataflowNode.SetInputConcreteType(GetConnectionReference(DataflowInputs, InputIndex), FName(TDataflowPolicyTypeName::GetName())); Pins.Emplace(UE::Dataflow::FPin{ UE::Dataflow::FPin::EDirection::INPUT, DeformerInput.GetType(), DeformerInput.GetName() }); } template FORCEINLINE PinType GetPinValue(const TArray& DataflowInputs, const FDataflowNode& DataflowNode, UE::Dataflow::FDataflowSimulationContext& SimulationContext, const int32& InputIndex) { PinType ResultValue = PinType(); const UE::Dataflow::TConnectionReference InputReference = GetConnectionReference(DataflowInputs, InputIndex); if (DataflowNode.IsConnected(InputReference)) { const StorageType PinValue = DataflowNode.GetValue(SimulationContext, InputReference); FDataflowConverter::To(PinValue, ResultValue); } return ResultValue; } FORCEINLINE void CreateDeformerInstance(UOptimusDeformer* DeformerGraph, UMeshDeformerInstance* DeformerInstance, const FGuid InstanceGuid, UDataflow* DataflowObject) { if(DeformerGraph && DeformerInstance && DeformerInstance->GetOuter()) { FFunctionGraphTask::CreateAndDispatchWhenReady([DeformerGraph, DeformerInstance, InstanceGuid, DataflowObject]() { if (UMeshComponent* MeshComponent = Cast(DeformerInstance->GetOuter())) { if (!MeshComponent->IsBeingDestroyed() && MeshComponent->GetScene()) { if (!UE::IsSavingPackage(nullptr) && !IsGarbageCollectingAndLockingUObjectHashTables()) { if (UOptimusDeformerDynamicInstanceManager* DeformerInstanceManager = Cast(DeformerInstance)) { if (!DeformerInstanceManager->GetDeformerInstance(InstanceGuid)) { DeformerInstanceManager->AddProducerDeformer(DataflowObject, InstanceGuid, DeformerGraph); } } } } } }, TStatId(), NULL, ENamedThreads::GameThread); } } } void FAddSolverDeformerDataflowNode::EvaluateSimulation(UE::Dataflow::FDataflowSimulationContext& SimulationContext, const FDataflowOutput* Output) const { const TArray SolverProperties = GetValue(SimulationContext, &PhysicsSolvers); const float SimulationDeltaTime = GetValue(SimulationContext, &SimulationTime).DeltaTime; if(!SolverProperties.IsEmpty() && MeshDeformer) { for(const FDataflowSimulationProperty& SolverProperty : SolverProperties) { if(SolverProperty.SimulationProxy) { if(FDataflowGroomSolverProxy* GroomProxy = SolverProperty.SimulationProxy->AsType()) { FGuid& DeformerInstanceGuid = GroomProxy->DeformerInstanceGuids.FindOrAdd(GetGuid()); if (!DeformerInstanceGuid.IsValid()) { // Build the deformer instance given that GUID if(UDataflow* DataflowObject = Cast(SimulationContext.Owner)) { if(MeshDeformer && GroomProxy->DeformerInstance) { // Create a new GUID for the new deformer instance DeformerInstanceGuid = FGuid::NewGuid(); // Build a deformer instance given a guid UE::Groom::Private::CreateDeformerInstance(MeshDeformer, GroomProxy->DeformerInstance, DeformerInstanceGuid, DataflowObject); } } } else if (UOptimusDeformerDynamicInstanceManager* DeformerInstanceManager = Cast(GroomProxy->DeformerInstance)) { if (UOptimusDeformerInstance* DeformerInstance = DeformerInstanceManager->GetDeformerInstance(DeformerInstanceGuid)) { // Enqueue the execution of the deformer instance DeformerInstanceManager->EnqueueProducerDeformer(DeformerInstanceGuid, EOptimusDeformerExecutionPhase::OverrideDefaultDeformer, 1); // Set the value of the deformer variables for(int32 InputIndex = 0; InputIndex < DeformerNumericInputs.Num(); ++InputIndex) { if (const FDataflowInput* const DeformerInput = FindInput( UE::Groom::Private::GetConnectionReference(DeformerNumericInputs, InputIndex))) { if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetIntVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerNumericInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetIntVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerNumericInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetFloatVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerNumericInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetFloatVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerNumericInputs, *this, SimulationContext, InputIndex)); } } } for(int32 InputIndex = 0; InputIndex < DeformerVectorInputs.Num(); ++InputIndex) { if (const FDataflowInput* const DeformerInput = FindInput( UE::Groom::Private::GetConnectionReference(DeformerVectorInputs, InputIndex))) { if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetVector2Variable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerVectorInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetVectorVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerVectorInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetVector4Variable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerVectorInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetQuatVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerVectorInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetLinearColorVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerVectorInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetInt2Variable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerVectorInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetInt3Variable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerVectorInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetInt4Variable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerVectorInputs, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetRotatorVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerVectorInputs, *this, SimulationContext, InputIndex)); } } } for(int32 InputIndex = 0; InputIndex < DeformerStringInputs.Num(); ++InputIndex) { if (const FDataflowInput* const DeformerInput = FindInput( UE::Groom::Private::GetConnectionReference(DeformerStringInputs, InputIndex))) { if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetNameVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerStringInputs, *this, SimulationContext, InputIndex)); } } } for(int32 InputIndex = 0; InputIndex < DeformerBoolInputs.Num(); ++InputIndex) { if (const FDataflowInput* const DeformerInput = FindInput( UE::Groom::Private::GetConnectionReference(DeformerBoolInputs, InputIndex))) { if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetBoolVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerBoolInputs, *this, SimulationContext, InputIndex)); } } } for(int32 InputIndex = 0; InputIndex < DeformerTransformInputs.Num(); ++InputIndex) { if (const FDataflowInput* const DeformerInput = FindInput( UE::Groom::Private::GetConnectionReference(DeformerTransformInputs, InputIndex))) { if(DeformerInput->GetType() == TDataflowPolicyTypeName::GetName()) { DeformerInstance->SetTransformVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue( DeformerTransformInputs, *this, SimulationContext, InputIndex)); } } } for(int32 InputIndex = 0; InputIndex < DeformerNumericArrays.Num(); ++InputIndex) { if (const FDataflowInput* const DeformerInput = FindInput( UE::Groom::Private::GetConnectionReference(DeformerNumericArrays, InputIndex))) { if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetIntArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerNumericArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetIntArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerNumericArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetFloatArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerNumericArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetFloatArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerNumericArrays, *this, SimulationContext, InputIndex)); } } } for(int32 InputIndex = 0; InputIndex < DeformerVectorArrays.Num(); ++InputIndex) { if (const FDataflowInput* const DeformerInput = FindInput( UE::Groom::Private::GetConnectionReference(DeformerVectorArrays, InputIndex))) { if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetVector2ArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerVectorArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetVectorArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerVectorArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetVector4ArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerVectorArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetQuatArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerVectorArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetLinearColorArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerVectorArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetInt2ArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerVectorArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetInt3ArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerVectorArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetInt4ArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerVectorArrays, *this, SimulationContext, InputIndex)); } else if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetRotatorArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerVectorArrays, *this, SimulationContext, InputIndex)); } } } for(int32 InputIndex = 0; InputIndex < DeformerBoolArrays.Num(); ++InputIndex) { if (const FDataflowInput* const DeformerInput = FindInput( UE::Groom::Private::GetConnectionReference(DeformerBoolArrays, InputIndex))) { if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetBoolArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerBoolArrays, *this, SimulationContext, InputIndex)); } } } for(int32 InputIndex = 0; InputIndex < DeformerTransformArrays.Num(); ++InputIndex) { if (const FDataflowInput* const DeformerInput = FindInput( UE::Groom::Private::GetConnectionReference(DeformerTransformArrays, InputIndex))) { if(DeformerInput->GetType() == TDataflowPolicyTypeName>::GetName()) { DeformerInstance->SetTransformArrayVariable(DeformerInput->GetName(), UE::Groom::Private::GetPinValue>( DeformerTransformArrays, *this, SimulationContext, InputIndex)); } } } } } } } } } SetValue(SimulationContext, SolverProperties, &PhysicsSolvers); } void FAddSolverDeformerDataflowNode::OnInvalidate() {} TArray FAddSolverDeformerDataflowNode::AddPins() { if(MeshDeformer) { TArray Pins; for (UOptimusVariableDescription* Variable : MeshDeformer->GetVariables()) { if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(*FIntProperty::StaticClass())) { UE::Groom::Private::AddOptionPin(DeformerNumericInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(*FUInt32Property::StaticClass())) { UE::Groom::Private::AddOptionPin(DeformerNumericInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(*FDoubleProperty::StaticClass())) { UE::Groom::Private::AddOptionPin(DeformerNumericInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(*FFloatProperty::StaticClass())) { UE::Groom::Private::AddOptionPin(DeformerNumericInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin(DeformerVectorInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin(DeformerVectorInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin(DeformerVectorInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin(DeformerVectorInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin(DeformerVectorInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin(DeformerVectorInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin(DeformerVectorInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin(DeformerVectorInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin(DeformerVectorInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(*FNameProperty::StaticClass())) { UE::Groom::Private::AddOptionPin(DeformerStringInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(*FBoolProperty::StaticClass())) { UE::Groom::Private::AddOptionPin(DeformerBoolInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin(DeformerTransformInputs, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(*FIntProperty::StaticClass())) { UE::Groom::Private::AddOptionPin>(DeformerNumericArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(*FUInt32Property::StaticClass())) { UE::Groom::Private::AddOptionPin>(DeformerNumericArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(*FDoubleProperty::StaticClass())) { UE::Groom::Private::AddOptionPin>(DeformerNumericArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(*FFloatProperty::StaticClass())) { UE::Groom::Private::AddOptionPin>(DeformerNumericArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin>(DeformerVectorArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin>(DeformerVectorArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin>(DeformerVectorArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin>(DeformerVectorArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin>(DeformerVectorArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin>(DeformerVectorArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin>(DeformerVectorArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin>(DeformerVectorArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin>(DeformerVectorArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(*FNameProperty::StaticClass())) { UE::Groom::Private::AddOptionPin>(DeformerStringArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(*FBoolProperty::StaticClass())) { UE::Groom::Private::AddOptionPin>(DeformerBoolArrays, *this, Variable->VariableName, Pins); } else if (Variable->DataType == FOptimusDataTypeRegistry::Get().FindArrayType(TBaseStructure::Get())) { UE::Groom::Private::AddOptionPin>(DeformerTransformArrays, *this, Variable->VariableName, Pins); } else { UE_LOG(LogTemp, Error, TEXT("Unsupported Dataflow variable type")); } } return Pins; } return Super::AddPins(); } TArray FAddSolverDeformerDataflowNode::GetPinsToRemove() const { if(!DeformerNumericInputs.IsEmpty() || !DeformerStringInputs.IsEmpty() || !DeformerVectorInputs.IsEmpty() || !DeformerBoolInputs.IsEmpty() || !DeformerTransformInputs.IsEmpty()) { TArray Pins; UE::Groom::Private::GatherOptionPins(DeformerNumericInputs, *this, Pins); UE::Groom::Private::GatherOptionPins(DeformerVectorInputs, *this, Pins); UE::Groom::Private::GatherOptionPins(DeformerStringInputs, *this, Pins); UE::Groom::Private::GatherOptionPins(DeformerBoolInputs, *this, Pins); UE::Groom::Private::GatherOptionPins(DeformerTransformInputs, *this, Pins); UE::Groom::Private::GatherOptionPins(DeformerNumericArrays, *this, Pins); UE::Groom::Private::GatherOptionPins(DeformerVectorArrays, *this, Pins); UE::Groom::Private::GatherOptionPins(DeformerStringArrays, *this, Pins); UE::Groom::Private::GatherOptionPins(DeformerBoolArrays, *this, Pins); UE::Groom::Private::GatherOptionPins(DeformerTransformArrays, *this, Pins); return Pins; } return Super::GetPinsToRemove(); } void FAddSolverDeformerDataflowNode::OnPinRemoved(const UE::Dataflow::FPin& Pin) { if(!DeformerNumericInputs.IsEmpty() || !DeformerStringInputs.IsEmpty() || !DeformerVectorInputs.IsEmpty() || !DeformerBoolInputs.IsEmpty() || !DeformerTransformInputs.IsEmpty()) { UE::Groom::Private::RemoveOptionPin(DeformerNumericInputs, *this, Pin); UE::Groom::Private::RemoveOptionPin(DeformerVectorInputs, *this, Pin); UE::Groom::Private::RemoveOptionPin(DeformerStringInputs, *this, Pin); UE::Groom::Private::RemoveOptionPin(DeformerBoolInputs, *this, Pin); UE::Groom::Private::RemoveOptionPin(DeformerTransformInputs, *this, Pin); UE::Groom::Private::RemoveOptionPin(DeformerNumericArrays, *this, Pin); UE::Groom::Private::RemoveOptionPin(DeformerVectorArrays, *this, Pin); UE::Groom::Private::RemoveOptionPin(DeformerStringArrays, *this, Pin); UE::Groom::Private::RemoveOptionPin(DeformerBoolArrays, *this, Pin); UE::Groom::Private::RemoveOptionPin(DeformerTransformArrays, *this, Pin); } return Super::OnPinRemoved(Pin); } void FAddSolverDeformerDataflowNode::PostSerialize(const FArchive& Ar) { // because we add pins we need to make sure we restore them when loading // to make sure they can get properly reconnected if (Ar.IsLoading()) { UE::Groom::Private::RegisterArrayConnection(DeformerNumericInputs, *this); UE::Groom::Private::RegisterArrayConnection(DeformerVectorInputs, *this); UE::Groom::Private::RegisterArrayConnection(DeformerStringInputs, *this); UE::Groom::Private::RegisterArrayConnection(DeformerBoolInputs, *this); UE::Groom::Private::RegisterArrayConnection(DeformerTransformInputs, *this); UE::Groom::Private::RegisterArrayConnection(DeformerNumericArrays, *this); UE::Groom::Private::RegisterArrayConnection(DeformerVectorArrays, *this); UE::Groom::Private::RegisterArrayConnection(DeformerStringArrays, *this); UE::Groom::Private::RegisterArrayConnection(DeformerBoolArrays, *this); UE::Groom::Private::RegisterArrayConnection(DeformerTransformArrays, *this); if (Ar.IsTransacting()) { UE::Groom::Private::UnregisterArrayConnection(DeformerNumericInputs, *this); UE::Groom::Private::UnregisterArrayConnection(DeformerVectorInputs, *this); UE::Groom::Private::UnregisterArrayConnection(DeformerStringInputs, *this); UE::Groom::Private::UnregisterArrayConnection(DeformerBoolInputs, *this); UE::Groom::Private::UnregisterArrayConnection(DeformerTransformInputs, *this); UE::Groom::Private::UnregisterArrayConnection(DeformerNumericArrays, *this); UE::Groom::Private::UnregisterArrayConnection(DeformerVectorArrays, *this); UE::Groom::Private::UnregisterArrayConnection(DeformerStringArrays, *this); UE::Groom::Private::UnregisterArrayConnection(DeformerBoolArrays, *this); UE::Groom::Private::UnregisterArrayConnection(DeformerTransformArrays, *this); } else { ensureAlways((DeformerNumericInputs.Num() + DeformerVectorInputs.Num() + DeformerStringInputs.Num() + DeformerBoolInputs.Num() + DeformerTransformInputs.Num() + DeformerNumericArrays.Num() + DeformerVectorArrays.Num() + DeformerStringArrays.Num() + DeformerBoolArrays.Num() + DeformerTransformArrays.Num() + 2)== GetNumInputs()); } } }