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

330 lines
7.5 KiB
C++
Raw Normal View History

2023-07-03 16:17:13 +00:00
// Copyright 2020 Phyronnaz
#include "VoxelGraphNode_Base.h"
#include "VoxelGraphSchema.h"
#include "VoxelPinCategory.h"
#include "EdGraph/EdGraphSchema.h"
#include "EdGraph/EdGraphPin.h"
#include "EdGraph/EdGraph.h"
TArray<UEdGraphPin*> UVoxelGraphNode_Base::GetOutputPins() const
{
return Pins.FilterByPredicate([&](const UEdGraphPin* Pin) { return Pin->Direction == EGPD_Output; });
}
TArray<UEdGraphPin*> UVoxelGraphNode_Base::GetInputPins() const
{
return Pins.FilterByPredicate([&](const UEdGraphPin* Pin) { return Pin->Direction == EGPD_Input; });
}
UEdGraphPin* UVoxelGraphNode_Base::GetInputPin(int32 InputIndex)
{
check(InputIndex >= 0 && InputIndex < GetInputCount());
for (int32 PinIndex = 0, FoundInputs = 0; PinIndex < Pins.Num(); PinIndex++)
{
if (Pins[PinIndex]->Direction == EGPD_Input)
{
if (InputIndex == FoundInputs)
{
return Pins[PinIndex];
}
else
{
FoundInputs++;
}
}
}
return nullptr;
}
UEdGraphPin* UVoxelGraphNode_Base::GetOutputPin(int32 OutputIndex)
{
check(OutputIndex >= 0 && OutputIndex < GetOutputCount());
for (int32 PinIndex = 0, FoundOutputs = 0; PinIndex < Pins.Num(); PinIndex++)
{
if (Pins[PinIndex]->Direction == EGPD_Output)
{
if (OutputIndex == FoundOutputs)
{
return Pins[PinIndex];
}
else
{
FoundOutputs++;
}
}
}
return nullptr;
}
int32 UVoxelGraphNode_Base::GetInputPinIndex(const UEdGraphPin* Pin) const
{
for (int32 PinIndex = 0, FoundInputs = 0; PinIndex < Pins.Num(); PinIndex++)
{
if (Pins[PinIndex]->Direction == EGPD_Input)
{
if (Pins[PinIndex] == Pin)
{
return FoundInputs;
}
else
{
FoundInputs++;
}
}
}
return -1;
}
int32 UVoxelGraphNode_Base::GetOutputPinIndex(const UEdGraphPin* Pin) const
{
for (int32 PinIndex = 0, FoundOutputs = 0; PinIndex < Pins.Num(); PinIndex++)
{
if (Pins[PinIndex]->Direction == EGPD_Output)
{
if (Pins[PinIndex] == Pin)
{
return FoundOutputs;
}
else
{
FoundOutputs++;
}
}
}
return -1;
}
int32 UVoxelGraphNode_Base::GetInputCount() const
{
int32 InputCount = 0;
for (int32 PinIndex = 0; PinIndex < Pins.Num(); PinIndex++)
{
if (Pins[PinIndex]->Direction == EGPD_Input)
{
InputCount++;
}
}
return InputCount;
}
int32 UVoxelGraphNode_Base::GetOutputCount() const
{
int32 OutputCount = 0;
for (int32 PinIndex = 0; PinIndex < Pins.Num(); PinIndex++)
{
if (Pins[PinIndex]->Direction == EGPD_Output)
{
OutputCount++;
}
}
return OutputCount;
}
void UVoxelGraphNode_Base::InsertNewNode(UEdGraphPin* FromPin, UEdGraphPin* NewLinkPin, TSet<UEdGraphNode*>& OutNodeList)
{
const UVoxelGraphSchema* Schema = CastChecked<UVoxelGraphSchema>(GetSchema());
// The pin we are creating from already has a connection that needs to be broken. We want to "insert" the new node in between, so that the output of the new node is hooked up too
UEdGraphPin* OldLinkedPin = FromPin->LinkedTo[0];
check(OldLinkedPin);
FromPin->BreakAllPinLinks();
// Hook up the old linked pin to the first valid output pin on the new node
for (int32 OutpinPinIdx = 0; OutpinPinIdx < Pins.Num(); OutpinPinIdx++)
{
UEdGraphPin* OutputExecPin = Pins[OutpinPinIdx];
check(OutputExecPin);
if (ECanCreateConnectionResponse::CONNECT_RESPONSE_MAKE == Schema->CanCreateConnection(OldLinkedPin, OutputExecPin).Response)
{
if (Schema->TryCreateConnection(OldLinkedPin, OutputExecPin))
{
OutNodeList.Add(OldLinkedPin->GetOwningNode());
OutNodeList.Add(this);
}
break;
}
}
if (Schema->TryCreateConnection(FromPin, NewLinkPin))
{
OutNodeList.Add(FromPin->GetOwningNode());
OutNodeList.Add(this);
}
}
void UVoxelGraphNode_Base::AllocateDefaultPins()
{
check(Pins.Num() == 0);
CreateInputPins();
CreateOutputPins();
}
inline bool MovePin(UEdGraphPin* OldPin, UEdGraphPin* NewPin)
{
const auto OldType = FVoxelPinCategory::FromString(OldPin->PinType.PinCategory);
const auto NewType = FVoxelPinCategory::FromString(NewPin->PinType.PinCategory);
if (OldType == NewType ||
OldType == EVoxelPinCategory::Wildcard ||
NewType == EVoxelPinCategory::Wildcard)
{
NewPin->MovePersistentDataFromOldPin(*OldPin);
return true;
}
else
{
return false;
}
}
inline void MovePins(const TArray<UEdGraphPin*>& OldPins, const TArray<UEdGraphPin*>& NewPins)
{
TSet<UEdGraphPin*> MovedOldPins;
TSet<UEdGraphPin*> MovedNewPins;
// Tricky case: renaming a macro node pin
// First try the PinId
for (auto* OldPin : OldPins)
{
UEdGraphPin* const * NewPinPtr = nullptr;
if (!NewPinPtr)
{
NewPinPtr = NewPins.FindByPredicate([&](auto* NewPin) { return NewPin->PinId == OldPin->PinId; });
}
if (NewPinPtr)
{
auto* NewPin = *NewPinPtr;
if (!MovedNewPins.Contains(NewPin) && MovePin(OldPin, NewPin))
{
MovedOldPins.Add(OldPin);
MovedNewPins.Add(NewPin);
}
}
}
// Else use the index
for (int32 Index = 0; Index < OldPins.Num(); Index++)
{
auto* OldPin = OldPins[Index];
if (!MovedOldPins.Contains(OldPin) && NewPins.IsValidIndex(Index))
{
auto* NewPin = NewPins[Index];
if (!MovedNewPins.Contains(NewPin) && MovePin(OldPin, NewPin))
{
MovedOldPins.Add(OldPin);
MovedNewPins.Add(NewPin);
}
}
}
}
void UVoxelGraphNode_Base::ReconstructNode()
{
Super::ReconstructNode();
if (!ensure(this))
{
return;
}
Modify();
// Break any links to 'orphan' pins
for (auto& Pin : Pins)
{
for (auto& OtherPin : Pin->LinkedTo)
{
// If we are linked to a pin that its owner doesn't know about, break that link
if (!OtherPin->GetOwningNode()->Pins.Contains(OtherPin))
{
Pin->LinkedTo.Remove(OtherPin);
}
}
}
// Store the old Input and Output pins
const TArray<UEdGraphPin*> OldInputPins = GetInputPins();
const TArray<UEdGraphPin*> OldOutputPins = GetOutputPins();
// Move the existing pins to a saved array
const TArray<UEdGraphPin*> OldPins = Pins;
Pins.Reset();
// Recreate the new pins
AllocateDefaultPins();
// Restore vector pins
RestoreVectorPins(OldInputPins, OldOutputPins);
// Get new Input and Output pins
const TArray<UEdGraphPin*> NewInputPins = GetInputPins();
const TArray<UEdGraphPin*> NewOutputPins = GetOutputPins();
MovePins(OldInputPins, NewInputPins);
MovePins(OldOutputPins, NewOutputPins);
// Throw away the original pins
for (UEdGraphPin* OldPin : OldPins)
{
OldPin->Modify();
UEdGraphNode::DestroyPin(OldPin);
}
GetGraph()->NotifyGraphChanged();
}
void UVoxelGraphNode_Base::AutowireNewNode(UEdGraphPin* FromPin)
{
if (FromPin != NULL)
{
const UVoxelGraphSchema* Schema = CastChecked<UVoxelGraphSchema>(GetSchema());
TSet<UEdGraphNode*> NodeList;
// auto-connect from dragged pin to first compatible pin on the new node
for (int32 i = 0; i < Pins.Num(); i++)
{
UEdGraphPin* Pin = Pins[i];
check(Pin);
FPinConnectionResponse Response = Schema->CanCreateConnection(FromPin, Pin);
if (ECanCreateConnectionResponse::CONNECT_RESPONSE_MAKE == Response.Response)
{
if (Schema->TryCreateConnection(FromPin, Pin))
{
NodeList.Add(FromPin->GetOwningNode());
NodeList.Add(this);
}
break;
}
else if (ECanCreateConnectionResponse::CONNECT_RESPONSE_BREAK_OTHERS_A == Response.Response)
{
InsertNewNode(FromPin, Pin, NodeList);
break;
}
}
// Send all nodes that received a new pin connection a notification
for (auto It = NodeList.CreateConstIterator(); It; ++It)
{
UEdGraphNode* Node = (*It);
Node->NodeConnectionListChanged();
}
}
}
bool UVoxelGraphNode_Base::CanCreateUnderSpecifiedSchema(const UEdGraphSchema* Schema) const
{
return Schema->IsA(UVoxelGraphSchema::StaticClass());
}