Up to Unreal 5.7
This commit is contained in:
parent
8a63902c06
commit
1a64805d43
239 changed files with 3947 additions and 296 deletions
|
|
@ -0,0 +1,849 @@
|
|||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "HandSocketComponentDetails.h"
|
||||
#include "HandSocketVisualizer.h"
|
||||
//#include "PropertyEditing.h"
|
||||
#include "Widgets/Text/STextBlock.h"
|
||||
#include "Widgets/Input/SButton.h"
|
||||
#include "PropertyHandle.h"
|
||||
#include "DetailLayoutBuilder.h"
|
||||
#include "DetailWidgetRow.h"
|
||||
#include "DetailCategoryBuilder.h"
|
||||
#include "IDetailsView.h"
|
||||
|
||||
#include "Developer/AssetTools/Public/IAssetTools.h"
|
||||
#include "Developer/AssetTools/Public/AssetToolsModule.h"
|
||||
#include "Editor/ContentBrowser/Public/IContentBrowserSingleton.h"
|
||||
#include "Editor/ContentBrowser/Public/ContentBrowserModule.h"
|
||||
#include "AnimationUtils.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "UObject/SavePackage.h"
|
||||
#include "Misc/MessageDialog.h"
|
||||
#include "Widgets/Layout/SBorder.h"
|
||||
#include "Widgets/Layout/SSeparator.h"
|
||||
#include "Widgets/Layout/SUniformGridPanel.h"
|
||||
#include "Widgets/Input/SEditableTextBox.h"
|
||||
#include "Editor.h"
|
||||
#include "EditorStyleSet.h"
|
||||
#include "Styling/CoreStyle.h"
|
||||
|
||||
#include "Animation/AnimData/AnimDataModel.h"
|
||||
|
||||
#include "Editor/UnrealEdEngine.h"
|
||||
#include "UnrealEdGlobals.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "HandSocketComponentDetails"
|
||||
|
||||
FText SCreateHandAnimationDlg::LastUsedAssetPath;
|
||||
|
||||
static bool PromptUserForAssetPath(FString& AssetPath, FString& AssetName)
|
||||
{
|
||||
TSharedRef<SCreateHandAnimationDlg> NewAnimDlg = SNew(SCreateHandAnimationDlg);
|
||||
if (NewAnimDlg->ShowModal() != EAppReturnType::Cancel)
|
||||
{
|
||||
AssetPath = NewAnimDlg->GetFullAssetPath();
|
||||
AssetName = NewAnimDlg->GetAssetName();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
TWeakObjectPtr<UAnimSequence> FHandSocketComponentDetails::SaveAnimationAsset(const FString& InAssetPath, const FString& InAssetName)
|
||||
{
|
||||
|
||||
TWeakObjectPtr<UAnimSequence> FinalAnimation;
|
||||
|
||||
// Replace when this moves to custom display
|
||||
if (!HandSocketComponent.IsValid())
|
||||
return FinalAnimation;
|
||||
|
||||
/*if (!HandSocketComponent->HandVisualizerComponent)// || !HandSocketComponent->HandVisualizerComponent->SkeletalMesh || !HandSocketComponent->HandVisualizerComponent->SkeletalMesh->Skeleton)
|
||||
{
|
||||
return false;
|
||||
}*/
|
||||
|
||||
if (!HandSocketComponent->HandTargetAnimation && (!HandSocketComponent->VisualizationMesh || !HandSocketComponent->VisualizationMesh->GetSkeleton()))
|
||||
{
|
||||
return FinalAnimation;
|
||||
}
|
||||
|
||||
// create the asset
|
||||
FText InvalidPathReason;
|
||||
bool const bValidPackageName = FPackageName::IsValidLongPackageName(InAssetPath, false, &InvalidPathReason);
|
||||
if (bValidPackageName == false)
|
||||
{
|
||||
UE_LOG(LogAnimation, Log, TEXT("%s is an invalid asset path, prompting user for new asset path. Reason: %s"), *InAssetPath, *InvalidPathReason.ToString());
|
||||
}
|
||||
|
||||
FString ValidatedAssetPath = InAssetPath;
|
||||
FString ValidatedAssetName = InAssetName;
|
||||
|
||||
UObject* Parent = bValidPackageName ? CreatePackage(*ValidatedAssetPath) : nullptr;
|
||||
if (Parent == nullptr)
|
||||
{
|
||||
// bad or no path passed in, do the popup
|
||||
if (PromptUserForAssetPath(ValidatedAssetPath, ValidatedAssetName) == false)
|
||||
{
|
||||
return FinalAnimation;
|
||||
}
|
||||
|
||||
Parent = CreatePackage(*ValidatedAssetPath);
|
||||
}
|
||||
|
||||
UObject* const Object = LoadObject<UObject>(Parent, *ValidatedAssetName, nullptr, LOAD_Quiet, nullptr);
|
||||
// if object with same name exists, warn user
|
||||
if (Object)
|
||||
{
|
||||
EAppReturnType::Type ReturnValue = FMessageDialog::Open(EAppMsgType::YesNo, LOCTEXT("Error_AssetExist", "Asset with same name exists. Do you wish to overwrite it?"));
|
||||
if (ReturnValue == EAppReturnType::No)
|
||||
{
|
||||
return FinalAnimation; // failed
|
||||
}
|
||||
}
|
||||
|
||||
UAnimSequence* BaseAnimation = HandSocketComponent->HandTargetAnimation;
|
||||
TArray<FTransform> LocalPoses;
|
||||
|
||||
if (!BaseAnimation)
|
||||
{
|
||||
LocalPoses = HandSocketComponent->VisualizationMesh->GetRefSkeleton().GetRefBonePose();
|
||||
}
|
||||
|
||||
// If not, create new one now.
|
||||
UAnimSequence* const NewSeq = NewObject<UAnimSequence>(Parent, *ValidatedAssetName, RF_Public | RF_Standalone);
|
||||
if (NewSeq)
|
||||
{
|
||||
// set skeleton
|
||||
if (BaseAnimation)
|
||||
{
|
||||
NewSeq->SetSkeleton(BaseAnimation->GetSkeleton());
|
||||
}
|
||||
else
|
||||
{
|
||||
NewSeq->SetSkeleton(HandSocketComponent->VisualizationMesh->GetSkeleton());
|
||||
}
|
||||
|
||||
// Notify the asset registry
|
||||
FAssetRegistryModule::AssetCreated(NewSeq);
|
||||
//StartRecord(Component, NewSeq);
|
||||
|
||||
//return true;
|
||||
UAnimSequence* AnimationObject = NewSeq;
|
||||
|
||||
IAnimationDataController& AnimController = AnimationObject->GetController();
|
||||
{
|
||||
IAnimationDataController::FScopedBracket ScopedBracket(AnimController, LOCTEXT("SaveAnimationAsset_VRE", "Creating Animation Sequence based on hand pose"));
|
||||
AnimationObject->ResetAnimation();
|
||||
if (BaseAnimation)
|
||||
{
|
||||
AnimationObject->BoneCompressionSettings = BaseAnimation->BoneCompressionSettings;
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimationObject->BoneCompressionSettings = FAnimationUtils::GetDefaultAnimationBoneCompressionSettings();
|
||||
}
|
||||
|
||||
AnimController.InitializeModel();
|
||||
AnimController.RemoveAllBoneTracks(false);
|
||||
|
||||
|
||||
//checkf(MovieScene, TEXT("No Movie Scene found for SequencerDataModel"));
|
||||
//AnimController.SetPlayLength(4.f);
|
||||
AnimController.SetNumberOfFrames(FFrameNumber(1), false);
|
||||
|
||||
// Set frame rate to 1 to 1 as we don't animate
|
||||
AnimController.SetFrameRate(FFrameRate(1, 1));
|
||||
|
||||
TArray<FName> TrackNames;
|
||||
const IAnimationDataModel* BaseDataModel = BaseAnimation ? BaseAnimation->GetController().GetModel() : nullptr;
|
||||
|
||||
if (BaseAnimation)
|
||||
{
|
||||
if (BaseDataModel)
|
||||
{
|
||||
BaseDataModel->GetBoneTrackNames(TrackNames);
|
||||
for (FName TrackName : TrackNames)
|
||||
{
|
||||
AnimController.AddBoneCurve(TrackName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FinalAnimation;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int numBones = HandSocketComponent->VisualizationMesh->GetRefSkeleton().GetNum();
|
||||
for (int i = 0; i < LocalPoses.Num() && i < numBones; ++i)
|
||||
{
|
||||
AnimController.AddBoneCurve(HandSocketComponent->VisualizationMesh->GetRefSkeleton().GetBoneName(i));
|
||||
//AnimController.AddBoneTrack(HandSocketComponent->VisualizationMesh->GetRefSkeleton().GetBoneName(i));
|
||||
}
|
||||
}
|
||||
|
||||
if (BaseAnimation)
|
||||
{
|
||||
AnimationObject->RetargetSource = BaseAnimation->RetargetSource;
|
||||
}
|
||||
else
|
||||
{
|
||||
AnimationObject->RetargetSource = HandSocketComponent->VisualizationMesh ? HandSocketComponent->VisualizationMesh->GetSkeleton()->GetRetargetSourceForMesh(HandSocketComponent->VisualizationMesh) : NAME_None;
|
||||
}
|
||||
|
||||
const IAnimationDataModel* DataModel = AnimController.GetModel();
|
||||
|
||||
/// SAVE POSE
|
||||
if (BaseAnimation && DataModel && BaseDataModel)
|
||||
{
|
||||
for (int32 TrackIndex = 0; TrackIndex < /*DataModel->GetBoneAnimationTracks().Num()*/BaseDataModel->GetNumBoneTracks(); ++TrackIndex)
|
||||
{
|
||||
FName TrackName = TrackIndex < TrackNames.Num() ? TrackNames[TrackIndex] : NAME_None;
|
||||
if (!BaseDataModel->IsValidBoneTrackName(TrackName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
FTransform FinalTrans = BaseDataModel->GetBoneTrackTransform(TrackName, 0);
|
||||
//FTransform FinalTrans(Rot, Loc, Scale);
|
||||
|
||||
FQuat DeltaQuat = FQuat::Identity;
|
||||
for (FBPVRHandPoseBonePair& HandPair : HandSocketComponent->CustomPoseDeltas)
|
||||
{
|
||||
if (HandPair.BoneName == TrackName)
|
||||
{
|
||||
DeltaQuat = HandPair.DeltaPose;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
FinalTrans.ConcatenateRotation(DeltaQuat);
|
||||
FinalTrans.NormalizeRotation();
|
||||
|
||||
//FRawAnimSequenceTrack& RawNewTrack = DataModel->GetBoneTrackByIndex(TrackIndex).InternalTrackData;
|
||||
AnimController.SetBoneTrackKeys(TrackName, { FinalTrans.GetTranslation() }, { FinalTrans.GetRotation() }, { FinalTrans.GetScale3D() });
|
||||
}
|
||||
}
|
||||
else if(DataModel)
|
||||
{
|
||||
USkeletalMesh* SkeletalMesh = HandSocketComponent->VisualizationMesh;
|
||||
FReferenceSkeleton RefSkeleton = SkeletalMesh->GetRefSkeleton();
|
||||
USkeleton* AnimSkeleton = SkeletalMesh->GetSkeleton();
|
||||
|
||||
for (int32 TrackIndex = 0; TrackIndex < RefSkeleton.GetNum(); ++TrackIndex)
|
||||
{
|
||||
|
||||
FName TrackName = RefSkeleton.GetBoneName(TrackIndex);
|
||||
if (!DataModel->IsValidBoneTrackName(TrackName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int32 BoneTreeIndex = RefSkeleton.FindBoneIndex(TrackName);
|
||||
|
||||
// verify if this bone exists in skeleton
|
||||
//int32 BoneTreeIndex = DataModel->GetBoneTrackByIndex(TrackIndex).BoneTreeIndex;
|
||||
|
||||
if (BoneTreeIndex != INDEX_NONE)
|
||||
{
|
||||
|
||||
int32 BoneIndex = BoneTreeIndex;//AnimSkeleton->GetMeshBoneIndexFromSkeletonBoneIndex(SkeletalMesh, BoneTreeIndex);
|
||||
//int32 ParentIndex = SkeletalMesh->RefSkeleton.GetParentIndex(BoneIndex);
|
||||
FTransform LocalTransform = LocalPoses[BoneIndex];
|
||||
//FTransform LocalTransform = RefSkeleton.GetRefBonePose()[BoneIndex];
|
||||
|
||||
FName BoneName = AnimSkeleton->GetReferenceSkeleton().GetBoneName(BoneIndex);
|
||||
|
||||
FQuat DeltaQuat = FQuat::Identity;
|
||||
for (FBPVRHandPoseBonePair& HandPair : HandSocketComponent->CustomPoseDeltas)
|
||||
{
|
||||
if (HandPair.BoneName == BoneName)
|
||||
{
|
||||
DeltaQuat = HandPair.DeltaPose;
|
||||
}
|
||||
}
|
||||
|
||||
LocalTransform.ConcatenateRotation(DeltaQuat);
|
||||
LocalTransform.NormalizeRotation();
|
||||
|
||||
AnimController.SetBoneTrackKeys(BoneName, { LocalTransform.GetTranslation() }, { LocalTransform.GetRotation() }, { LocalTransform.GetScale3D() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AnimController.NotifyPopulated();
|
||||
}
|
||||
/// END SAVE POSE
|
||||
///
|
||||
///
|
||||
///
|
||||
|
||||
// init notifies
|
||||
AnimationObject->InitializeNotifyTrack();
|
||||
//#TODO: 5.1, need to figure out what they replaced this with
|
||||
//PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
//AnimationObject->PostProcessSequence();
|
||||
//PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||
AnimationObject->MarkPackageDirty();
|
||||
|
||||
//if (bAutoSaveAsset)
|
||||
{
|
||||
UPackage* const Package = AnimationObject->GetOutermost();
|
||||
FString const PackageName = Package->GetName();
|
||||
FString const PackageFileName = FPackageName::LongPackageNameToFilename(PackageName, FPackageName::GetAssetPackageExtension());
|
||||
|
||||
double StartTime = FPlatformTime::Seconds();
|
||||
|
||||
FSavePackageArgs PackageArguments;
|
||||
PackageArguments.SaveFlags = RF_Standalone;
|
||||
PackageArguments.SaveFlags = SAVE_NoError;
|
||||
UPackage::SavePackage(Package, NULL, *PackageFileName, PackageArguments);
|
||||
//UPackage::SavePackage(Package, NULL, RF_Standalone, *PackageFileName, GError, nullptr, false, true, SAVE_NoError);
|
||||
|
||||
double ElapsedTime = FPlatformTime::Seconds() - StartTime;
|
||||
UE_LOG(LogAnimation, Log, TEXT("Animation Recorder saved %s in %0.2f seconds"), *PackageName, ElapsedTime);
|
||||
}
|
||||
|
||||
FinalAnimation = AnimationObject;
|
||||
return FinalAnimation;
|
||||
}
|
||||
|
||||
return FinalAnimation;
|
||||
}
|
||||
TSharedRef< IDetailCustomization > FHandSocketComponentDetails::MakeInstance()
|
||||
{
|
||||
return MakeShareable(new FHandSocketComponentDetails);
|
||||
}
|
||||
|
||||
void FHandSocketComponentDetails::OnHandRelativeUpdated(IDetailLayoutBuilder* LayoutBuilder)
|
||||
{
|
||||
|
||||
if (!HandSocketComponent.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HandSocketComponent->Modify();
|
||||
if (AActor* Owner = HandSocketComponent->GetOwner())
|
||||
{
|
||||
Owner->Modify();
|
||||
}
|
||||
|
||||
TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(HandSocketComponent->GetClass());
|
||||
FHandSocketVisualizer* HandVisualizer = (FHandSocketVisualizer*)Visualizer.Get();
|
||||
|
||||
if (HandVisualizer)
|
||||
{
|
||||
if (UHandSocketComponent* RefHand = HandVisualizer->GetCurrentlyEditingComponent())
|
||||
{
|
||||
RefHand->HandRelativePlacement = HandSocketComponent->HandRelativePlacement;
|
||||
}
|
||||
}
|
||||
|
||||
FComponentVisualizer::NotifyPropertyModified(HandSocketComponent.Get(), FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandRelativePlacement)));
|
||||
}
|
||||
|
||||
void FHandSocketComponentDetails::OnLeftDominantUpdated(IDetailLayoutBuilder* LayoutBuilder)
|
||||
{
|
||||
|
||||
if (!HandSocketComponent.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Default to always flipping this
|
||||
//if (HandSocketComponent->bFlipForLeftHand)
|
||||
{
|
||||
FTransform relTrans = HandSocketComponent->GetRelativeTransform();
|
||||
FTransform HandPlacement = HandSocketComponent->GetHandRelativePlacement();
|
||||
|
||||
if (HandSocketComponent->bDecoupleMeshPlacement)
|
||||
{
|
||||
relTrans = FTransform::Identity;
|
||||
}
|
||||
|
||||
FTransform ReturnTrans = (HandPlacement * relTrans);
|
||||
|
||||
HandSocketComponent->MirrorHandTransform(ReturnTrans, relTrans);
|
||||
|
||||
HandSocketComponent->Modify();
|
||||
if (AActor* Owner = HandSocketComponent->GetOwner())
|
||||
{
|
||||
Owner->Modify();
|
||||
}
|
||||
ReturnTrans = ReturnTrans.GetRelativeTransform(relTrans);
|
||||
HandSocketComponent->HandRelativePlacement = ReturnTrans;
|
||||
|
||||
TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(HandSocketComponent->GetClass());
|
||||
FHandSocketVisualizer* HandVisualizer = (FHandSocketVisualizer*)Visualizer.Get();
|
||||
|
||||
if (HandVisualizer)
|
||||
{
|
||||
if (UHandSocketComponent* RefHand = HandVisualizer->GetCurrentlyEditingComponent())
|
||||
{
|
||||
RefHand->HandRelativePlacement = HandSocketComponent->HandRelativePlacement;
|
||||
//FComponentVisualizer::NotifyPropertyModified(RefHand, FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandRelativePlacement)));
|
||||
}
|
||||
}
|
||||
|
||||
FComponentVisualizer::NotifyPropertyModified(HandSocketComponent.Get(), FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandRelativePlacement)));
|
||||
}
|
||||
}
|
||||
|
||||
void FHandSocketComponentDetails::OnLockedStateUpdated(IDetailLayoutBuilder* LayoutBuilder)
|
||||
{
|
||||
|
||||
if (!HandSocketComponent.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (HandSocketComponent->bDecoupleMeshPlacement)
|
||||
{
|
||||
//FTransform RelTrans = HandSocketComponent->GetRelativeTransform();
|
||||
//FTransform WorldTrans = HandSocketComponent->GetComponentTransform();
|
||||
//if (USceneComponent* ParentComp = HandSocketComponent->GetAttachParent())
|
||||
{
|
||||
|
||||
HandSocketComponent->Modify();
|
||||
if (AActor* Owner = HandSocketComponent->GetOwner())
|
||||
{
|
||||
Owner->Modify();
|
||||
}
|
||||
|
||||
HandSocketComponent->HandRelativePlacement = HandSocketComponent->HandRelativePlacement * HandSocketComponent->GetRelativeTransform();// HandSocketComponent->GetComponentTransform();
|
||||
HandSocketComponent->bDecoupled = true;
|
||||
|
||||
TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(HandSocketComponent->GetClass());
|
||||
FHandSocketVisualizer* HandVisualizer = (FHandSocketVisualizer*)Visualizer.Get();
|
||||
|
||||
if (HandVisualizer)
|
||||
{
|
||||
if (UHandSocketComponent* RefHand = HandVisualizer->GetCurrentlyEditingComponent())
|
||||
{
|
||||
RefHand->HandRelativePlacement = HandSocketComponent->HandRelativePlacement;
|
||||
RefHand->bDecoupled = true;
|
||||
//FComponentVisualizer::NotifyPropertyModified(RefHand, FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandRelativePlacement)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (USceneComponent* ParentComp = HandSocketComponent->GetAttachParent())
|
||||
{
|
||||
HandSocketComponent->Modify();
|
||||
if (AActor* Owner = HandSocketComponent->GetOwner())
|
||||
{
|
||||
Owner->Modify();
|
||||
}
|
||||
HandSocketComponent->HandRelativePlacement = HandSocketComponent->HandRelativePlacement.GetRelativeTransform(HandSocketComponent->GetRelativeTransform());
|
||||
HandSocketComponent->bDecoupled = false;
|
||||
|
||||
TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(HandSocketComponent->GetClass());
|
||||
FHandSocketVisualizer* HandVisualizer = (FHandSocketVisualizer*)Visualizer.Get();
|
||||
|
||||
if (HandVisualizer)
|
||||
{
|
||||
if (UHandSocketComponent* RefHand = HandVisualizer->GetCurrentlyEditingComponent())
|
||||
{
|
||||
RefHand->HandRelativePlacement = HandSocketComponent->HandRelativePlacement;
|
||||
RefHand->bDecoupled = false;
|
||||
//FComponentVisualizer::NotifyPropertyModified(RefHand, FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandRelativePlacement)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TArray<FProperty*> PropertiesToModify;
|
||||
PropertiesToModify.Add(FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandRelativePlacement)));
|
||||
PropertiesToModify.Add(FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, bDecoupled)));
|
||||
FComponentVisualizer::NotifyPropertiesModified(HandSocketComponent.Get(), PropertiesToModify);
|
||||
}
|
||||
|
||||
void FHandSocketComponentDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
|
||||
{
|
||||
// Hide the SplineCurves property
|
||||
//TSharedPtr<IPropertyHandle> HandPlacementProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandRelativePlacement));
|
||||
//HandPlacementProperty->MarkHiddenByCustomization();
|
||||
|
||||
|
||||
TArray<TWeakObjectPtr<UObject>> ObjectsBeingCustomized;
|
||||
DetailBuilder.GetObjectsBeingCustomized(ObjectsBeingCustomized);
|
||||
|
||||
if (ObjectsBeingCustomized.Num() == 1)
|
||||
{
|
||||
UHandSocketComponent* CurrentHandSocket = Cast<UHandSocketComponent>(ObjectsBeingCustomized[0]);
|
||||
if (CurrentHandSocket != NULL)
|
||||
{
|
||||
if (HandSocketComponent != CurrentHandSocket)
|
||||
{
|
||||
TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(CurrentHandSocket->GetClass());
|
||||
FHandSocketVisualizer* HandVisualizer = (FHandSocketVisualizer*)Visualizer.Get();
|
||||
|
||||
if (HandVisualizer)
|
||||
{
|
||||
HandVisualizer->CurrentlySelectedBoneIdx = INDEX_NONE;
|
||||
HandVisualizer->CurrentlySelectedBone = NAME_None;
|
||||
HandVisualizer->HandPropertyPath = FComponentPropertyPath();
|
||||
//HandVisualizer->OldHandSocketComp = CurrentHandSocket;
|
||||
}
|
||||
|
||||
HandSocketComponent = CurrentHandSocket;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*const TArray< TWeakObjectPtr<UObject> >& SelectedObjects = DetailBuilder.GetSelectedObjects();
|
||||
for (int32 ObjectIndex = 0; ObjectIndex < SelectedObjects.Num(); ++ObjectIndex)
|
||||
{
|
||||
const TWeakObjectPtr<UObject>& CurrentObject = SelectedObjects[ObjectIndex];
|
||||
if (CurrentObject.IsValid())
|
||||
{
|
||||
UHandSocketComponent* CurrentHandSocket = Cast<UHandSocketComponent>(CurrentObject.Get());
|
||||
if (CurrentHandSocket != NULL)
|
||||
{
|
||||
if (HandSocketComponent != CurrentHandSocket)
|
||||
{
|
||||
TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(CurrentHandSocket->GetClass());
|
||||
FHandSocketVisualizer* HandVisualizer = (FHandSocketVisualizer*)Visualizer.Get();
|
||||
|
||||
if (HandVisualizer)
|
||||
{
|
||||
HandVisualizer->CurrentlySelectedBoneIdx = INDEX_NONE;
|
||||
HandVisualizer->CurrentlySelectedBone = NAME_None;
|
||||
HandVisualizer->HandPropertyPath = FComponentPropertyPath();
|
||||
//HandVisualizer->OldHandSocketComp = CurrentHandSocket;
|
||||
}
|
||||
|
||||
HandSocketComponent = CurrentHandSocket;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
DetailBuilder.HideCategory(FName("ComponentTick"));
|
||||
DetailBuilder.HideCategory(FName("GameplayTags"));
|
||||
DetailBuilder.HideCategory(FName("VRGripInterface"));
|
||||
DetailBuilder.HideCategory(FName("VRGripInterface|Replication"));
|
||||
DetailBuilder.HideCategory(FName("Tags"));
|
||||
DetailBuilder.HideCategory(FName("AssetUserData"));
|
||||
DetailBuilder.HideCategory(FName("Events"));
|
||||
DetailBuilder.HideCategory(FName("Activation"));
|
||||
DetailBuilder.HideCategory(FName("Cooking"));
|
||||
DetailBuilder.HideCategory(FName("ComponentReplication"));
|
||||
|
||||
TSharedPtr<IPropertyHandle> LockedLocationProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UHandSocketComponent, bDecoupleMeshPlacement));
|
||||
TSharedPtr<IPropertyHandle> HandRelativePlacementProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandRelativePlacement));
|
||||
TSharedPtr<IPropertyHandle> LeftHandDominateProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UHandSocketComponent, bLeftHandDominant));
|
||||
|
||||
FSimpleDelegate OnHandRelativeChangedDelegate = FSimpleDelegate::CreateSP(this, &FHandSocketComponentDetails::OnHandRelativeUpdated, &DetailBuilder);
|
||||
HandRelativePlacementProperty->SetOnPropertyValueChanged(OnHandRelativeChangedDelegate);
|
||||
|
||||
FSimpleDelegate OnLockedStateChangedDelegate = FSimpleDelegate::CreateSP(this, &FHandSocketComponentDetails::OnLockedStateUpdated, &DetailBuilder);
|
||||
LockedLocationProperty->SetOnPropertyValueChanged(OnLockedStateChangedDelegate);
|
||||
|
||||
FSimpleDelegate OnLeftDominateChangedDelegate = FSimpleDelegate::CreateSP(this, &FHandSocketComponentDetails::OnLeftDominantUpdated, &DetailBuilder);
|
||||
LeftHandDominateProperty->SetOnPropertyValueChanged(OnLeftDominateChangedDelegate);
|
||||
|
||||
TSharedPtr<IPropertyHandle> ShowVisualizationProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UHandSocketComponent, bShowVisualizationMesh));
|
||||
|
||||
FSimpleDelegate OnShowVisChangedDelegate = FSimpleDelegate::CreateSP(this, &FHandSocketComponentDetails::OnUpdateShowMesh, &DetailBuilder);
|
||||
ShowVisualizationProperty->SetOnPropertyValueChanged(OnShowVisChangedDelegate);
|
||||
|
||||
DetailBuilder.EditCategory("Hand Animation")
|
||||
.AddCustomRow(LOCTEXT("UpdateHandSocketRow", "Save Current Pose"))
|
||||
.NameContent()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Font(IDetailLayoutBuilder::GetDetailFont())
|
||||
.Text(LOCTEXT("UpdateHandSocketText", "Save Current Pose"))
|
||||
]
|
||||
.ValueContent()
|
||||
.MaxDesiredWidth(125.f)
|
||||
.MinDesiredWidth(125.f)
|
||||
[
|
||||
SNew(SButton)
|
||||
.ContentPadding(2)
|
||||
.VAlign(VAlign_Center)
|
||||
.HAlign(HAlign_Center)
|
||||
.OnClicked(this, &FHandSocketComponentDetails::OnUpdateSavePose)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Font(IDetailLayoutBuilder::GetDetailFont())
|
||||
.Text(LOCTEXT("UpdateHandSocketButton", "Save"))
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
void FHandSocketComponentDetails::OnUpdateShowMesh(IDetailLayoutBuilder* LayoutBuilder)
|
||||
{
|
||||
if (!HandSocketComponent.IsValid())
|
||||
return;
|
||||
|
||||
TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(HandSocketComponent->GetClass());
|
||||
FHandSocketVisualizer* HandVisualizer = (FHandSocketVisualizer*)Visualizer.Get();
|
||||
|
||||
if (HandVisualizer)
|
||||
{
|
||||
HandVisualizer->CurrentlySelectedBoneIdx = INDEX_NONE;
|
||||
HandVisualizer->CurrentlySelectedBone = NAME_None;
|
||||
HandVisualizer->HandPropertyPath = FComponentPropertyPath();
|
||||
}
|
||||
}
|
||||
|
||||
FReply FHandSocketComponentDetails::OnUpdateSavePose()
|
||||
{
|
||||
if (HandSocketComponent.IsValid() && HandSocketComponent->CustomPoseDeltas.Num() > 0)
|
||||
{
|
||||
if (HandSocketComponent->HandTargetAnimation || HandSocketComponent->VisualizationMesh)
|
||||
{
|
||||
// Save Animation Pose here
|
||||
FString AssetPath;
|
||||
FString AssetName;
|
||||
PromptUserForAssetPath(AssetPath, AssetName);
|
||||
TWeakObjectPtr<UAnimSequence> NewAnim = SaveAnimationAsset(AssetPath, AssetName);
|
||||
|
||||
// Finally remove the deltas
|
||||
if (NewAnim.IsValid())
|
||||
{
|
||||
HandSocketComponent->Modify();
|
||||
if (AActor* Owner = HandSocketComponent->GetOwner())
|
||||
{
|
||||
Owner->Modify();
|
||||
}
|
||||
|
||||
HandSocketComponent->HandTargetAnimation = NewAnim.Get();
|
||||
HandSocketComponent->CustomPoseDeltas.Empty();
|
||||
HandSocketComponent->bUseCustomPoseDeltas = false;
|
||||
|
||||
TSharedPtr<FComponentVisualizer> Visualizer = GUnrealEd->FindComponentVisualizer(HandSocketComponent->GetClass());
|
||||
FHandSocketVisualizer* HandVisualizer = (FHandSocketVisualizer*)Visualizer.Get();
|
||||
|
||||
if (HandVisualizer)
|
||||
{
|
||||
if (UHandSocketComponent* RefHand = HandVisualizer->GetCurrentlyEditingComponent())
|
||||
{
|
||||
RefHand->HandTargetAnimation = NewAnim.Get();
|
||||
RefHand->CustomPoseDeltas.Empty();
|
||||
RefHand->bUseCustomPoseDeltas = false;
|
||||
/*TArray<FProperty*> PropertiesToModify;
|
||||
PropertiesToModify.Add(FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandTargetAnimation)));
|
||||
PropertiesToModify.Add(FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, bUseCustomPoseDeltas)));
|
||||
PropertiesToModify.Add(FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, CustomPoseDeltas)));
|
||||
FComponentVisualizer::NotifyPropertiesModified(RefHand, PropertiesToModify);*/
|
||||
}
|
||||
}
|
||||
|
||||
// Modify all of the properties at once
|
||||
TArray<FProperty*> PropertiesToModify;
|
||||
PropertiesToModify.Add(FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandTargetAnimation)));
|
||||
PropertiesToModify.Add(FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, bUseCustomPoseDeltas)));
|
||||
PropertiesToModify.Add(FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, CustomPoseDeltas)));
|
||||
FComponentVisualizer::NotifyPropertiesModified(HandSocketComponent.Get(), PropertiesToModify);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
void SCreateHandAnimationDlg::Construct(const FArguments& InArgs)
|
||||
{
|
||||
AssetPath = FText::FromString(FPackageName::GetLongPackagePath(InArgs._DefaultAssetPath.ToString()));
|
||||
AssetName = FText::FromString(FPackageName::GetLongPackageAssetName(InArgs._DefaultAssetPath.ToString()));
|
||||
|
||||
if (AssetPath.IsEmpty())
|
||||
{
|
||||
AssetPath = LastUsedAssetPath;
|
||||
// still empty?
|
||||
if (AssetPath.IsEmpty())
|
||||
{
|
||||
AssetPath = FText::FromString(TEXT("/Game"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LastUsedAssetPath = AssetPath;
|
||||
}
|
||||
|
||||
if (AssetName.IsEmpty())
|
||||
{
|
||||
// find default name for them
|
||||
FAssetToolsModule& AssetToolsModule = FModuleManager::Get().LoadModuleChecked<FAssetToolsModule>("AssetTools");
|
||||
FString OutPackageName, OutAssetName;
|
||||
FString PackageName = AssetPath.ToString() + TEXT("/NewAnimation");
|
||||
|
||||
AssetToolsModule.Get().CreateUniqueAssetName(PackageName, TEXT(""), OutPackageName, OutAssetName);
|
||||
AssetName = FText::FromString(OutAssetName);
|
||||
}
|
||||
|
||||
FPathPickerConfig PathPickerConfig;
|
||||
PathPickerConfig.DefaultPath = AssetPath.ToString();
|
||||
PathPickerConfig.OnPathSelected = FOnPathSelected::CreateSP(this, &SCreateHandAnimationDlg::OnPathChange);
|
||||
PathPickerConfig.bAddDefaultPath = true;
|
||||
|
||||
FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
|
||||
|
||||
SWindow::Construct(SWindow::FArguments()
|
||||
.Title(LOCTEXT("SCreateHandAnimationDlg_Title", "Create New Animation Object"))
|
||||
.SupportsMinimize(false)
|
||||
.SupportsMaximize(false)
|
||||
//.SizingRule( ESizingRule::Autosized )
|
||||
.ClientSize(FVector2D(450, 450))
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
|
||||
+ SVerticalBox::Slot() // Add user input block
|
||||
.Padding(2)
|
||||
[
|
||||
SNew(SBorder)
|
||||
.BorderImage(FAppStyle::GetBrush("ToolPanel.GroupBorder"))
|
||||
[
|
||||
SNew(SVerticalBox)
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(LOCTEXT("SelectPath", "Select Path to create animation"))
|
||||
.Font(FCoreStyle::GetDefaultFontStyle("Regular", 14))
|
||||
]
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.FillHeight(1)
|
||||
.Padding(3)
|
||||
[
|
||||
ContentBrowserModule.Get().CreatePathPicker(PathPickerConfig)
|
||||
]
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
[
|
||||
SNew(SSeparator)
|
||||
]
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
.Padding(3)
|
||||
[
|
||||
SNew(SHorizontalBox)
|
||||
|
||||
+ SHorizontalBox::Slot()
|
||||
.AutoWidth()
|
||||
.Padding(0, 0, 10, 0)
|
||||
.VAlign(VAlign_Center)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Text(LOCTEXT("AnimationName", "Animation Name"))
|
||||
]
|
||||
|
||||
+ SHorizontalBox::Slot()
|
||||
[
|
||||
SNew(SEditableTextBox)
|
||||
.Text(AssetName)
|
||||
.OnTextCommitted(this, &SCreateHandAnimationDlg::OnNameChange)
|
||||
.MinDesiredWidth(250)
|
||||
]
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
+ SVerticalBox::Slot()
|
||||
.AutoHeight()
|
||||
.HAlign(HAlign_Right)
|
||||
.Padding(5)
|
||||
[
|
||||
SNew(SUniformGridPanel)
|
||||
.SlotPadding(FAppStyle::GetMargin("StandardDialog.SlotPadding"))
|
||||
.MinDesiredSlotWidth(FAppStyle::GetFloat("StandardDialog.MinDesiredSlotWidth"))
|
||||
.MinDesiredSlotHeight(FAppStyle::GetFloat("StandardDialog.MinDesiredSlotHeight"))
|
||||
+ SUniformGridPanel::Slot(0, 0)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.ContentPadding(FAppStyle::GetMargin("StandardDialog.ContentPadding"))
|
||||
.Text(LOCTEXT("OK", "OK"))
|
||||
.OnClicked(this, &SCreateHandAnimationDlg::OnButtonClick, EAppReturnType::Ok)
|
||||
]
|
||||
+ SUniformGridPanel::Slot(1, 0)
|
||||
[
|
||||
SNew(SButton)
|
||||
.HAlign(HAlign_Center)
|
||||
.ContentPadding(FAppStyle::GetMargin("StandardDialog.ContentPadding"))
|
||||
.Text(LOCTEXT("Cancel", "Cancel"))
|
||||
.OnClicked(this, &SCreateHandAnimationDlg::OnButtonClick, EAppReturnType::Cancel)
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
void SCreateHandAnimationDlg::OnNameChange(const FText& NewName, ETextCommit::Type CommitInfo)
|
||||
{
|
||||
AssetName = NewName;
|
||||
}
|
||||
|
||||
void SCreateHandAnimationDlg::OnPathChange(const FString& NewPath)
|
||||
{
|
||||
AssetPath = FText::FromString(NewPath);
|
||||
LastUsedAssetPath = AssetPath;
|
||||
}
|
||||
|
||||
FReply SCreateHandAnimationDlg::OnButtonClick(EAppReturnType::Type ButtonID)
|
||||
{
|
||||
UserResponse = ButtonID;
|
||||
|
||||
if (ButtonID != EAppReturnType::Cancel)
|
||||
{
|
||||
if (!ValidatePackage())
|
||||
{
|
||||
// reject the request
|
||||
return FReply::Handled();
|
||||
}
|
||||
}
|
||||
|
||||
RequestDestroyWindow();
|
||||
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
/** Ensures supplied package name information is valid */
|
||||
bool SCreateHandAnimationDlg::ValidatePackage()
|
||||
{
|
||||
FText Reason;
|
||||
FString FullPath = GetFullAssetPath();
|
||||
|
||||
if (!FPackageName::IsValidLongPackageName(FullPath, false, &Reason)
|
||||
|| !FName(*AssetName.ToString()).IsValidObjectName(Reason))
|
||||
{
|
||||
FMessageDialog::Open(EAppMsgType::Ok, Reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
EAppReturnType::Type SCreateHandAnimationDlg::ShowModal()
|
||||
{
|
||||
GEditor->EditorAddModalWindow(SharedThis(this));
|
||||
return UserResponse;
|
||||
}
|
||||
|
||||
FString SCreateHandAnimationDlg::GetAssetPath()
|
||||
{
|
||||
return AssetPath.ToString();
|
||||
}
|
||||
|
||||
FString SCreateHandAnimationDlg::GetAssetName()
|
||||
{
|
||||
return AssetName.ToString();
|
||||
}
|
||||
|
||||
FString SCreateHandAnimationDlg::GetFullAssetPath()
|
||||
{
|
||||
return AssetPath.ToString() + "/" + AssetName.ToString();
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
|
@ -0,0 +1,484 @@
|
|||
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "HandSocketVisualizer.h"
|
||||
#include "CanvasItem.h"
|
||||
#include "CanvasTypes.h"
|
||||
#include "SceneManagement.h"
|
||||
//#include "UObject/Field.h"
|
||||
#include "VRBPDatatypes.h"
|
||||
#include "ScopedTransaction.h"
|
||||
#include "Modules/ModuleManager.h"
|
||||
#include "EditorViewportClient.h"
|
||||
#include "Components/PoseableMeshComponent.h"
|
||||
#include "Misc/PackageName.h"
|
||||
//#include "Persona.h"
|
||||
|
||||
IMPLEMENT_HIT_PROXY(HHandSocketVisProxy, HComponentVisProxy);
|
||||
#define LOCTEXT_NAMESPACE "HandSocketVisualizer"
|
||||
|
||||
bool FHandSocketVisualizer::VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, const FViewportClick& Click)
|
||||
{
|
||||
bool bEditing = false;
|
||||
if (VisProxy && VisProxy->Component.IsValid())
|
||||
{
|
||||
bEditing = true;
|
||||
if (VisProxy->IsA(HHandSocketVisProxy::StaticGetType()))
|
||||
{
|
||||
|
||||
if( const UHandSocketComponent * HandComp = UpdateSelectedHandComponent(VisProxy))
|
||||
{
|
||||
HHandSocketVisProxy* Proxy = (HHandSocketVisProxy*)VisProxy;
|
||||
if (Proxy)
|
||||
{
|
||||
CurrentlySelectedBone = Proxy->TargetBoneName;
|
||||
CurrentlySelectedBoneIdx = Proxy->BoneIdx;
|
||||
TargetViewport = InViewportClient->Viewport;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bEditing;
|
||||
}
|
||||
|
||||
|
||||
bool FHandSocketVisualizer::GetCustomInputCoordinateSystem(const FEditorViewportClient* ViewportClient, FMatrix& OutMatrix) const
|
||||
{
|
||||
if (TargetViewport == nullptr || TargetViewport != ViewportClient->Viewport)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HandPropertyPath.IsValid() && CurrentlySelectedBone != NAME_None/* && CurrentlySelectedBone != "HandSocket"*/)
|
||||
{
|
||||
if (CurrentlySelectedBone == "HandSocket")
|
||||
{
|
||||
UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent();
|
||||
if (CurrentlyEditingComponent)
|
||||
{
|
||||
if (CurrentlyEditingComponent->bMirrorVisualizationMesh)
|
||||
{
|
||||
FTransform NewTrans = CurrentlyEditingComponent->GetRelativeTransform();
|
||||
NewTrans.Mirror(CurrentlyEditingComponent->GetAsEAxis(CurrentlyEditingComponent->MirrorAxis), CurrentlyEditingComponent->GetAsEAxis(CurrentlyEditingComponent->FlipAxis));
|
||||
|
||||
if (USceneComponent* ParentComp = CurrentlyEditingComponent->GetAttachParent())
|
||||
{
|
||||
NewTrans = NewTrans * ParentComp->GetComponentTransform();
|
||||
}
|
||||
|
||||
OutMatrix = FRotationMatrix::Make(NewTrans.GetRotation());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else if (CurrentlySelectedBone == "Visualizer")
|
||||
{
|
||||
if (UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent())
|
||||
{
|
||||
|
||||
FTransform newTrans = FTransform::Identity;
|
||||
if (CurrentlyEditingComponent->bDecoupleMeshPlacement)
|
||||
{
|
||||
if (USceneComponent* ParentComp = CurrentlyEditingComponent->GetAttachParent())
|
||||
{
|
||||
newTrans = CurrentlyEditingComponent->HandRelativePlacement * ParentComp->GetComponentTransform();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newTrans = CurrentlyEditingComponent->GetHandRelativePlacement() * CurrentlyEditingComponent->GetComponentTransform();
|
||||
}
|
||||
|
||||
OutMatrix = FRotationMatrix::Make(newTrans.GetRotation());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent())
|
||||
{
|
||||
if (IsValid(CurrentlyEditingComponent->HandVisualizerComponent))
|
||||
{
|
||||
FTransform newTrans = CurrentlyEditingComponent->HandVisualizerComponent->GetBoneTransform(CurrentlySelectedBoneIdx);
|
||||
FQuat Rot = newTrans.GetRotation();
|
||||
if (!newTrans.GetRotation().ContainsNaN())
|
||||
{
|
||||
Rot.Normalize();
|
||||
OutMatrix = FRotationMatrix::Make(Rot);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FHandSocketVisualizer::IsVisualizingArchetype() const
|
||||
{
|
||||
return (HandPropertyPath.IsValid() && HandPropertyPath.GetParentOwningActor() && FActorEditorUtils::IsAPreviewOrInactiveActor(HandPropertyPath.GetParentOwningActor()));
|
||||
}
|
||||
|
||||
void FHandSocketVisualizer::DrawVisualizationHUD(const UActorComponent* Component, const FViewport* Viewport, const FSceneView* View, FCanvas* Canvas)
|
||||
{
|
||||
if (TargetViewport == nullptr || TargetViewport != Viewport)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (const UHandSocketComponent* HandComp = Cast<const UHandSocketComponent>(Component))
|
||||
{
|
||||
if (CurrentlySelectedBone != NAME_None)
|
||||
{
|
||||
if (UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent())
|
||||
{
|
||||
if (!IsValid(CurrentlyEditingComponent->HandVisualizerComponent))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int32 XL;
|
||||
int32 YL;
|
||||
const FIntRect CanvasRect = Canvas->GetViewRect();
|
||||
|
||||
FPlane location = View->Project(CurrentlyEditingComponent->HandVisualizerComponent->GetBoneTransform(CurrentlySelectedBoneIdx).GetLocation());
|
||||
StringSize(GEngine->GetLargeFont(), XL, YL, *CurrentlySelectedBone.ToString());
|
||||
//const float DrawPositionX = location.X - XL;
|
||||
//const float DrawPositionY = location.Y - YL;
|
||||
const float DrawPositionX = FMath::FloorToFloat(CanvasRect.Min.X + (CanvasRect.Width() - XL) * 0.5f);
|
||||
const float DrawPositionY = CanvasRect.Min.Y + 50.0f;
|
||||
Canvas->DrawShadowedString(DrawPositionX, DrawPositionY, *CurrentlySelectedBone.ToString(), GEngine->GetLargeFont(), FLinearColor::Yellow);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FHandSocketVisualizer::DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI)
|
||||
{
|
||||
//UWorld* World = Component->GetWorld();
|
||||
//return World && (World->WorldType == EWorldType::EditorPreview || World->WorldType == EWorldType::Inactive);
|
||||
|
||||
//cast the component into the expected component type
|
||||
if (const UHandSocketComponent* HandComponent = Cast<UHandSocketComponent>(Component))
|
||||
{
|
||||
if (!HandComponent->HandVisualizerComponent)
|
||||
return;
|
||||
|
||||
//This is an editor only uproperty of our targeting component, that way we can change the colors if we can't see them against the background
|
||||
const FLinearColor SelectedColor = FLinearColor::Yellow;//TargetingComponent->EditorSelectedColor;
|
||||
const FLinearColor UnselectedColor = FLinearColor::White;//TargetingComponent->EditorUnselectedColor;
|
||||
const FVector Location = HandComponent->HandVisualizerComponent->GetComponentLocation();
|
||||
float BoneScale = 1.0f - ((View->ViewLocation - Location).SizeSquared() / FMath::Square(100.0f));
|
||||
BoneScale = FMath::Clamp(BoneScale, 0.2f, 1.0f);
|
||||
HHandSocketVisProxy* newHitProxy = new HHandSocketVisProxy(Component);
|
||||
newHitProxy->TargetBoneName = "Visualizer";
|
||||
PDI->SetHitProxy(newHitProxy);
|
||||
PDI->DrawPoint(Location, CurrentlySelectedBone == newHitProxy->TargetBoneName ? SelectedColor : FLinearColor::Red, 20.f * BoneScale, SDPG_Foreground);
|
||||
PDI->SetHitProxy(NULL);
|
||||
newHitProxy = nullptr;
|
||||
|
||||
newHitProxy = new HHandSocketVisProxy(Component);
|
||||
newHitProxy->TargetBoneName = "HandSocket";
|
||||
BoneScale = 1.0f - ((View->ViewLocation - HandComponent->GetComponentLocation()).SizeSquared() / FMath::Square(100.0f));
|
||||
BoneScale = FMath::Clamp(BoneScale, 0.2f, 1.0f);
|
||||
PDI->SetHitProxy(newHitProxy);
|
||||
PDI->DrawPoint(HandComponent->GetComponentLocation(), FLinearColor::Green, 20.f * BoneScale, SDPG_Foreground);
|
||||
PDI->SetHitProxy(NULL);
|
||||
newHitProxy = nullptr;
|
||||
|
||||
if (HandComponent->bUseCustomPoseDeltas)
|
||||
{
|
||||
TArray<FTransform> BoneTransforms = HandComponent->HandVisualizerComponent->GetBoneSpaceTransforms();
|
||||
FTransform ParentTrans = HandComponent->HandVisualizerComponent->GetComponentTransform();
|
||||
// We skip root bone, moving the visualizer itself handles that
|
||||
for (int i = 1; i < HandComponent->HandVisualizerComponent->GetNumBones(); i++)
|
||||
{
|
||||
|
||||
FName BoneName = HandComponent->HandVisualizerComponent->GetBoneName(i);
|
||||
|
||||
if (HandComponent->bFilterBonesByPostfix)
|
||||
{
|
||||
if (BoneName.ToString().Right(2) != HandComponent->FilterPostfix)
|
||||
{
|
||||
// Skip visualizing this bone its the incorrect side
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (HandComponent->BonesToSkip.Contains(BoneName))
|
||||
{
|
||||
// Skip visualizing this bone as its in the ignore array
|
||||
continue;
|
||||
}
|
||||
|
||||
FTransform BoneTransform = HandComponent->HandVisualizerComponent->GetBoneTransform(i);
|
||||
FVector BoneLoc = BoneTransform.GetLocation();
|
||||
BoneScale = 1.0f - ((View->ViewLocation - BoneLoc).SizeSquared() / FMath::Square(100.0f));
|
||||
BoneScale = FMath::Clamp(BoneScale, 0.1f, 0.9f);
|
||||
newHitProxy = new HHandSocketVisProxy(Component);
|
||||
newHitProxy->TargetBoneName = BoneName;
|
||||
newHitProxy->BoneIdx = i;
|
||||
PDI->SetHitProxy(newHitProxy);
|
||||
PDI->DrawPoint(BoneLoc, CurrentlySelectedBone == newHitProxy->TargetBoneName ? SelectedColor : UnselectedColor, 20.f * BoneScale, SDPG_Foreground);
|
||||
PDI->SetHitProxy(NULL);
|
||||
newHitProxy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (HandComponent->bShowRangeVisualization)
|
||||
{
|
||||
float RangeVisualization = HandComponent->OverrideDistance;
|
||||
|
||||
if (RangeVisualization <= 0.0f)
|
||||
{
|
||||
if (USceneComponent* Parent = Cast<USceneComponent>(HandComponent->GetAttachParent()))
|
||||
{
|
||||
FStructProperty* ObjectProperty = CastField<FStructProperty>(Parent->GetClass()->FindPropertyByName("VRGripInterfaceSettings"));
|
||||
|
||||
AActor* ParentsActor = nullptr;
|
||||
if (!ObjectProperty)
|
||||
{
|
||||
ParentsActor = Parent->GetOwner();
|
||||
if (ParentsActor)
|
||||
{
|
||||
ObjectProperty = CastField<FStructProperty>(Parent->GetOwner()->GetClass()->FindPropertyByName("VRGripInterfaceSettings"));
|
||||
}
|
||||
}
|
||||
|
||||
if (ObjectProperty)
|
||||
{
|
||||
UObject* Target = ParentsActor;
|
||||
|
||||
if (Target == nullptr)
|
||||
{
|
||||
Target = Parent;
|
||||
}
|
||||
|
||||
if (const FBPInterfaceProperties* Curve = ObjectProperty->ContainerPtrToValuePtr<FBPInterfaceProperties>(Target))
|
||||
{
|
||||
if (HandComponent->SlotPrefix == "VRGripS")
|
||||
{
|
||||
RangeVisualization = Curve->SecondarySlotRange;
|
||||
}
|
||||
else
|
||||
{
|
||||
RangeVisualization = Curve->PrimarySlotRange;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Scale into our parents space as that is actually what the range is based on
|
||||
FBox BoxToDraw = FBox::BuildAABB(FVector::ZeroVector, FVector(RangeVisualization) * HandComponent->GetAttachParent()->GetComponentScale());
|
||||
BoxToDraw.Min += HandComponent->GetComponentLocation();
|
||||
BoxToDraw.Max += HandComponent->GetComponentLocation();
|
||||
|
||||
DrawWireBox(PDI, BoxToDraw, FColor::Green, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FHandSocketVisualizer::GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const
|
||||
{
|
||||
if (TargetViewport == nullptr || TargetViewport != ViewportClient->Viewport)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (HandPropertyPath.IsValid() && CurrentlySelectedBone != NAME_None && CurrentlySelectedBone != "HandSocket")
|
||||
{
|
||||
if (CurrentlySelectedBone == "HandSocket")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (CurrentlySelectedBone == "Visualizer")
|
||||
{
|
||||
if (UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent())
|
||||
{
|
||||
FTransform newTrans = FTransform::Identity;
|
||||
if (CurrentlyEditingComponent->bDecoupleMeshPlacement)
|
||||
{
|
||||
if (USceneComponent* ParentComp = CurrentlyEditingComponent->GetAttachParent())
|
||||
{
|
||||
newTrans = CurrentlyEditingComponent->HandRelativePlacement * ParentComp->GetComponentTransform();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newTrans = CurrentlyEditingComponent->GetHandRelativePlacement() * CurrentlyEditingComponent->GetComponentTransform();
|
||||
}
|
||||
|
||||
OutLocation = newTrans.GetLocation();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent())
|
||||
{
|
||||
if (IsValid(CurrentlyEditingComponent->HandVisualizerComponent))
|
||||
{
|
||||
OutLocation = CurrentlyEditingComponent->HandVisualizerComponent->GetBoneTransform(CurrentlySelectedBoneIdx).GetLocation();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FHandSocketVisualizer::HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, FRotator& DeltaRotate, FVector& DeltaScale)
|
||||
{
|
||||
|
||||
if (TargetViewport == nullptr || TargetViewport != Viewport)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bHandled = false;
|
||||
|
||||
if (HandPropertyPath.IsValid())
|
||||
{
|
||||
if (CurrentlySelectedBone == "HandSocket" || CurrentlySelectedBone == NAME_None)
|
||||
{
|
||||
bHandled = false;
|
||||
}
|
||||
else if (CurrentlySelectedBone == "Visualizer")
|
||||
{
|
||||
const FScopedTransaction Transaction(LOCTEXT("ChangingComp", "ChangingComp"));
|
||||
|
||||
UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent();
|
||||
if (!CurrentlyEditingComponent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CurrentlyEditingComponent->Modify();
|
||||
if (AActor* Owner = CurrentlyEditingComponent->GetOwner())
|
||||
{
|
||||
Owner->Modify();
|
||||
}
|
||||
bool bLevelEdit = ViewportClient->IsLevelEditorClient();
|
||||
|
||||
FTransform CurrentTrans = FTransform::Identity;
|
||||
|
||||
if (CurrentlyEditingComponent->bDecoupleMeshPlacement)
|
||||
{
|
||||
if (USceneComponent* ParentComp = CurrentlyEditingComponent->GetAttachParent())
|
||||
{
|
||||
CurrentTrans = CurrentlyEditingComponent->HandRelativePlacement * ParentComp->GetComponentTransform();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentTrans = CurrentlyEditingComponent->GetHandRelativePlacement() * CurrentlyEditingComponent->GetComponentTransform();
|
||||
}
|
||||
|
||||
if (!DeltaTranslate.IsNearlyZero())
|
||||
{
|
||||
CurrentTrans.AddToTranslation(DeltaTranslate);
|
||||
}
|
||||
|
||||
if (!DeltaRotate.IsNearlyZero())
|
||||
{
|
||||
CurrentTrans.SetRotation(DeltaRotate.Quaternion() * CurrentTrans.GetRotation());
|
||||
}
|
||||
|
||||
if (!DeltaScale.IsNearlyZero())
|
||||
{
|
||||
CurrentTrans.MultiplyScale3D(DeltaScale);
|
||||
}
|
||||
|
||||
if (CurrentlyEditingComponent->bDecoupleMeshPlacement)
|
||||
{
|
||||
if (USceneComponent* ParentComp = CurrentlyEditingComponent->GetAttachParent())
|
||||
{
|
||||
CurrentlyEditingComponent->HandRelativePlacement = CurrentTrans.GetRelativeTransform(ParentComp->GetComponentTransform());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentlyEditingComponent->HandRelativePlacement = CurrentTrans.GetRelativeTransform(CurrentlyEditingComponent->GetComponentTransform());
|
||||
}
|
||||
|
||||
NotifyPropertyModified(CurrentlyEditingComponent, FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, HandRelativePlacement)));
|
||||
//GEditor->RedrawLevelEditingViewports(true);
|
||||
bHandled = true;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
UHandSocketComponent* CurrentlyEditingComponent = GetCurrentlyEditingComponent();
|
||||
if (!CurrentlyEditingComponent || !CurrentlyEditingComponent->HandVisualizerComponent)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const FScopedTransaction Transaction(LOCTEXT("ChangingComp", "ChangingComp"));
|
||||
|
||||
CurrentlyEditingComponent->Modify();
|
||||
if (AActor* Owner = CurrentlyEditingComponent->GetOwner())
|
||||
{
|
||||
Owner->Modify();
|
||||
}
|
||||
bool bLevelEdit = ViewportClient->IsLevelEditorClient();
|
||||
|
||||
FTransform BoneTrans = CurrentlyEditingComponent->HandVisualizerComponent->GetBoneTransform(CurrentlySelectedBoneIdx);
|
||||
FTransform NewTrans = BoneTrans;
|
||||
NewTrans.SetRotation(DeltaRotate.Quaternion() * NewTrans.GetRotation());
|
||||
|
||||
FQuat DeltaRotateMod = NewTrans.GetRelativeTransform(BoneTrans).GetRotation();
|
||||
bool bFoundBone = false;
|
||||
for (FBPVRHandPoseBonePair& BonePair : CurrentlyEditingComponent->CustomPoseDeltas)
|
||||
{
|
||||
if (BonePair.BoneName == CurrentlySelectedBone)
|
||||
{
|
||||
bFoundBone = true;
|
||||
BonePair.DeltaPose *= DeltaRotateMod;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bFoundBone)
|
||||
{
|
||||
FBPVRHandPoseBonePair newBonePair;
|
||||
newBonePair.BoneName = CurrentlySelectedBone;
|
||||
newBonePair.DeltaPose *= DeltaRotateMod;
|
||||
CurrentlyEditingComponent->CustomPoseDeltas.Add(newBonePair);
|
||||
bFoundBone = true;
|
||||
}
|
||||
|
||||
if (bFoundBone)
|
||||
{
|
||||
NotifyPropertyModified(CurrentlyEditingComponent, FindFProperty<FProperty>(UHandSocketComponent::StaticClass(), GET_MEMBER_NAME_CHECKED(UHandSocketComponent, CustomPoseDeltas)));
|
||||
}
|
||||
|
||||
//GEditor->RedrawLevelEditingViewports(true);
|
||||
bHandled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return bHandled;
|
||||
}
|
||||
|
||||
void FHandSocketVisualizer::EndEditing()
|
||||
{
|
||||
HandPropertyPath = FComponentPropertyPath();
|
||||
CurrentlySelectedBone = NAME_None;
|
||||
CurrentlySelectedBoneIdx = INDEX_NONE;
|
||||
TargetViewport = nullptr;
|
||||
}
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "VRExpansionEditor.h"
|
||||
#include "Editor/UnrealEdEngine.h"
|
||||
#include "UnrealEdGlobals.h"
|
||||
#include "Grippables/HandSocketComponent.h"
|
||||
#include "PropertyEditorModule.h"
|
||||
#include "HandSocketVisualizer.h"
|
||||
#include "HandSocketComponentDetails.h"
|
||||
#include "VRGlobalSettingsDetails.h"
|
||||
#include "VRGlobalSettings.h"
|
||||
|
||||
|
||||
IMPLEMENT_MODULE(FVRExpansionEditorModule, VRExpansionEditor);
|
||||
|
||||
void FVRExpansionEditorModule::StartupModule()
|
||||
{
|
||||
RegisterComponentVisualizer(UHandSocketComponent::StaticClass()->GetFName(), MakeShareable(new FHandSocketVisualizer));
|
||||
|
||||
// Register detail customizations
|
||||
{
|
||||
auto& PropertyModule = FModuleManager::LoadModuleChecked< FPropertyEditorModule >("PropertyEditor");
|
||||
|
||||
// Register our customization to be used by a class 'UMyClass' or 'AMyClass'. Note the prefix must be dropped.
|
||||
PropertyModule.RegisterCustomClassLayout(
|
||||
UHandSocketComponent::StaticClass()->GetFName(),
|
||||
FOnGetDetailCustomizationInstance::CreateStatic(&FHandSocketComponentDetails::MakeInstance)
|
||||
);
|
||||
|
||||
PropertyModule.RegisterCustomClassLayout(
|
||||
UVRGlobalSettings::StaticClass()->GetFName(),
|
||||
FOnGetDetailCustomizationInstance::CreateStatic(&FVRGlobalSettingsDetails::MakeInstance)
|
||||
);
|
||||
|
||||
PropertyModule.NotifyCustomizationModuleChanged();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void FVRExpansionEditorModule::ShutdownModule()
|
||||
{
|
||||
if (GUnrealEd != NULL)
|
||||
{
|
||||
// Iterate over all class names we registered for
|
||||
for (FName ClassName : RegisteredComponentClassNames)
|
||||
{
|
||||
GUnrealEd->UnregisterComponentVisualizer(ClassName);
|
||||
}
|
||||
}
|
||||
|
||||
if (FModuleManager::Get().IsModuleLoaded("PropertyEditor"))
|
||||
{
|
||||
auto& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
||||
|
||||
PropertyModule.UnregisterCustomClassLayout(UHandSocketComponent::StaticClass()->GetFName());
|
||||
PropertyModule.UnregisterCustomClassLayout(UVRGlobalSettings::StaticClass()->GetFName());
|
||||
}
|
||||
}
|
||||
|
||||
void FVRExpansionEditorModule::RegisterComponentVisualizer(FName ComponentClassName, TSharedPtr<FComponentVisualizer> Visualizer)
|
||||
{
|
||||
if (GUnrealEd != NULL)
|
||||
{
|
||||
GUnrealEd->RegisterComponentVisualizer(ComponentClassName, Visualizer);
|
||||
}
|
||||
|
||||
RegisteredComponentClassNames.Add(ComponentClassName);
|
||||
|
||||
if (Visualizer.IsValid())
|
||||
{
|
||||
Visualizer->OnRegister();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#include "VRGlobalSettingsDetails.h"
|
||||
#include "VRGlobalSettings.h"
|
||||
//#include "PropertyEditing.h"
|
||||
#include "Widgets/Text/STextBlock.h"
|
||||
#include "Widgets/Input/SButton.h"
|
||||
//#include "PropertyHandle.h"
|
||||
#include "DetailLayoutBuilder.h"
|
||||
#include "DetailWidgetRow.h"
|
||||
#include "DetailCategoryBuilder.h"
|
||||
#include "IDetailsView.h"
|
||||
|
||||
//#include "Developer/AssetTools/Public/IAssetTools.h"
|
||||
//#include "Developer/AssetTools/Public/AssetToolsModule.h"
|
||||
//#include "Editor/ContentBrowser/Public/IContentBrowserSingleton.h"
|
||||
//#include "Editor/ContentBrowser/Public/ContentBrowserModule.h"
|
||||
//#include "AnimationUtils.h"
|
||||
|
||||
#include "UObject/SavePackage.h"
|
||||
#include "Misc/MessageDialog.h"
|
||||
//#include "Widgets/Layout/SBorder.h"
|
||||
//#include "Widgets/Layout/SSeparator.h"
|
||||
//#include "Widgets/Layout/SUniformGridPanel.h"
|
||||
//#include "Widgets/Input/SEditableTextBox.h"
|
||||
#include "Editor.h"
|
||||
#include "EditorStyleSet.h"
|
||||
#include "Styling/CoreStyle.h"
|
||||
|
||||
#include "Animation/AnimData/AnimDataModel.h"
|
||||
#include "AssetRegistry/AssetRegistryModule.h"
|
||||
#include "AssetRegistry/ARFilter.h"
|
||||
|
||||
#include "FileHelpers.h"
|
||||
#include "Engine/Engine.h"
|
||||
#include "Editor/UnrealEdEngine.h"
|
||||
#include "UnrealEdGlobals.h"
|
||||
|
||||
#define LOCTEXT_NAMESPACE "VRGlobalSettingsDetails"
|
||||
|
||||
|
||||
TSharedRef< IDetailCustomization > FVRGlobalSettingsDetails::MakeInstance()
|
||||
{
|
||||
return MakeShareable(new FVRGlobalSettingsDetails);
|
||||
}
|
||||
|
||||
void FVRGlobalSettingsDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
|
||||
{
|
||||
//DetailBuilder.HideCategory(FName("ComponentTick"));
|
||||
//DetailBuilder.HideCategory(FName("GameplayTags"));
|
||||
|
||||
|
||||
//TSharedPtr<IPropertyHandle> LockedLocationProperty = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UHandSocketComponent, bDecoupleMeshPlacement));
|
||||
|
||||
//FSimpleDelegate OnLockedStateChangedDelegate = FSimpleDelegate::CreateSP(this, &FVRGlobalSettingsDetails::OnLockedStateUpdated, &DetailBuilder);
|
||||
//LockedLocationProperty->SetOnPropertyValueChanged(OnLockedStateChangedDelegate);
|
||||
|
||||
DetailBuilder.EditCategory("Utilities")
|
||||
.AddCustomRow(LOCTEXT("FixInvalidAnimationAssets", "Fix Invalid 5.2 Animation Assets"))
|
||||
.NameContent()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Font(IDetailLayoutBuilder::GetDetailFont())
|
||||
.Text(LOCTEXT("FixInvalidAnimationAssets", "Fix Invalid 5.2 Animation Assets"))
|
||||
]
|
||||
.ValueContent()
|
||||
.MaxDesiredWidth(125.f)
|
||||
.MinDesiredWidth(125.f)
|
||||
[
|
||||
SNew(SButton)
|
||||
.ContentPadding(2)
|
||||
.VAlign(VAlign_Center)
|
||||
.HAlign(HAlign_Center)
|
||||
.OnClicked(this, &FVRGlobalSettingsDetails::OnCorrectInvalidAnimationAssets)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Font(IDetailLayoutBuilder::GetDetailFont())
|
||||
.Text(LOCTEXT("FixInvalidAnimationAssetsButton", "Fix Animation Assets"))
|
||||
]
|
||||
];
|
||||
|
||||
/*DetailBuilder.EditCategory("Utilities")
|
||||
.AddCustomRow(LOCTEXT("Fix 5.4.0 Shadow Shader", "Fix Broken 5.4.0 Shadow Shader"))
|
||||
.NameContent()
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Font(IDetailLayoutBuilder::GetDetailFont())
|
||||
.Text(LOCTEXT("Fix54ShadowShader", "Fix Broken 5.4.0 Shadow Shader"))
|
||||
]
|
||||
.ValueContent()
|
||||
.MaxDesiredWidth(125.f)
|
||||
.MinDesiredWidth(125.f)
|
||||
[
|
||||
SNew(SButton)
|
||||
.ContentPadding(2)
|
||||
.VAlign(VAlign_Center)
|
||||
.HAlign(HAlign_Center)
|
||||
.OnClicked(this, &FVRGlobalSettingsDetails::OnFixShadowShader)
|
||||
[
|
||||
SNew(STextBlock)
|
||||
.Font(IDetailLayoutBuilder::GetDetailFont())
|
||||
.Text(LOCTEXT("Fix54ShadowShaderButton", "Fix Broken 5.4.0 Shadow Shader"))
|
||||
]
|
||||
];*/
|
||||
}
|
||||
|
||||
/*FReply FVRGlobalSettingsDetails::OnFixShadowShader()
|
||||
{
|
||||
#if ENGINE_MAJOR_VERSION == 5 && ENGINE_MINOR_VERSION == 4
|
||||
FString EnginePath = FPaths::EngineDir();
|
||||
EnginePath += "/Shaders/Private/ShadowProjectionPixelShader.usf";
|
||||
|
||||
if (FPlatformFileManager::Get().GetPlatformFile().FileExists(*EnginePath))
|
||||
{
|
||||
FString FileStr = "";
|
||||
if (FFileHelper::LoadFileToString(FileStr, *EnginePath))
|
||||
{
|
||||
// Don't need to do anything complicated, the shader only contains one line with this define in it
|
||||
FileStr = FileStr.Replace(TEXT("#if MOBILE_MULTI_VIEW || INSTANCED_STEREO"),TEXT("#if ((MOBILE_MULTI_VIEW || INSTANCED_STEREO) && SHADING_PATH_MOBILE)"));
|
||||
|
||||
FFileHelper::SaveStringToFile(FileStr, *EnginePath);
|
||||
|
||||
GEngine->Exec(GEngine->GetWorld(), TEXT("recompileshaders changed"));
|
||||
UE_LOG(LogPath, Log, TEXT("ShadowProjectionPixelShader.usf resaved and recompiled!"));
|
||||
return FReply::Handled();
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
UE_LOG(LogPath, Error, TEXT("ShadowProjectionPixelShader.usf could not be found, edited, or the engine version is incorrect!"));
|
||||
return FReply::Handled();
|
||||
}*/
|
||||
|
||||
FReply FVRGlobalSettingsDetails::OnCorrectInvalidAnimationAssets()
|
||||
{
|
||||
|
||||
// Load the asset registry module
|
||||
FAssetRegistryModule& AssetRegistryModule = FModuleManager::LoadModuleChecked< FAssetRegistryModule >(FName("AssetRegistry"));
|
||||
IAssetRegistry& AssetRegistry = AssetRegistryModule.Get();
|
||||
TArray< FString > ContentPaths;
|
||||
ContentPaths.Add(TEXT("/Game"));
|
||||
AssetRegistry.ScanPathsSynchronous(ContentPaths);
|
||||
|
||||
FARFilter Filter;
|
||||
Filter.ClassPaths.Add(UAnimSequence::StaticClass()->GetClassPathName());
|
||||
//Filter.ClassNames.Add(UAnimSequence::StaticClass()->GetFName());
|
||||
Filter.bRecursiveClasses = true;
|
||||
//if (!Path.IsEmpty())
|
||||
//{
|
||||
// Filter.PackagePaths.Add(*Path);
|
||||
//}
|
||||
Filter.bRecursivePaths = true;
|
||||
|
||||
TArray< FAssetData > AssetList;
|
||||
AssetRegistry.GetAssets(Filter, AssetList);
|
||||
|
||||
// Iterate over retrieved blueprint assets
|
||||
for (auto& Asset : AssetList)
|
||||
{
|
||||
// Check the anim sequence for invalid data
|
||||
if (UAnimSequence* AnimSeq = Cast<UAnimSequence>(Asset.GetAsset()))
|
||||
{
|
||||
IAnimationDataController& AnimController = AnimSeq->GetController();
|
||||
{
|
||||
IAnimationDataController::FScopedBracket ScopedBracket(AnimController, LOCTEXT("FixAnimationAsset_VRE", "Fixing invalid anim sequences"));
|
||||
const IAnimationDataModel* AnimModel = AnimController.GetModel();
|
||||
|
||||
FFrameRate FrameRate = AnimModel->GetFrameRate();
|
||||
//int32 NumFrames = AnimModel->GetNumberOfFrames();
|
||||
double FrameRateD = FrameRate.AsDecimal();
|
||||
|
||||
// I was saving with a below 1.0 frame rate and 1 frame
|
||||
if (FrameRateD < 1.0f)
|
||||
{
|
||||
// We have an invalid frame rate for 5.2
|
||||
AnimController.SetFrameRate(FFrameRate(1, 1));
|
||||
AnimSeq->MarkPackageDirty();
|
||||
|
||||
UPackage* const Package = AnimSeq->GetOutermost();
|
||||
FString const PackageName = Package->GetName();
|
||||
FString const PackageFileName = FPackageName::LongPackageNameToFilename(PackageName, FPackageName::GetAssetPackageExtension());
|
||||
|
||||
double StartTime = FPlatformTime::Seconds();
|
||||
|
||||
FSavePackageArgs PackageArguments;
|
||||
PackageArguments.SaveFlags = RF_Standalone;
|
||||
PackageArguments.SaveFlags = SAVE_NoError;
|
||||
UPackage::SavePackage(Package, NULL, *PackageFileName, PackageArguments);
|
||||
//UPackage::SavePackage(Package, NULL, RF_Standalone, *PackageFileName, GError, nullptr, false, true, SAVE_NoError);
|
||||
|
||||
double ElapsedTime = FPlatformTime::Seconds() - StartTime;
|
||||
UE_LOG(LogAnimation, Log, TEXT("Animation re-saved %s in %0.2f seconds"), *PackageName, ElapsedTime);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return FReply::Handled();
|
||||
}
|
||||
|
||||
|
||||
#undef LOCTEXT_NAMESPACE
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Grippables/HandSocketComponent.h"
|
||||
#include "IDetailCustomization.h"
|
||||
#include "Input/Reply.h"
|
||||
#include "Widgets/DeclarativeSyntaxSupport.h"
|
||||
#include "Widgets/SWindow.h"
|
||||
|
||||
class IDetailLayoutBuilder;
|
||||
|
||||
class FHandSocketComponentDetails : public IDetailCustomization
|
||||
{
|
||||
public:
|
||||
/** Makes a new instance of this detail layout class for a specific detail view requesting it */
|
||||
static TSharedRef<IDetailCustomization> MakeInstance();
|
||||
|
||||
/** IDetailCustomization interface */
|
||||
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
|
||||
//void SortCategories(const TMap<FName, IDetailCategoryBuilder*>& AllCategoryMap);
|
||||
|
||||
// The selected hand component
|
||||
TWeakObjectPtr<UHandSocketComponent> HandSocketComponent;
|
||||
FReply OnUpdateSavePose();
|
||||
TWeakObjectPtr<UAnimSequence> SaveAnimationAsset(const FString& InAssetPath, const FString& InAssetName);
|
||||
|
||||
void OnLockedStateUpdated(IDetailLayoutBuilder* LayoutBuilder);
|
||||
void OnLeftDominantUpdated(IDetailLayoutBuilder* LayoutBuilder);
|
||||
void OnHandRelativeUpdated(IDetailLayoutBuilder* LayoutBuilder);
|
||||
void OnUpdateShowMesh(IDetailLayoutBuilder* LayoutBuilder);
|
||||
|
||||
FHandSocketComponentDetails()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class SCreateHandAnimationDlg : public SWindow
|
||||
{
|
||||
public:
|
||||
SLATE_BEGIN_ARGS(SCreateHandAnimationDlg)
|
||||
{
|
||||
}
|
||||
|
||||
SLATE_ARGUMENT(FText, DefaultAssetPath)
|
||||
SLATE_END_ARGS()
|
||||
|
||||
SCreateHandAnimationDlg()
|
||||
: UserResponse(EAppReturnType::Cancel)
|
||||
{
|
||||
}
|
||||
|
||||
void Construct(const FArguments& InArgs);
|
||||
|
||||
public:
|
||||
/** Displays the dialog in a blocking fashion */
|
||||
EAppReturnType::Type ShowModal();
|
||||
|
||||
/** Gets the resulting asset path */
|
||||
FString GetAssetPath();
|
||||
|
||||
/** Gets the resulting asset name */
|
||||
FString GetAssetName();
|
||||
|
||||
/** Gets the resulting full asset path (path+'/'+name) */
|
||||
FString GetFullAssetPath();
|
||||
|
||||
protected:
|
||||
void OnPathChange(const FString& NewPath);
|
||||
void OnNameChange(const FText& NewName, ETextCommit::Type CommitInfo);
|
||||
FReply OnButtonClick(EAppReturnType::Type ButtonID);
|
||||
|
||||
bool ValidatePackage();
|
||||
|
||||
EAppReturnType::Type UserResponse;
|
||||
FText AssetPath;
|
||||
FText AssetName;
|
||||
|
||||
static FText LastUsedAssetPath;
|
||||
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
|
||||
#include "ComponentVisualizer.h"
|
||||
#include "Grippables/HandSocketComponent.h"
|
||||
#include "ActorEditorUtils.h"
|
||||
|
||||
class FEditorViewportClient;
|
||||
|
||||
/**Base class for clickable targeting editing proxies*/
|
||||
struct VREXPANSIONEDITOR_API HHandSocketVisProxy : public HComponentVisProxy
|
||||
{
|
||||
DECLARE_HIT_PROXY();
|
||||
|
||||
HHandSocketVisProxy(const UActorComponent* InComponent)
|
||||
: HComponentVisProxy(InComponent, HPP_Wireframe)
|
||||
{
|
||||
BoneIdx = 0;
|
||||
TargetBoneName = NAME_None;
|
||||
}
|
||||
|
||||
uint32 BoneIdx;
|
||||
FName TargetBoneName;
|
||||
};
|
||||
|
||||
class VREXPANSIONEDITOR_API FHandSocketVisualizer : public FComponentVisualizer
|
||||
{
|
||||
public:
|
||||
FHandSocketVisualizer()
|
||||
{
|
||||
CurrentlySelectedBone = NAME_None;
|
||||
CurrentlySelectedBoneIdx = INDEX_NONE;
|
||||
HandPropertyPath = FComponentPropertyPath();
|
||||
TargetViewport = nullptr;
|
||||
}
|
||||
|
||||
virtual ~FHandSocketVisualizer()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
UPROPERTY()
|
||||
FComponentPropertyPath HandPropertyPath;
|
||||
|
||||
FName CurrentlySelectedBone;
|
||||
uint32 CurrentlySelectedBoneIdx;
|
||||
|
||||
UPROPERTY()
|
||||
FViewport* TargetViewport;
|
||||
|
||||
UHandSocketComponent* GetCurrentlyEditingComponent() const
|
||||
{
|
||||
return Cast<UHandSocketComponent>(HandPropertyPath.GetComponent());;
|
||||
}
|
||||
|
||||
const UHandSocketComponent* UpdateSelectedHandComponent(HComponentVisProxy* VisProxy)
|
||||
{
|
||||
const UHandSocketComponent* HandComp = CastChecked<const UHandSocketComponent>(VisProxy->Component.Get());
|
||||
UHandSocketComponent* OldHandComp = Cast<UHandSocketComponent>(HandPropertyPath.GetComponent());
|
||||
AActor* OldOwningActor = HandPropertyPath.GetParentOwningActor();
|
||||
HandPropertyPath = FComponentPropertyPath(HandComp);
|
||||
AActor* NewOwningActor = HandPropertyPath.GetParentOwningActor();
|
||||
|
||||
if (HandPropertyPath.IsValid())
|
||||
{
|
||||
if (OldOwningActor != NewOwningActor || OldHandComp != HandComp)
|
||||
{
|
||||
// Reset selection state if we are selecting a different actor to the one previously selected
|
||||
CurrentlySelectedBoneIdx = INDEX_NONE;
|
||||
CurrentlySelectedBone = NAME_None;
|
||||
}
|
||||
|
||||
return HandComp;
|
||||
}
|
||||
|
||||
HandPropertyPath = FComponentPropertyPath();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool SaveAnimationAsset(const FString& InAssetPath, const FString& InAssetName);
|
||||
|
||||
|
||||
bool GetCustomInputCoordinateSystem(const FEditorViewportClient* ViewportClient, FMatrix& OutMatrix) const override;
|
||||
|
||||
bool IsVisualizingArchetype() const override;
|
||||
|
||||
virtual void DrawVisualization(const UActorComponent* Component, const FSceneView* View, FPrimitiveDrawInterface* PDI) override;
|
||||
virtual void DrawVisualizationHUD(const UActorComponent* Component, const FViewport* Viewport, const FSceneView* View, FCanvas* Canvas) override;
|
||||
virtual bool VisProxyHandleClick(FEditorViewportClient* InViewportClient, HComponentVisProxy* VisProxy, const FViewportClick& Click) override;
|
||||
bool GetWidgetLocation(const FEditorViewportClient* ViewportClient, FVector& OutLocation) const override;
|
||||
bool HandleInputDelta(FEditorViewportClient* ViewportClient, FViewport* Viewport, FVector& DeltaTranslate, FRotator& DeltaRotate, FVector& DeltaScale) override;
|
||||
virtual void EndEditing() override;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Runtime/Core/Public/Modules/ModuleInterface.h"
|
||||
|
||||
#include "ComponentVisualizer.h"
|
||||
|
||||
class FVRExpansionEditorModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
void RegisterComponentVisualizer(FName ComponentClassName, TSharedPtr<FComponentVisualizer> Visualizer);
|
||||
|
||||
/** Array of component class names we have registered, so we know what to unregister afterwards */
|
||||
TArray<FName> RegisteredComponentClassNames;
|
||||
};
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "IDetailCustomization.h"
|
||||
#include "Input/Reply.h"
|
||||
#include "Widgets/DeclarativeSyntaxSupport.h"
|
||||
#include "Widgets/SWindow.h"
|
||||
|
||||
class IDetailLayoutBuilder;
|
||||
|
||||
class FVRGlobalSettingsDetails : public IDetailCustomization
|
||||
{
|
||||
public:
|
||||
/** Makes a new instance of this detail layout class for a specific detail view requesting it */
|
||||
static TSharedRef<IDetailCustomization> MakeInstance();
|
||||
|
||||
/** IDetailCustomization interface */
|
||||
virtual void CustomizeDetails(IDetailLayoutBuilder& DetailBuilder) override;
|
||||
|
||||
FReply OnCorrectInvalidAnimationAssets();
|
||||
|
||||
FReply OnFixShadowShader();
|
||||
|
||||
void OnLockedStateUpdated(IDetailLayoutBuilder* LayoutBuilder);
|
||||
|
||||
|
||||
FVRGlobalSettingsDetails()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
|
||||
|
||||
using System.IO;
|
||||
|
||||
namespace UnrealBuildTool.Rules
|
||||
{
|
||||
public class VRExpansionEditor : ModuleRules
|
||||
{
|
||||
|
||||
public VRExpansionEditor(ReadOnlyTargetRules Target) : base(Target)
|
||||
{
|
||||
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
|
||||
|
||||
PublicIncludePaths.AddRange(
|
||||
new string[] {
|
||||
// ... add public include paths required here ...
|
||||
}
|
||||
);
|
||||
|
||||
PrivateIncludePaths.AddRange(
|
||||
new string[] {
|
||||
// ... add other private include paths required here ...
|
||||
}
|
||||
);
|
||||
|
||||
PublicDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
// ... add other public dependencies that you statically link with here ...
|
||||
"Engine",
|
||||
"Core",
|
||||
"CoreUObject",
|
||||
"VRExpansionPlugin",
|
||||
}
|
||||
);
|
||||
|
||||
PrivateDependencyModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
"UnrealEd",
|
||||
"BlueprintGraph",
|
||||
"AnimGraph",
|
||||
"AnimGraphRuntime",
|
||||
"SlateCore",
|
||||
"Slate",
|
||||
"InputCore",
|
||||
"Engine",
|
||||
"UnrealEd",
|
||||
"EditorStyle",
|
||||
"AssetRegistry"
|
||||
}
|
||||
);
|
||||
|
||||
DynamicallyLoadedModuleNames.AddRange(
|
||||
new string[]
|
||||
{
|
||||
// ... add any modules that your module loads dynamically here ...
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue