Files
UnrealEngineUWP/Engine/Source/Editor/AnimGraph/Private/AnimGraphNode_BoneDrivenController.cpp
lina halper 93d3255859 Copying //UE4/Dev-Anim to //UE4/Dev-Main (Source: //UE4/Dev-Anim [at] 4335583)
#lockdown Nick.Penwarden
#rb:none
============================
  MAJOR FEATURES & CHANGES
============================

Change 4300079 by Thomas.Sarkanen

	Fixed incorrect sub instance error reporting when multiple sub-instances of the same class are used

	#jira UE-62613 - Using a Sub Anim Instance causes a "Sub Instance Loop" Compile Error

Change 4301787 by Lina.Halper

	Fix crash when multi select with bone driven controller

	- make sure you can't continue with mismatching types of classes, code becomes very vulnerable

	#jira: UE-58531

Change 4302310 by Lina.Halper

	Fix for anim slot window of small icons

	#jira: UE-54822

Change 4302385 by Lina.Halper

	remove constructor female data from control rig example

Change 4303861 by Lina.Halper

	PR #4298: Avoid division by 0 in AnimLinkableElement (Contributed by DSDambuster)


	#jira: UE-53260

Change 4304915 by Lina.Halper

	PR #4842: UE-52767: UAnimComposite doesn't inherit from UAnimSequence (Contributed by projectgheist)

	Fixes issue with stepping not working with AnimComposite
	- it also loops around


	#jira: UE-61367

Change 4307241 by Lina.Halper

	Control rig : invalid FOV issue

	#jira: UE-62799

Change 4310924 by Lina.Halper

	Only display native control rig class for parent class picker

	#jira: UE-62798

Change 4314164 by Jurre.deBaare

	Fix issue with propagating vertex colors to static meshes in some cases not working correctly
	#fix Using .OverrideVertexColors instead of .OverrideMapBuildData to do pointer comparison

	#jira none

Change 4321197 by Lina.Halper

	fix aim offset assets

	- removed aimtest2 as it doens't really do anything

Change 4321673 by Martin.Wilson

	Autoload Animation Blueprint compiler module in editor so that we can set up logging category (following how normal blueprint compiler works)

	#jira UE-59319

Change 4321898 by Martin.Wilson

	Change Live Link tab to nomad

	#jira UE-54412

Change 4322333 by Thomas.Sarkanen

	Fix additional params being displayed on blutility asset/actor actions dialog

	#jira UE-62063 - Blutility context menu popup shows all pins inside function

Change 4322338 by Thomas.Sarkanen

	Fixed mis-reported HLOD build indicator

	#jira UE-62648 - HLOD cluster needs to be rebuilt even though they have been build

Change 4322368 by Lina.Halper

	fixed build error

Change 4322378 by Lina.Halper

	Fix issue where preview asset is not saved and not loaded unless it's loaded manually

	#jira: UE-63254

Change 4322490 by Lina.Halper

	- added an option to refresh transform as that can solve quick issues where ref pose goes wrong
	- fixed search

	#jira: UE-63136, UE-63181

Change 4322824 by Martin.Wilson

	Fix possible crash due to retarget asset being cleaned up on ULiveLinkInstance

	#jira UE-62265

Change 4325357 by Thomas.Sarkanen

	Perform anim update even when we have zero bones, but still skip evaluation

	This ensures that notifies still get triggered in all update-relevant tick modes, even on dedicated servers.

	#jira UE-63204 - Dedicated servers do not trigger anim notifies in anim sequences

Change 4325358 by Thomas.Sarkanen

	Fix incorrect interpolations when using URO and CopyPoseFromMesh

	This ensures that CopyPoseFromMesh uses the correct target pose to inteprolate to, rather than the already-interpolated output pose.

	#jira UE-62588 - URO is incompatible with CopyPoseFromMesh in certain circumstances

Change 4325552 by Martin.Wilson

	Fix doubling of playrate in marker sync code

	#jira UE-59008

Change 4331507 by Thomas.Sarkanen

	Fixed crash when creating a new notify in certain circumstances

	When creating a notify causes a timing order change, then the timing panel wasnt getting refreshed and was accessing the wrong notify to do its drawing.

	#jira UE-63476 - Editor crashes if you add a notify to montage

#ROBOMERGE-OWNER: jason.bestimt
#ROBOMERGE-SOURCE: CL 4335668 in //UE4/Main/...
#ROBOMERGE-BOT: DEVVR (Main -> Dev-VR)

[CL 4335669 by lina halper in Dev-VR branch]
2018-08-30 20:29:58 -04:00

558 lines
21 KiB
C++

// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
#include "AnimGraphNode_BoneDrivenController.h"
#include "SceneManagement.h"
#include "Components/SkeletalMeshComponent.h"
#include "Widgets/Text/STextBlock.h"
#include "Kismet2/CompilerResultsLog.h"
#include "PropertyHandle.h"
#include "DetailLayoutBuilder.h"
#include "DetailWidgetRow.h"
#include "IDetailPropertyRow.h"
#include "DetailCategoryBuilder.h"
#include "AnimationCustomVersion.h"
#define LOCTEXT_NAMESPACE "A3Nodes"
UAnimGraphNode_BoneDrivenController::UAnimGraphNode_BoneDrivenController(const FObjectInitializer& ObjectInitializer)
:Super(ObjectInitializer)
{
}
void UAnimGraphNode_BoneDrivenController::Serialize(FArchive& Ar)
{
Super::Serialize(Ar);
Ar.UsingCustomVersion(FAnimationCustomVersion::GUID);
const int32 AnimVersion = Ar.CustomVer(FAnimationCustomVersion::GUID);
if (AnimVersion < FAnimationCustomVersion::BoneDrivenControllerRemapping)
{
if (AnimVersion < FAnimationCustomVersion::BoneDrivenControllerMatchingMaya)
{
// The node used to be able to only drive a single component rather than a selection of components
Node.ConvertTargetComponentToBits();
// The old definition of range was clamping the output, rather than the input
if (Node.bUseRange && !FMath::IsNearlyZero(Node.Multiplier))
{
// Before: Output = clamp(Input * Multipler)
// After: Output = clamp(Input) * Multiplier
Node.RangeMin /= Node.Multiplier;
Node.RangeMax /= Node.Multiplier;
}
}
Node.RemappedMin = Node.RangeMin;
Node.RemappedMax = Node.RangeMax;
}
}
FText UAnimGraphNode_BoneDrivenController::GetTooltipText() const
{
return LOCTEXT("UAnimGraphNode_BoneDrivenController_ToolTip", "Drives the transform of a bone or morph target using the transform of another bone");
}
FText UAnimGraphNode_BoneDrivenController::GetNodeTitle(ENodeTitleType::Type TitleType) const
{
if ((Node.SourceBone.BoneName == NAME_None) && (Node.TargetBone.BoneName == NAME_None) && ((TitleType == ENodeTitleType::ListView) || (TitleType == ENodeTitleType::MenuTitle)))
{
return GetControllerDescription();
}
else
{
// Determine the mapping
FText FinalSourceExpression;
{
FFormatNamedArguments SourceArgs;
SourceArgs.Add(TEXT("SourceBone"), FText::FromName(Node.SourceBone.BoneName));
SourceArgs.Add(TEXT("SourceComponent"), ComponentTypeToText(Node.SourceComponent));
if (Node.DrivingCurve != nullptr)
{
FinalSourceExpression = LOCTEXT("BoneDrivenByCurve", "curve({SourceBone}.{SourceComponent})");
}
else
{
if (Node.bUseRange)
{
if (Node.Multiplier == 1.0f)
{
FinalSourceExpression = LOCTEXT("WithRangeBoneMultiplierIs1", "remap({SourceBone}.{SourceComponent})");
}
else
{
SourceArgs.Add(TEXT("Multiplier"), FText::AsNumber(Node.Multiplier));
FinalSourceExpression = LOCTEXT("WithRangeNonUnityMultiplier", "remap({SourceBone}.{SourceComponent}) * {Multiplier}");
}
}
else
{
if (Node.Multiplier == 1.0f)
{
FinalSourceExpression = LOCTEXT("BoneMultiplierIs1", "{SourceBone}.{SourceComponent}");
}
else
{
SourceArgs.Add(TEXT("Multiplier"), FText::AsNumber(Node.Multiplier));
FinalSourceExpression = LOCTEXT("NonUnityMultiplier", "{SourceBone}.{SourceComponent} * {Multiplier}");
}
}
}
FinalSourceExpression = FText::Format(FinalSourceExpression, SourceArgs);
}
FFormatNamedArguments Args;
Args.Add(TEXT("ControllerDesc"), GetControllerDescription());
Args.Add(TEXT("ParameterName"), FText::FromName(Node.ParameterName));
Args.Add(TEXT("TargetBone"), FText::FromName(Node.TargetBone.BoneName));
// Determine the target component
int32 NumComponents = 0;
EComponentType::Type TargetComponent = EComponentType::None;
#define UE_CHECK_TARGET_COMPONENT(ComponentProperty, ComponentChoice) if (ComponentProperty) { ++NumComponents; TargetComponent = ComponentChoice; }
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetTranslationX, EComponentType::TranslationX);
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetTranslationY, EComponentType::TranslationY);
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetTranslationZ, EComponentType::TranslationZ);
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetRotationX, EComponentType::RotationX);
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetRotationY, EComponentType::RotationY);
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetRotationZ, EComponentType::RotationZ);
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetScaleX, EComponentType::ScaleX);
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetScaleY, EComponentType::ScaleY);
UE_CHECK_TARGET_COMPONENT(Node.bAffectTargetScaleZ, EComponentType::ScaleZ);
Args.Add(TEXT("TargetComponents"), (NumComponents <= 1) ? ComponentTypeToText(TargetComponent) : LOCTEXT("MultipleTargetComponents", "multiple"));
if ((TitleType == ENodeTitleType::ListView) || (TitleType == ENodeTitleType::MenuTitle))
{
Args.Add(TEXT("Delim"), FText::FromString(TEXT(" - ")));
}
else
{
Args.Add(TEXT("Delim"), FText::FromString(TEXT("\n")));
}
Args.Add(TEXT("SourceExpression"), FinalSourceExpression);
FText FormattedText;
if (Node.DestinationMode == EDrivenDestinationMode::Bone)
{
FormattedText = FText::Format(LOCTEXT("AnimGraphNode_BoneDrivenController_Title_Bone", "{TargetBone}.{TargetComponents} = {SourceExpression}{Delim}{ControllerDesc}"), Args);
}
else if ( Node.DestinationMode == EDrivenDestinationMode::MorphTarget || Node.DestinationMode == EDrivenDestinationMode::MaterialParameter)
{
FormattedText = FText::Format(LOCTEXT("AnimGraphNode_BoneDrivenController_Title_Curve", "{ParameterName} = {SourceExpression}{Delim}{ControllerDesc}"), Args);
}
return FormattedText;
}
}
FText UAnimGraphNode_BoneDrivenController::GetControllerDescription() const
{
return LOCTEXT("BoneDrivenController", "Bone Driven Controller");
}
void UAnimGraphNode_BoneDrivenController::Draw(FPrimitiveDrawInterface* PDI, USkeletalMeshComponent* SkelMeshComp) const
{
static const float ArrowHeadWidth = 5.0f;
static const float ArrowHeadHeight = 8.0f;
const int32 SourceIdx = SkelMeshComp->GetBoneIndex(Node.SourceBone.BoneName);
const int32 TargetIdx = SkelMeshComp->GetBoneIndex(Node.TargetBone.BoneName);
if ((SourceIdx != INDEX_NONE) && (TargetIdx != INDEX_NONE))
{
const FTransform SourceTM = SkelMeshComp->GetComponentSpaceTransforms()[SourceIdx] * SkelMeshComp->GetComponentTransform();
const FTransform TargetTM = SkelMeshComp->GetComponentSpaceTransforms()[TargetIdx] * SkelMeshComp->GetComponentTransform();
PDI->DrawLine(TargetTM.GetLocation(), SourceTM.GetLocation(), FLinearColor(0.0f, 0.0f, 1.0f), SDPG_Foreground, 0.5f);
const FVector ToTarget = TargetTM.GetTranslation() - SourceTM.GetTranslation();
const FVector UnitToTarget = ToTarget.GetSafeNormal();
FVector Midpoint = SourceTM.GetTranslation() + 0.5f * ToTarget + 0.5f * UnitToTarget * ArrowHeadHeight;
FVector YAxis;
FVector ZAxis;
UnitToTarget.FindBestAxisVectors(YAxis, ZAxis);
const FMatrix ArrowMatrix(UnitToTarget, YAxis, ZAxis, Midpoint);
DrawConnectedArrow(PDI, ArrowMatrix, FLinearColor(0.0f, 1.0f, 0.0), ArrowHeadHeight, ArrowHeadWidth, SDPG_Foreground);
PDI->DrawPoint(SourceTM.GetTranslation(), FLinearColor(0.8f, 0.8f, 0.2f), 5.0f, SDPG_Foreground);
PDI->DrawPoint(SourceTM.GetTranslation() + ToTarget, FLinearColor(0.8f, 0.8f, 0.2f), 5.0f, SDPG_Foreground);
}
}
void UAnimGraphNode_BoneDrivenController::ValidateAnimNodeDuringCompilation(USkeleton* ForSkeleton, FCompilerResultsLog& MessageLog)
{
if (ForSkeleton->GetReferenceSkeleton().FindBoneIndex(Node.SourceBone.BoneName) == INDEX_NONE)
{
MessageLog.Warning(*LOCTEXT("DriverJoint_NoSourceBone", "@@ - You must pick a source bone as the Driver joint").ToString(), this);
}
if (Node.SourceComponent == EComponentType::None)
{
MessageLog.Warning(*LOCTEXT("DriverJoint_NoSourceComponent", "@@ - You must pick a source component on the Driver joint").ToString(), this);
}
if (Node.DestinationMode == EDrivenDestinationMode::Bone)
{
if (ForSkeleton->GetReferenceSkeleton().FindBoneIndex(Node.TargetBone.BoneName) == INDEX_NONE)
{
MessageLog.Warning(*LOCTEXT("DriverJoint_NoTargetBone", "@@ - You must pick a target bone as the Driven joint").ToString(), this);
}
const bool bAffectsTranslation = Node.bAffectTargetTranslationX || Node.bAffectTargetTranslationY || Node.bAffectTargetTranslationZ;
const bool bAffectsRotation = Node.bAffectTargetRotationX || Node.bAffectTargetRotationY || Node.bAffectTargetRotationZ;
const bool bAffectsScale = Node.bAffectTargetScaleX || Node.bAffectTargetScaleY || Node.bAffectTargetScaleZ;
if (!bAffectsTranslation && !bAffectsRotation && !bAffectsScale)
{
MessageLog.Warning(*LOCTEXT("DriverJoint_NoTargetComponent", "@@ - You must pick one or more target components on the Driven joint").ToString(), this);
}
}
Super::ValidateAnimNodeDuringCompilation(ForSkeleton, MessageLog);
}
void UAnimGraphNode_BoneDrivenController::AddTripletPropertyRow(const FText& Name, const FText& Tooltip, IDetailCategoryBuilder& Category, TSharedRef<IPropertyHandle> PropertyHandle, const FName XPropertyName, const FName YPropertyName, const FName ZPropertyName, TAttribute<EVisibility> VisibilityAttribute)
{
const float XYZPadding = 5.0f;
TSharedPtr<IPropertyHandle> XProperty = PropertyHandle->GetChildHandle(XPropertyName);
Category.GetParentLayout().HideProperty(XProperty);
TSharedPtr<IPropertyHandle> YProperty = PropertyHandle->GetChildHandle(YPropertyName);
Category.GetParentLayout().HideProperty(YProperty);
TSharedPtr<IPropertyHandle> ZProperty = PropertyHandle->GetChildHandle(ZPropertyName);
Category.GetParentLayout().HideProperty(ZProperty);
Category.AddCustomRow(Name)
.Visibility(VisibilityAttribute)
.NameContent()
[
SNew(STextBlock)
.Text(Name)
.ToolTipText(Tooltip)
.Font(IDetailLayoutBuilder::GetDetailFont())
]
.ValueContent()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(0.f, 0.f, XYZPadding, 0.f)
.AutoWidth()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
XProperty->CreatePropertyNameWidget()
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
XProperty->CreatePropertyValueWidget()
]
]
+ SHorizontalBox::Slot()
.Padding(0.f, 0.f, XYZPadding, 0.f)
.AutoWidth()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
YProperty->CreatePropertyNameWidget()
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
YProperty->CreatePropertyValueWidget()
]
]
+ SHorizontalBox::Slot()
.Padding(0.f, 0.f, XYZPadding, 0.f)
.AutoWidth()
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.AutoWidth()
[
ZProperty->CreatePropertyNameWidget()
]
+ SHorizontalBox::Slot()
.AutoWidth()
[
ZProperty->CreatePropertyValueWidget()
]
]
];
}
void UAnimGraphNode_BoneDrivenController::AddRangePropertyRow(const FText& Name, const FText& Tooltip, IDetailCategoryBuilder& Category, TSharedRef<IPropertyHandle> PropertyHandle, const FName MinPropertyName, const FName MaxPropertyName, TAttribute<EVisibility> VisibilityAttribute)
{
const float MiddlePadding = 4.0f;
TSharedPtr<IPropertyHandle> MinProperty = PropertyHandle->GetChildHandle(MinPropertyName);
Category.GetParentLayout().HideProperty(MinProperty);
TSharedPtr<IPropertyHandle> MaxProperty = PropertyHandle->GetChildHandle(MaxPropertyName);
Category.GetParentLayout().HideProperty(MaxProperty);
Category.AddCustomRow(Name)
.Visibility(VisibilityAttribute)
.NameContent()
[
SNew(STextBlock)
.Text(Name)
.ToolTipText(Tooltip)
.Font(IDetailLayoutBuilder::GetDetailFont())
]
.ValueContent()
.MinDesiredWidth(100.0f * 2.0f)
.MaxDesiredWidth(100.0f * 2.0f)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.FillWidth(1)
.Padding(0.0f, 0.0f, MiddlePadding, 0.0f)
.VAlign(VAlign_Center)
[
MinProperty->CreatePropertyValueWidget()
]
+SHorizontalBox::Slot()
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("MinMaxSpacer", ".."))
.Font(IDetailLayoutBuilder::GetDetailFont())
]
+SHorizontalBox::Slot()
.FillWidth(1)
.Padding(MiddlePadding, 0.0f, 0.0f, 0.0f)
.VAlign(VAlign_Center)
[
MaxProperty->CreatePropertyValueWidget()
]
];
}
void UAnimGraphNode_BoneDrivenController::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
{
Super::CustomizeDetails(DetailBuilder);
TSharedRef<IPropertyHandle> NodeHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UAnimGraphNode_BoneDrivenController, Node), GetClass());
// if it doesn't have this node, that means this isn't really bone driven controller
if (!NodeHandle->IsValidHandle())
{
return;
}
TAttribute<EVisibility> NotUsingCurveVisibility = TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&UAnimGraphNode_BoneDrivenController::AreNonCurveMappingValuesVisible, &DetailBuilder));
TAttribute<EVisibility> MapRangeVisiblity = TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&UAnimGraphNode_BoneDrivenController::AreRemappingValuesVisible, &DetailBuilder));
// Source (Driver) category
IDetailCategoryBuilder& SourceCategory = DetailBuilder.EditCategory(TEXT("Source (Driver)"));
// Mapping category
IDetailCategoryBuilder& MappingCategory = DetailBuilder.EditCategory(TEXT("Mapping"));
MappingCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, DrivingCurve)));
MappingCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bUseRange))).Visibility(NotUsingCurveVisibility);
AddRangePropertyRow(
/*Name=*/ LOCTEXT("InputRangeLabel", "Source Range"),
/*Tooltip=*/ LOCTEXT("InputRangeTooltip", "The range (relative to the reference pose) over which to limit the effect of the input component on the output component"),
/*Category=*/ MappingCategory,
/*PropertyHandle=*/ NodeHandle,
/*X=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, RangeMin),
/*Y=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, RangeMax),
MapRangeVisiblity);
AddRangePropertyRow(
/*Name=*/ LOCTEXT("MappedRangeLabel", "Mapped Range"),
/*Tooltip=*/ LOCTEXT("MappedRangeTooltip", "The range of mapped values that correspond to the input range"),
/*Category=*/ MappingCategory,
/*PropertyHandle=*/ NodeHandle,
/*X=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, RemappedMin),
/*Y=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, RemappedMax),
MapRangeVisiblity);
MappingCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, Multiplier))).Visibility(NotUsingCurveVisibility);
// Destination visiblity
TAttribute<EVisibility> BoneTargetVisibility = TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&UAnimGraphNode_BoneDrivenController::AreTargetBonePropertiesVisible, &DetailBuilder));
TAttribute<EVisibility> CurveTargetVisibility = TAttribute<EVisibility>::Create(TAttribute<EVisibility>::FGetter::CreateStatic(&UAnimGraphNode_BoneDrivenController::AreTargetCurvePropertiesVisible, &DetailBuilder));
// Destination (Driven) category
IDetailCategoryBuilder& TargetCategory = DetailBuilder.EditCategory(TEXT("Destination (Driven)"));
TargetCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, DestinationMode)));
TargetCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, ParameterName))).Visibility(CurveTargetVisibility);
TargetCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, TargetBone))).Visibility(BoneTargetVisibility);
// Add a note about the space (it is not configurable, and this helps set expectations)
const FText TargetBoneSpaceName = LOCTEXT("TargetComponentSpace", "Target Component Space");
TargetCategory.AddCustomRow(TargetBoneSpaceName)
.NameContent()
[
SNew(STextBlock)
.Text(TargetBoneSpaceName)
.Font(IDetailLayoutBuilder::GetDetailFont())
]
.ValueContent()
[
SNew(STextBlock)
.Text(LOCTEXT("TargetComponentSpaceIsAlwaysParentBoneSpace", "Parent Bone Space"))
.Font(IDetailLayoutBuilder::GetDetailFont())
]
.Visibility(BoneTargetVisibility);
AddTripletPropertyRow(
/*Name=*/ LOCTEXT("DrivenTranslationLabel", "Translation"),
/*Tooltip=*/ LOCTEXT("DrivenTranslationTooltip", "Should the source bone drive one or more translation components of the target bone?"),
/*Category=*/ TargetCategory,
/*PropertyHandle=*/ NodeHandle,
/*X=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetTranslationX),
/*Y=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetTranslationY),
/*Z=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetTranslationZ),
BoneTargetVisibility);
AddTripletPropertyRow(
/*Name=*/ LOCTEXT("DrivenRotationLabel", "Rotation"),
/*Tooltip=*/ LOCTEXT("DrivenRotationTooltip", "Should the source bone drive one or more rotation components of the target bone?"),
/*Category=*/ TargetCategory,
/*PropertyHandle=*/ NodeHandle,
/*X=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetRotationX),
/*Y=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetRotationY),
/*Z=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetRotationZ),
BoneTargetVisibility);
AddTripletPropertyRow(
/*Name=*/ LOCTEXT("DrivenScaleLabel", "Scale"),
/*Tooltip=*/ LOCTEXT("DrivenScaleTooltip", "Should the source bone drive one or more scale components of the target bone?"),
/*Category=*/ TargetCategory,
/*PropertyHandle=*/ NodeHandle,
/*X=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetScaleX),
/*Y=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetScaleY),
/*Z=*/ GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, bAffectTargetScaleZ),
BoneTargetVisibility);
TargetCategory.AddProperty(NodeHandle->GetChildHandle(GET_MEMBER_NAME_CHECKED(FAnimNode_BoneDrivenController, ModificationMode))).Visibility(BoneTargetVisibility);
}
FText UAnimGraphNode_BoneDrivenController::ComponentTypeToText(EComponentType::Type Component)
{
switch (Component)
{
case EComponentType::TranslationX:
return LOCTEXT("ComponentType_TranslationX", "translateX");
case EComponentType::TranslationY:
return LOCTEXT("ComponentType_TranslationY", "translateY");
case EComponentType::TranslationZ:
return LOCTEXT("ComponentType_TranslationZ", "translateZ");
case EComponentType::RotationX:
return LOCTEXT("ComponentType_RotationX", "rotateX");
case EComponentType::RotationY:
return LOCTEXT("ComponentType_RotationY", "rotateY");
case EComponentType::RotationZ:
return LOCTEXT("ComponentType_RotationZ", "rotateZ");
case EComponentType::Scale:
return LOCTEXT("ComponentType_ScaleMax", "scaleMax");
case EComponentType::ScaleX:
return LOCTEXT("ComponentType_ScaleX", "scaleX");
case EComponentType::ScaleY:
return LOCTEXT("ComponentType_ScaleY", "scaleY");
case EComponentType::ScaleZ:
return LOCTEXT("ComponentType_ScaleZ", "scaleZ");
default:
return LOCTEXT("ComponentType_None", "(none)");
}
}
EVisibility UAnimGraphNode_BoneDrivenController::AreNonCurveMappingValuesVisible(IDetailLayoutBuilder* DetailLayoutBuilder)
{
const TArray<TWeakObjectPtr<UObject>>& SelectedObjectsList = DetailLayoutBuilder->GetSelectedObjects();
for(TWeakObjectPtr<UObject> Object : SelectedObjectsList)
{
if(UAnimGraphNode_BoneDrivenController* BoneDrivenController = Cast<UAnimGraphNode_BoneDrivenController>(Object.Get()))
{
if (BoneDrivenController->Node.DrivingCurve == nullptr)
{
return EVisibility::Visible;
}
}
}
return EVisibility::Collapsed;
}
EVisibility UAnimGraphNode_BoneDrivenController::AreRemappingValuesVisible(IDetailLayoutBuilder* DetailLayoutBuilder)
{
const TArray<TWeakObjectPtr<UObject>>& SelectedObjectsList = DetailLayoutBuilder->GetSelectedObjects();
for(TWeakObjectPtr<UObject> Object : SelectedObjectsList)
{
if(UAnimGraphNode_BoneDrivenController* BoneDrivenController = Cast<UAnimGraphNode_BoneDrivenController>(Object.Get()))
{
if((BoneDrivenController->Node.DrivingCurve == nullptr) && BoneDrivenController->Node.bUseRange)
{
return EVisibility::Visible;
}
}
}
return EVisibility::Collapsed;
}
EVisibility UAnimGraphNode_BoneDrivenController::AreTargetBonePropertiesVisible(IDetailLayoutBuilder* DetailLayoutBuilder)
{
const TArray<TWeakObjectPtr<UObject>>& SelectedObjectsList = DetailLayoutBuilder->GetSelectedObjects();
for(TWeakObjectPtr<UObject> Object : SelectedObjectsList)
{
if(UAnimGraphNode_BoneDrivenController* BoneDrivenController = Cast<UAnimGraphNode_BoneDrivenController>(Object.Get()))
{
if(BoneDrivenController->Node.DestinationMode == EDrivenDestinationMode::Bone)
{
return EVisibility::Visible;
}
}
}
return EVisibility::Collapsed;
}
EVisibility UAnimGraphNode_BoneDrivenController::AreTargetCurvePropertiesVisible(IDetailLayoutBuilder* DetailLayoutBuilder)
{
TArray<TWeakObjectPtr<UObject>> SelectedObjectsList = DetailLayoutBuilder->GetSelectedObjects();
for(TWeakObjectPtr<UObject> Object : SelectedObjectsList)
{
if(UAnimGraphNode_BoneDrivenController* BoneDrivenController = Cast<UAnimGraphNode_BoneDrivenController>(Object.Get()))
{
if(BoneDrivenController->Node.DestinationMode == EDrivenDestinationMode::MorphTarget || BoneDrivenController->Node.DestinationMode == EDrivenDestinationMode::MaterialParameter)
{
return EVisibility::Visible;
}
}
}
return EVisibility::Collapsed;
}
#undef LOCTEXT_NAMESPACE