CelticCraft/Plugins/VoxelFree/Source/VoxelGraphEditor/Private/VoxelGraphNodes/VoxelGraphNode_Knot.cpp

238 lines
No EOL
5.5 KiB
C++

// Copyright 2020 Phyronnaz
#include "VoxelGraphNode_Knot.h"
#include "EdGraph/EdGraphPin.h"
#include "VoxelPinCategory.h"
const static FName Wildcard(FVoxelPinCategory::GetName(EVoxelPinCategory::Wildcard));
void UVoxelGraphNode_Knot::CreateInputPins()
{
UEdGraphPin* InputPin = CreatePin(EGPD_Input, Wildcard, "InputPin");
InputPin->bDefaultValueIsIgnored = true;
}
void UVoxelGraphNode_Knot::CreateOutputPins()
{
CreatePin(EGPD_Output, Wildcard, "OutputPin");
}
void UVoxelGraphNode_Knot::ReconstructNode()
{
Super::ReconstructNode();
PropagatePinType();
}
FText UVoxelGraphNode_Knot::GetTooltipText() const
{
return VOXEL_LOCTEXT("Reroute Node (reroutes wires)");
}
FText UVoxelGraphNode_Knot::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
if (TitleType == ENodeTitleType::EditableTitle)
{
return FText::FromString(NodeComment);
}
else if (TitleType == ENodeTitleType::MenuTitle)
{
return VOXEL_LOCTEXT("Add Reroute Node...");
}
else
{
return VOXEL_LOCTEXT("Reroute Node");
}
}
bool UVoxelGraphNode_Knot::CanSplitPin(const UEdGraphPin* Pin) const
{
return false;
}
void UVoxelGraphNode_Knot::PropagatePinType()
{
UEdGraphPin* InputPin = GetInputPin();
UEdGraphPin* OutputPin = GetOutputPin();
for (UEdGraphPin* Inputs : InputPin->LinkedTo)
{
if (Inputs->PinType.PinCategory != Wildcard)
{
PropagatePinTypeFromInput();
return;
}
}
for (UEdGraphPin* Outputs : OutputPin->LinkedTo)
{
if (Outputs->PinType.PinCategory != Wildcard)
{
PropagatePinTypeFromOutput();
return;
}
}
// if all inputs/outputs are wildcards, still favor the inputs first (propagate array/reference/etc. state)
if (InputPin->LinkedTo.Num() > 0)
{
// If we can't mirror from output type, we should at least get the type information from the input connection chain
PropagatePinTypeFromInput();
}
else if (OutputPin->LinkedTo.Num() > 0)
{
// Try to mirror from output first to make sure we get appropriate member references
PropagatePinTypeFromOutput();
}
else
{
// Revert to wildcard
InputPin->BreakAllPinLinks();
InputPin->PinType.ResetToDefaults();
InputPin->PinType.PinCategory = Wildcard;
OutputPin->BreakAllPinLinks();
OutputPin->PinType.ResetToDefaults();
OutputPin->PinType.PinCategory = Wildcard;
}
}
TArray<UEdGraphPin*> UVoxelGraphNode_Knot::GetAllInputPins()
{
TArray<UEdGraphPin*> KnotRecursiveInputPins;
{
TArray<UVoxelGraphNode_Knot*> KnotsToProcess;
KnotsToProcess.Add(this);
while (KnotsToProcess.Num() > 0)
{
auto CurrentKnot = KnotsToProcess.Pop();
auto InputPin = CurrentKnot->GetInputPin();
for (auto& Pin : InputPin->LinkedTo)
{
auto Knot = Cast<UVoxelGraphNode_Knot>(Pin->GetOwningNode());
if (Knot)
{
KnotsToProcess.Add(Knot);
}
else
{
KnotRecursiveInputPins.Add(Pin);
}
}
}
}
return KnotRecursiveInputPins;
}
TArray<UEdGraphPin*> UVoxelGraphNode_Knot::GetAllOutputPins()
{
TArray<UEdGraphPin*> KnotRecursiveOutputPins;
{
TArray<UVoxelGraphNode_Knot*> KnotsToProcess;
KnotsToProcess.Add(this);
while (KnotsToProcess.Num() > 0)
{
auto CurrentKnot = KnotsToProcess.Pop();
auto OutputPin = CurrentKnot->GetOutputPin();
for (auto& Pin : OutputPin->LinkedTo)
{
auto Knot = Cast<UVoxelGraphNode_Knot>(Pin->GetOwningNode());
if (Knot)
{
KnotsToProcess.Add(Knot);
}
else
{
KnotRecursiveOutputPins.Add(Pin);
}
}
}
}
return KnotRecursiveOutputPins;
}
void UVoxelGraphNode_Knot::PropagatePinTypeFromInput()
{
if (bRecursionGuard)
{
return;
}
// Set the type of the pin based on input connections.
// We have to move up the chain of linked reroute nodes until we reach a node
// with type information before percolating that information down.
UEdGraphPin* MyInputPin = GetInputPin();
UEdGraphPin* MyOutputPin = GetOutputPin();
TGuardValue<bool> RecursionGuard(bRecursionGuard, true);
for (UEdGraphPin* InPin : MyInputPin->LinkedTo)
{
if (UVoxelGraphNode_Knot* KnotNode = Cast<UVoxelGraphNode_Knot>(InPin->GetOwningNode()))
{
KnotNode->PropagatePinTypeFromInput();
}
}
UEdGraphPin* TypeSource = MyInputPin->LinkedTo.Num() ? MyInputPin->LinkedTo[0] : nullptr;
if (TypeSource)
{
MyInputPin->PinType = TypeSource->PinType;
MyOutputPin->PinType = TypeSource->PinType;
}
}
void UVoxelGraphNode_Knot::PropagatePinTypeFromOutput()
{
if (bRecursionGuard)
{
return;
}
// Set the type of the pin based on the output connection, and then percolate
// that type information up until we no longer reach another Reroute node
UEdGraphPin* InputPin = GetInputPin();
UEdGraphPin* OutputPin = GetOutputPin();
TGuardValue<bool> RecursionGuard(bRecursionGuard, true);
for (UEdGraphPin* InPin : OutputPin->LinkedTo)
{
if (UVoxelGraphNode_Knot* KnotNode = Cast<UVoxelGraphNode_Knot>(InPin->GetOwningNode()))
{
KnotNode->PropagatePinTypeFromOutput();
}
}
UEdGraphPin* TypeSource = OutputPin->LinkedTo.Num() ? OutputPin->LinkedTo[0] : nullptr;
if (TypeSource)
{
InputPin->PinType = TypeSource->PinType;
OutputPin->PinType = TypeSource->PinType;
}
}
bool UVoxelGraphNode_Knot::ShouldOverridePinNames() const
{
return true;
}
FText UVoxelGraphNode_Knot::GetPinNameOverride(const UEdGraphPin& Pin) const
{
// Keep the pin size tiny
return FText::GetEmpty();
}
void UVoxelGraphNode_Knot::OnRenameNode(const FString& NewName)
{
NodeComment = NewName;
}
UEdGraphPin* UVoxelGraphNode_Knot::GetPassThroughPin(const UEdGraphPin* FromPin) const
{
if (FromPin && Pins.Contains(FromPin))
{
return FromPin == Pins[0] ? Pins[1] : Pins[0];
}
return nullptr;
}