395 lines
13 KiB
C++
395 lines
13 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
EditorModeInterpolation : Editor mode for setting up interpolation sequences.
|
|
|
|
=============================================================================*/
|
|
|
|
#include "EditorModeInterpolation.h"
|
|
#include "EditorViewportClient.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "Editor/GroupActor.h"
|
|
#include "EditorModeManager.h"
|
|
#include "EditorModes.h"
|
|
#include "InterpolationHitProxy.h"
|
|
|
|
#include "Editor/Matinee/Public/MatineeModule.h"
|
|
#include "Editor/Matinee/Public/IMatinee.h"
|
|
#include "Framework/Notifications/NotificationManager.h"
|
|
#include "Widgets/Notifications/SNotificationList.h"
|
|
#include "ActorGroupingUtils.h"
|
|
|
|
static const float CurveHandleScale = 0.5f;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FEdModeInterpEdit
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
FEdModeInterpEdit::FEdModeInterpEdit()
|
|
{
|
|
MatineeActor = NULL;
|
|
InterpEd = NULL;
|
|
|
|
Tools.Add(new FModeTool_InterpEdit());
|
|
SetCurrentTool(MT_InterpEdit);
|
|
|
|
bLeavingMode = false;
|
|
}
|
|
|
|
FEdModeInterpEdit::~FEdModeInterpEdit()
|
|
{
|
|
}
|
|
|
|
bool FEdModeInterpEdit::InputKey(FEditorViewportClient* ViewportClient, FViewport* Viewport, FKey Key, EInputEvent Event)
|
|
{
|
|
// Enter key drops new key frames
|
|
if (Key == EKeys::Enter &&
|
|
(Event == IE_Pressed || Event == IE_Repeat) &&
|
|
(!ViewportClient->IsShiftPressed() &&
|
|
!ViewportClient->IsAltPressed() &&
|
|
!ViewportClient->IsCtrlPressed()))
|
|
{
|
|
if (InterpEd != NULL)
|
|
{
|
|
// Add a new key!
|
|
InterpEd->AddKey();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return FEdMode::InputKey(ViewportClient, Viewport, Key, Event);
|
|
}
|
|
|
|
void FEdModeInterpEdit::Enter()
|
|
{
|
|
FEdMode::Enter();
|
|
|
|
// Disable Grouping while in InterpEdit mode
|
|
bGroupingActiveSaved = UActorGroupingUtils::IsGroupingActive();
|
|
UActorGroupingUtils::SetGroupingActive(false);
|
|
}
|
|
|
|
void FEdModeInterpEdit::Exit()
|
|
{
|
|
MatineeActor = NULL;
|
|
|
|
// If there is one, close the Interp Editor and clear pointers.
|
|
if (InterpEd != NULL)
|
|
{
|
|
bLeavingMode = true; // This is so the editor being closed doesn't try and change the mode again!
|
|
|
|
InterpEd->Close(true);
|
|
|
|
bLeavingMode = false;
|
|
}
|
|
|
|
InterpEd = NULL;
|
|
|
|
// Grouping is always disabled while in InterpEdit Mode, re-enable the saved value on exit
|
|
UActorGroupingUtils::SetGroupingActive(bGroupingActiveSaved);
|
|
AGroupActor::SelectGroupsInSelection();
|
|
|
|
FEdMode::Exit();
|
|
}
|
|
|
|
// We see if we have
|
|
void FEdModeInterpEdit::ActorMoveNotify()
|
|
{
|
|
if (!InterpEd)
|
|
return;
|
|
|
|
InterpEd->ActorModified();
|
|
}
|
|
|
|
void FEdModeInterpEdit::CamMoveNotify(FEditorViewportClient* ViewportClient)
|
|
{
|
|
if (!InterpEd)
|
|
return;
|
|
|
|
if (ViewportClient->AllowsCinematicControl())
|
|
{
|
|
InterpEd->CamMoved(ViewportClient->GetViewLocation(), ViewportClient->GetViewRotation());
|
|
}
|
|
}
|
|
|
|
void FEdModeInterpEdit::ActorPropChangeNotify()
|
|
{
|
|
if (!InterpEd)
|
|
return;
|
|
|
|
InterpEd->ActorModified();
|
|
}
|
|
|
|
void FEdModeInterpEdit::UpdateSelectedActor()
|
|
{
|
|
// would this be enough?
|
|
InterpEd->ActorSelectionChange();
|
|
}
|
|
|
|
// Set the currently edited MatineeActor and open timeline window. Should always be called after we change to FBuiltinEditorModes::EM_InterpEdit.
|
|
void FEdModeInterpEdit::InitInterpMode(AMatineeActor* InMatineeActor)
|
|
{
|
|
check(InMatineeActor);
|
|
check(!InterpEd);
|
|
|
|
MatineeActor = InMatineeActor;
|
|
|
|
EToolkitMode::Type Mode = EToolkitMode::Standalone;
|
|
IMatineeModule* MatineeModule = &FModuleManager::LoadModuleChecked<IMatineeModule>("Matinee");
|
|
|
|
InterpEd = &(MatineeModule->CreateMatinee(Mode, TSharedPtr<IToolkitHost>(), InMatineeActor).Get());
|
|
}
|
|
|
|
void FEdModeInterpEdit::Render(const FSceneView* View, FViewport* Viewport, FPrimitiveDrawInterface* PDI)
|
|
{
|
|
FEdMode::Render(View, Viewport, PDI);
|
|
|
|
check(GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_InterpEdit));
|
|
|
|
if (InterpEd && !InterpEd->Hide3DTrackView() && View->Family->EngineShowFlags.Splines)
|
|
{
|
|
InterpEd->DrawTracks3D(View, PDI);
|
|
}
|
|
}
|
|
|
|
void FEdModeInterpEdit::DrawHUD(FEditorViewportClient* ViewportClient, FViewport* Viewport, const FSceneView* View, FCanvas* Canvas)
|
|
{
|
|
FEdMode::DrawHUD(ViewportClient, Viewport, View, Canvas);
|
|
|
|
if (InterpEd)
|
|
{
|
|
InterpEd->DrawModeHUD(ViewportClient, Viewport, View, Canvas);
|
|
}
|
|
}
|
|
|
|
bool FEdModeInterpEdit::AllowWidgetMove()
|
|
{
|
|
FModeTool_InterpEdit* InterpTool = (FModeTool_InterpEdit*)FindTool(MT_InterpEdit);
|
|
|
|
if (InterpTool->bMovingHandle)
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
void FEdModeInterpEdit::ActorSelectionChangeNotify()
|
|
{
|
|
FEdMode::ActorSelectionChangeNotify();
|
|
|
|
if (InterpEd)
|
|
{
|
|
InterpEd->ActorSelectionChange();
|
|
}
|
|
}
|
|
|
|
bool FEdModeInterpEdit::IsCompatibleWith(FEditorModeID OtherModeID) const
|
|
{
|
|
return OtherModeID == FBuiltinEditorModes::EM_Placement ||
|
|
OtherModeID == FBuiltinEditorModes::EM_MeshPaint;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// FModeTool_InterpEdit
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
FModeTool_InterpEdit::FModeTool_InterpEdit()
|
|
{
|
|
ID = MT_InterpEdit;
|
|
|
|
bMovingHandle = false;
|
|
DragGroup = NULL;
|
|
DragTrackIndex = false;
|
|
DragKeyIndex = false;
|
|
bDragArriving = false;
|
|
}
|
|
|
|
FModeTool_InterpEdit::~FModeTool_InterpEdit()
|
|
{
|
|
}
|
|
|
|
bool FModeTool_InterpEdit::MouseMove(FEditorViewportClient* ViewportClient, FViewport* Viewport, int32 x, int32 y)
|
|
{
|
|
check(GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_InterpEdit));
|
|
|
|
FEdModeInterpEdit* mode = (FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_InterpEdit);
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool FModeTool_InterpEdit::InputAxis(FEditorViewportClient* InViewportClient, FViewport* Viewport, int32 ControllerId, FKey Key, float Delta, float DeltaTime)
|
|
{
|
|
if (InViewportClient->GetCurrentWidgetAxis() == EAxisList::None && !InViewportClient->Viewport->KeyState(EKeys::MiddleMouseButton))
|
|
{
|
|
// We need to set up a widget axis here to prevent our drag operation being co-opted by box/frustum selection
|
|
ELevelViewportType ViewportType = InViewportClient->ViewportType;
|
|
switch (ViewportType)
|
|
{
|
|
case LVT_OrthoXY:
|
|
case LVT_OrthoNegativeXY:
|
|
InViewportClient->SetCurrentWidgetAxis(EAxisList::XY);
|
|
break;
|
|
case LVT_OrthoXZ:
|
|
case LVT_OrthoNegativeXZ:
|
|
InViewportClient->SetCurrentWidgetAxis(EAxisList::XZ);
|
|
break;
|
|
case LVT_OrthoYZ:
|
|
case LVT_OrthoNegativeYZ:
|
|
InViewportClient->SetCurrentWidgetAxis(EAxisList::YZ);
|
|
break;
|
|
case LVT_OrthoFreelook:
|
|
case LVT_Perspective:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FModeTool_InterpEdit::InputKey(FEditorViewportClient* ViewportClient, FViewport* Viewport, FKey Key, EInputEvent Event)
|
|
{
|
|
check(GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_InterpEdit));
|
|
|
|
FEdModeInterpEdit* mode = (FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_InterpEdit);
|
|
if (!mode->InterpEd)
|
|
{
|
|
// Abort cleanly on InerpEd not yet being assigned. This can occasionally be the case when receiving
|
|
// modifier key release events when changing into interp edit mode.
|
|
return false;
|
|
}
|
|
|
|
bool bCtrlDown = Viewport->KeyState(EKeys::LeftControl) || Viewport->KeyState(EKeys::RightControl);
|
|
bool bAltDown = Viewport->KeyState(EKeys::LeftAlt) || Viewport->KeyState(EKeys::RightAlt);
|
|
bool bShiftDown = Viewport->KeyState(EKeys::LeftShift) || Viewport->KeyState(EKeys::RightShift);
|
|
|
|
if (Key == EKeys::LeftMouseButton)
|
|
{
|
|
|
|
if (Event == IE_Pressed)
|
|
{
|
|
int32 HitX = ViewportClient->Viewport->GetMouseX();
|
|
int32 HitY = ViewportClient->Viewport->GetMouseY();
|
|
HHitProxy* HitResult = ViewportClient->Viewport->GetHitProxy(HitX, HitY);
|
|
|
|
if (HitResult)
|
|
{
|
|
if (HitResult->IsA(HInterpTrackKeypointProxy::StaticGetType()))
|
|
{
|
|
HInterpTrackKeypointProxy* KeyProxy = (HInterpTrackKeypointProxy*)HitResult;
|
|
UInterpGroup* Group = KeyProxy->Group;
|
|
UInterpTrack* Track = KeyProxy->Track;
|
|
int32 KeyIndex = KeyProxy->KeyIndex;
|
|
|
|
// Using the CTRL modifier invokes multi-select keyframe selection.
|
|
if (bCtrlDown)
|
|
{
|
|
// If key is already selected, deselect the key.
|
|
if (mode->InterpEd->KeyIsInSelection(Group, Track, KeyIndex))
|
|
{
|
|
mode->InterpEd->RemoveKeyFromSelection(Group, Track, KeyIndex);
|
|
mode->InterpEd->InvalidateTrackWindowViewports();
|
|
}
|
|
// Otherwise, select the key while preserving previous selection.
|
|
else
|
|
{
|
|
// This will invalidate the display - so we must not access the KeyProxy after this!
|
|
mode->InterpEd->SelectTrack(Group, Track, false);
|
|
mode->InterpEd->AddKeyToSelection(Group, Track, KeyIndex, !bShiftDown);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mode->InterpEd->SelectTrack(Group, Track);
|
|
// NOTE: Clear previously-selected tracks because ctrl is not down.
|
|
mode->InterpEd->ClearKeySelection();
|
|
mode->InterpEd->AddKeyToSelection(Group, Track, KeyIndex, !bShiftDown);
|
|
}
|
|
}
|
|
else if (HitResult->IsA(HInterpTrackKeyHandleProxy::StaticGetType()))
|
|
{
|
|
// If we clicked on a 3D track handle, remember which key.
|
|
HInterpTrackKeyHandleProxy* KeyProxy = (HInterpTrackKeyHandleProxy*)HitResult;
|
|
DragGroup = KeyProxy->Group;
|
|
DragTrackIndex = KeyProxy->TrackIndex;
|
|
DragKeyIndex = KeyProxy->KeyIndex;
|
|
bDragArriving = KeyProxy->bArriving;
|
|
|
|
bMovingHandle = true;
|
|
|
|
mode->InterpEd->BeginDrag3DHandle(DragGroup, DragTrackIndex);
|
|
}
|
|
}
|
|
}
|
|
else if (Event == IE_Released)
|
|
{
|
|
if (bMovingHandle)
|
|
{
|
|
mode->InterpEd->EndDrag3DHandle();
|
|
bMovingHandle = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle keys
|
|
if (Event == IE_Pressed)
|
|
{
|
|
// Swallow 'Delete' key to avoid deleting stuff when trying to interpolate it!
|
|
if (Key == EKeys::Platform_Delete)
|
|
{
|
|
// Can't delete actors if Matinee is open.
|
|
const FText ErrorMsg = NSLOCTEXT("UnrealEd", "Error_WrongModeForActorDeletion", "Cannot delete actor while Matinee is open");
|
|
FNotificationInfo Info(ErrorMsg);
|
|
FSlateNotificationManager::Get().AddNotification(Info);
|
|
return true;
|
|
}
|
|
else if (mode->InterpEd->ProcessKeyPress(Key, bCtrlDown, bAltDown))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return FModeTool::InputKey(ViewportClient, Viewport, Key, Event);
|
|
}
|
|
|
|
bool FModeTool_InterpEdit::InputDelta(FEditorViewportClient* InViewportClient, FViewport* InViewport, FVector& InDrag, FRotator& InRot, FVector& InScale)
|
|
{
|
|
check(GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_InterpEdit));
|
|
|
|
FEdModeInterpEdit* mode = (FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_InterpEdit);
|
|
check(mode->InterpEd);
|
|
|
|
bool bShiftDown = InViewport->KeyState(EKeys::LeftShift) || InViewport->KeyState(EKeys::RightShift);
|
|
|
|
FVector InputDeltaDrag(InDrag);
|
|
|
|
// If we are grabbing a 'handle' on the movement curve, pass that info to Matinee
|
|
if (bMovingHandle)
|
|
{
|
|
mode->InterpEd->Move3DHandle(DragGroup, DragTrackIndex, DragKeyIndex, bDragArriving, InputDeltaDrag * (1.f / CurveHandleScale));
|
|
|
|
return 1;
|
|
}
|
|
// If shift is downOnly do 'move initial position' if dragging the widget
|
|
else if (bShiftDown && InViewportClient->GetCurrentWidgetAxis() != EAxisList::None)
|
|
{
|
|
mode->InterpEd->MoveInitialPosition(InputDeltaDrag, InRot);
|
|
|
|
return 1;
|
|
}
|
|
|
|
InViewportClient->Viewport->Invalidate();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void FModeTool_InterpEdit::SelectNone()
|
|
{
|
|
check(GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_InterpEdit));
|
|
|
|
FEdModeInterpEdit* mode = (FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_InterpEdit);
|
|
}
|