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

3203 lines
105 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "SAnimationEditorViewport.h"
#include "AdvancedPreviewSceneMenus.h"
#include "Widgets/Layout/SBorder.h"
#include "Widgets/Text/STextBlock.h"
#include "Styling/AppStyle.h"
#include "Styling/CoreStyle.h"
#include "Framework/Application/SlateApplication.h"
#include "Widgets/Input/SEditableTextBox.h"
#include "Widgets/Input/SButton.h"
#include "Animation/AnimMontage.h"
#include "Preferences/PersonaOptions.h"
#include "Rendering/SkeletalMeshRenderData.h"
#include "SAnimationScrubPanel.h"
#include "SAnimMontageScrubPanel.h"
#include "SAnimViewportToolBar.h"
#include "AnimViewportMenuCommands.h"
#include "AnimViewportShowCommands.h"
#include "AnimViewportLODCommands.h"
#include "AnimViewportPlaybackCommands.h"
#include "AnimPreviewInstance.h"
#include "AssetViewerSettings.h"
#include "Widgets/Input/STextComboBox.h"
#include "IEditableSkeleton.h"
#include "EditorAxisDisplayInfo.h"
#include "EditorViewportCommands.h"
#include "TabSpawners.h"
#include "ShowFlagMenuCommands.h"
#include "BufferVisualizationMenuCommands.h"
#include "UICommandList_Pinnable.h"
#include "IPersonaEditorModeManager.h"
#include "PreviewProfileController.h"
#include "Materials/Material.h"
#include "EditorFontGlyphs.h"
#include "Tools/EdModeInteractiveToolsContext.h"
#include "ContextObjectStore.h"
#include "IPersonaEditMode.h"
#include "IPersonaToolkit.h"
#include "IPinnedCommandList.h"
#include "IPinnedCommandListModule.h"
#include "Subsystems/AssetEditorSubsystem.h"
#include "SNameComboBox.h"
#include "ToolMenus.h"
#include "Viewports.h"
#include "ViewportToolbar/AnimViewportContext.h"
#include "ViewportToolbar/AnimationEditorMenus.h"
#include "ViewportToolbar/UnrealEdViewportToolbar.h"
#include "Widgets/Text/SRichTextBlock.h"
#define LOCTEXT_NAMESPACE "PersonaViewportToolbar"
//////////////////////////////////////////////////////////////////////////
// SAnimationEditorViewport
void SAnimationEditorViewport::Construct(const FArguments& InArgs, const FAnimationEditorViewportRequiredArgs& InRequiredArgs)
{
PreviewScenePtr = InRequiredArgs.PreviewScene;
TabBodyPtr = InRequiredArgs.TabBody;
AssetEditorToolkitPtr = InRequiredArgs.AssetEditorToolkit;
Extenders = InArgs._Extenders;
ContextName = InArgs._ContextName;
bShowShowMenu = InArgs._ShowShowMenu;
bShowLODMenu = InArgs._ShowLODMenu;
bShowPlaySpeedMenu = InArgs._ShowPlaySpeedMenu;
bShowStats = InArgs._ShowStats;
bShowFloorOptions = InArgs._ShowFloorOptions;
bShowTurnTable = InArgs._ShowTurnTable;
bShowPhysicsMenu = InArgs._ShowPhysicsMenu;
ViewportIndex = InRequiredArgs.ViewportIndex;
SEditorViewport::Construct(
SEditorViewport::FArguments()
.IsEnabled(FSlateApplication::Get().GetNormalExecutionAttribute())
.AddMetaData<FTagMetaData>(TEXT("Persona.Viewport"))
);
Client->VisibilityDelegate.BindSP(this, &SAnimationEditorViewport::IsVisible);
// restore last used feature level
auto ScenePtr = PreviewScenePtr.Pin();
if (ScenePtr.IsValid())
{
UWorld* World = ScenePtr->GetWorld();
if (World != nullptr)
{
World->ChangeFeatureLevel(GWorld->GetFeatureLevel());
}
}
UEditorEngine* Editor = (UEditorEngine*)GEngine;
PreviewFeatureLevelChangedHandle = Editor->OnPreviewFeatureLevelChanged().AddLambda(
[PreviewScenePtrWeak = PreviewScenePtr](ERHIFeatureLevel::Type NewFeatureLevel)
{
if (TSharedPtr<IPersonaPreviewScene> ScenePtr = PreviewScenePtrWeak.Pin())
{
UWorld* World = ScenePtr->GetWorld();
if (World != nullptr)
{
World->ChangeFeatureLevel(NewFeatureLevel);
}
}
});
}
SAnimationEditorViewport::~SAnimationEditorViewport()
{
UEditorEngine* Editor = (UEditorEngine*)GEngine;
Editor->OnPreviewFeatureLevelChanged().Remove(PreviewFeatureLevelChangedHandle);
}
void SAnimationEditorViewport::PopulateViewportOverlays(TSharedRef<SOverlay> Overlay)
{
SEditorViewport::PopulateViewportOverlays(Overlay);
// add the feature level display widget
Overlay->AddSlot()
.VAlign(VAlign_Bottom)
.HAlign(HAlign_Right)
.Padding(5.0f)
[
BuildFeatureLevelWidget()
];
if (TSharedPtr<SAnimationEditorViewportTabBody> ViewportTab = TabBodyPtr.Pin())
{
TSharedRef<SVerticalBox> VerticalBox = SNew(SVerticalBox);
const TAttribute<FMargin> Padding = TAttribute<FMargin>::CreateLambda(
[]() -> FMargin
{
// The old viewport toolbar draws inside the viewport, so we need to pad to not overlap it.
const float TopPadding = UE::UnrealEd::ShowOldViewportToolbars() ? 29.0f : 0;
return FMargin(0, TopPadding, 0, 0);
}
);
// clang-format off
Overlay->AddSlot()
.VAlign(VAlign_Top)
.HAlign(HAlign_Fill)
.Padding(Padding)
[
VerticalBox
];
// clang-format on
if (TSharedPtr<IPinnedCommandList> PinnedCommands = ViewportTab->GetPinnedCommands())
{
// clang-format off
VerticalBox->AddSlot()
.AutoHeight()
[
PinnedCommands.ToSharedRef()
];
// clang-format on
}
// clang-format off
VerticalBox->AddSlot()
.AutoHeight()
.Padding(FMargin(4.0f, 3.0f, 0.0f, 0.0f))
[
// Display text (e.g., item being previewed)
SNew(SRichTextBlock)
.Visibility(EVisibility::SelfHitTestInvisible)
.DecoratorStyleSet(&FAppStyle::Get())
.Text(ViewportTab.Get(), &SAnimationEditorViewportTabBody::GetDisplayString)
.TextStyle(&FAppStyle::Get().GetWidgetStyle<FTextBlockStyle>("AnimViewport.MessageText"))
];
// clang-format on
}
}
TSharedRef<FEditorViewportClient> SAnimationEditorViewport::MakeEditorViewportClient()
{
using namespace EditorViewportDefs;
// Create an animation viewport client
LevelViewportClient = MakeShareable(new FAnimationViewportClient(PreviewScenePtr.Pin().ToSharedRef(), SharedThis(this), AssetEditorToolkitPtr.Pin().ToSharedRef(), ViewportIndex, bShowStats));
// Done after constructor, as the delegates require the shared pointer to be assigned
LevelViewportClient->Initialize();
LevelViewportClient->ViewportType = LVT_Perspective;
LevelViewportClient->bSetListenerPosition = false;
const bool bUsingLUFCoordinateSysem = AxisDisplayInfo::GetAxisDisplayCoordinateSystem() == EAxisList::LeftUpForward;
FVector LocalViewLocation = FVector(DefaultPerspectiveViewLocation.X,
(bUsingLUFCoordinateSysem ? -DefaultPerspectiveViewLocation.Y : DefaultPerspectiveViewLocation.Y),
DefaultPerspectiveViewLocation.Z);
FRotator LocalViewRotation = DefaultPerspectiveViewRotation + (bUsingLUFCoordinateSysem ? FRotator(0, -90, 0) : FRotator(0, 0, 0));
LevelViewportClient->SetInitialViewTransform(LVT_Perspective, LocalViewLocation, LocalViewRotation, DEFAULT_ORTHOZOOM);
return LevelViewportClient.ToSharedRef();
}
TSharedPtr<SWidget> SAnimationEditorViewport::MakeViewportToolbar()
{
// clang-format off
TSharedRef<SVerticalBox> ToolbarWidget =
SNew(SVerticalBox)
+ SVerticalBox::Slot()
[
SAssignNew(ViewportToolbar, SAnimViewportToolBar, TabBodyPtr.Pin(), SharedThis(this))
.Visibility(EVisibility::SelfHitTestInvisible)
.Cursor(EMouseCursor::Default)
.Extenders(Extenders)
.ContextName(ContextName)
.ShowShowMenu(bShowShowMenu)
.ShowLODMenu(bShowLODMenu)
.ShowPlaySpeedMenu(bShowPlaySpeedMenu)
.ShowFloorOptions(bShowFloorOptions)
.ShowTurnTable(bShowTurnTable)
.ShowPhysicsMenu(bShowPhysicsMenu)
];
// clang-format on
return ToolbarWidget;
}
TSharedPtr<SWidget> SAnimationEditorViewport::BuildViewportToolbar()
{
// Register the viewport toolbar if another viewport hasn't already (it's shared).
const FName ViewportToolbarName = "AnimationEditor.ViewportToolbar";
if (!UToolMenus::Get()->IsMenuRegistered(ViewportToolbarName))
{
UToolMenu* const ViewportToolbarMenu = UToolMenus::Get()->RegisterMenu(
ViewportToolbarName, NAME_None /* parent */, EMultiBoxType::SlimHorizontalToolBar
);
ViewportToolbarMenu->StyleName = "ViewportToolbar";
// Add the left-aligned part of the viewport toolbar.
{
FToolMenuSection& LeftSection = ViewportToolbarMenu->AddSection("Left");
LeftSection.AddEntry(UE::UnrealEd::CreateTransformsSubmenu());
// TODO: Needs specific Select menu for Skel Mesh.
LeftSection.AddEntry(UE::UnrealEd::CreateSnappingSubmenu());
}
// Add the right-aligned part of the viewport toolbar.
{
FToolMenuSection& RightSection = ViewportToolbarMenu->AddSection("Right");
RightSection.Alignment = EToolMenuSectionAlign::Last;
// Add the "Camera" submenu.
{
// Build the menu name our Camera menu will be using so we can extend it.
RightSection.AddEntry(UE::UnrealEd::CreateCameraSubmenu(UE::UnrealEd::FViewportCameraMenuOptions().ShowAll()));
const FName SubmenuName = UToolMenus::JoinMenuPaths(ViewportToolbarName, "Camera");
UE::AnimationEditor::ExtendCameraMenu(SubmenuName);
}
// Add the "View Modes" sub menu.
{
const FName ViewModesMenuName = "AnimationEditor.ViewportToolbar.ViewModes";
// Stay backward-compatible with the old viewport toolbar.
{
const FName ParentSubmenuName = "UnrealEd.ViewportToolbar.View";
// Create our parent menu.
if (!UToolMenus::Get()->IsMenuRegistered(ParentSubmenuName))
{
UToolMenus::Get()->RegisterMenu(ParentSubmenuName);
}
// Register our ToolMenu here first, before we create the submenu, so we can set our parent.
UToolMenus::Get()->RegisterMenu(ViewModesMenuName, ParentSubmenuName);
}
UE::AnimationEditor::ExtendViewModesSubmenu(ViewModesMenuName);
RightSection.AddEntry(UE::UnrealEd::CreateViewModesSubmenu());
}
RightSection.AddEntry(UE::AnimationEditor::CreateShowSubmenu());
RightSection.AddEntry(UE::AnimationEditor::CreateLODSubmenu());
// Add Preview Scene Submenu
{
const FName AssetViewerProfileMenuName = "AnimationEditor.ViewportToolbar.AssetViewerProfile";
RightSection.AddEntry(UE::UnrealEd::CreateAssetViewerProfileSubmenu());
UE::AdvancedPreviewScene::Menus::ExtendAdvancedPreviewSceneSettings(AssetViewerProfileMenuName);
UE::AnimationEditor::ExtendPreviewSceneSettingsSubmenu(AssetViewerProfileMenuName);
UE::UnrealEd::ExtendPreviewSceneSettingsWithTabEntry(AssetViewerProfileMenuName);
}
// Add the "Physics" sub menu (only shown when bShowPhysicsMenu is true)
{
FToolMenuInsert PhysicsSubmenuInsert("LOD", EToolMenuInsertType::Before);
UE::AnimationEditor::AddPhysicsMenu(ViewportToolbarName, PhysicsSubmenuInsert);
}
}
}
FToolMenuContext ViewportToolbarContext;
{
if (TSharedPtr<IPersonaPreviewScene> PreviewScene = PreviewScenePtr.Pin())
{
ViewportToolbarContext.AppendCommandList(PreviewScene->GetCommandList());
}
if (TSharedPtr<SAnimationEditorViewportTabBody> TabBody = TabBodyPtr.Pin())
{
ViewportToolbarContext.AppendCommandList(TabBody->GetCommandList());
}
ViewportToolbarContext.AppendCommandList(GetCommandList());
// Add extenders
{
Extenders.Add(UE::AnimationEditor::GetViewModesLegacyExtenders(TabBodyPtr));
ViewportToolbarContext.AddExtender(FExtender::Combine(Extenders));
}
// Add the UnrealEd viewport toolbar context.
{
UUnrealEdViewportToolbarContext* const ContextObject =
UE::UnrealEd::CreateViewportToolbarDefaultContext(SharedThis(this));
ContextObject->AssetEditorToolkit = AssetEditorToolkitPtr;
ContextObject->PreviewSettingsTabId = FPersonaTabs::AdvancedPreviewSceneSettingsID;
ViewportToolbarContext.AddObject(ContextObject);
}
// Add the Anim viewport toolbar context.
{
UAnimViewportContext* const ContextObject = NewObject<UAnimViewportContext>();
ContextObject->ViewportTabBody = TabBodyPtr.Pin();
ViewportToolbarContext.AddObject(ContextObject);
}
// Give the asset editor a chance to extend the context.
if (TSharedPtr<SAnimationEditorViewportTabBody> Tab = TabBodyPtr.Pin())
{
Tab->GetAssetEditorToolkit()->InitToolMenuContext(ViewportToolbarContext);
}
}
return UToolMenus::Get()->GenerateWidget(ViewportToolbarName, ViewportToolbarContext);
}
TSharedPtr<IPreviewProfileController> SAnimationEditorViewport::CreatePreviewProfileController()
{
return MakeShared<FPreviewProfileController>();
}
void SAnimationEditorViewport::PostUndo( bool bSuccess )
{
LevelViewportClient->Invalidate();
}
void SAnimationEditorViewport::PostRedo( bool bSuccess )
{
LevelViewportClient->Invalidate();
}
void SAnimationEditorViewport::OnFocusViewportToSelection()
{
if (LevelViewportClient)
{
TSharedRef<FAnimationViewportClient> AnimViewportClient = StaticCastSharedRef<FAnimationViewportClient>(LevelViewportClient.ToSharedRef());
AnimViewportClient->OnFocusViewportToSelection();
}
}
void SAnimationEditorViewport::BindCommands()
{
SEditorViewport::BindCommands();
FShowFlagMenuCommands::Get().BindCommands(*CommandList, Client);
FBufferVisualizationMenuCommands::Get().BindCommands(*CommandList, Client);
if (TSharedPtr<SAnimationEditorViewportTabBody> TabBody = TabBodyPtr.Pin())
{
if (TSharedPtr<FAssetEditorToolkit> ParentAssetEditor = TabBody->GetAssetEditorToolkit())
{
CommandList->Append(ParentAssetEditor->GetToolkitCommands());
}
}
}
void SAnimationEditorViewport::OnDragEnter(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
SEditorViewport::OnDragEnter(MyGeometry, DragDropEvent);
if(AssetEditorToolkitPtr.IsValid())
{
AssetEditorToolkitPtr.Pin()->OnViewportDragEnter(MyGeometry, DragDropEvent);
}
}
void SAnimationEditorViewport::OnDragLeave(const FDragDropEvent& DragDropEvent)
{
SEditorViewport::OnDragLeave(DragDropEvent);
if(AssetEditorToolkitPtr.IsValid())
{
AssetEditorToolkitPtr.Pin()->OnViewportDragLeave(DragDropEvent);
}
}
FReply SAnimationEditorViewport::OnDrop(const FGeometry& MyGeometry, const FDragDropEvent& DragDropEvent)
{
if(AssetEditorToolkitPtr.IsValid())
{
const FReply ReplyFromToolkit = AssetEditorToolkitPtr.Pin()->OnViewportDrop(MyGeometry, DragDropEvent);
if(ReplyFromToolkit.IsEventHandled())
{
return ReplyFromToolkit;
}
}
return SEditorViewport::OnDrop(MyGeometry, DragDropEvent);
}
//////////////////////////////////////////////////////////////////////////
// SAnimationEditorViewportTabBody
SAnimationEditorViewportTabBody::SAnimationEditorViewportTabBody()
: SelectedTurnTableSpeed(EAnimationPlaybackSpeeds::Normal)
, SelectedTurnTableMode(EPersonaTurnTableMode::Stopped)
, SectionsDisplayMode(ESectionDisplayMode::None)
{
CreatePinnedCommands();
}
SAnimationEditorViewportTabBody::~SAnimationEditorViewportTabBody()
{
// Close viewport
if (LevelViewportClient.IsValid())
{
LevelViewportClient->Viewport = nullptr;
}
// Release our reference to the viewport client
LevelViewportClient.Reset();
PendingTransaction.Reset();
}
bool SAnimationEditorViewportTabBody::CanUseGizmos() const
{
if (bAlwaysShowTransformToolbar)
{
return true;
}
class UDebugSkelMeshComponent* Component = GetPreviewScene()->GetPreviewMeshComponent();
if (Component != NULL)
{
if (Component->bForceRefpose)
{
return false;
}
else if (Component->IsPreviewOn())
{
return true;
}
}
if (LevelViewportClient.IsValid())
{
if(const FEditorModeTools* ModeTools = LevelViewportClient->GetModeTools())
{
if(ModeTools->UsesTransformWidget())
{
return true;
}
}
}
return false;
}
FText ConcatenateLine(const FText& InText, const FText& InNewLine)
{
if(InText.IsEmpty())
{
return InNewLine;
}
return FText::Format(LOCTEXT("ViewportTextNewlineFormatter", "{0}\n{1}"), InText, InNewLine);
}
FText SAnimationEditorViewportTabBody::GetDisplayString() const
{
class UDebugSkelMeshComponent* Component = GetPreviewScene()->GetPreviewMeshComponent();
TSharedPtr<IEditableSkeleton> EditableSkeleton = GetPreviewScene()->GetPersonaToolkit()->GetEditableSkeleton();
FName TargetSkeletonName = (EditableSkeleton.IsValid() && EditableSkeleton->IsSkeletonValid()) ? EditableSkeleton->GetSkeleton().GetFName() : NAME_None;
FText DefaultText;
if (Component != NULL)
{
if (Component->bForceRefpose)
{
DefaultText = LOCTEXT("ReferencePose", "Reference pose");
}
else if (Component->IsPreviewOn())
{
DefaultText = FText::Format(LOCTEXT("Previewing", "Previewing {0}"), FText::FromString(Component->GetPreviewText()));
}
else if (Component->AnimClass != NULL)
{
TSharedPtr<FBlueprintEditor> BPEditor = BlueprintEditorPtr.Pin();
const bool bWarnAboutBoneManip = BPEditor.IsValid() && BPEditor->IsModeCurrent(FPersonaModes::AnimBlueprintEditMode);
if (bWarnAboutBoneManip)
{
DefaultText = FText::Format(LOCTEXT("PreviewingAnimBP_WarnDisabled", "Previewing {0}. \nBone manipulation is disabled in this mode. "), FText::FromString(Component->AnimClass->GetName()));
}
else
{
DefaultText = FText::Format(LOCTEXT("PreviewingAnimBP", "Previewing {0}"), FText::FromString(Component->AnimClass->GetName()));
}
}
else if (Component->GetSkeletalMeshAsset() == NULL && TargetSkeletonName != NAME_None)
{
DefaultText = FText::Format(LOCTEXT("NoMeshFound", "No skeletal mesh found for skeleton '{0}'"), FText::FromName(TargetSkeletonName));
}
}
if(OnGetViewportText.IsBound())
{
DefaultText = ConcatenateLine(DefaultText, OnGetViewportText.Execute(EViewportCorner::TopLeft));
}
TSharedPtr<FAnimationViewportClient> AnimViewportClient = StaticCastSharedPtr<FAnimationViewportClient>(LevelViewportClient);
if(AnimViewportClient->IsShowingMeshStats())
{
DefaultText = ConcatenateLine(DefaultText, AnimViewportClient->GetDisplayInfo(AnimViewportClient->IsDetailedMeshStats()));
}
else if(AnimViewportClient->IsShowingSelectedNodeStats())
{
// Allow edit modes (inc. skeletal control modes) to draw with the canvas, and collect on screen strings to draw later
if (IAnimationEditContext* PersonaContext = AnimViewportClient->GetModeTools()->GetInteractiveToolsContext()->ContextObjectStore->FindContext<UAnimationEditModeContext>())
{
TArray<FText> EditModeDebugText;
PersonaContext->GetOnScreenDebugInfo(EditModeDebugText);
for(FText& Text : EditModeDebugText)
{
DefaultText = ConcatenateLine(DefaultText, Text);
}
}
}
if(Component)
{
for(const FGetExtendedViewportText& TextDelegate : Component->GetExtendedViewportTextDelegates())
{
DefaultText = ConcatenateLine(DefaultText, TextDelegate.Execute());
}
}
return DefaultText;
}
TSharedRef<IPersonaViewportState> SAnimationEditorViewportTabBody::SaveState() const
{
TSharedRef<FPersonaModeSharedData> State = MakeShareable(new(FPersonaModeSharedData));
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
State->Save(AnimViewportClient.ToSharedRef());
}
return State;
}
void SAnimationEditorViewportTabBody::RestoreState(TSharedRef<IPersonaViewportState> InState)
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
TSharedRef<FPersonaModeSharedData> State = StaticCastSharedRef<FPersonaModeSharedData>(InState);
State->Restore(AnimViewportClient.ToSharedRef());
}
}
FEditorViewportClient& SAnimationEditorViewportTabBody::GetViewportClient() const
{
return *LevelViewportClient;
}
TSharedRef<IPinnedCommandList> SAnimationEditorViewportTabBody::GetPinnedCommandList() const
{
return PinnedCommands.ToSharedRef();
}
const TSharedPtr<IPinnedCommandList>& SAnimationEditorViewportTabBody::GetPinnedCommands()
{
if (!PinnedCommands)
{
CreatePinnedCommands();
}
return PinnedCommands;
}
TWeakPtr<SWidget> SAnimationEditorViewportTabBody::AddNotification(TAttribute<EMessageSeverity::Type> InSeverity, TAttribute<bool> InCanBeDismissed, const TSharedRef<SWidget>& InNotificationWidget, FPersonaViewportNotificationOptions InOptions)
{
TSharedPtr<SBorder> ContainingWidget = nullptr;
TWeakPtr<SWidget> WeakNotificationWidget = InNotificationWidget;
auto GetPadding = [WeakNotificationWidget]()
{
if(WeakNotificationWidget.IsValid())
{
return WeakNotificationWidget.Pin()->GetVisibility() == EVisibility::Visible ? FMargin(2.0f) : FMargin(0.0f);
}
return FMargin(0.0f);
};
TAttribute<EVisibility> GetVisibility(EVisibility::Visible);
if (InOptions.OnGetVisibility.IsSet())
{
GetVisibility = InOptions.OnGetVisibility;
}
TAttribute<const FSlateBrush*> GetBrushForSeverity = TAttribute<const FSlateBrush*>::Create([InSeverity]()
{
switch(InSeverity.Get())
{
case EMessageSeverity::Error:
return FAppStyle::GetBrush("AnimViewport.Notification.Error");
case EMessageSeverity::PerformanceWarning:
case EMessageSeverity::Warning:
return FAppStyle::GetBrush("AnimViewport.Notification.Warning");
default:
case EMessageSeverity::Info:
return FAppStyle::GetBrush("AnimViewport.Notification.Message");
}
});
if (InOptions.OnGetBrushOverride.IsSet())
{
GetBrushForSeverity = InOptions.OnGetBrushOverride;
}
TSharedPtr<SHorizontalBox> BodyBox = nullptr;
ViewportNotificationsContainer->AddSlot()
.HAlign(HAlign_Right)
.AutoHeight()
.Padding(MakeAttributeLambda(GetPadding))
[
SAssignNew(ContainingWidget, SBorder)
.Visibility(GetVisibility)
.BorderImage(GetBrushForSeverity)
[
SAssignNew(BodyBox, SHorizontalBox)
+SHorizontalBox::Slot()
.FillWidth(1.0f)
[
InNotificationWidget
]
]
];
TWeakPtr<SWidget> WeakContainingWidget = ContainingWidget;
auto DismissNotification = [this, WeakContainingWidget]()
{
if(WeakContainingWidget.IsValid())
{
RemoveNotification(WeakContainingWidget.Pin().ToSharedRef());
}
return FReply::Handled();
};
auto GetDismissButtonVisibility = [InCanBeDismissed]()
{
return InCanBeDismissed.Get() ? EVisibility::Visible : EVisibility::Collapsed;
};
// add dismiss button
BodyBox->InsertSlot(0)
.AutoWidth()
.HAlign(HAlign_Center)
.VAlign(VAlign_Top)
[
SNew(SButton)
.Visibility_Lambda(GetDismissButtonVisibility)
.ButtonStyle(FAppStyle::Get(), "AnimViewport.Notification.CloseButton")
.ToolTipText(LOCTEXT("DismissNotificationToolTip", "Dismiss this notification."))
.OnClicked_Lambda(DismissNotification)
];
return ContainingWidget;
}
void SAnimationEditorViewportTabBody::RemoveNotification(const TWeakPtr<SWidget>& InContainingWidget)
{
if(InContainingWidget.IsValid())
{
ViewportNotificationsContainer->RemoveSlot(InContainingWidget.Pin().ToSharedRef());
}
}
void SAnimationEditorViewportTabBody::AddToolbarExtender(FName MenuToExtend, FMenuExtensionDelegate MenuBuilderDelegate)
{
return ViewportWidget->ViewportToolbar->AddMenuExtender(MenuToExtend, MenuBuilderDelegate);
}
void SAnimationEditorViewportTabBody::AddOverlayWidget(TSharedRef<SWidget> InOverlaidWidget, int32 ZOrder)
{
ViewportWidget->ViewportOverlay->AddSlot(ZOrder)
[
InOverlaidWidget
];
}
void SAnimationEditorViewportTabBody::RemoveOverlayWidget(TSharedRef<SWidget> InOverlaidWidget)
{
ViewportWidget->ViewportOverlay->RemoveSlot(InOverlaidWidget);
}
void SAnimationEditorViewportTabBody::RefreshViewport()
{
LevelViewportClient->Invalidate();
}
TSharedPtr<FAssetEditorToolkit> SAnimationEditorViewportTabBody::GetAssetEditorToolkit() const
{
return AssetEditorToolkitPtr.Pin();
}
bool SAnimationEditorViewportTabBody::IsVisible() const
{
return ViewportWidget.IsValid();
}
FReply SAnimationEditorViewportTabBody::OnKeyDown(const FGeometry& MyGeometry, const FKeyEvent& InKeyEvent)
{
if (UICommandList.IsValid() && UICommandList->ProcessCommandBindings(InKeyEvent))
{
return FReply::Handled();
}
if (OnKeyDownDelegate.IsBound())
{
return OnKeyDownDelegate.Execute(MyGeometry, InKeyEvent);
}
return FReply::Unhandled();
}
void SAnimationEditorViewportTabBody::Construct(const FArguments& InArgs, const TSharedRef<class IPersonaPreviewScene>& InPreviewScene, const TSharedRef<class FAssetEditorToolkit>& InAssetEditorToolkit, int32 InViewportIndex)
{
PreviewScenePtr = StaticCastSharedRef<FAnimationEditorPreviewScene>(InPreviewScene);
AssetEditorToolkitPtr = InAssetEditorToolkit;
BlueprintEditorPtr = InArgs._BlueprintEditor;
bShowTimeline = InArgs._ShowTimeline;
bAlwaysShowTransformToolbar = InArgs._AlwaysShowTransformToolbar;
OnInvokeTab = InArgs._OnInvokeTab;
OnGetViewportText = InArgs._OnGetViewportText;
ContextName = InArgs._ContextName;
TimelineDelegates = InArgs._TimelineDelegates;
// register delegates for change notifications
InPreviewScene->RegisterOnAnimChanged(FOnAnimChanged::CreateSP(this, &SAnimationEditorViewportTabBody::AnimChanged));
InPreviewScene->RegisterOnPreviewMeshChanged(FOnPreviewMeshChanged::CreateSP(this, &SAnimationEditorViewportTabBody::HandlePreviewMeshChanged));
const FSlateFontInfo SmallLayoutFont = FCoreStyle::GetDefaultFontStyle("Regular", 9);
FAnimViewportMenuCommands::Register();
FAnimViewportShowCommands::Register();
FAnimViewportLODCommands::Register();
FAnimViewportPlaybackCommands::Register();
// Build toolbar widgets
UVChannelCombo = SNew(STextComboBox)
.OptionsSource(&UVChannels)
.Font(SmallLayoutFont)
.OnSelectionChanged(this, &SAnimationEditorViewportTabBody::ComboBoxSelectionChanged);
PopulateSkinWeightProfileNames();
SkinWeightCombo = SNew(SNameComboBox)
.OptionsSource(&SkinWeightProfileNames)
.InitiallySelectedItem(SkinWeightProfileNames.Num() > 0 ? SkinWeightProfileNames[0] : nullptr)
.OnComboBoxOpening(FOnComboBoxOpening::CreateLambda([this]()
{
// Retrieve currently selected value, and check whether or not it is still valid, it could be that a profile has been renamed or removed without updating the entries
FName Name = SkinWeightCombo->GetSelectedItem().IsValid() ? *SkinWeightCombo->GetSelectedItem().Get() : NAME_None;
PopulateSkinWeightProfileNames();
const int32 Index = SkinWeightProfileNames.IndexOfByPredicate([Name](TSharedPtr<FName> SearchName) { return Name == *SearchName; });
if (Index != INDEX_NONE)
{
SkinWeightCombo->SetSelectedItem(SkinWeightProfileNames[Index]);
}
}))
.OnSelectionChanged(SNameComboBox::FOnNameSelectionChanged::CreateLambda([WeakScenePtr = PreviewScenePtr](TSharedPtr<FName> SelectedProfile, ESelectInfo::Type SelectInfo)
{
// Apply the skin weight profile to the component, according to the selected the name,
if (WeakScenePtr.IsValid() && SelectedProfile.IsValid())
{
UDebugSkelMeshComponent* MeshComponent = WeakScenePtr.Pin()->GetPreviewMeshComponent();
if (MeshComponent)
{
MeshComponent->ClearSkinWeightProfile();
if (*SelectedProfile != NAME_None)
{
MeshComponent->SetSkinWeightProfile(*SelectedProfile);
}
}
}
}));
FAnimationEditorViewportRequiredArgs ViewportArgs(InPreviewScene, SharedThis(this), InAssetEditorToolkit, InViewportIndex);
ViewportWidget = SNew(SAnimationEditorViewport, ViewportArgs)
.Extenders(InArgs._Extenders)
.ContextName(InArgs._ContextName)
.ShowShowMenu(InArgs._ShowShowMenu)
.ShowLODMenu(InArgs._ShowLODMenu)
.ShowPlaySpeedMenu(InArgs._ShowPlaySpeedMenu)
.ShowStats(InArgs._ShowStats)
.ShowFloorOptions(InArgs._ShowFloorOptions)
.ShowTurnTable(InArgs._ShowTurnTable)
.ShowPhysicsMenu(InArgs._ShowPhysicsMenu);
TSharedPtr<SVerticalBox> ViewportContainer = nullptr;
this->ChildSlot
[
SAssignNew(ViewportContainer, SVerticalBox)
// Build our toolbar level toolbar
+SVerticalBox::Slot()
.FillHeight(1)
[
SNew(SOverlay)
// The viewport
+SOverlay::Slot()
[
ViewportWidget.ToSharedRef()
]
// The 'dirty/in-error' indicator text in the bottom-right corner
+SOverlay::Slot()
.Padding(8)
.VAlign(VAlign_Bottom)
.HAlign(HAlign_Right)
[
SAssignNew(ViewportNotificationsContainer, SVerticalBox)
]
]
];
if(bShowTimeline && ViewportContainer.IsValid())
{
ViewportContainer->AddSlot()
.AutoHeight()
[
SAssignNew(ScrubPanelContainer, SVerticalBox)
+SVerticalBox::Slot()
.AutoHeight()
[
SNew(SAnimationScrubPanel, GetPreviewScene())
.ViewInputMin(this, &SAnimationEditorViewportTabBody::GetViewMinInput)
.ViewInputMax(this, &SAnimationEditorViewportTabBody::GetViewMaxInput)
.bAllowZoom(true)
.TimelineDelegates(TimelineDelegates)
]
];
UpdateScrubPanel(InPreviewScene->GetPreviewAnimationAsset());
}
LevelViewportClient = ViewportWidget->GetViewportClient();
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
// Load the view mode from config
AnimViewportClient->SetViewMode(AnimViewportClient->ConfigOption
->GetAssetEditorOptions(AssetEditorToolkitPtr.Pin()->GetEditorName())
.ViewportConfigs[InViewportIndex]
.ViewModeIndex);
}
UpdateShowFlagForMeshEdges();
OnSetTurnTableMode(SelectedTurnTableMode);
OnSetTurnTableSpeed(SelectedTurnTableSpeed);
BindCommands();
PopulateNumUVChannels();
PopulateSkinWeightProfileNames();
GetPreviewScene()->OnRecordingStateChanged().AddSP(this, &SAnimationEditorViewportTabBody::AddRecordingNotification);
if (GetPreviewScene()->GetPreviewMesh())
{
GetPreviewScene()->GetPreviewMesh()->OnPostMeshCached().AddSP(this, &SAnimationEditorViewportTabBody::UpdateSkinWeightSelection);
}
AddPostProcessNotification();
AddMinLODNotification();
AddSkinWeightProfileNotification();
if (TSharedPtr<FAnimationEditorPreviewScene> PreviewScene = PreviewScenePtr.Pin())
{
UE::AdvancedPreviewScene::BindDefaultOnSettingsChangedHandler(PreviewScene, LevelViewportClient);
}
}
void SAnimationEditorViewportTabBody::BindCommands()
{
FUICommandList_Pinnable& CommandList = *UICommandList;
//Bind menu commands
const FAnimViewportMenuCommands& MenuActions = FAnimViewportMenuCommands::Get();
CommandList.MapAction(
MenuActions.TogglePauseAnimationOnCameraMove,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::TogglePauseAnimationOnCameraMove),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::GetShouldPauseAnimationOnCameraMove));
CommandList.MapAction(
MenuActions.CameraFollowNone,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::SetCameraFollowMode, EAnimationViewportCameraFollowMode::None, FName()),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::CanChangeCameraMode),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsCameraFollowEnabled, EAnimationViewportCameraFollowMode::None));
CommandList.MapAction(
MenuActions.CameraFollowBounds,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::SetCameraFollowMode, EAnimationViewportCameraFollowMode::Bounds, FName()),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::CanChangeCameraMode),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsCameraFollowEnabled, EAnimationViewportCameraFollowMode::Bounds));
CommandList.MapAction(
MenuActions.CameraFollowRoot,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::SetCameraFollowMode, EAnimationViewportCameraFollowMode::Root, FName()),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::CanChangeCameraMode),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsCameraFollowEnabled, EAnimationViewportCameraFollowMode::Root));
CommandList.MapAction(
MenuActions.JumpToDefaultCamera,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::JumpToDefaultCamera),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::HasDefaultCameraSet));
CommandList.MapAction(
MenuActions.SaveCameraAsDefault,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::SaveCameraAsDefault),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::CanSaveCameraAsDefault));
CommandList.MapAction(
MenuActions.ClearDefaultCamera,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::ClearDefaultCamera),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::HasDefaultCameraSet));
CommandList.MapAction(
MenuActions.PreviewSceneSettings,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OpenPreviewSceneSettings));
if (const TSharedPtr<FAnimationViewportClient>& AnimationViewportClientPtr = GetAnimationViewportClient())
{
if (FAnimationViewportClient* AnimViewportClient = AnimationViewportClientPtr.Get())
{
CommandList.MapAction(
MenuActions.SetCPUSkinning,
FExecuteAction::CreateSP(AnimViewportClient, &FAnimationViewportClient::ToggleCPUSkinning),
FCanExecuteAction(),
FIsActionChecked::CreateSP(AnimViewportClient, &FAnimationViewportClient::IsSetCPUSkinningChecked)
);
CommandList.MapAction(
MenuActions.SetShowNormals,
FExecuteAction::CreateSP(AnimViewportClient, &FAnimationViewportClient::ToggleShowNormals),
FCanExecuteAction(),
FIsActionChecked::CreateSP(AnimViewportClient, &FAnimationViewportClient::IsSetShowNormalsChecked)
);
CommandList.MapAction(
MenuActions.SetShowTangents,
FExecuteAction::CreateSP(AnimViewportClient, &FAnimationViewportClient::ToggleShowTangents),
FCanExecuteAction(),
FIsActionChecked::CreateSP(AnimViewportClient, &FAnimationViewportClient::IsSetShowTangentsChecked)
);
CommandList.MapAction(
MenuActions.SetShowBinormals,
FExecuteAction::CreateSP(AnimViewportClient, &FAnimationViewportClient::ToggleShowBinormals),
FCanExecuteAction(),
FIsActionChecked::CreateSP(AnimViewportClient, &FAnimationViewportClient::IsSetShowBinormalsChecked)
);
}
}
//Bind Show commands
const FAnimViewportShowCommands& ViewportShowMenuCommands = FAnimViewportShowCommands::Get();
CommandList.MapAction(
ViewportShowMenuCommands.ShowBound,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::ShowBound),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::CanShowBound),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowBoundEnabled));
CommandList.MapAction(
ViewportShowMenuCommands.UseInGameBound,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::UseInGameBound),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::CanUseInGameBound),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsUsingInGameBound));
CommandList.MapAction(
ViewportShowMenuCommands.UseFixedBounds,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::UseFixedBounds),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::CanUseFixedBounds),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsUsingFixedBounds));
CommandList.MapAction(
ViewportShowMenuCommands.UsePreSkinnedBounds,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::UsePreSkinnedBounds),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::CanUsePreSkinnedBounds),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsUsingPreSkinnedBounds));
CommandList.MapAction(
ViewportShowMenuCommands.ShowPreviewMesh,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::ToggleShowPreviewMesh),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::CanShowPreviewMesh),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowPreviewMeshEnabled));
CommandList.MapAction(
ViewportShowMenuCommands.ShowMorphTargets,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowMorphTargets),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingMorphTargets));
CommandList.MapAction(
ViewportShowMenuCommands.ShowBoneNames,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowBoneNames),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingBoneNames));
CommandList.MapAction(
ViewportShowMenuCommands.ShowBoneColors,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowBoneColors),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingBoneColors));
CommandList.MapAction(
ViewportShowMenuCommands.ShowRawAnimation,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowRawAnimation),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingRawAnimation));
CommandList.MapAction(
ViewportShowMenuCommands.ShowNonRetargetedAnimation,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowNonRetargetedAnimation),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingNonRetargetedPose));
CommandList.MapAction(
ViewportShowMenuCommands.ShowAdditiveBaseBones,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowAdditiveBase),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::IsPreviewingAnimation),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingAdditiveBase));
CommandList.MapAction(
ViewportShowMenuCommands.ShowSourceRawAnimation,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowSourceRawAnimation),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingSourceRawAnimation));
CommandList.MapAction(
ViewportShowMenuCommands.ShowBakedAnimation,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowBakedAnimation),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingBakedAnimation));
//Display info
CommandList.BeginGroup(TEXT("MeshDisplayInfo"));
CommandList.MapAction(
ViewportShowMenuCommands.ShowDisplayInfoBasic,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowDisplayInfo, (int32)EDisplayInfoMode::Basic),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingMeshInfo, (int32)EDisplayInfoMode::Basic));
CommandList.MapAction(
ViewportShowMenuCommands.ShowDisplayInfoDetailed,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowDisplayInfo, (int32)EDisplayInfoMode::Detailed),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingMeshInfo, (int32)EDisplayInfoMode::Detailed));
CommandList.MapAction(
ViewportShowMenuCommands.ShowDisplayInfoSkelControls,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowDisplayInfo, (int32)EDisplayInfoMode::SkeletalControls),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingMeshInfo, (int32)EDisplayInfoMode::SkeletalControls));
CommandList.MapAction(
ViewportShowMenuCommands.HideDisplayInfo,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowDisplayInfo, (int32)EDisplayInfoMode::None),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingMeshInfo, (int32)EDisplayInfoMode::None));
CommandList.EndGroup();
//Material overlay option
CommandList.BeginGroup(TEXT("MaterialOverlay"));
CommandList.MapAction(
ViewportShowMenuCommands.ShowOverlayNone,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowOverlayNone),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingOverlayNone));
CommandList.MapAction(
ViewportShowMenuCommands.ShowBoneWeight,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowOverlayBoneWeight),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingOverlayBoneWeight));
CommandList.MapAction(
ViewportShowMenuCommands.ShowMorphTargetVerts,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowOverlayMorphTargetVert),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingOverlayMorphTargetVerts));
CommandList.EndGroup();
// Show sockets
CommandList.MapAction(
ViewportShowMenuCommands.ShowSockets,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowSockets),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingSockets));
// Show transform attributes
CommandList.MapAction(
ViewportShowMenuCommands.ShowAttributes,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnShowAttributes),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowingAttributes));
// Set bone drawing mode
CommandList.BeginGroup(TEXT("BoneDrawingMode"));
CommandList.MapAction(
ViewportShowMenuCommands.ShowBoneDrawNone,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetBoneDrawMode, (int32)EBoneDrawMode::None),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsBoneDrawModeSet, (int32)EBoneDrawMode::None));
CommandList.MapAction(
ViewportShowMenuCommands.ShowBoneDrawSelected,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetBoneDrawMode, (int32)EBoneDrawMode::Selected),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsBoneDrawModeSet, (int32)EBoneDrawMode::Selected));
CommandList.MapAction(
ViewportShowMenuCommands.ShowBoneDrawSelectedAndParents,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetBoneDrawMode, (int32)EBoneDrawMode::SelectedAndParents),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsBoneDrawModeSet, (int32)EBoneDrawMode::SelectedAndParents));
CommandList.MapAction(
ViewportShowMenuCommands.ShowBoneDrawSelectedAndChildren,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetBoneDrawMode, (int32)EBoneDrawMode::SelectedAndChildren),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsBoneDrawModeSet, (int32)EBoneDrawMode::SelectedAndChildren));
CommandList.MapAction(
ViewportShowMenuCommands.ShowBoneDrawSelectedAndParentsAndChildren,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetBoneDrawMode, (int32)EBoneDrawMode::SelectedAndParentsAndChildren),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsBoneDrawModeSet, (int32)EBoneDrawMode::SelectedAndParentsAndChildren));
CommandList.MapAction(
ViewportShowMenuCommands.ShowBoneDrawAll,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetBoneDrawMode, (int32)EBoneDrawMode::All),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsBoneDrawModeSet, (int32)EBoneDrawMode::All));
CommandList.EndGroup();
// Set bone local axes mode
CommandList.BeginGroup(TEXT("BoneLocalAxesMode"));
CommandList.MapAction(
ViewportShowMenuCommands.ShowLocalAxesNone,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetLocalAxesMode, (int32)ELocalAxesMode::None),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsLocalAxesModeSet, (int32)ELocalAxesMode::None));
CommandList.MapAction(
ViewportShowMenuCommands.ShowLocalAxesSelected,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetLocalAxesMode, (int32)ELocalAxesMode::Selected),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsLocalAxesModeSet, (int32)ELocalAxesMode::Selected));
CommandList.MapAction(
ViewportShowMenuCommands.ShowLocalAxesAll,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetLocalAxesMode, (int32)ELocalAxesMode::All),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsLocalAxesModeSet, (int32)ELocalAxesMode::All));
CommandList.EndGroup();
//Clothing show options
CommandList.MapAction(
ViewportShowMenuCommands.EnableClothSimulation,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnEnableClothSimulation),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsClothSimulationEnabled));
CommandList.MapAction(
ViewportShowMenuCommands.ResetClothSimulation,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnResetClothSimulation),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::IsClothSimulationEnabled));
CommandList.MapAction(
ViewportShowMenuCommands.EnableCollisionWithAttachedClothChildren,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnEnableCollisionWithAttachedClothChildren),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsEnablingCollisionWithAttachedClothChildren));
CommandList.MapAction(
ViewportShowMenuCommands.PauseClothWithAnim,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnPauseClothingSimWithAnim),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsPausingClothingSimWithAnim));
CommandList.BeginGroup(TEXT("ClothSectionDisplayMode"));
CommandList.MapAction(
ViewportShowMenuCommands.ShowAllSections,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetSectionsDisplayMode, ESectionDisplayMode::ShowAll),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsSectionsDisplayMode, ESectionDisplayMode::ShowAll));
CommandList.MapAction(
ViewportShowMenuCommands.ShowOnlyClothSections,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetSectionsDisplayMode, ESectionDisplayMode::ShowOnlyClothSections),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsSectionsDisplayMode, ESectionDisplayMode::ShowOnlyClothSections));
CommandList.MapAction(
ViewportShowMenuCommands.HideOnlyClothSections,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetSectionsDisplayMode, ESectionDisplayMode::HideOnlyClothSections),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsSectionsDisplayMode, ESectionDisplayMode::HideOnlyClothSections));
CommandList.EndGroup();
CommandList.BeginGroup(TEXT("TimecodeSettings"));
CommandList.MapAction(
ViewportShowMenuCommands.ShowTimecode,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnToggleShowTimecode),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsShowTimecode));
CommandList.EndGroup();
GetPreviewScene()->RegisterOnSelectedLODChanged(FOnSelectedLODChanged::CreateSP(this, &SAnimationEditorViewportTabBody::OnLODModelChanged));
//Bind LOD preview menu commands
const FAnimViewportLODCommands& ViewportLODMenuCommands = FAnimViewportLODCommands::Get();
CommandList.BeginGroup(TEXT("LOD"));
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (PreviewComponent)
{
//LOD Debug
CommandList.MapAction(
ViewportLODMenuCommands.LODDebug,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetLODTrackDebuggedInstance),
FCanExecuteAction::CreateLambda([PreviewComponent]() { return PreviewComponent->PreviewInstance ? (bool)PreviewComponent->PreviewInstance->GetDebugSkeletalMeshComponent() : false; }),
FIsActionChecked::CreateLambda([PreviewComponent]() { return PreviewComponent->IsTrackingAttachedLOD(); }),
FIsActionButtonVisible::CreateLambda([PreviewComponent]() { return PreviewComponent->PreviewInstance ? (bool)PreviewComponent->PreviewInstance->GetDebugSkeletalMeshComponent() : false; }));
PreviewComponent->RegisterOnDebugForceLODChangedDelegate(FOnDebugForceLODChanged::CreateSP(this, &SAnimationEditorViewportTabBody::OnDebugForcedLODChanged));
}
//LOD Auto
CommandList.MapAction(
ViewportLODMenuCommands.LODAuto,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetLODModel, 0),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsLODModelSelected, 0));
// LOD 0
CommandList.MapAction(
ViewportLODMenuCommands.LOD0,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetLODModel, 1),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsLODModelSelected, 1));
// all other LODs will be added dynamically
CommandList.EndGroup();
CommandList.MapAction(
ViewportShowMenuCommands.AutoAlignFloorToMesh,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnToggleAutoAlignFloor),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsAutoAlignFloor));
//Bind LOD preview menu commands
const FAnimViewportPlaybackCommands& ViewportPlaybackCommands = FAnimViewportPlaybackCommands::Get();
CommandList.MapAction(
ViewportShowMenuCommands.MuteAudio,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnToggleMuteAudio),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsAudioMuted));
CommandList.MapAction(
ViewportShowMenuCommands.UseAudioAttenuation,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnToggleUseAudioAttenuation),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsAudioAttenuationEnabled));
CommandList.BeginGroup(TEXT("RootMotion"));
CommandList.MapAction(
ViewportShowMenuCommands.DoNotProcessRootMotion,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::SetProcessRootMotionMode, EProcessRootMotionMode::Ignore),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::CanUseProcessRootMotionMode, EProcessRootMotionMode::Ignore),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsProcessRootMotionModeSet, EProcessRootMotionMode::Ignore));
CommandList.MapAction(
ViewportShowMenuCommands.ProcessRootMotionLoopAndReset,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::SetProcessRootMotionMode, EProcessRootMotionMode::LoopAndReset),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::CanUseProcessRootMotionMode, EProcessRootMotionMode::LoopAndReset),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsProcessRootMotionModeSet, EProcessRootMotionMode::LoopAndReset));
CommandList.MapAction(
ViewportShowMenuCommands.ProcessRootMotionLoop,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::SetProcessRootMotionMode, EProcessRootMotionMode::Loop),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::CanUseProcessRootMotionMode, EProcessRootMotionMode::Loop),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsProcessRootMotionModeSet, EProcessRootMotionMode::Loop));
CommandList.MapAction(
ViewportShowMenuCommands.DoNotVisualizeRootMotion,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::SetVisualizeRootMotionMode, EVisualizeRootMotionMode::None),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::CanVisualizeRootMotion),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsVisualizeRootMotionModeSet, EVisualizeRootMotionMode::None));
CommandList.MapAction(
ViewportShowMenuCommands.VisualizeRootMotionTrajectory,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::SetVisualizeRootMotionMode, EVisualizeRootMotionMode::Trajectory),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::CanVisualizeRootMotion),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsVisualizeRootMotionModeSet, EVisualizeRootMotionMode::Trajectory));
CommandList.MapAction(
ViewportShowMenuCommands.VisualizeRootMotionTrajectoryAndOrientation,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::SetVisualizeRootMotionMode, EVisualizeRootMotionMode::TrajectoryAndOrientation),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::CanVisualizeRootMotion),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsVisualizeRootMotionModeSet, EVisualizeRootMotionMode::TrajectoryAndOrientation));
CommandList.MapAction(
ViewportShowMenuCommands.ShowNotificationVisualizations,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::ToggleNotificationVisualizations),
FIsActionChecked(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsNotificationVisualizationsEnabled));
CommandList.MapAction(
ViewportShowMenuCommands.ShowAssetUserDataVisualizations,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::ToggleAssetUserDataVisualizations),
FIsActionChecked(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsAssetUserDataVisualizationsEnabled));
CommandList.EndGroup();
CommandList.MapAction(
ViewportShowMenuCommands.DisablePostProcessBlueprint,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnToggleDisablePostProcess),
FCanExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::CanDisablePostProcess),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsDisablePostProcessChecked));
CommandList.BeginGroup(TEXT("TurnTableSpeeds"));
// Turn Table Controls
for (int32 i = 0; i < int(EAnimationPlaybackSpeeds::NumPlaybackSpeeds); ++i)
{
CommandList.MapAction(
ViewportPlaybackCommands.TurnTableSpeeds[i],
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetTurnTableSpeed, i),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsTurnTableSpeedSelected, i));
}
CommandList.EndGroup();
CommandList.BeginGroup(TEXT("TurnTableMode"));
CommandList.MapAction(
ViewportPlaybackCommands.PersonaTurnTablePlay,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetTurnTableMode, int32(EPersonaTurnTableMode::Playing)),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsTurnTableModeSelected, int32(EPersonaTurnTableMode::Playing)));
CommandList.MapAction(
ViewportPlaybackCommands.PersonaTurnTablePause,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetTurnTableMode, int32(EPersonaTurnTableMode::Paused)),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsTurnTableModeSelected, int32(EPersonaTurnTableMode::Paused)));
CommandList.MapAction(
ViewportPlaybackCommands.PersonaTurnTableStop,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::OnSetTurnTableMode, int32(EPersonaTurnTableMode::Stopped)),
FCanExecuteAction(),
FIsActionChecked::CreateSP(this, &SAnimationEditorViewportTabBody::IsTurnTableModeSelected, int32(EPersonaTurnTableMode::Stopped)));
CommandList.EndGroup();
CommandList.MapAction(
FEditorViewportCommands::Get().FocusViewportToSelection,
FExecuteAction::CreateSP(this, &SAnimationEditorViewportTabBody::HandleFocusCamera));
if (const TSharedPtr<FAssetEditorToolkit>& AssetEditorToolkit = GetAssetEditorToolkit())
{
TSharedPtr<FUICommandList> ToolkitCommandList =
ConstCastSharedRef<FUICommandList>(AssetEditorToolkit->GetToolkitCommands());
ToolkitCommandList->Append(UICommandList->AsShared());
}
PinnedCommands->BindCommandList(UICommandList.ToSharedRef());
if (TSharedPtr<FAnimationEditorPreviewScene> AnimationEditorPreviewScene = PreviewScenePtr.Pin())
{
PinnedCommands->BindCommandList(AnimationEditorPreviewScene->GetPinnedCommandList().ToSharedRef());
}
}
void SAnimationEditorViewportTabBody::OnSetTurnTableSpeed(int32 SpeedIndex)
{
SelectedTurnTableSpeed = (EAnimationPlaybackSpeeds::Type)SpeedIndex;
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (PreviewComponent)
{
const float TurnTableSpeed = (SelectedTurnTableSpeed == EAnimationPlaybackSpeeds::Custom)
? GetCustomTurnTableSpeed()
: EAnimationPlaybackSpeeds::Values[SelectedTurnTableSpeed];
PreviewComponent->TurnTableSpeedScaling = TurnTableSpeed;
}
}
bool SAnimationEditorViewportTabBody::IsTurnTableSpeedSelected(int32 SpeedIndex) const
{
return (SelectedTurnTableSpeed == SpeedIndex);
}
void SAnimationEditorViewportTabBody::OnSetTurnTableMode(int32 ModeIndex)
{
SelectedTurnTableMode = (EPersonaTurnTableMode::Type)ModeIndex;
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (PreviewComponent)
{
PreviewComponent->SetTurnTableMode(SelectedTurnTableMode);
}
}
bool SAnimationEditorViewportTabBody::IsTurnTableModeSelected(int32 ModeIndex) const
{
return (SelectedTurnTableMode == ModeIndex);
}
int32 SAnimationEditorViewportTabBody::GetLODModelCount() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if( PreviewComponent && PreviewComponent->GetSkeletalMeshAsset())
{
return PreviewComponent->GetSkeletalMeshAsset()->GetResourceForRendering()->LODRenderData.Num();
}
return 0;
}
void SAnimationEditorViewportTabBody::OnShowMorphTargets()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* InMesh)
{
InMesh->bDisableMorphTarget = !InMesh->bDisableMorphTarget;
InMesh->MarkRenderStateDirty();
});
RefreshViewport();
}
void SAnimationEditorViewportTabBody::OnShowBoneNames()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* InMesh)
{
InMesh->bShowBoneNames = !InMesh->bShowBoneNames;
InMesh->MarkRenderStateDirty();
});
RefreshViewport();
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->UpdateBonesToDraw();
}
}
void SAnimationEditorViewportTabBody::OnShowRawAnimation()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* InMesh)
{
InMesh->bDisplayRawAnimation = !InMesh->bDisplayRawAnimation;
InMesh->MarkRenderStateDirty();
});
RefreshViewport();
}
void SAnimationEditorViewportTabBody::OnShowNonRetargetedAnimation()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* InMesh)
{
InMesh->bDisplayNonRetargetedPose = !InMesh->bDisplayNonRetargetedPose;
InMesh->MarkRenderStateDirty();
});
RefreshViewport();
}
void SAnimationEditorViewportTabBody::OnShowSourceRawAnimation()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* InMesh)
{
InMesh->bDisplaySourceAnimation = !InMesh->bDisplaySourceAnimation;
InMesh->MarkRenderStateDirty();
});
RefreshViewport();
}
void SAnimationEditorViewportTabBody::OnShowBakedAnimation()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* InMesh)
{
InMesh->bDisplayBakedAnimation = !InMesh->bDisplayBakedAnimation;
InMesh->MarkRenderStateDirty();
});
RefreshViewport();
}
void SAnimationEditorViewportTabBody::OnShowAdditiveBase()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* InMesh)
{
InMesh->bDisplayAdditiveBasePose = !InMesh->bDisplayAdditiveBasePose;
InMesh->MarkRenderStateDirty();
});
RefreshViewport();
}
bool SAnimationEditorViewportTabBody::IsPreviewingAnimation() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return (PreviewComponent && PreviewComponent->PreviewInstance && (PreviewComponent->PreviewInstance == PreviewComponent->GetAnimInstance()));
}
bool SAnimationEditorViewportTabBody::IsShowingMorphTargets() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bDisableMorphTarget == false;
}
bool SAnimationEditorViewportTabBody::IsShowingBoneNames() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bShowBoneNames;
}
void SAnimationEditorViewportTabBody::OnShowBoneColors()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* InMesh)
{
UPersonaOptions* Settings = GetMutableDefault<UPersonaOptions>();
Settings->bShowBoneColors = !Settings->bShowBoneColors;
InMesh->MarkRenderStateDirty();
});
RefreshViewport();
}
bool SAnimationEditorViewportTabBody::IsShowingBoneColors() const
{
const UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent && GetDefault<UPersonaOptions>()->bShowBoneColors;
}
bool SAnimationEditorViewportTabBody::IsShowingRawAnimation() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bDisplayRawAnimation;
}
void SAnimationEditorViewportTabBody::OnToggleDisablePostProcess()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* InMesh)
{
InMesh->ToggleDisablePostProcessBlueprint();
});
AddPostProcessNotification();
}
bool SAnimationEditorViewportTabBody::CanDisablePostProcess() const
{
const TArray<UDebugSkelMeshComponent*> PreviewMeshComponents = GetPreviewScene()->GetAllPreviewMeshComponents();
for (const UDebugSkelMeshComponent* PreviewMeshComponent : PreviewMeshComponents)
{
if (PreviewMeshComponent->PostProcessAnimInstance && PreviewMeshComponent->IsVisible())
{
return true;
}
}
return false;
}
bool SAnimationEditorViewportTabBody::IsDisablePostProcessChecked()
{
TArray<UDebugSkelMeshComponent*> PreviewMeshComponents = GetPreviewScene()->GetAllPreviewMeshComponents();
for (UDebugSkelMeshComponent* PreviewMeshComponent : PreviewMeshComponents)
{
if (PreviewMeshComponent->GetDisablePostProcessBlueprint())
{
return true;
}
}
return false;
}
bool SAnimationEditorViewportTabBody::IsShowingNonRetargetedPose() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bDisplayNonRetargetedPose;
}
bool SAnimationEditorViewportTabBody::IsShowingAdditiveBase() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bDisplayAdditiveBasePose;
}
bool SAnimationEditorViewportTabBody::IsShowingSourceRawAnimation() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bDisplaySourceAnimation;
}
bool SAnimationEditorViewportTabBody::IsShowingBakedAnimation() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bDisplayBakedAnimation;
}
void SAnimationEditorViewportTabBody::OnShowDisplayInfo(int32 DisplayInfoMode)
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->OnSetShowMeshStats(DisplayInfoMode);
}
}
bool SAnimationEditorViewportTabBody::IsShowingMeshInfo(int32 DisplayInfoMode) const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->GetShowMeshStats() == DisplayInfoMode;
}
return false;
}
void SAnimationEditorViewportTabBody::OnShowOverlayNone()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* PreviewMeshComponent)
{
PreviewMeshComponent->SetShowBoneWeight(false);
PreviewMeshComponent->SetShowMorphTargetVerts(false);
PreviewMeshComponent->MarkRenderStateDirty();
});
UpdateShowFlagForMeshEdges();
RefreshViewport();
}
bool SAnimationEditorViewportTabBody::IsShowingOverlayNone() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && !PreviewComponent->bDrawBoneInfluences && !PreviewComponent->bDrawMorphTargetVerts;
}
void SAnimationEditorViewportTabBody::OnShowOverlayBoneWeight()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* PreviewMeshComponent)
{
PreviewMeshComponent->SetShowBoneWeight( !PreviewMeshComponent->bDrawBoneInfluences );
PreviewMeshComponent->MarkRenderStateDirty();
});
UpdateShowFlagForMeshEdges();
RefreshViewport();
}
bool SAnimationEditorViewportTabBody::IsShowingOverlayBoneWeight() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bDrawBoneInfluences;
}
void SAnimationEditorViewportTabBody::OnShowOverlayMorphTargetVert()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* PreviewMeshComponent)
{
PreviewMeshComponent->SetShowMorphTargetVerts(!PreviewMeshComponent->bDrawMorphTargetVerts);
PreviewMeshComponent->MarkRenderStateDirty();
});
UpdateShowFlagForMeshEdges();
RefreshViewport();
}
bool SAnimationEditorViewportTabBody::IsShowingOverlayMorphTargetVerts() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bDrawMorphTargetVerts;
}
void SAnimationEditorViewportTabBody::SetBoneDrawSize(float BoneDrawSize)
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->SetBoneDrawSize(BoneDrawSize);
}
}
float SAnimationEditorViewportTabBody::GetBoneDrawSize() const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->GetBoneDrawSize();
}
return 0.0f;
}
void SAnimationEditorViewportTabBody::SetCustomTurnTableSpeed(float InCustomTurnTableSpeed)
{
CustomTurnTableSpeed = InCustomTurnTableSpeed;
OnSetTurnTableSpeed(EAnimationPlaybackSpeeds::Custom);
}
float SAnimationEditorViewportTabBody::GetCustomTurnTableSpeed() const
{
return CustomTurnTableSpeed;
}
void SAnimationEditorViewportTabBody::OnSetBoneDrawMode(int32 BoneDrawMode)
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->SetBoneDrawMode((EBoneDrawMode::Type)BoneDrawMode);
}
}
bool SAnimationEditorViewportTabBody::IsBoneDrawModeSet(int32 BoneDrawMode) const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->IsBoneDrawModeSet((EBoneDrawMode::Type)BoneDrawMode);
}
return false;
}
void SAnimationEditorViewportTabBody::OnSetLocalAxesMode(int32 LocalAxesMode)
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->SetLocalAxesMode((ELocalAxesMode::Type)LocalAxesMode);
}
}
bool SAnimationEditorViewportTabBody::IsLocalAxesModeSet(int32 LocalAxesMode) const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->IsLocalAxesModeSet((ELocalAxesMode::Type)LocalAxesMode);
}
return false;
}
void SAnimationEditorViewportTabBody::OnShowSockets()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* PreviewMeshComponent)
{
PreviewMeshComponent->bDrawSockets = !PreviewMeshComponent->bDrawSockets;
PreviewMeshComponent->MarkRenderStateDirty();
});
RefreshViewport();
}
bool SAnimationEditorViewportTabBody::IsShowingSockets() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bDrawSockets;
}
void SAnimationEditorViewportTabBody::OnShowAttributes()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* PreviewMeshComponent)
{
PreviewMeshComponent->bDrawAttributes = !PreviewMeshComponent->bDrawAttributes;
PreviewMeshComponent->MarkRenderStateDirty();
});
RefreshViewport();
}
bool SAnimationEditorViewportTabBody::IsShowingAttributes() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bDrawAttributes;
}
void SAnimationEditorViewportTabBody::OnToggleAutoAlignFloor()
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->OnToggleAutoAlignFloor();
}
}
bool SAnimationEditorViewportTabBody::IsAutoAlignFloor() const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->IsAutoAlignFloor();
}
return false;
}
void SAnimationEditorViewportTabBody::ShowBound()
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->ToggleShowBounds();
ForEachDebugMesh(
[AnimViewportClientWeak = AnimViewportClient.ToWeakPtr()](UDebugSkelMeshComponent* PreviewMeshComponent)
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = AnimViewportClientWeak.Pin())
{
PreviewMeshComponent->bDisplayBound = AnimViewportClient->EngineShowFlags.Bounds;
PreviewMeshComponent->RecreateRenderState_Concurrent();
}
}
);
}
}
bool SAnimationEditorViewportTabBody::CanShowBound() const
{
return !GetPreviewScene()->GetAllPreviewMeshComponents().IsEmpty();
}
bool SAnimationEditorViewportTabBody::IsShowBoundEnabled() const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->IsSetShowBoundsChecked();
}
return false;
}
void SAnimationEditorViewportTabBody::ToggleShowPreviewMesh()
{
const bool bCurrentlyVisible = IsShowPreviewMeshEnabled();
ForEachDebugMesh([bCurrentlyVisible](UDebugSkelMeshComponent* PreviewMeshComponent)
{
PreviewMeshComponent->SetVisibility(!bCurrentlyVisible);
});
}
bool SAnimationEditorViewportTabBody::CanShowPreviewMesh() const
{
return !GetPreviewScene()->GetAllPreviewMeshComponents().IsEmpty();
}
bool SAnimationEditorViewportTabBody::IsShowPreviewMeshEnabled() const
{
TArray<UDebugSkelMeshComponent*> PreviewMeshComponents = GetPreviewScene()->GetAllPreviewMeshComponents();
for (UDebugSkelMeshComponent* PreviewMeshComponent : PreviewMeshComponents)
{
if(PreviewMeshComponent && PreviewMeshComponent->IsVisible())
{
return true;
}
}
return false;
}
void SAnimationEditorViewportTabBody::OnToggleShowTimecode()
{
GetPreviewScene()->ToggleShowTimecode();
}
bool SAnimationEditorViewportTabBody::IsShowTimecode() const
{
return GetPreviewScene()->IsShowTimecode();
}
void SAnimationEditorViewportTabBody::UseInGameBound()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* PreviewMeshComponent)
{
PreviewMeshComponent->UseInGameBounds(! PreviewMeshComponent->IsUsingInGameBounds());
});
}
bool SAnimationEditorViewportTabBody::CanUseInGameBound() const
{
TArray<UDebugSkelMeshComponent*> PreviewMeshComponents = GetPreviewScene()->GetAllPreviewMeshComponents();
for (UDebugSkelMeshComponent* PreviewMeshComponent : PreviewMeshComponents)
{
if(IsShowBoundEnabled())
{
return true;
}
}
return false;
}
bool SAnimationEditorViewportTabBody::IsUsingInGameBound() const
{
TArray<UDebugSkelMeshComponent*> PreviewMeshComponents = GetPreviewScene()->GetAllPreviewMeshComponents();
for (UDebugSkelMeshComponent* PreviewMeshComponent : PreviewMeshComponents)
{
if(PreviewMeshComponent->IsUsingInGameBounds())
{
return true;
}
}
return false;
}
void SAnimationEditorViewportTabBody::UseFixedBounds()
{
ForEachDebugMesh([](UDebugSkelMeshComponent* PreviewMeshComponent)
{
PreviewMeshComponent->bComponentUseFixedSkelBounds = !PreviewMeshComponent->bComponentUseFixedSkelBounds;
});
}
bool SAnimationEditorViewportTabBody::CanUseFixedBounds() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && IsShowBoundEnabled();
}
bool SAnimationEditorViewportTabBody::IsUsingFixedBounds() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->bComponentUseFixedSkelBounds;
}
void SAnimationEditorViewportTabBody::UsePreSkinnedBounds()
{
GetPreviewScene()->ForEachPreviewMesh([](UDebugSkelMeshComponent* PreviewMeshComponent)
{
PreviewMeshComponent->UsePreSkinnedBounds(!PreviewMeshComponent->IsUsingPreSkinnedBounds());
});
}
bool SAnimationEditorViewportTabBody::CanUsePreSkinnedBounds() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && IsShowBoundEnabled();
}
bool SAnimationEditorViewportTabBody::IsUsingPreSkinnedBounds() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent != NULL && PreviewComponent->IsUsingPreSkinnedBounds();
}
void SAnimationEditorViewportTabBody::HandlePreviewMeshChanged(class USkeletalMesh* OldSkeletalMesh, class USkeletalMesh* NewSkeletalMesh)
{
PopulateNumUVChannels();
PopulateSkinWeightProfileNames();
if (OldSkeletalMesh)
{
OldSkeletalMesh->OnPostMeshCached().RemoveAll(this);
}
if (NewSkeletalMesh)
{
NewSkeletalMesh->OnPostMeshCached().AddSP(this, &SAnimationEditorViewportTabBody::UpdateSkinWeightSelection);
}
}
void SAnimationEditorViewportTabBody::AnimChanged(UAnimationAsset* AnimAsset)
{
UpdateScrubPanel(AnimAsset);
}
void SAnimationEditorViewportTabBody::ComboBoxSelectionChanged(TSharedPtr<FString> NewSelection, ESelectInfo::Type SelectInfo)
{
const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient();
if (!AnimViewportClient)
{
return;
}
int32 NewUVSelection = UVChannels.Find(NewSelection) - 1;
// "None" is index -1 here.
if ( NewUVSelection < 0 )
{
AnimViewportClient->SetDrawUVOverlay(false);
return;
}
AnimViewportClient->SetDrawUVOverlay(true);
AnimViewportClient->SetUVChannelToDraw(NewUVSelection);
RefreshViewport();
}
void SAnimationEditorViewportTabBody::PopulateNumUVChannels()
{
NumUVChannels.Empty();
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
if (FSkeletalMeshRenderData* MeshResource = PreviewComponent->GetSkeletalMeshRenderData())
{
int32 NumLods = MeshResource->LODRenderData.Num();
NumUVChannels.AddZeroed(NumLods);
for(int32 LOD = 0; LOD < NumLods; ++LOD)
{
NumUVChannels[LOD] = MeshResource->LODRenderData[LOD].StaticVertexBuffers.StaticMeshVertexBuffer.GetNumTexCoords();
}
}
}
PopulateUVChoices();
}
void SAnimationEditorViewportTabBody::PopulateUVChoices()
{
const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient();
if (!AnimViewportClient)
{
return;
}
// Fill out the UV channels combo.
UVChannels.Empty();
UVChannels.Add(MakeShareable(new FString(NSLOCTEXT("AnimationEditorViewport", "NoUVChannel", "None").ToString())));
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
int32 CurrentLOD = FMath::Clamp(PreviewComponent->GetForcedLOD() - 1, 0, NumUVChannels.Num() - 1);
if (NumUVChannels.IsValidIndex(CurrentLOD))
{
for (int32 UVChannelID = 0; UVChannelID < NumUVChannels[CurrentLOD]; ++UVChannelID)
{
UVChannels.Add( MakeShareable( new FString( FText::Format( NSLOCTEXT("AnimationEditorViewport", "UVChannel_ID", "UV Channel {0}"), FText::AsNumber( UVChannelID ) ).ToString() ) ) );
}
int32 CurrentUVChannel = AnimViewportClient->GetUVChannelToDraw();
if (!UVChannels.IsValidIndex(CurrentUVChannel))
{
CurrentUVChannel = 0;
}
AnimViewportClient->SetUVChannelToDraw(CurrentUVChannel);
if (UVChannelCombo.IsValid() && UVChannels.IsValidIndex(CurrentUVChannel))
{
UVChannelCombo->SetSelectedItem(UVChannels[CurrentUVChannel]);
}
}
}
}
void SAnimationEditorViewportTabBody::PopulateSkinWeightProfileNames()
{
SkinWeightProfileNames.Empty();
// Always make sure we have a default 'none' option
const FName DefaultProfileName = NAME_None;
SkinWeightProfileNames.Add(MakeShared<FName>(DefaultProfileName));
// Retrieve all possible skin weight profiles from the component
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
if (USkeletalMesh* Mesh = PreviewComponent->GetSkeletalMeshAsset())
{
for (const FSkinWeightProfileInfo& Profile : Mesh->GetSkinWeightProfiles())
{
SkinWeightProfileNames.AddUnique(MakeShared<FName>(Profile.Name));
}
}
}
}
void SAnimationEditorViewportTabBody::UpdateSkinWeightSelection(USkeletalMesh* InSkeletalMesh)
{
// Check (post a mesh build) whether or not our currently selected profile name is still valid, and if not reset to 'none'
if (SkinWeightCombo->GetSelectedItem().IsValid())
{
const FName OldSelection = *SkinWeightCombo->GetSelectedItem();
PopulateSkinWeightProfileNames();
const int32 SelectionIndex = SkinWeightProfileNames.IndexOfByPredicate([OldSelection](TSharedPtr<FName> InName) { return *InName == OldSelection; });
// Select new entry or otherwise select none
SkinWeightCombo->SetSelectedItem(SelectionIndex != INDEX_NONE ? SkinWeightProfileNames[SelectionIndex] : SkinWeightProfileNames[0]);
}
}
void SAnimationEditorViewportTabBody::UpdateScrubPanel(UAnimationAsset* AnimAsset)
{
// We might not have a scrub panel if we're in animation mode.
if (ScrubPanelContainer.IsValid())
{
ScrubPanelContainer->ClearChildren();
bool bUseDefaultScrubPanel = true;
if (UAnimMontage* Montage = Cast<UAnimMontage>(AnimAsset))
{
ScrubPanelContainer->AddSlot()
.AutoHeight()
[
SNew(SAnimMontageScrubPanel, GetPreviewScene())
.ViewInputMin(this, &SAnimationEditorViewportTabBody::GetViewMinInput)
.ViewInputMax(this, &SAnimationEditorViewportTabBody::GetViewMaxInput)
.bAllowZoom(true)
];
bUseDefaultScrubPanel = false;
}
if(bUseDefaultScrubPanel)
{
ScrubPanelContainer->AddSlot()
.AutoHeight()
[
SNew(SAnimationScrubPanel, GetPreviewScene())
.ViewInputMin(this, &SAnimationEditorViewportTabBody::GetViewMinInput)
.ViewInputMax(this, &SAnimationEditorViewportTabBody::GetViewMaxInput)
.bAllowZoom(true)
.bDisplayAnimScrubBarEditing(false)
.TimelineDelegates(TimelineDelegates)
];
}
}
}
float SAnimationEditorViewportTabBody::GetViewMinInput() const
{
if(TimelineDelegates.GetPlaybackTimeRangeDelegate.IsBound())
{
const TOptional<FVector2f> TimeRange = TimelineDelegates.GetPlaybackTimeRangeDelegate.Execute();
if(TimeRange.IsSet())
{
return TimeRange.GetValue().X;
}
}
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
UObject* PreviewAsset = GetPreviewScene()->GetPreviewAnimationAsset();
if (PreviewAsset != NULL)
{
return 0.0f;
}
else if (PreviewComponent->GetAnimInstance() != NULL)
{
return FMath::Max<float>((float)(PreviewComponent->GetAnimInstance()->LifeTimer - 30.0), 0.0f);
}
}
return 0.f;
}
float SAnimationEditorViewportTabBody::GetViewMaxInput() const
{
if(TimelineDelegates.GetPlaybackTimeRangeDelegate.IsBound())
{
const TOptional<FVector2f> TimeRange = TimelineDelegates.GetPlaybackTimeRangeDelegate.Execute();
if(TimeRange.IsSet())
{
return TimeRange.GetValue().Y;
}
}
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (PreviewComponent != NULL)
{
UObject* PreviewAsset = GetPreviewScene()->GetPreviewAnimationAsset();
if ((PreviewAsset != NULL) && (PreviewComponent->PreviewInstance != NULL))
{
return PreviewComponent->PreviewInstance->GetLength();
}
else if (PreviewComponent->GetAnimInstance() != NULL)
{
return static_cast<float>(PreviewComponent->GetAnimInstance()->LifeTimer);
}
}
return 0.f;
}
void SAnimationEditorViewportTabBody::UpdateShowFlagForMeshEdges()
{
bool bUseOverlayMaterial = false;
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
bUseOverlayMaterial = PreviewComponent->bDrawBoneInfluences || PreviewComponent->bDrawMorphTargetVerts;
}
//@TODO: SNOWPOCALYPSE: broke UnlitWithMeshEdges
bool bShowMeshEdgesViewMode = false;
#if 0
bShowMeshEdgesViewMode = (CurrentViewMode == EAnimationEditorViewportMode::UnlitWithMeshEdges);
#endif
LevelViewportClient->EngineShowFlags.SetMeshEdges(bUseOverlayMaterial || bShowMeshEdgesViewMode);
}
int32 SAnimationEditorViewportTabBody::GetLODSelection() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (PreviewComponent)
{
// If we are forcing a LOD level, report the actual LOD level we are displaying
// as the mesh can potentially change LOD count under the viewport.
if(PreviewComponent->GetForcedLOD() > 0)
{
return PreviewComponent->GetPredictedLODLevel() + 1;
}
else
{
return PreviewComponent->GetForcedLOD();
}
}
return 0;
}
bool SAnimationEditorViewportTabBody::IsLODModelSelected(int32 LODSelectionType) const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (PreviewComponent && PreviewComponent->IsTrackingAttachedLOD())
{
return false;
}
return GetLODSelection() == LODSelectionType;
}
bool SAnimationEditorViewportTabBody::IsTrackingAttachedMeshLOD() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (PreviewComponent)
{
return PreviewComponent->IsTrackingAttachedLOD();
}
return false;
}
void SAnimationEditorViewportTabBody::OnSetLODModel(int32 LODSelectionType)
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if( PreviewComponent )
{
LODSelection = LODSelectionType;
PreviewComponent->SetDebugForcedLOD(LODSelectionType);
PreviewComponent->bTrackAttachedInstanceLOD = false;
}
}
void SAnimationEditorViewportTabBody::OnSetLODTrackDebuggedInstance()
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (PreviewComponent)
{
PreviewComponent->bTrackAttachedInstanceLOD = true;
}
}
void SAnimationEditorViewportTabBody::OnLODModelChanged()
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (PreviewComponent && LODSelection != PreviewComponent->GetForcedLOD())
{
LODSelection = PreviewComponent->GetForcedLOD();
PopulateUVChoices();
}
}
void SAnimationEditorViewportTabBody::OnDebugForcedLODChanged()
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (PreviewComponent)
{
PopulateUVChoices();
GetPreviewScene()->BroadcastOnSelectedLODChanged();
}
}
void SAnimationEditorViewportTabBody::OnBeginSliderMovementFloorOffset()
{
// This value is saved in a UPROPERTY for the floor mesh, so changes are transactional
PendingTransaction = MakeUnique<FScopedTransaction>(LOCTEXT("SetFloorOffset", "Set Floor Offset"));
PinnedCommands->AddCustomWidget(TEXT("FloorOffsetWidget"));
}
void SAnimationEditorViewportTabBody::OnFloorOffsetChanged(float InNewValue)
{
FAnimationViewportClient& AnimViewportClient = (FAnimationViewportClient&)GetLevelViewportClient();
AnimViewportClient.SetFloorOffset(InNewValue);
PinnedCommands->AddCustomWidget(TEXT("FloorOffsetWidget"));
}
void SAnimationEditorViewportTabBody::OnFloorOffsetCommitted(float InNewValue, ETextCommit::Type InCommitType)
{
if (!PendingTransaction)
{
// Create the transaction here if it doesn't already exist. This can happen when changes come via text entry to the slider.
PendingTransaction = MakeUnique<FScopedTransaction>(LOCTEXT("SetFloorOffset", "Set Floor Offset"));
}
FAnimationViewportClient& AnimViewportClient = (FAnimationViewportClient&)GetLevelViewportClient();
AnimViewportClient.SetFloorOffset(InNewValue);
PinnedCommands->AddCustomWidget(TEXT("FloorOffsetWidget"));
PendingTransaction.Reset();
}
void SAnimationEditorViewportTabBody::CreatePinnedCommands()
{
// Create our pinned commands before we bind commands
IPinnedCommandListModule& PinnedCommandListModule =
FModuleManager::LoadModuleChecked<IPinnedCommandListModule>(TEXT("PinnedCommandList"));
PinnedCommands =
PinnedCommandListModule.CreatePinnedCommandList((ContextName != NAME_None) ? ContextName : TEXT("PersonaViewport"));
PinnedCommands->SetStyle(&FAppStyle::Get(), TEXT("ViewportPinnedCommandList"));
UICommandList = MakeShareable(new FUICommandList_Pinnable);
}
TSharedPtr<FAnimationViewportClient> SAnimationEditorViewportTabBody::GetAnimationViewportClient() const
{
return StaticCastSharedPtr<FAnimationViewportClient>(LevelViewportClient);
}
void SAnimationEditorViewportTabBody::OpenPreviewSceneSettings()
{
OnInvokeTab.ExecuteIfBound(FPersonaTabs::AdvancedPreviewSceneSettingsID);
}
void SAnimationEditorViewportTabBody::SetCameraFollowMode(EAnimationViewportCameraFollowMode InCameraFollowMode, FName InBoneName)
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->SetCameraFollowMode(InCameraFollowMode, InBoneName);
}
}
bool SAnimationEditorViewportTabBody::IsCameraFollowEnabled(EAnimationViewportCameraFollowMode InCameraFollowMode) const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return (AnimViewportClient->GetCameraFollowMode() == InCameraFollowMode);
}
return false;
}
void SAnimationEditorViewportTabBody::ToggleRotateCameraToFollowBone()
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->ToggleRotateCameraToFollowBone();
}
}
bool SAnimationEditorViewportTabBody::GetShouldRotateCameraToFollowBone() const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->GetShouldRotateCameraToFollowBone();
}
return false;
}
void SAnimationEditorViewportTabBody::TogglePauseAnimationOnCameraMove()
{
GetMutableDefault<UPersonaOptions>()->bPauseAnimationOnCameraMove = !GetMutableDefault<UPersonaOptions>()->bPauseAnimationOnCameraMove;
}
bool SAnimationEditorViewportTabBody::GetShouldPauseAnimationOnCameraMove() const
{
return GetMutableDefault<UPersonaOptions>()->bPauseAnimationOnCameraMove;
}
FName SAnimationEditorViewportTabBody::GetCameraFollowBoneName() const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->GetCameraFollowBoneName();
}
return NAME_None;
}
void SAnimationEditorViewportTabBody::SaveCameraAsDefault()
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->SaveCameraAsDefault();
}
}
void SAnimationEditorViewportTabBody::ClearDefaultCamera()
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->ClearDefaultCamera();
}
}
void SAnimationEditorViewportTabBody::JumpToDefaultCamera()
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->JumpToDefaultCamera();
}
}
bool SAnimationEditorViewportTabBody::CanSaveCameraAsDefault() const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->CanSaveCameraAsDefault();
}
return false;
}
bool SAnimationEditorViewportTabBody::HasDefaultCameraSet() const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return (AnimViewportClient->HasDefaultCameraSet());
}
return false;
}
bool SAnimationEditorViewportTabBody::CanChangeCameraMode() const
{
//Not allowed to change camera type when we are in an ortho camera
return !LevelViewportClient->IsOrtho();
}
void SAnimationEditorViewportTabBody::OnToggleMuteAudio()
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->OnToggleMuteAudio();
}
}
bool SAnimationEditorViewportTabBody::IsAudioMuted() const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->IsAudioMuted();
}
return false;
}
void SAnimationEditorViewportTabBody::OnToggleUseAudioAttenuation()
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->OnToggleUseAudioAttenuation();
}
}
bool SAnimationEditorViewportTabBody::IsAudioAttenuationEnabled() const
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
return AnimViewportClient->IsUsingAudioAttenuation();
}
return false;
}
void SAnimationEditorViewportTabBody::SetProcessRootMotionMode(EProcessRootMotionMode Mode)
{
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
PreviewComponent->SetProcessRootMotionMode(Mode);
}
}
bool SAnimationEditorViewportTabBody::IsProcessRootMotionModeSet(EProcessRootMotionMode Mode) const
{
const UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
return PreviewComponent ? (PreviewComponent->GetRequestedProcessRootMotionMode() == Mode) : false;
}
bool SAnimationEditorViewportTabBody::CanUseProcessRootMotionMode(EProcessRootMotionMode Mode) const
{
if(const UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
return PreviewComponent->CanUseProcessRootMotionMode(Mode);
}
return false;
}
void SAnimationEditorViewportTabBody::SetVisualizeRootMotionMode(EVisualizeRootMotionMode Mode)
{
if(UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
return PreviewComponent->SetVisualizeRootMotionMode(Mode);
}
}
bool SAnimationEditorViewportTabBody::IsVisualizeRootMotionModeSet(EVisualizeRootMotionMode Mode) const
{
if(const UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
return PreviewComponent->IsVisualizeRootMotionMode(Mode);
}
return false;
}
bool SAnimationEditorViewportTabBody::CanVisualizeRootMotion() const
{
if(const UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
return PreviewComponent->DoesCurrentAssetHaveRootMotion();
}
return false;
}
void SAnimationEditorViewportTabBody::ToggleNotificationVisualizations()
{
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
PreviewComponent->SetShowNotificationVisualizations(!PreviewComponent->IsNotificationVisualizationsEnabled());
}
}
bool SAnimationEditorViewportTabBody::IsNotificationVisualizationsEnabled() const
{
if (const UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
return PreviewComponent->IsNotificationVisualizationsEnabled();
}
return false;
}
void SAnimationEditorViewportTabBody::ToggleAssetUserDataVisualizations()
{
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
PreviewComponent->SetShowAssetUserDataVisualizations(!PreviewComponent->IsAssetUserDataVisualizationsEnabled());
}
}
bool SAnimationEditorViewportTabBody::IsAssetUserDataVisualizationsEnabled() const
{
if (const UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
return PreviewComponent->IsAssetUserDataVisualizationsEnabled();
}
return false;
}
bool SAnimationEditorViewportTabBody::IsClothSimulationEnabled() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if( PreviewComponent )
{
return !PreviewComponent->bDisableClothSimulation;
}
return true;
}
void SAnimationEditorViewportTabBody::OnEnableClothSimulation()
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if( PreviewComponent )
{
PreviewComponent->bDisableClothSimulation = !PreviewComponent->bDisableClothSimulation;
RefreshViewport();
}
}
void SAnimationEditorViewportTabBody::OnResetClothSimulation()
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if( PreviewComponent )
{
PreviewComponent->RecreateClothingActors();
RefreshViewport();
}
}
bool SAnimationEditorViewportTabBody::IsApplyingClothWind() const
{
return GetPreviewScene()->IsWindEnabled();
}
void SAnimationEditorViewportTabBody::OnPauseClothingSimWithAnim()
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if(PreviewComponent)
{
PreviewComponent->bPauseClothingSimulationWithAnim = !PreviewComponent->bPauseClothingSimulationWithAnim;
bool bShouldPause = PreviewComponent->bPauseClothingSimulationWithAnim;
if(PreviewComponent->IsPreviewOn() && PreviewComponent->PreviewInstance)
{
UAnimSingleNodeInstance* PreviewInstance = PreviewComponent->PreviewInstance;
const bool bPlaying = PreviewInstance->IsPlaying();
if(!bPlaying && bShouldPause)
{
PreviewComponent->SuspendClothingSimulation();
}
else if(!bShouldPause && PreviewComponent->IsClothingSimulationSuspended())
{
PreviewComponent->ResumeClothingSimulation();
}
}
}
}
bool SAnimationEditorViewportTabBody::IsPausingClothingSimWithAnim()
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if(PreviewComponent)
{
return PreviewComponent->bPauseClothingSimulationWithAnim;
}
return false;
}
void SAnimationEditorViewportTabBody::SetWindStrength(float SliderPos)
{
TSharedRef<FAnimationEditorPreviewScene> PreviewScene = GetPreviewScene();
if ( SliderPos <= 0.0f )
{
if ( PreviewScene->IsWindEnabled() )
{
PreviewScene->EnableWind(false);
PreviewScene->SetWindStrength(0.0f);
RefreshViewport();
}
return;
}
if ( !PreviewScene->IsWindEnabled() )
{
PreviewScene->EnableWind(true);
}
GetPreviewScene()->SetWindStrength(SliderPos);
RefreshViewport();
}
TOptional<float> SAnimationEditorViewportTabBody::GetWindStrengthSliderValue() const
{
return GetPreviewScene()->GetWindStrength();
}
void SAnimationEditorViewportTabBody::SetGravityScale(float SliderPos)
{
GetPreviewScene()->SetGravityScale(SliderPos);
RefreshViewport();
}
float SAnimationEditorViewportTabBody::GetGravityScaleSliderValue() const
{
return GetPreviewScene()->GetGravityScale();
}
void SAnimationEditorViewportTabBody::OnEnableCollisionWithAttachedClothChildren()
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if( PreviewComponent )
{
PreviewComponent->bCollideWithAttachedChildren = !PreviewComponent->bCollideWithAttachedChildren;
RefreshViewport();
}
}
bool SAnimationEditorViewportTabBody::IsEnablingCollisionWithAttachedClothChildren() const
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if( PreviewComponent )
{
return PreviewComponent->bCollideWithAttachedChildren;
}
return false;
}
void SAnimationEditorViewportTabBody::OnSetSectionsDisplayMode(ESectionDisplayMode DisplayMode)
{
UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent();
if (!PreviewComponent)
{
return;
}
SectionsDisplayMode = DisplayMode;
switch (SectionsDisplayMode)
{
case ESectionDisplayMode::ShowAll:
// restore to the original states
PreviewComponent->RestoreClothSectionsVisibility();
break;
case ESectionDisplayMode::ShowOnlyClothSections:
// disable all except clothing sections and shows only cloth sections
PreviewComponent->ToggleClothSectionsVisibility(true);
break;
case ESectionDisplayMode::HideOnlyClothSections:
// disables only clothing sections
PreviewComponent->ToggleClothSectionsVisibility(false);
break;
}
RefreshViewport();
}
bool SAnimationEditorViewportTabBody::IsSectionsDisplayMode(ESectionDisplayMode DisplayMode) const
{
return SectionsDisplayMode == DisplayMode;
}
void SAnimationEditorViewportTabBody::AddRecordingNotification()
{
if(WeakRecordingNotification.IsValid())
{
return;
}
auto GetRecordingStateText = [this]()
{
if(GetPreviewScene()->IsRecording())
{
UAnimSequence* Recording = GetPreviewScene()->GetCurrentRecording();
const FString& Name = Recording ? Recording->GetName() : TEXT("None");
float TimeRecorded = GetPreviewScene()->GetCurrentRecordingTime();
FNumberFormattingOptions NumberOption;
NumberOption.MaximumFractionalDigits = 2;
NumberOption.MinimumFractionalDigits = 2;
return FText::Format(LOCTEXT("AnimRecorder", "Recording '{0}' {1} secs"),
FText::FromString(Name), FText::AsNumber(TimeRecorded, &NumberOption));
}
return FText::GetEmpty();
};
auto GetRecordingStateStateVisibility = [this]()
{
if (GetPreviewScene()->IsRecording())
{
return EVisibility::Visible;
}
return EVisibility::Collapsed;
};
auto StopRecording = [this]()
{
if (GetPreviewScene()->IsRecording())
{
GetPreviewScene()->StopRecording();
}
return FReply::Handled();
};
WeakRecordingNotification = AddNotification(EMessageSeverity::Info,
true,
SNew(SHorizontalBox)
.Visibility_Lambda(GetRecordingStateStateVisibility)
.ToolTipText(LOCTEXT("RecordingStatusTooltip", "Shows the status of animation recording."))
+SHorizontalBox::Slot()
.FillWidth(1.0f)
.Padding(2.0f, 4.0f)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
.Font(FAppStyle::Get().GetFontStyle("FontAwesome.9"))
.Text(FEditorFontGlyphs::Video_Camera)
]
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text_Lambda(GetRecordingStateText)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
]
]
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
SNew(SButton)
.ForegroundColor(FSlateColor::UseForeground())
.ButtonStyle(FAppStyle::Get(), "FlatButton.Success")
.ToolTipText(LOCTEXT("RecordingInViewportStop", "Stop recording animation."))
.OnClicked_Lambda(StopRecording)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
.Font(FAppStyle::Get().GetFontStyle("FontAwesome.9"))
.Text(FEditorFontGlyphs::Stop)
]
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
.Text(LOCTEXT("AnimViewportStopRecordingButtonLabel", "Stop"))
]
]
],
FPersonaViewportNotificationOptions(TAttribute<EVisibility>::Create(GetRecordingStateStateVisibility))
);
}
void SAnimationEditorViewportTabBody::AddPostProcessNotification()
{
if(WeakPostProcessNotification.IsValid())
{
return;
}
auto GetVisibility = [this]()
{
return CanDisablePostProcess() ? EVisibility::Visible : EVisibility::Collapsed;
};
auto GetPostProcessGraphName = [this]()
{
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
if(PreviewComponent->GetSkeletalMeshAsset() && PreviewComponent->GetSkeletalMeshAsset()->GetPostProcessAnimBlueprint() && PreviewComponent->GetSkeletalMeshAsset()->GetPostProcessAnimBlueprint()->ClassGeneratedBy)
{
return FText::FromString(PreviewComponent->GetSkeletalMeshAsset()->GetPostProcessAnimBlueprint()->ClassGeneratedBy->GetName());
}
}
return FText::GetEmpty();
};
auto DoesPostProcessModifyCurves = [this]()
{
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
return (PreviewComponent->PostProcessAnimInstance && PreviewComponent->PostProcessAnimInstance->HasActiveCurves());
}
return false;
};
auto GetText = [this, GetPostProcessGraphName, DoesPostProcessModifyCurves]()
{
return IsDisablePostProcessChecked() ?
FText::Format(LOCTEXT("PostProcessDisabledText", "Post process Animation Blueprint '{0}' is disabled."), GetPostProcessGraphName()) :
FText::Format(LOCTEXT("PostProcessRunningText", "Post process Animation Blueprint '{0}' is running. {1}"), GetPostProcessGraphName(), DoesPostProcessModifyCurves() ? LOCTEXT("PostProcessModifiesCurves", "Post process modifes curves.") : FText::GetEmpty()) ;
};
auto GetButtonText = [this]()
{
return IsDisablePostProcessChecked() ? LOCTEXT("PostProcessEnableText", "Enable") : LOCTEXT("PostProcessDisableText", "Disable");
};
auto GetButtonTooltipText = [this]()
{
return IsDisablePostProcessChecked() ? LOCTEXT("PostProcessEnableTooltip", "Enable post process animation blueprint.") : LOCTEXT("PostProcessDisableTooltip", "Disable post process animation blueprint.");
};
auto GetButtonIcon = [this]()
{
return IsDisablePostProcessChecked() ? FEditorFontGlyphs::Check : FEditorFontGlyphs::Times;
};
auto EnablePostProcess = [this]()
{
OnToggleDisablePostProcess();
return FReply::Handled();
};
auto EditPostProcess = [this]()
{
if (UDebugSkelMeshComponent* PreviewComponent = GetPreviewScene()->GetPreviewMeshComponent())
{
if(PreviewComponent->GetSkeletalMeshAsset() && !PreviewComponent->GetSkeletalMeshAsset()->IsCompiling() && PreviewComponent->GetSkeletalMeshAsset()->GetPostProcessAnimBlueprint())
{
GEditor->GetEditorSubsystem<UAssetEditorSubsystem>()->OpenEditorForAssets(TArray<UObject*>({ PreviewComponent->GetSkeletalMeshAsset()->GetPostProcessAnimBlueprint()->ClassGeneratedBy }));
}
}
return FReply::Handled();
};
WeakPostProcessNotification = AddNotification(EMessageSeverity::Warning,
true,
SNew(SHorizontalBox)
.Visibility_Lambda(GetVisibility)
+SHorizontalBox::Slot()
.FillWidth(1.0f)
.Padding(4.0f, 4.0f)
[
SNew(SHorizontalBox)
.ToolTipText_Lambda(GetText)
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
.Font(FAppStyle::Get().GetFontStyle("FontAwesome.9"))
.Text(FEditorFontGlyphs::Exclamation_Triangle)
]
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text_Lambda(GetText)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
]
]
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
SNew(SButton)
.ForegroundColor(FSlateColor::UseForeground())
.ButtonStyle(FAppStyle::Get(), "FlatButton.Success")
.ToolTipText_Lambda(GetButtonTooltipText)
.OnClicked_Lambda(EnablePostProcess)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
.Font(FAppStyle::Get().GetFontStyle("FontAwesome.9"))
.Text_Lambda(GetButtonIcon)
]
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
.Text_Lambda(GetButtonText)
]
]
]
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(2.0f, 0.0f)
[
SNew(SButton)
.ForegroundColor(FSlateColor::UseForeground())
.ButtonStyle(FAppStyle::Get(), "FlatButton")
.ToolTipText(LOCTEXT("EditPostProcessAnimBPButtonToolTip", "Edit the post process Animation Blueprint."))
.OnClicked_Lambda(EditPostProcess)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
.Font(FAppStyle::Get().GetFontStyle("FontAwesome.9"))
.Text(FEditorFontGlyphs::Pencil)
]
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
.Text(LOCTEXT("EditPostProcessAnimBPButtonText", "Edit"))
]
]
],
FPersonaViewportNotificationOptions(TAttribute<EVisibility>::Create(GetVisibility))
);
}
void SAnimationEditorViewportTabBody::AddMinLODNotification()
{
if(WeakMinLODNotification.IsValid())
{
return;
}
auto GetMinLODNotificationVisibility = [this]()
{
if (GetPreviewScene()->GetPreviewMesh() && !GetPreviewScene()->GetPreviewMesh()->IsCompiling() && GetPreviewScene()->GetPreviewMesh()->GetDefaultMinLod() != 0)
{
return EVisibility::Visible;
}
return EVisibility::Collapsed;
};
WeakMinLODNotification = AddNotification(EMessageSeverity::Info,
true,
SNew(SHorizontalBox)
.Visibility_Lambda(GetMinLODNotificationVisibility)
.ToolTipText(LOCTEXT("MinLODNotificationTooltip", "This asset has a minimum LOD applied."))
+SHorizontalBox::Slot()
.FillWidth(1.0f)
.Padding(2.0f, 4.0f)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
.Font(FAppStyle::Get().GetFontStyle("FontAwesome.9"))
.Text(FEditorFontGlyphs::Level_Down)
]
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text(LOCTEXT("MinLODNotification", "Min LOD applied"))
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
]
],
FPersonaViewportNotificationOptions(TAttribute<EVisibility>::Create(GetMinLODNotificationVisibility))
);
}
void SAnimationEditorViewportTabBody::AddSkinWeightProfileNotification()
{
if(WeakSkinWeightPreviewNotification.IsValid())
{
return;
}
auto GetSkinWeightProfileNotificationVisibility = [this]()
{
if (GetPreviewScene()->GetPreviewMeshComponent() && GetPreviewScene()->GetPreviewMeshComponent()->IsUsingSkinWeightProfile())
{
return EVisibility::Visible;
}
return EVisibility::Collapsed;
};
auto GetSkinWeightProfileNotificationText = [this]() -> FText
{
FName ProfileName = NAME_None;
if (GetPreviewScene()->GetPreviewMeshComponent())
{
ProfileName = GetPreviewScene()->GetPreviewMeshComponent()->GetCurrentSkinWeightProfileName();
}
return FText::FormatOrdered(LOCTEXT("ProfileSkinWeightPreviewNotification", "Previewing Skin Weight Profile: {0}"), FText::FromName(ProfileName));
};
WeakSkinWeightPreviewNotification = AddNotification(EMessageSeverity::Info,
false,
SNew(SHorizontalBox)
.Visibility_Lambda(GetSkinWeightProfileNotificationVisibility)
.ToolTipText(LOCTEXT("ProfileSkinWeightPreviewTooltip", "Previewing a Skin Weight Profile."))
+SHorizontalBox::Slot()
.FillWidth(1.0f)
.Padding(2.0f, 4.0f)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.AutoWidth()
.VAlign(VAlign_Center)
.Padding(0.0f, 0.0f, 4.0f, 0.0f)
[
SNew(STextBlock)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
.Font(FAppStyle::Get().GetFontStyle("FontAwesome.9"))
.Text(FEditorFontGlyphs::Eye)
]
+SHorizontalBox::Slot()
.VAlign(VAlign_Center)
.FillWidth(1.0f)
[
SNew(STextBlock)
.Text_Lambda(GetSkinWeightProfileNotificationText)
.TextStyle(FAppStyle::Get(), "AnimViewport.MessageText")
]
],
FPersonaViewportNotificationOptions(TAttribute<EVisibility>::Create(GetSkinWeightProfileNotificationVisibility))
);
}
void SAnimationEditorViewportTabBody::HandleFocusCamera()
{
if (const TSharedPtr<FAnimationViewportClient>& AnimViewportClient = GetAnimationViewportClient())
{
AnimViewportClient->FocusViewportOnPreviewMesh(false);
}
}
#undef LOCTEXT_NAMESPACE