2019-12-26 15:33:43 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
2014-04-24 08:49:31 -04:00
# include "AnimGraphNode_TwoBoneIK.h"
2016-09-22 15:33:34 -04:00
# include "AnimNodeEditModes.h"
2017-06-21 10:25:35 -04:00
# include "Animation/AnimInstance.h"
2014-03-14 14:13:41 -04:00
2014-09-22 09:45:11 -04:00
// for customization details
2016-11-23 15:48:37 -05:00
# include "PropertyHandle.h"
# include "DetailLayoutBuilder.h"
# include "DetailCategoryBuilder.h"
2014-09-22 09:45:11 -04:00
2017-07-13 10:13:07 -04:00
// version handling
# include "AnimationCustomVersion.h"
2018-01-20 11:19:29 -05:00
# include "UObject/ReleaseObjectVersion.h"
2017-07-13 10:13:07 -04:00
# define LOCTEXT_NAMESPACE "AnimGraphNode_TwoBoneIK"
2014-09-22 09:45:11 -04:00
/////////////////////////////////////////////////////
// FTwoBoneIKDelegate
class FTwoBoneIKDelegate : public TSharedFromThis < FTwoBoneIKDelegate >
{
public :
void UpdateLocationSpace ( class IDetailLayoutBuilder * DetailBuilder )
{
if ( DetailBuilder )
{
DetailBuilder - > ForceRefreshDetails ( ) ;
}
}
} ;
2014-11-14 05:00:37 -05:00
TSharedPtr < FTwoBoneIKDelegate > UAnimGraphNode_TwoBoneIK : : TwoBoneIKDelegate = NULL ;
2014-03-14 14:13:41 -04:00
/////////////////////////////////////////////////////
// UAnimGraphNode_TwoBoneIK
2014-04-23 18:30:37 -04:00
2014-10-14 10:29:11 -04:00
UAnimGraphNode_TwoBoneIK : : UAnimGraphNode_TwoBoneIK ( const FObjectInitializer & ObjectInitializer )
: Super ( ObjectInitializer )
2014-03-14 14:13:41 -04:00
{
}
2014-04-23 18:30:37 -04:00
FText UAnimGraphNode_TwoBoneIK : : GetControllerDescription ( ) const
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:30:37 -04:00
return LOCTEXT ( " TwoBoneIK " , " Two Bone IK " ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-03 18:14:09 -04:00
FText UAnimGraphNode_TwoBoneIK : : GetTooltipText ( ) const
2014-03-14 14:13:41 -04:00
{
2014-09-03 18:14:09 -04:00
return LOCTEXT ( " AnimGraphNode_TwoBoneIK_Tooltip " , " The Two Bone IK control applies an inverse kinematic (IK) solver to a 3 - joint chain , such as the limbs of a character . " ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:30:37 -04:00
FText UAnimGraphNode_TwoBoneIK : : GetNodeTitle ( ENodeTitleType : : Type TitleType ) const
2014-03-14 14:13:41 -04:00
{
2014-09-16 15:01:38 -04:00
if ( ( TitleType = = ENodeTitleType : : ListView | | TitleType = = ENodeTitleType : : MenuTitle ) & & ( Node . IKBone . BoneName = = NAME_None ) )
2014-09-04 11:25:05 -04:00
{
return GetControllerDescription ( ) ;
}
2014-09-24 14:15:13 -04:00
// @TODO: the bone can be altered in the property editor, so we have to
// choose to mark this dirty when that happens for this to properly work
2015-04-02 11:16:23 -04:00
else //if (!CachedNodeTitles.IsTitleCached(TitleType, this))
2014-09-04 11:25:05 -04:00
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " ControllerDescription " ) , GetControllerDescription ( ) ) ;
Args . Add ( TEXT ( " BoneName " ) , FText : : FromName ( Node . IKBone . BoneName ) ) ;
2014-04-23 18:30:37 -04:00
2014-09-04 11:25:05 -04:00
// FText::Format() is slow, so we cache this to save on performance
2014-09-16 15:01:38 -04:00
if ( TitleType = = ENodeTitleType : : ListView | | TitleType = = ENodeTitleType : : MenuTitle )
2014-08-21 18:50:33 -04:00
{
2015-04-02 11:16:23 -04:00
CachedNodeTitles . SetCachedTitle ( TitleType , FText : : Format ( LOCTEXT ( " AnimGraphNode_IKBone_ListTitle " , " {ControllerDescription} - Bone: {BoneName} " ) , Args ) , this ) ;
2014-09-04 11:25:05 -04:00
}
else
{
2015-04-02 11:16:23 -04:00
CachedNodeTitles . SetCachedTitle ( TitleType , FText : : Format ( LOCTEXT ( " AnimGraphNode_IKBone_Title " , " {ControllerDescription} \n Bone: {BoneName} " ) , Args ) , this ) ;
2014-08-21 18:50:33 -04:00
}
2014-04-23 18:30:37 -04:00
}
2014-09-04 11:25:05 -04:00
return CachedNodeTitles [ TitleType ] ;
2014-04-23 18:30:37 -04:00
}
2016-09-22 15:33:34 -04:00
void UAnimGraphNode_TwoBoneIK : : CopyNodeDataToPreviewNode ( FAnimNode_Base * InPreviewNode )
2014-03-14 14:13:41 -04:00
{
2016-09-22 15:33:34 -04:00
FAnimNode_TwoBoneIK * TwoBoneIK = static_cast < FAnimNode_TwoBoneIK * > ( InPreviewNode ) ;
2014-11-14 05:00:37 -05:00
// copies Pin values from the internal node to get data which are not compiled yet
2016-09-22 15:33:34 -04:00
TwoBoneIK - > EffectorLocation = Node . EffectorLocation ;
TwoBoneIK - > JointTargetLocation = Node . JointTargetLocation ;
2014-11-14 05:00:37 -05:00
}
2016-09-22 15:33:34 -04:00
void UAnimGraphNode_TwoBoneIK : : CopyPinDefaultsToNodeData ( UEdGraphPin * InPin )
2014-11-14 05:00:37 -05:00
{
2016-09-22 15:33:34 -04:00
if ( InPin - > GetName ( ) = = GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , EffectorLocation ) )
2015-02-18 03:59:11 -05:00
{
2016-09-22 15:33:34 -04:00
GetDefaultValue ( GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , EffectorLocation ) , Node . EffectorLocation ) ;
2015-02-18 03:59:11 -05:00
}
2016-09-22 15:33:34 -04:00
else if ( InPin - > GetName ( ) = = GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , JointTargetLocation ) )
2015-02-18 03:59:11 -05:00
{
2016-09-22 15:33:34 -04:00
GetDefaultValue ( GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , JointTargetLocation ) , Node . JointTargetLocation ) ;
2014-11-14 05:00:37 -05:00
}
}
2014-09-22 09:45:11 -04:00
void UAnimGraphNode_TwoBoneIK : : CustomizeDetails ( class IDetailLayoutBuilder & DetailBuilder )
{
2018-05-23 21:04:31 -04:00
Super : : CustomizeDetails ( DetailBuilder ) ;
2014-09-22 09:45:11 -04:00
// initialize just once
if ( ! TwoBoneIKDelegate . IsValid ( ) )
{
TwoBoneIKDelegate = MakeShareable ( new FTwoBoneIKDelegate ( ) ) ;
}
2017-07-14 08:20:47 -04:00
// do this first, so that we can include these properties first
const FString EffectorLocationSpace = FString : : Printf ( TEXT ( " Node.%s " ) , GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , EffectorLocationSpace ) ) ;
const FString JointTargetLocationSpace = FString : : Printf ( TEXT ( " Node.%s " ) , GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , JointTargetLocationSpace ) ) ;
IDetailCategoryBuilder & IKCategory = DetailBuilder . EditCategory ( " IK " ) ;
IDetailCategoryBuilder & EffectorCategory = DetailBuilder . EditCategory ( " Effector " ) ;
IDetailCategoryBuilder & JointCategory = DetailBuilder . EditCategory ( " JointTarget " ) ;
// refresh UIs when bone space is changed
TSharedRef < IPropertyHandle > EffectorLocHandle = DetailBuilder . GetProperty ( * EffectorLocationSpace , GetClass ( ) ) ;
if ( EffectorLocHandle - > IsValidHandle ( ) )
{
EffectorCategory . AddProperty ( EffectorLocHandle ) ;
FSimpleDelegate UpdateEffectorSpaceDelegate = FSimpleDelegate : : CreateSP ( TwoBoneIKDelegate . Get ( ) , & FTwoBoneIKDelegate : : UpdateLocationSpace , & DetailBuilder ) ;
EffectorLocHandle - > SetOnPropertyValueChanged ( UpdateEffectorSpaceDelegate ) ;
}
TSharedRef < IPropertyHandle > JointTragetLocHandle = DetailBuilder . GetProperty ( * JointTargetLocationSpace , GetClass ( ) ) ;
if ( JointTragetLocHandle - > IsValidHandle ( ) )
{
JointCategory . AddProperty ( JointTragetLocHandle ) ;
FSimpleDelegate UpdateJointSpaceDelegate = FSimpleDelegate : : CreateSP ( TwoBoneIKDelegate . Get ( ) , & FTwoBoneIKDelegate : : UpdateLocationSpace , & DetailBuilder ) ;
JointTragetLocHandle - > SetOnPropertyValueChanged ( UpdateJointSpaceDelegate ) ;
}
2014-09-22 09:45:11 -04:00
EBoneControlSpace Space = Node . EffectorLocationSpace ;
2014-11-14 05:00:37 -05:00
const FString TakeRotationPropName = FString : : Printf ( TEXT ( " Node.%s " ) , GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , bTakeRotationFromEffectorSpace ) ) ;
2017-07-14 08:20:47 -04:00
const FString EffectorTargetName = FString : : Printf ( TEXT ( " Node.%s " ) , GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , EffectorTarget ) ) ;
2014-11-14 05:00:37 -05:00
const FString EffectorLocationPropName = FString : : Printf ( TEXT ( " Node.%s " ) , GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , EffectorLocation ) ) ;
2014-09-22 09:45:11 -04:00
if ( Space = = BCS_BoneSpace | | Space = = BCS_ParentBoneSpace )
{
TSharedPtr < IPropertyHandle > PropertyHandle ;
2014-11-14 05:00:37 -05:00
PropertyHandle = DetailBuilder . GetProperty ( * TakeRotationPropName , GetClass ( ) ) ;
2014-09-22 09:45:11 -04:00
EffectorCategory . AddProperty ( PropertyHandle ) ;
2017-07-14 08:20:47 -04:00
PropertyHandle = DetailBuilder . GetProperty ( * EffectorTargetName , GetClass ( ) ) ;
2014-09-22 09:45:11 -04:00
EffectorCategory . AddProperty ( PropertyHandle ) ;
}
else // hide all properties in EndEffector category
{
2014-11-14 05:00:37 -05:00
TSharedPtr < IPropertyHandle > PropertyHandle = DetailBuilder . GetProperty ( * EffectorLocationPropName , GetClass ( ) ) ;
2014-09-22 09:45:11 -04:00
DetailBuilder . HideProperty ( PropertyHandle ) ;
2014-11-14 05:00:37 -05:00
PropertyHandle = DetailBuilder . GetProperty ( * TakeRotationPropName , GetClass ( ) ) ;
2014-09-22 09:45:11 -04:00
DetailBuilder . HideProperty ( PropertyHandle ) ;
2017-07-14 08:20:47 -04:00
PropertyHandle = DetailBuilder . GetProperty ( * EffectorTargetName , GetClass ( ) ) ;
2014-09-22 09:45:11 -04:00
DetailBuilder . HideProperty ( PropertyHandle ) ;
}
Space = Node . JointTargetLocationSpace ;
2014-11-14 05:00:37 -05:00
bool bPinVisibilityChanged = false ;
2017-07-14 08:20:47 -04:00
const FString JointTargetName = FString : : Printf ( TEXT ( " Node.%s " ) , GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , JointTarget ) ) ;
2014-11-14 05:00:37 -05:00
const FString JointTargetLocation = FString : : Printf ( TEXT ( " Node.%s " ) , GET_MEMBER_NAME_STRING_CHECKED ( FAnimNode_TwoBoneIK , JointTargetLocation ) ) ;
2014-09-22 09:45:11 -04:00
if ( Space = = BCS_BoneSpace | | Space = = BCS_ParentBoneSpace )
{
TSharedPtr < IPropertyHandle > PropertyHandle ;
2017-07-14 08:20:47 -04:00
PropertyHandle = DetailBuilder . GetProperty ( * JointTargetName , GetClass ( ) ) ;
JointCategory . AddProperty ( PropertyHandle ) ;
2014-09-22 09:45:11 -04:00
}
else // hide all properties in JointTarget category except for JointTargetLocationSpace
{
2017-07-14 08:20:47 -04:00
TSharedPtr < IPropertyHandle > PropertyHandle = DetailBuilder . GetProperty ( * JointTargetName , GetClass ( ) ) ;
2014-09-22 09:45:11 -04:00
DetailBuilder . HideProperty ( PropertyHandle ) ;
}
2014-11-14 05:00:37 -05:00
}
2016-09-22 15:33:34 -04:00
FEditorModeID UAnimGraphNode_TwoBoneIK : : GetEditorMode ( ) const
{
return AnimNodeEditModes : : TwoBoneIK ;
}
2016-11-15 15:29:41 -05:00
void UAnimGraphNode_TwoBoneIK : : Serialize ( FArchive & Ar )
{
Super : : Serialize ( Ar ) ;
Ar . UsingCustomVersion ( FAnimationCustomVersion : : GUID ) ;
const int32 CustomAnimVersion = Ar . CustomVer ( FAnimationCustomVersion : : GUID ) ;
if ( CustomAnimVersion < FAnimationCustomVersion : : RenamedStretchLimits )
{
// fix up deprecated variables
Node . StartStretchRatio = Node . StretchLimits_DEPRECATED . X ;
Node . MaxStretchScale = Node . StretchLimits_DEPRECATED . Y ;
}
2017-07-13 10:13:07 -04:00
Ar . UsingCustomVersion ( FReleaseObjectVersion : : GUID ) ;
if ( Ar . CustomVer ( FReleaseObjectVersion : : GUID ) < FReleaseObjectVersion : : RenameNoTwistToAllowTwistInTwoBoneIK )
{
Node . bAllowTwist = ! Node . bNoTwist_DEPRECATED ;
}
2017-07-14 08:20:47 -04:00
if ( CustomAnimVersion < FAnimationCustomVersion : : ConvertIKToSupportBoneSocketTarget )
{
if ( Node . EffectorSpaceBoneName_DEPRECATED ! = NAME_None )
{
Node . EffectorTarget = FBoneSocketTarget ( Node . EffectorSpaceBoneName_DEPRECATED ) ;
}
if ( Node . JointTargetSpaceBoneName_DEPRECATED ! = NAME_None )
{
Node . JointTarget = FBoneSocketTarget ( Node . JointTargetSpaceBoneName_DEPRECATED ) ;
}
}
2016-11-15 15:29:41 -05:00
}
2017-06-21 10:25:35 -04:00
void UAnimGraphNode_TwoBoneIK : : Draw ( FPrimitiveDrawInterface * PDI , USkeletalMeshComponent * SkelMeshComp ) const
{
if ( bEnableDebugDraw & & SkelMeshComp )
{
if ( FAnimNode_TwoBoneIK * ActiveNode = GetActiveInstanceNode < FAnimNode_TwoBoneIK > ( SkelMeshComp - > GetAnimInstance ( ) ) )
{
ActiveNode - > ConditionalDebugDraw ( PDI , SkelMeshComp ) ;
}
}
}
2014-04-23 18:30:37 -04:00
# undef LOCTEXT_NAMESPACE