bool FMaterialEditorUtilities::HasCompatibleConnection(UClass* ExpressionClass, uint32 TestType, EEdGraphPinDirection TestDirection, bool bMaterialFunction) { if (TestType != 0) { UMaterialExpression* DefaultExpression = CastChecked<UMaterialExpression>(ExpressionClass->GetDefaultObject()); if (TestDirection == EGPD_Output) { int32 NumInputs = DefaultExpression->GetInputs().Num(); for (int32 Index = 0; Index < NumInputs; ++Index) { uint32 InputType = DefaultExpression->GetInputType(Index); if (CanConnectMaterialValueTypes(InputType, TestType)) { return true; } } } else { int32 NumOutputs = DefaultExpression->GetOutputs().Num(); for (int32 Index = 0; Index < NumOutputs; ++Index) { uint32 OutputType = DefaultExpression->GetOutputType(Index); if (CanConnectMaterialValueTypes(TestType, OutputType)) { return true; } } } if (bMaterialFunction) { // Specific test as Default object won't have texture input if (ExpressionClass == UMaterialExpressionTextureSample::StaticClass() && TestType & MCT_Texture && TestDirection == EGPD_Output) { return true; } // Always allow creation of new inputs as they can take any type else if (ExpressionClass == UMaterialExpressionFunctionInput::StaticClass()) { return true; } // Allow creation of outputs for floats and material attributes else if (ExpressionClass == UMaterialExpressionFunctionOutput::StaticClass() && TestType & (MCT_Float|MCT_MaterialAttributes)) { return true; } } } return false; }
void UMaterialGraph::LinkGraphNodesFromMaterial() { for (int32 Index = 0; Index < Nodes.Num(); ++Index) { Nodes[Index]->BreakAllNodeLinks(); } if (RootNode) { // Use Material Inputs to make GraphNode Connections for (int32 Index = 0; Index < MaterialInputs.Num(); ++Index) { UEdGraphPin* InputPin = RootNode->GetInputPin(Index); auto ExpressionInput = MaterialInputs[Index].GetExpressionInput(Material); if (ExpressionInput.Expression) { UMaterialGraphNode* GraphNode = CastChecked<UMaterialGraphNode>(ExpressionInput.Expression->GraphNode); InputPin->MakeLinkTo(GraphNode->GetOutputPin(GetValidOutputIndex(&ExpressionInput))); } } } for (int32 Index = 0; Index < Material->Expressions.Num(); Index++) { UMaterialExpression* Expression = Material->Expressions[Index]; if (Expression) { const TArray<FExpressionInput*> ExpressionInputs = Expression->GetInputs(); for (int32 InputIndex = 0; InputIndex < ExpressionInputs.Num(); ++InputIndex) { UEdGraphPin* InputPin = CastChecked<UMaterialGraphNode>(Expression->GraphNode)->GetInputPin(InputIndex); if ( ExpressionInputs[InputIndex]->Expression) { UMaterialGraphNode* GraphNode = CastChecked<UMaterialGraphNode>(ExpressionInputs[InputIndex]->Expression->GraphNode); InputPin->MakeLinkTo(GraphNode->GetOutputPin(GetValidOutputIndex(ExpressionInputs[InputIndex]))); } } } } NotifyGraphChanged(); }
void UMaterialGraph::LinkMaterialExpressionsFromGraph() const { // Use GraphNodes to make Material Expression Connections TArray<UEdGraphPin*> InputPins; TArray<UEdGraphPin*> OutputPins; for (int32 NodeIndex = 0; NodeIndex < Nodes.Num(); ++NodeIndex) { if (RootNode && RootNode == Nodes[NodeIndex]) { // Setup Material's inputs from root node Material->Modify(); InputPins = RootNode->Pins; Material->EditorX = RootNode->NodePosX; Material->EditorY = RootNode->NodePosY; check(InputPins.Num() == MaterialInputs.Num()); for (int32 PinIndex = 0; PinIndex < InputPins.Num() && PinIndex < MaterialInputs.Num(); ++PinIndex) { FExpressionInput& MaterialInput = MaterialInputs[PinIndex].GetExpressionInput(Material); if (InputPins[PinIndex]->LinkedTo.Num() > 0) { UMaterialGraphNode* ConnectedNode = CastChecked<UMaterialGraphNode>(InputPins[PinIndex]->LinkedTo[0]->GetOwningNode()); ConnectedNode->GetOutputPins(OutputPins); // Work out the index of the connected pin for (int32 OutPinIndex = 0; OutPinIndex < OutputPins.Num(); ++OutPinIndex) { if (OutputPins[OutPinIndex] == InputPins[PinIndex]->LinkedTo[0]) { if (MaterialInput.OutputIndex != OutPinIndex || MaterialInput.Expression != ConnectedNode->MaterialExpression) { ConnectedNode->MaterialExpression->Modify(); MaterialInput.Connect(OutPinIndex, ConnectedNode->MaterialExpression); } break; } } } else if (MaterialInput.Expression) { MaterialInput.Expression = NULL; } } } else { if (UMaterialGraphNode* GraphNode = Cast<UMaterialGraphNode>(Nodes[NodeIndex])) { // Need to be sure that we are changing the expression before calling modify - // triggers a rebuild of its preview when it is called UMaterialExpression* Expression = GraphNode->MaterialExpression; bool bModifiedExpression = false; if (Expression->MaterialExpressionEditorX != GraphNode->NodePosX || Expression->MaterialExpressionEditorY != GraphNode->NodePosY || Expression->Desc != GraphNode->NodeComment) { bModifiedExpression = true; Expression->Modify(); // Update positions and comments Expression->MaterialExpressionEditorX = GraphNode->NodePosX; Expression->MaterialExpressionEditorY = GraphNode->NodePosY; Expression->Desc = GraphNode->NodeComment; } GraphNode->GetInputPins(InputPins); const TArray<FExpressionInput*> ExpressionInputs = Expression->GetInputs(); checkf(InputPins.Num() == ExpressionInputs.Num(), TEXT("Mismatched inputs for '%s'"), *Expression->GetFullName()); for (int32 PinIndex = 0; PinIndex < InputPins.Num() && PinIndex < ExpressionInputs.Num(); ++PinIndex) { FExpressionInput* ExpressionInput = ExpressionInputs[PinIndex]; if (InputPins[PinIndex]->LinkedTo.Num() > 0) { UMaterialGraphNode* ConnectedNode = CastChecked<UMaterialGraphNode>(InputPins[PinIndex]->LinkedTo[0]->GetOwningNode()); ConnectedNode->GetOutputPins(OutputPins); // Work out the index of the connected pin for (int32 OutPinIndex = 0; OutPinIndex < OutputPins.Num(); ++OutPinIndex) { if (OutputPins[OutPinIndex] == InputPins[PinIndex]->LinkedTo[0]) { if (ExpressionInput->OutputIndex != OutPinIndex || ExpressionInput->Expression != ConnectedNode->MaterialExpression) { if (!bModifiedExpression) { bModifiedExpression = true; Expression->Modify(); } ConnectedNode->MaterialExpression->Modify(); ExpressionInput->Connect(OutPinIndex, ConnectedNode->MaterialExpression); } break; } } } else if (ExpressionInput->Expression) { if (!bModifiedExpression) { bModifiedExpression = true; Expression->Modify(); } ExpressionInput->Expression = NULL; } } } else if (UMaterialGraphNode_Comment* CommentNode = Cast<UMaterialGraphNode_Comment>(Nodes[NodeIndex])) { UMaterialExpressionComment* Comment = CommentNode->MaterialExpressionComment; if (Comment->MaterialExpressionEditorX != CommentNode->NodePosX || Comment->MaterialExpressionEditorY != CommentNode->NodePosY || Comment->Text != CommentNode->NodeComment || Comment->SizeX != CommentNode->NodeWidth || Comment->SizeY != CommentNode->NodeHeight || Comment->CommentColor != CommentNode->CommentColor) { Comment->Modify(); // Update positions and comments Comment->MaterialExpressionEditorX = CommentNode->NodePosX; Comment->MaterialExpressionEditorY = CommentNode->NodePosY; Comment->Text = CommentNode->NodeComment; Comment->SizeX = CommentNode->NodeWidth; Comment->SizeY = CommentNode->NodeHeight; Comment->CommentColor = CommentNode->CommentColor; } } } } }