You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#ttp 331829 - Mobile Preview in Editor #proj Engine #branch UE4 #summary First pass of changes to remove GRHIFeatureLevel, allowing for multiple scenes with different feature levels to exist. First step towards dynamic mobile preview in the editor. #change Added GMaxRHIFeature level which contains the highest supported feature level on this machine #change Added a cvar "r.FeatureLevelPreview" which, when set to 1, enables a feature level selection in the quick settings menu. Not wired up to anything at the minute #change Added a feature level variable to FScene, which is currently initialized to whatever GRHIFeatureLevel is. Accessed with GetFeatureLevel() #change Added a helper accessor GetFeatureLevel() to FSceneView which gets the feature level from the relevant scene. Purely to reduce the amount of typing needed to get to a feature level #change Many changes across the renderer to try and read the current feature level from the view or scene. Not everything is done yet, but this is almost all of the "easy" stuff. As there is still just a global feature level in the engine, nothing should change. [CL 2066905 by Graeme Thornton in Main branch]
572 lines
18 KiB
C++
572 lines
18 KiB
C++
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "DetailCustomizationsPrivatePCH.h"
|
|
#include "AnimSequenceDetails.h"
|
|
#include "AnimMontageSegmentDetails.h"
|
|
#include "AnimPreviewInstance.h"
|
|
#include "Runtime/Engine/Public/Slate/SceneViewport.h"
|
|
#include "Editor/KismetWidgets/Public/SScrubControlPanel.h"
|
|
#include "Runtime/Engine/Public/FXSystem.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "AnimSequenceDetails"
|
|
|
|
// default name for retarget source
|
|
#define DEFAULT_RETARGET_SOURCE_NAME TEXT("Default")
|
|
|
|
TSharedRef<IDetailCustomization> FAnimSequenceDetails::MakeInstance()
|
|
{
|
|
return MakeShareable(new FAnimSequenceDetails);
|
|
}
|
|
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
void FAnimSequenceDetails::CustomizeDetails(IDetailLayoutBuilder& DetailBuilder)
|
|
{
|
|
// retarget source handler
|
|
IDetailCategoryBuilder& AnimationCategory = DetailBuilder.EditCategory("Animation");
|
|
RetargetSourceNameHandler = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UAnimSequence, RetargetSource));
|
|
|
|
// first create profile combo list
|
|
RetargetSourceComboList.Empty();
|
|
// first one is default one
|
|
RetargetSourceComboList.Add( MakeShareable( new FString (DEFAULT_RETARGET_SOURCE_NAME) ));
|
|
|
|
// find skeleton
|
|
TSharedPtr<IPropertyHandle> SkeletonHanlder = DetailBuilder.GetProperty(TEXT("Skeleton"));
|
|
FName CurrentPoseName;
|
|
ensure (RetargetSourceNameHandler->GetValue(CurrentPoseName) != FPropertyAccess::Fail);
|
|
|
|
// Check if we use only one skeleton
|
|
USkeleton * Skeleton = NULL;
|
|
TArray< TWeakObjectPtr<UObject> > SelectedObjectsList = DetailBuilder.GetDetailsView().GetSelectedObjects();
|
|
for (auto SelectionIt = SelectedObjectsList.CreateIterator(); SelectionIt; ++SelectionIt)
|
|
{
|
|
if (UAnimSequence* TestAnimSequence = Cast<UAnimSequence>(SelectionIt->Get()))
|
|
{
|
|
// we should only have one selected anim sequence
|
|
if(Skeleton && Skeleton != TestAnimSequence->GetSkeleton())
|
|
{
|
|
// Multiple different skeletons
|
|
Skeleton = NULL;
|
|
break;
|
|
}
|
|
Skeleton = TestAnimSequence->GetSkeleton();
|
|
}
|
|
}
|
|
|
|
// set target skeleton. It can be null
|
|
TargetSkeleton = Skeleton;
|
|
|
|
// find what is initial selection is
|
|
TSharedPtr<FString> InitialSelected;
|
|
if (TargetSkeleton.IsValid())
|
|
{
|
|
RegisterRetargetSourceChanged();
|
|
// go through profile and see if it has mine
|
|
for (auto Iter = TargetSkeleton->AnimRetargetSources.CreateConstIterator(); Iter; ++Iter)
|
|
{
|
|
RetargetSourceComboList.Add( MakeShareable( new FString ( Iter.Key().ToString() )));
|
|
|
|
if (Iter.Key() == CurrentPoseName)
|
|
{
|
|
InitialSelected = RetargetSourceComboList.Last();
|
|
}
|
|
}
|
|
}
|
|
|
|
// add widget for editing retarget source
|
|
AnimationCategory.AddCustomRow(RetargetSourceNameHandler->GetPropertyDisplayName())
|
|
.NameContent()
|
|
[
|
|
RetargetSourceNameHandler->CreatePropertyNameWidget()
|
|
]
|
|
.ValueContent()
|
|
[
|
|
SAssignNew(RetargetSourceComboBox, SComboBox< TSharedPtr<FString> >)
|
|
.OptionsSource(&RetargetSourceComboList)
|
|
.OnGenerateWidget(this, &FAnimSequenceDetails::MakeRetargetSourceComboWidget)
|
|
.OnSelectionChanged(this, &FAnimSequenceDetails::OnRetargetSourceChanged)
|
|
.OnComboBoxOpening(this, &FAnimSequenceDetails::OnRetargetSourceComboOpening)
|
|
.InitiallySelectedItem(InitialSelected)
|
|
.IsEnabled( FSlateApplication::Get().GetNormalExecutionAttribute() )
|
|
.ContentPadding(0)
|
|
.Content()
|
|
[
|
|
SNew( STextBlock )
|
|
.Text(this, &FAnimSequenceDetails::GetRetargetSourceComboBoxContent)
|
|
.Font( IDetailLayoutBuilder::GetDetailFont() )
|
|
.ToolTipText(this, &FAnimSequenceDetails::GetRetargetSourceComboBoxToolTip)
|
|
]
|
|
];
|
|
|
|
DetailBuilder.HideProperty(RetargetSourceNameHandler);
|
|
|
|
// now customize to combo box
|
|
IDetailCategoryBuilder& AdditiveSettingsCategory = DetailBuilder.EditCategory("AdditiveSettings");
|
|
|
|
// hide all properties for additive anim and replace them with custom additive settings setup
|
|
AdditiveAnimTypeHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UAnimSequence, AdditiveAnimType));
|
|
RefPoseTypeHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UAnimSequence, RefPoseType));
|
|
RefPoseSeqHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UAnimSequence, RefPoseSeq));
|
|
RefFrameIndexHandle = DetailBuilder.GetProperty(GET_MEMBER_NAME_CHECKED(UAnimSequence, RefFrameIndex));
|
|
|
|
CreateOverridenProperty(DetailBuilder, AdditiveSettingsCategory, AdditiveAnimTypeHandle, TAttribute<EVisibility>( EVisibility::Visible ));
|
|
CreateOverridenProperty(DetailBuilder, AdditiveSettingsCategory, RefPoseTypeHandle, TAttribute<EVisibility>( this, &FAnimSequenceDetails::ShouldShowRefPoseType ));
|
|
|
|
DetailBuilder.HideProperty(RefPoseSeqHandle);
|
|
|
|
AdditiveSettingsCategory.AddCustomRow(RefPoseSeqHandle->GetPropertyDisplayName())
|
|
.Visibility(TAttribute<EVisibility>( this, &FAnimSequenceDetails::ShouldShowRefAnimInfo ))
|
|
.NameContent()
|
|
[
|
|
RefPoseSeqHandle->CreatePropertyNameWidget()
|
|
]
|
|
.ValueContent()
|
|
[
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
RefPoseSeqHandle->CreatePropertyValueWidget()
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew(SAnimationRefPoseViewport)
|
|
.Skeleton(TargetSkeleton.Get())
|
|
.AnimRefPropertyHandle(RefPoseSeqHandle)
|
|
.RefPoseTypeHandle(RefPoseTypeHandle)
|
|
.RefFrameIndexPropertyHandle(RefFrameIndexHandle)
|
|
]
|
|
];
|
|
|
|
CreateOverridenProperty(DetailBuilder, AdditiveSettingsCategory, RefFrameIndexHandle, TAttribute<EVisibility>( this, &FAnimSequenceDetails::ShouldShowRefFrameIndex ));
|
|
}
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
void FAnimSequenceDetails::CreateOverridenProperty(IDetailLayoutBuilder& DetailBuilder, IDetailCategoryBuilder& AdditiveSettingsCategory, TSharedPtr<IPropertyHandle> PropertyHandle, TAttribute<EVisibility> VisibilityAttribute)
|
|
{
|
|
DetailBuilder.HideProperty(PropertyHandle);
|
|
|
|
AdditiveSettingsCategory.AddCustomRow(PropertyHandle->GetPropertyDisplayName())
|
|
.Visibility(VisibilityAttribute)
|
|
.NameContent()
|
|
[
|
|
PropertyHandle->CreatePropertyNameWidget()
|
|
]
|
|
.ValueContent()
|
|
[
|
|
PropertyHandle->CreatePropertyValueWidget()
|
|
];
|
|
}
|
|
|
|
EVisibility FAnimSequenceDetails::ShouldShowRefPoseType() const
|
|
{
|
|
uint8 AdditiveAnimType = AAT_None;
|
|
AdditiveAnimTypeHandle->GetValue(AdditiveAnimType);
|
|
return AdditiveAnimType != AAT_None? EVisibility::Visible : EVisibility::Hidden;
|
|
}
|
|
|
|
EVisibility FAnimSequenceDetails::ShouldShowRefAnimInfo() const
|
|
{
|
|
uint8 AdditiveAnimType = AAT_None;
|
|
uint8 RefPoseType = ABPT_None;
|
|
AdditiveAnimTypeHandle->GetValue(AdditiveAnimType);
|
|
RefPoseTypeHandle->GetValue(RefPoseType);
|
|
return TargetSkeleton.IsValid() && AdditiveAnimType != AAT_None && (RefPoseType == ABPT_AnimScaled || RefPoseType == ABPT_AnimFrame)? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
EVisibility FAnimSequenceDetails::ShouldShowRefFrameIndex() const
|
|
{
|
|
uint8 AdditiveAnimType = AAT_None;
|
|
uint8 RefPoseType = ABPT_None;
|
|
AdditiveAnimTypeHandle->GetValue(AdditiveAnimType);
|
|
RefPoseTypeHandle->GetValue(RefPoseType);
|
|
return TargetSkeleton.IsValid() && AdditiveAnimType != AAT_None && RefPoseType == ABPT_AnimFrame? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
|
|
TSharedRef<SWidget> FAnimSequenceDetails::MakeRetargetSourceComboWidget( TSharedPtr<FString> InItem )
|
|
{
|
|
return SNew(STextBlock) .Text( *InItem ) .Font( IDetailLayoutBuilder::GetDetailFont() );
|
|
}
|
|
|
|
void FAnimSequenceDetails::DelegateRetargetSourceChanged()
|
|
{
|
|
if (TargetSkeleton.IsValid())
|
|
{
|
|
// first create profile combo list
|
|
RetargetSourceComboList.Empty();
|
|
// first one is default one
|
|
RetargetSourceComboList.Add( MakeShareable( new FString (DEFAULT_RETARGET_SOURCE_NAME) ));
|
|
|
|
// go through profile and see if it has mine
|
|
for (auto Iter = TargetSkeleton->AnimRetargetSources.CreateConstIterator(); Iter; ++Iter)
|
|
{
|
|
RetargetSourceComboList.Add( MakeShareable( new FString ( Iter.Key().ToString() )));
|
|
}
|
|
|
|
RetargetSourceComboBox->RefreshOptions();
|
|
}
|
|
}
|
|
|
|
void FAnimSequenceDetails::RegisterRetargetSourceChanged()
|
|
{
|
|
if (TargetSkeleton.IsValid() && !OnDelegateRetargetSourceChanged.IsBound())
|
|
{
|
|
OnDelegateRetargetSourceChanged = USkeleton::FOnRetargetSourceChanged::CreateSP( this, &FAnimSequenceDetails::DelegateRetargetSourceChanged );
|
|
TargetSkeleton->RegisterOnRetargetSourceChanged(OnDelegateRetargetSourceChanged);
|
|
}
|
|
}
|
|
|
|
FAnimSequenceDetails::~FAnimSequenceDetails()
|
|
{
|
|
if (TargetSkeleton.IsValid() && OnDelegateRetargetSourceChanged.IsBound())
|
|
{
|
|
TargetSkeleton->UnregisterOnRetargetSourceChanged(OnDelegateRetargetSourceChanged);
|
|
}
|
|
}
|
|
|
|
void FAnimSequenceDetails::OnRetargetSourceComboOpening()
|
|
{
|
|
FName RetargetSourceName;
|
|
if (RetargetSourceNameHandler->GetValue(RetargetSourceName) != FPropertyAccess::Result::MultipleValues)
|
|
{
|
|
TSharedPtr<FString> ComboStringPtr = GetRetargetSourceString(RetargetSourceName);
|
|
if( ComboStringPtr.IsValid() )
|
|
{
|
|
RetargetSourceComboBox->SetSelectedItem(ComboStringPtr);
|
|
}
|
|
}
|
|
}
|
|
|
|
void FAnimSequenceDetails::OnRetargetSourceChanged( TSharedPtr<FString> NewSelection, ESelectInfo::Type SelectInfo )
|
|
{
|
|
// if it's set from code, we did that on purpose
|
|
if (SelectInfo != ESelectInfo::Direct)
|
|
{
|
|
FString NewValue = *NewSelection.Get();
|
|
|
|
if (NewValue == DEFAULT_RETARGET_SOURCE_NAME)
|
|
{
|
|
NewValue = TEXT("");
|
|
}
|
|
// set profile set up
|
|
ensure ( RetargetSourceNameHandler->SetValue(NewValue) == FPropertyAccess::Result::Success );
|
|
}
|
|
}
|
|
|
|
FString FAnimSequenceDetails::GetRetargetSourceComboBoxContent() const
|
|
{
|
|
FName RetargetSourceName;
|
|
if (RetargetSourceNameHandler->GetValue(RetargetSourceName) == FPropertyAccess::Result::MultipleValues)
|
|
{
|
|
return TEXT("Multiple Values");
|
|
}
|
|
|
|
return (*GetRetargetSourceString(RetargetSourceName).Get());
|
|
}
|
|
|
|
FString FAnimSequenceDetails::GetRetargetSourceComboBoxToolTip() const
|
|
{
|
|
return TEXT("When retargeting, this pose will be used as a base of animation");
|
|
}
|
|
|
|
TSharedPtr<FString> FAnimSequenceDetails::GetRetargetSourceString(FName RetargetSourceName) const
|
|
{
|
|
FString RetargetSourceString = RetargetSourceName.ToString();
|
|
|
|
// go through profile and see if it has mine
|
|
for (int32 Index=1; Index<RetargetSourceComboList.Num(); ++Index)
|
|
{
|
|
if (RetargetSourceString == *RetargetSourceComboList[Index])
|
|
{
|
|
return RetargetSourceComboList[Index];
|
|
}
|
|
}
|
|
|
|
return RetargetSourceComboList[0];
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////
|
|
// based on SAnimationSegmentViewport
|
|
SAnimationRefPoseViewport::~SAnimationRefPoseViewport()
|
|
{
|
|
FFXSystemInterface::Destroy(FXSystem);
|
|
|
|
// clean up components
|
|
if (PreviewComponent)
|
|
{
|
|
for (int32 I=PreviewComponent->AttachChildren.Num()-1; I >= 0; --I) // Iterate backwards because Cleancomponent will remove from AttachChildren
|
|
{
|
|
// PreviewComponet will be cleaned up by PreviewScene,
|
|
// but if anything is attached, it won't be cleaned up,
|
|
// so we'll need to clean them up manually
|
|
CleanupComponent(PreviewComponent->AttachChildren[I]);
|
|
}
|
|
|
|
PreviewComponent->AttachChildren.Empty();
|
|
}
|
|
|
|
// Close viewport
|
|
if (LevelViewportClient.IsValid())
|
|
{
|
|
LevelViewportClient->Viewport = NULL;
|
|
}
|
|
}
|
|
|
|
void SAnimationRefPoseViewport::CleanupComponent(USceneComponent* Component)
|
|
{
|
|
if (Component)
|
|
{
|
|
for (int32 I=0; I<Component->AttachChildren.Num(); ++I)
|
|
{
|
|
CleanupComponent(Component->AttachChildren[I]);
|
|
}
|
|
|
|
Component->AttachChildren.Empty();
|
|
Component->DestroyComponent();
|
|
}
|
|
}
|
|
|
|
SAnimationRefPoseViewport::SAnimationRefPoseViewport()
|
|
: PreviewScene(FPreviewScene::ConstructionValues())
|
|
{
|
|
}
|
|
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
void SAnimationRefPoseViewport::Construct(const FArguments& InArgs)
|
|
{
|
|
FXSystem = FFXSystemInterface::Create(GRHIFeatureLevel);
|
|
|
|
TargetSkeleton = InArgs._Skeleton;
|
|
AnimRefPropertyHandle = InArgs._AnimRefPropertyHandle;
|
|
RefPoseTypeHandle = InArgs._RefPoseTypeHandle;
|
|
RefFrameIndexPropertyHandle = InArgs._RefFrameIndexPropertyHandle;
|
|
|
|
this->ChildSlot
|
|
[
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SAssignNew(Description, STextBlock)
|
|
.Text(LOCTEXT("DefaultViewportLabel", "Default View"))
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew(SBorder)
|
|
.HAlign(HAlign_Center)
|
|
[
|
|
SAssignNew(ViewportWidget, SViewport)
|
|
.EnableGammaCorrection(false)
|
|
]
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew(SAnimationSegmentScrubPanel)
|
|
.ViewInputMin(this, &SAnimationRefPoseViewport::GetViewMinInput)
|
|
.ViewInputMax(this, &SAnimationRefPoseViewport::GetViewMaxInput)
|
|
.PreviewInstance(this, &SAnimationRefPoseViewport::GetPreviewInstance)
|
|
.DraggableBars(this, &SAnimationRefPoseViewport::GetBars)
|
|
.OnBarDrag(this, &SAnimationRefPoseViewport::OnBarDrag)
|
|
.bAllowZoom(true)
|
|
]
|
|
];
|
|
|
|
|
|
// Create a viewport client
|
|
LevelViewportClient = MakeShareable(new FAnimationSegmentViewportClient(PreviewScene, FXSystem));
|
|
|
|
LevelViewportClient->ViewportType = LVT_Perspective;
|
|
LevelViewportClient->bSetListenerPosition = false;
|
|
LevelViewportClient->SetViewLocation( EditorViewportDefs::DefaultPerspectiveViewLocation );
|
|
LevelViewportClient->SetViewRotation( EditorViewportDefs::DefaultPerspectiveViewRotation );
|
|
|
|
SceneViewport = MakeShareable(new FSceneViewport(LevelViewportClient.Get(), ViewportWidget));
|
|
LevelViewportClient->Viewport = SceneViewport.Get();
|
|
LevelViewportClient->SetRealtime(true);
|
|
LevelViewportClient->VisibilityDelegate.BindSP(this, &SAnimationRefPoseViewport::IsVisible);
|
|
LevelViewportClient->SetViewMode(VMI_Lit);
|
|
|
|
ViewportWidget->SetViewportInterface(SceneViewport.ToSharedRef());
|
|
|
|
PreviewComponent = ConstructObject<UDebugSkelMeshComponent>(UDebugSkelMeshComponent::StaticClass());
|
|
PreviewComponent->MeshComponentUpdateFlag = EMeshComponentUpdateFlag::AlwaysTickPoseAndRefreshBones;
|
|
PreviewScene.AddComponent(PreviewComponent, FTransform::Identity);
|
|
|
|
InitSkeleton();
|
|
}
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
void SAnimationRefPoseViewport::InitSkeleton()
|
|
{
|
|
UObject *Object = NULL;
|
|
AnimRefPropertyHandle->GetValue(Object);
|
|
AnimRef = Cast<UAnimSequence>(Object);
|
|
USkeleton *Skeleton = NULL;
|
|
if(AnimRef != NULL)
|
|
{
|
|
Skeleton = AnimRef->GetSkeleton();
|
|
}
|
|
|
|
if(PreviewComponent != NULL && Skeleton != NULL)
|
|
{
|
|
UAnimSingleNodeInstance * Preview = PreviewComponent->PreviewInstance;
|
|
USkeletalMesh* PreviewSkeletalMesh = Skeleton->GetPreviewMesh();
|
|
if((Preview == NULL || Preview->CurrentAsset != AnimRef) || PreviewComponent->SkeletalMesh != PreviewSkeletalMesh)
|
|
{
|
|
PreviewComponent->SetSkeletalMesh(PreviewSkeletalMesh);
|
|
PreviewComponent->EnablePreview(true, AnimRef, NULL);
|
|
PreviewComponent->PreviewInstance->SetLooping(true);
|
|
|
|
//Place the camera at a good viewer position
|
|
FVector NewPosition = LevelViewportClient->GetViewLocation();
|
|
NewPosition.Normalize();
|
|
if(PreviewSkeletalMesh)
|
|
{
|
|
NewPosition *= (PreviewSkeletalMesh->Bounds.SphereRadius*1.5f);
|
|
}
|
|
LevelViewportClient->SetViewLocation( NewPosition );
|
|
}
|
|
}
|
|
|
|
TargetSkeleton = Skeleton;
|
|
}
|
|
|
|
void SAnimationRefPoseViewport::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
|
|
{
|
|
SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
|
|
|
|
class UDebugSkelMeshComponent* Component = PreviewComponent;
|
|
|
|
FString TargetSkeletonName = TargetSkeleton? TargetSkeleton->GetName() : FName(NAME_None).ToString();
|
|
|
|
if (Component != NULL)
|
|
{
|
|
// Reinit the skeleton if the anim ref has changed
|
|
InitSkeleton();
|
|
|
|
if (Component->IsPreviewOn() && AnimRef != NULL)
|
|
{
|
|
if(PreviewComponent != NULL && PreviewComponent->PreviewInstance != NULL)
|
|
{
|
|
uint8 RefPoseType;
|
|
RefPoseTypeHandle->GetValue(RefPoseType);
|
|
if (RefPoseType == ABPT_AnimFrame)
|
|
{
|
|
int RefFrameIndex;
|
|
RefFrameIndexPropertyHandle->GetValue(RefFrameIndex);
|
|
float Fraction = (AnimRef->NumFrames > 0)? FMath::Clamp<float>((float)RefFrameIndex/(float)AnimRef->NumFrames, 0.f, 1.f) : 0.f;
|
|
float RefTime = AnimRef->SequenceLength * Fraction;
|
|
PreviewComponent->PreviewInstance->SetPosition(RefTime, false);
|
|
PreviewComponent->PreviewInstance->SetPlaying(false);
|
|
}
|
|
else
|
|
{
|
|
PreviewComponent->PreviewInstance->SetPlaying(true);
|
|
}
|
|
// reinvalidate the viewport
|
|
LevelViewportClient->Invalidate();
|
|
}
|
|
|
|
Description->SetText(FText::Format( LOCTEXT("Previewing", "Previewing {0}"), FText::FromString(Component->GetPreviewText()) ).ToString());
|
|
}
|
|
else if (Component->AnimBlueprintGeneratedClass)
|
|
{
|
|
Description->SetText(FText::Format( LOCTEXT("Previewing", "Previewing {0}"), FText::FromString(Component->AnimBlueprintGeneratedClass->GetName()) ).ToString());
|
|
}
|
|
else if (Component->SkeletalMesh == NULL)
|
|
{
|
|
Description->SetText(FText::Format( LOCTEXT("NoMeshFound", "No skeletal mesh found for skeleton '{0}'"), FText::FromString(TargetSkeletonName) ).ToString());
|
|
}
|
|
else
|
|
{
|
|
Description->SetText(LOCTEXT("Default", "Default").ToString());
|
|
}
|
|
|
|
Component->GetScene()->GetWorld()->Tick(LEVELTICK_All, InDeltaTime);
|
|
}
|
|
else
|
|
{
|
|
Description->SetText(FText::Format( LOCTEXT("NoMeshFound", "No skeletal mesh found for skeleton '{0}'"), FText::FromString(TargetSkeletonName) ).ToString());
|
|
}
|
|
}
|
|
|
|
void SAnimationRefPoseViewport::RefreshViewport()
|
|
{
|
|
}
|
|
|
|
bool SAnimationRefPoseViewport::IsVisible() const
|
|
{
|
|
return ViewportWidget.IsValid();
|
|
}
|
|
|
|
float SAnimationRefPoseViewport::GetViewMinInput() const
|
|
{
|
|
if (PreviewComponent != NULL)
|
|
{
|
|
if (PreviewComponent->PreviewInstance != NULL)
|
|
{
|
|
return 0.0f;
|
|
}
|
|
else if (PreviewComponent->AnimScriptInstance != NULL)
|
|
{
|
|
return FMath::Max<float>((float)(PreviewComponent->AnimScriptInstance->LifeTimer - 30.0), 0.0f);
|
|
}
|
|
}
|
|
|
|
return 0.f;
|
|
}
|
|
|
|
float SAnimationRefPoseViewport::GetViewMaxInput() const
|
|
{
|
|
if (PreviewComponent != NULL)
|
|
{
|
|
if (PreviewComponent->PreviewInstance != NULL)
|
|
{
|
|
return PreviewComponent->PreviewInstance->GetLength();
|
|
}
|
|
else if (PreviewComponent->AnimScriptInstance != NULL)
|
|
{
|
|
return PreviewComponent->AnimScriptInstance->LifeTimer;
|
|
}
|
|
}
|
|
|
|
return 0.f;
|
|
}
|
|
|
|
TArray<float> SAnimationRefPoseViewport::GetBars() const
|
|
{
|
|
TArray<float> Bars;
|
|
if (AnimRef)
|
|
{
|
|
int RefFrameIndex;
|
|
RefFrameIndexPropertyHandle->GetValue(RefFrameIndex);
|
|
float Fraction = (AnimRef->NumFrames > 0)? FMath::Clamp<float>((float)RefFrameIndex/(float)AnimRef->NumFrames, 0.f, 1.f) : 0.f;
|
|
Bars.Add(AnimRef->SequenceLength * Fraction);
|
|
}
|
|
else
|
|
{
|
|
Bars.Add(0.0f);
|
|
}
|
|
return Bars;
|
|
}
|
|
|
|
void SAnimationRefPoseViewport::OnBarDrag(int32 Index, float Position)
|
|
{
|
|
if (AnimRef)
|
|
{
|
|
int RefFrameIndex = FMath::Clamp<int>(AnimRef->SequenceLength > 0.0f? (int)(Position * (float)AnimRef->NumFrames / AnimRef->SequenceLength + 0.5f) : 0.0f, 0, AnimRef->NumFrames - 1);
|
|
RefFrameIndexPropertyHandle->SetValue(RefFrameIndex);
|
|
}
|
|
}
|
|
|
|
UAnimSingleNodeInstance* SAnimationRefPoseViewport::GetPreviewInstance() const
|
|
{
|
|
return PreviewComponent ? PreviewComponent->PreviewInstance : NULL;
|
|
}
|
|
#undef LOCTEXT_NAMESPACE
|