Files
UnrealEngine/Engine/Source/Editor/PhysicsAssetEditor/Private/PhysicsAssetGraph/PhysicsAssetGraphSchema.cpp
2025-05-18 13:04:45 +08:00

218 lines
8.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "PhysicsAssetGraph/PhysicsAssetGraphSchema.h"
#include "Toolkits/GlobalEditorCommonCommands.h"
#include "PhysicsAssetGraph/PhysicsAssetGraph.h"
#include "PhysicsAssetGraph/PhysicsAssetGraphNode_Bone.h"
#include "PhysicsEngine/PhysicsAsset.h"
#include "PhysicsAssetGraph/PhysicsAssetConnectionDrawingPolicy.h"
#include "PhysicsAssetGraph/PhysicsAssetGraphNode_Constraint.h"
#include "PhysicsAssetGraph/PhysicsAssetGraph.h"
#include "PhysicsAssetEditor.h"
#include "ToolMenus.h"
#define LOCTEXT_NAMESPACE "PhysicsAssetGraphSchema"
UPhysicsAssetGraphSchema::UPhysicsAssetGraphSchema(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void UPhysicsAssetGraphSchema::GetContextMenuActions(UToolMenu* Menu, UGraphNodeContextMenuContext* Context) const
{
Menu->AddDynamicSection("PhysicsAssetGraphSchema", FNewToolMenuDelegateLegacy::CreateLambda([](FMenuBuilder& MenuBuilder, UToolMenu* InMenu)
{
UGraphNodeContextMenuContext* ContextObject = InMenu->FindContext<UGraphNodeContextMenuContext>();
if (!ContextObject)
{
return;
}
const UPhysicsAssetGraph* PhysicsAssetGraph = CastChecked<const UPhysicsAssetGraph>(ContextObject->Graph);
TSharedPtr<FPhysicsAssetEditorSharedData> SharedData = PhysicsAssetGraph->GetPhysicsAssetEditor()->GetSharedData();
if (const UPhysicsAssetGraphNode_Constraint* ConstraintNode = Cast<const UPhysicsAssetGraphNode_Constraint>(ContextObject->Node))
{
PhysicsAssetGraph->GetPhysicsAssetEditor()->BuildMenuWidgetConstraint(MenuBuilder);
}
else if (const UPhysicsAssetGraphNode_Bone* BoneNode = Cast<const UPhysicsAssetGraphNode_Bone>(ContextObject->Node))
{
PhysicsAssetGraph->GetPhysicsAssetEditor()->BuildMenuWidgetBody(MenuBuilder);
}
PhysicsAssetGraph->GetPhysicsAssetEditor()->BuildMenuWidgetSelection(MenuBuilder);
}));
}
FLinearColor UPhysicsAssetGraphSchema::GetPinTypeColor(const FEdGraphPinType& PinType) const
{
return FLinearColor::White;
}
void UPhysicsAssetGraphSchema::BreakPinLinks(UEdGraphPin& TargetPin, bool bSendsNodeNotifcation) const
{
// Don't allow breaking any links
}
void UPhysicsAssetGraphSchema::BreakSinglePinLink(UEdGraphPin* SourcePin, UEdGraphPin* TargetPin) const
{
// Don't allow breaking any links
}
FPinConnectionResponse UPhysicsAssetGraphSchema::MovePinLinks(UEdGraphPin& MoveFromPin, UEdGraphPin& MoveToPin, bool bIsIntermediateMove, bool bNotifyLinkedNodes) const
{
// Don't allow moving any links
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT(""));
}
FPinConnectionResponse UPhysicsAssetGraphSchema::CopyPinLinks(UEdGraphPin& CopyFromPin, UEdGraphPin& CopyToPin, bool bIsIntermediateCopy) const
{
// Don't allow copying any links
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, TEXT(""));
}
FConnectionDrawingPolicy* UPhysicsAssetGraphSchema::CreateConnectionDrawingPolicy(int32 InBackLayerID, int32 InFrontLayerID, float InZoomFactor, const FSlateRect& InClippingRect, class FSlateWindowElementList& InDrawElements, class UEdGraph* InGraphObj) const
{
return new FPhysicsAssetConnectionDrawingPolicy(InBackLayerID, InFrontLayerID, InZoomFactor, InClippingRect, InDrawElements);
}
UPhysicsAssetGraphNode_Bone* UPhysicsAssetGraphSchema::CreateGraphNodesForBone(UPhysicsAssetGraph* InGraph, USkeletalBodySetup* InBodySetup, int32 InBodyIndex, UPhysicsAsset* InPhysicsAsset) const
{
const bool bSelectNewNode = false;
FGraphNodeCreator<UPhysicsAssetGraphNode_Bone> GraphNodeCreator(*InGraph);
UPhysicsAssetGraphNode_Bone* BoneNode = GraphNodeCreator.CreateNode(bSelectNewNode);
GraphNodeCreator.Finalize();
BoneNode->SetupBoneNode(InBodySetup, InBodyIndex, InPhysicsAsset);
return BoneNode;
}
UPhysicsAssetGraphNode_Constraint* UPhysicsAssetGraphSchema::CreateGraphNodesForConstraint(UPhysicsAssetGraph* InGraph, UPhysicsConstraintTemplate* InConstraint, int32 InConstraintIndex, UPhysicsAsset* InPhysicsAsset) const
{
const bool bSelectNewNode = false;
FGraphNodeCreator<UPhysicsAssetGraphNode_Constraint> GraphNodeCreator(*InGraph);
UPhysicsAssetGraphNode_Constraint* ConstraintNode = GraphNodeCreator.CreateNode(bSelectNewNode);
GraphNodeCreator.Finalize();
ConstraintNode->SetupConstraintNode(InConstraint, InConstraintIndex, InPhysicsAsset);
return ConstraintNode;
}
void UPhysicsAssetGraphSchema::LayoutNodes(UPhysicsAssetGraph* InGraph, UPhysicsAsset* InPhysicsAsset) const
{
const int32 NodeMarginX = 20;
const int32 NodeMarginY = 5;
const TArray<UPhysicsAssetGraphNode_Bone*>& RootNodes = InGraph->GetRootNodes();
if (RootNodes.Num() > 0)
{
int32 CurrentColumnX = 0;
// Lay out root nodes
float MaxWidth = 0.0f;
int32 CurrentYOffset = 0;
int32 TotalRootY = 0;
for (int32 RootNodeIndex = 0; RootNodeIndex < RootNodes.Num(); ++RootNodeIndex)
{
UPhysicsAssetGraphNode_Bone* RootNode = RootNodes[RootNodeIndex];
TotalRootY += (int32)RootNode->GetDimensions().Y + NodeMarginY;
}
for (int32 RootNodeIndex = 0; RootNodeIndex < RootNodes.Num(); ++RootNodeIndex)
{
UPhysicsAssetGraphNode_Bone* RootNode = RootNodes[RootNodeIndex];
RootNode->NodePosX = CurrentColumnX;
RootNode->NodePosY = CurrentYOffset - (TotalRootY / 2);
CurrentYOffset += (int32)RootNode->GetDimensions().Y + NodeMarginY;
MaxWidth = FMath::Max(MaxWidth, RootNode->GetDimensions().X);
}
CurrentColumnX += (MaxWidth + NodeMarginX);
// Lay out constraints
MaxWidth = 0.0f;
CurrentYOffset = 0;
int32 TotalConstraintY = 0;
TArray<UPhysicsAssetGraphNode_Constraint*> ConstraintNodes;
for (UEdGraphNode* Node : InGraph->Nodes)
{
if (UPhysicsAssetGraphNode_Constraint* ConstraintNode = Cast<UPhysicsAssetGraphNode_Constraint>(Node))
{
ConstraintNodes.Add(ConstraintNode);
TotalConstraintY += (int32)ConstraintNode->GetDimensions().Y + NodeMarginY;
}
}
float ConstraintCount = ConstraintNodes.Num();
for (int32 ConstraintIndex = 0; ConstraintIndex < ConstraintNodes.Num(); ++ConstraintIndex)
{
UPhysicsAssetGraphNode_Constraint* ConstraintNode = ConstraintNodes[ConstraintIndex];
ConstraintNode->NodePosX = CurrentColumnX;
ConstraintNode->NodePosY = CurrentYOffset - (TotalConstraintY / 2);
CurrentYOffset += (int32)ConstraintNode->GetDimensions().Y + NodeMarginY;
MaxWidth = FMath::Max(MaxWidth, ConstraintNode->GetDimensions().X);
}
CurrentColumnX += (MaxWidth + NodeMarginX);
// now layout linked nodes
MaxWidth = 0.0f;
CurrentYOffset = 0;
int32 TotalLinkedNodeY = 0;
TArray<UPhysicsAssetGraphNode_Bone*> LinkedNodes;
for (int32 ConstraintIndex = 0; ConstraintIndex < ConstraintNodes.Num(); ++ConstraintIndex)
{
UPhysicsAssetGraphNode_Constraint* ConstraintNode = ConstraintNodes[ConstraintIndex];
if (ConstraintNode->GetOutputPin().LinkedTo.Num() > 0)
{
for(UEdGraphPin* LinkedPin : ConstraintNode->GetOutputPin().LinkedTo)
{
UPhysicsAssetGraphNode_Bone* BoneNode = CastChecked<UPhysicsAssetGraphNode_Bone>(LinkedPin->GetOwningNode());
LinkedNodes.AddUnique(BoneNode);
TotalLinkedNodeY += (int32)BoneNode->GetDimensions().Y + NodeMarginY;
}
}
}
for (int32 LinkedNodeIndex = 0; LinkedNodeIndex < LinkedNodes.Num(); ++LinkedNodeIndex)
{
UPhysicsAssetGraphNode_Bone* LinkedNode = LinkedNodes[LinkedNodeIndex];
LinkedNode->NodePosX = CurrentColumnX;
LinkedNode->NodePosY = CurrentYOffset - (TotalLinkedNodeY / 2);
CurrentYOffset += (int32)LinkedNode->GetDimensions().Y + NodeMarginY;
MaxWidth = FMath::Max(MaxWidth, LinkedNode->GetDimensions().X);
}
}
}
const FPinConnectionResponse UPhysicsAssetGraphSchema::CanCreateConnection(const UEdGraphPin* A, const UEdGraphPin* B) const
{
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("HowToMakeANewConstraint", "Drag from the output pin of a body and drop on\nempty space to create a new constraint"));
}
FPinConnectionResponse UPhysicsAssetGraphSchema::CanCreateNewNodes(UEdGraphPin* InSourcePin) const
{
if(UPhysicsAssetGraphNode_Bone* PhysicsAssetGraphNode = Cast<UPhysicsAssetGraphNode_Bone>(InSourcePin->GetOwningNode()))
{
if(InSourcePin->Direction == EGPD_Output)
{
return FPinConnectionResponse(CONNECT_RESPONSE_MAKE, LOCTEXT("MakeANewConstraint", "Create a new constraint"));
}
}
return FPinConnectionResponse(CONNECT_RESPONSE_DISALLOW, LOCTEXT("HowToMakeANewConstraint", "Drag from the output pin of a body and drop on\nempty space to create a new constraint"));
}
bool UPhysicsAssetGraphSchema::SupportsDropPinOnNode(UEdGraphNode* InTargetNode, const FEdGraphPinType& InSourcePinType, EEdGraphPinDirection InSourcePinDirection, FText& OutErrorMessage) const
{
OutErrorMessage = LOCTEXT("HowToMakeANewConstraint", "Drag from the output pin of a body and drop on\nempty space to create a new constraint");
return false;
}
#undef LOCTEXT_NAMESPACE