Files
UnrealEngineUWP/Engine/Source/Developer/LogVisualizer/Private/LogVisualizer.cpp
Max Chen 39a92c1fa2 Copying //UE4/Dev-Sequencer to //UE4/Main
==========================
MAJOR FEATURES + CHANGES
==========================

Change 2859626 on 2016/02/08 by Max.Preussner

	Editor: Added SaveAs functionality to content asset editors

Change 2859666 on 2016/02/08 by Max.Chen

	Sequencer: Fix crash in CheckForWorldGCLeaks when loading a new map because spawnables are left behind.

	#jira  UE-25616

Change 2859685 on 2016/02/08 by Max.Chen

	Sequencer: Add prompt to save sub level sequences if they are dirty

	#jira UE-26510

Change 2859715 on 2016/02/08 by Thomas.Sarkanen

	Adding actor spawning recording

	Actors are queued for record on spawn then added to the list like manually-specifed ones.
	Changed almost everything about UActorRecording. We now record on a per-component basis, with property tracks encapsulated in each actor recording. Much effort is expended to make sure that the correct components are owned by their respective actors, as we can add and remove components at runtime, but they must be created up-front in the UMovieScene Blueprints. We go as far as to add our own SCS nodes to make sure components are correctly spawned.
	Fixed infinite loop in FSequencer::AddSpawnable.
	Fixed visibility track instance to work with scene components as well as actors.
	Fixed particle track instance to work on UParticleSystemComponent rather than just AEmitters.
	Added particle recorder.
	Moved animation recording into an animation property recorder rather than having it as a special case. This still uses the animation recorder under the hood.
	Moved old-style Matinee animation control into FMovieSceneSkeletalAnimationTrackInstance & made this work on USkeletalMeshComponents directly, rather than via the old interface.
	Exposed SetMatineeAnimPositionInner and PreviewMatineeSetAnimPositionInner in FAnimMontageInstance so those utility functions can be used externally to Engine.
	Added a predicate version of UMovieScene::FindPossessable.
	Exposed UMovieSceneParticleSection::AddKey externally via MOVIESCENETRACKS_API so I can programmatically add keys.
	Fixed a crash in FScalableFloatDetails::CustomizeHeader when selecting PIE projectiles in Orion.
	Moved all recorders over to recording Actors or Components & store UObjects instead of AActors.
	Allowed skeletal animation tracks on components as well as actors.

Change 2862675 on 2016/02/10 by Max.Chen

	Sequencer: Add option to link the sequencer curve editor with the sequencer timeline.

	Under General Options->Link Curve Editor Time Range. The default is false, so the sequencer and curve editor have separate time ranges.

	#jira UE-25933

Change 2862699 on 2016/02/11 by Max.Chen

	Sequencer: Added a playback status of jumping which the AudioTrack and Skeletal Mesh Track (anim notifies) ignores for updates. This is used to updating thumbnail at certain times.

	#jira UE-26447, UE-26671

Change 2862712 on 2016/02/11 by Max.Chen

	Sequencer: Fix spawnables firing off their particles. Disable auto activate on spawnable components

	#jira UE-26390

Change 2862719 on 2016/02/11 by Max.Preussner

	Editor: Refactored detail customizations for colors, rotators, vectors

	- broke color and rotator customizations out into their own files
	- added vector customizations (placeholder)
	- cleaned up localization namespaces, forward declarations

Change 2866454 on 2016/02/14 by Max.Preussner

	Sequencer: Removed ULevelEditorSequencerSettings; moved default settings into INI

Change 2866455 on 2016/02/14 by Thomas.Sarkanen

	Sequence recorder can now record replays

	Added extra edtior-only UI to the replay playback controls to record sequences. Curretnly very placeholder: only records the entire sequence and provides no feedback in the UI if it is recording.
	Fixed bindings to recorded objects not working in various circumstances. Added the ability to manually create a binding.
	Recompiled actor blueprints post-record if we added components.
	Fixed a null ptr dereference in FOrionTeamUIInfo::Update.
	Removed tolerances when reducing tracks - they are now 'very small'.
	Added actor filter so actors of certain classes can be recorded.

Change 2866458 on 2016/02/14 by Max.Chen

	Sequencer: Fix anim notifies that fire at shot cuts. Anim notifies are fired from the last position to the current position. When jumping cuts, we want the delta to be 0 so that the anim notifies before the shot are not fired off.

	#jira UE-26390, UE-26671

Change 2866459 on 2016/02/14 by Max.Chen

	Sequencer: Add option to toggle visibility of combined keys

Change 2866466 on 2016/02/14 by Frank.Fella

	Sequencer - Add a track for controlling streamed level visibilty and remove visibility code from the master level blueprint.

Change 2866470 on 2016/02/14 by Max.Chen

	Sequencer: Add return value to indicate data has changed when a section has been added. This fixes a bug where creating a new section doesn't seem to add a key.

	#jira UE-26837

Change 2866481 on 2016/02/14 by Max.Preussner

	Sequencer: Implemented Presets for adding tracks automatically based on actor type (UE-24513)

	#Jira: UE-24513

Change 2866482 on 2016/02/14 by Max.Chen

	Sequencer: Allow for any actor that has a camera component to be a camera cut.

	#jira UE-26777

Change 2866484 on 2016/02/14 by Thomas.Sarkanen

	Added in/out times to sequence recording

	Also added the optional ability to record different actor types (heroes, projectiles, minions).

Change 2866495 on 2016/02/14 by Max.Chen

	Sequencer: Need to limit camera control to the section bounds of the camera cut otherwise, control won't be relinquished back to player at the end of the playback.

	#jira UE-26886

[CL 2874647 by Max Chen in Main branch]
2016-02-19 21:36:27 -05:00

335 lines
8.8 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#include "LogVisualizer.h"
#include "VisualLoggerRenderingActor.h"
#include "VisualLoggerCameraController.h"
#if WITH_EDITOR
# include "Editor/UnrealEd/Public/EditorComponents.h"
# include "Editor/UnrealEd/Public/EditorReimportHandler.h"
# include "Editor/UnrealEd/Public/TexAlignTools.h"
# include "Editor/UnrealEd/Public/TickableEditorObject.h"
# include "Editor/UnrealEd/Public/Editor.h"
# include "Editor/UnrealEd/Public/EditorViewportClient.h"
#endif
TSharedPtr< struct FLogVisualizer > FLogVisualizer::StaticInstance;
FColor FLogVisualizerColorPalette[] = {
FColor(0xff00A480),
FColorList::Aquamarine,
FColorList::Cyan,
FColorList::Brown,
FColorList::Green,
FColorList::Orange,
FColorList::Magenta,
FColorList::BrightGold,
FColorList::NeonBlue,
FColorList::MediumSlateBlue,
FColorList::SpicyPink,
FColorList::SpringGreen,
FColorList::SteelBlue,
FColorList::SummerSky,
FColorList::Violet,
FColorList::VioletRed,
FColorList::YellowGreen,
FColor(0xff62E200),
FColor(0xff1F7B67),
FColor(0xff62AA2A),
FColor(0xff70227E),
FColor(0xff006B53),
FColor(0xff409300),
FColor(0xff5D016D),
FColor(0xff34D2AF),
FColor(0xff8BF13C),
FColor(0xffBC38D3),
FColor(0xff5ED2B8),
FColor(0xffA6F16C),
FColor(0xffC262D3),
FColor(0xff0F4FA8),
FColor(0xff00AE68),
FColor(0xffDC0055),
FColor(0xff284C7E),
FColor(0xff21825B),
FColor(0xffA52959),
FColor(0xff05316D),
FColor(0xff007143),
FColor(0xff8F0037),
FColor(0xff4380D3),
FColor(0xff36D695),
FColor(0xffEE3B80),
FColor(0xff6996D3),
FColor(0xff60D6A7),
FColor(0xffEE6B9E)
};
void FLogVisualizer::Initialize()
{
StaticInstance = MakeShareable(new FLogVisualizer);
Get().TimeSliderController = MakeShareable(new FVisualLoggerTimeSliderController(FVisualLoggerTimeSliderArgs()));
}
void FLogVisualizer::Shutdown()
{
StaticInstance.Reset();
}
void FLogVisualizer::Reset()
{
TimeSliderController->SetTimesliderArgs(FVisualLoggerTimeSliderArgs());
}
FLogVisualizer& FLogVisualizer::Get()
{
return *StaticInstance;
}
FLinearColor FLogVisualizer::GetColorForCategory(int32 Index) const
{
if (Index >= 0 && Index < sizeof(FLogVisualizerColorPalette) / sizeof(FLogVisualizerColorPalette[0]))
{
return FLogVisualizerColorPalette[Index];
}
static bool bReateColorList = false;
static FColorList StaticColor;
if (!bReateColorList)
{
bReateColorList = true;
StaticColor.CreateColorMap();
}
return StaticColor.GetFColorByIndex(Index);
}
FLinearColor FLogVisualizer::GetColorForCategory(const FString& InFilterName) const
{
static TArray<FString> Filters;
int32 CategoryIndex = Filters.Find(InFilterName);
if (CategoryIndex == INDEX_NONE)
{
CategoryIndex = Filters.Add(InFilterName);
}
return GetColorForCategory(CategoryIndex);
}
UWorld* FLogVisualizer::GetWorld(UObject* OptionalObject)
{
UWorld* World = OptionalObject != nullptr ? GEngine->GetWorldFromContextObject(OptionalObject, false) : nullptr;
#if WITH_EDITOR
if (!World && GIsEditor)
{
UEditorEngine *EEngine = Cast<UEditorEngine>(GEngine);
// lets use PlayWorld during PIE/Simulate and regular world from editor otherwise, to draw debug information
World = EEngine != nullptr && EEngine->PlayWorld != nullptr ? EEngine->PlayWorld : EEngine->GetEditorWorldContext().World();
}
else
#endif
if (!World && !GIsEditor)
{
World = GEngine->GetWorld();
}
if (World == nullptr)
{
World = GWorld;
}
return World;
}
void FLogVisualizer::UpdateCameraPosition(FName RowName, int32 ItemIndes)
{
const FVisualLoggerDBRow& DBRow = FVisualLoggerDatabase::Get().GetRowByName(RowName);
auto &Entries = DBRow.GetItems();
if (DBRow.GetCurrentItemIndex() == INDEX_NONE || Entries.IsValidIndex(DBRow.GetCurrentItemIndex()) == false)
{
return;
}
UWorld* World = GetWorld();
FVector CurrentLocation = Entries[DBRow.GetCurrentItemIndex()].Entry.Location;
FVector Extent(150);
bool bFoundActor = false;
FName OwnerName = Entries[DBRow.GetCurrentItemIndex()].OwnerName;
for (FActorIterator It(World); It; ++It)
{
AActor* Actor = *It;
if (Actor->GetFName() == OwnerName)
{
FVector Orgin;
Actor->GetActorBounds(false, Orgin, Extent);
bFoundActor = true;
break;
}
}
const float DefaultCameraDistance = ULogVisualizerSettings::StaticClass()->GetDefaultObject<ULogVisualizerSettings>()->DefaultCameraDistance;
Extent = Extent.SizeSquared() < FMath::Square(DefaultCameraDistance) ? FVector(DefaultCameraDistance) : Extent;
#if WITH_EDITOR
UEditorEngine *EEngine = Cast<UEditorEngine>(GEngine);
if (GIsEditor && EEngine != NULL)
{
for (auto ViewportClient : EEngine->AllViewportClients)
{
ViewportClient->FocusViewportOnBox(FBox::BuildAABB(CurrentLocation, Extent));
}
}
else if (AVisualLoggerCameraController::IsEnabled(World) && AVisualLoggerCameraController::Instance.IsValid() && AVisualLoggerCameraController::Instance->GetSpectatorPawn())
{
ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(AVisualLoggerCameraController::Instance->Player);
if (LocalPlayer && LocalPlayer->ViewportClient && LocalPlayer->ViewportClient->Viewport)
{
FViewport* Viewport = LocalPlayer->ViewportClient->Viewport;
FBox BoundingBox = FBox::BuildAABB(CurrentLocation, Extent);
const FVector Position = BoundingBox.GetCenter();
float Radius = BoundingBox.GetExtent().Size();
FViewportCameraTransform ViewTransform;
ViewTransform.TransitionToLocation(Position, nullptr, true);
float NewOrthoZoom;
const float AspectRatio = 1.777777f;
uint32 MinAxisSize = (AspectRatio > 1.0f) ? Viewport->GetSizeXY().Y : Viewport->GetSizeXY().X;
float Zoom = Radius / (MinAxisSize / 2.0f);
NewOrthoZoom = Zoom * (Viewport->GetSizeXY().X*15.0f);
NewOrthoZoom = FMath::Clamp<float>(NewOrthoZoom, 250, MAX_FLT);
ViewTransform.SetOrthoZoom(NewOrthoZoom);
AVisualLoggerCameraController::Instance->GetSpectatorPawn()->TeleportTo(ViewTransform.GetLocation(), ViewTransform.GetRotation(), false, true);
}
}
#endif
}
int32 FLogVisualizer::GetNextItem(FName RowName, int32 MoveDistance)
{
FVisualLoggerDBRow& DBRow = FVisualLoggerDatabase::Get().GetRowByName(RowName);
int32 NewItemIndex = DBRow.GetCurrentItemIndex();
int32 Index = 0;
auto &Entries = DBRow.GetItems();
while (true)
{
NewItemIndex++;
if (Entries.IsValidIndex(NewItemIndex))
{
if (DBRow.IsItemVisible(NewItemIndex) == true && ++Index == MoveDistance)
{
break;
}
}
else
{
NewItemIndex = FMath::Clamp(NewItemIndex, 0, Entries.Num() - 1);
break;
}
}
return NewItemIndex;
}
int32 FLogVisualizer::GetPreviousItem(FName RowName, int32 MoveDistance)
{
FVisualLoggerDBRow& DBRow = FVisualLoggerDatabase::Get().GetRowByName(RowName);
int32 NewItemIndex = DBRow.GetCurrentItemIndex();
int32 Index = 0;
auto &Entries = DBRow.GetItems();
while (true)
{
NewItemIndex--;
if (Entries.IsValidIndex(NewItemIndex))
{
if (DBRow.IsItemVisible(NewItemIndex) == true && ++Index == MoveDistance)
{
break;
}
}
else
{
NewItemIndex = FMath::Clamp(NewItemIndex, 0, Entries.Num() - 1);
break;
}
}
return NewItemIndex;
}
void FLogVisualizer::GotoNextItem(FName RowName, int32 MoveDistance)
{
FVisualLoggerDBRow& DBRow = FVisualLoggerDatabase::Get().GetRowByName(RowName);
const int32 NewItemIndex = GetNextItem(RowName, MoveDistance);
if (NewItemIndex != DBRow.GetCurrentItemIndex())
{
auto &Entries = DBRow.GetItems();
float NewTimeStamp = Entries[NewItemIndex].Entry.TimeStamp;
}
}
void FLogVisualizer::GotoPreviousItem(FName RowName, int32 MoveDistance)
{
FVisualLoggerDBRow& DBRow = FVisualLoggerDatabase::Get().GetRowByName(RowName);
const int32 NewItemIndex = GetPreviousItem(RowName, MoveDistance);
if (NewItemIndex != DBRow.GetCurrentItemIndex())
{
auto &Entries = DBRow.GetItems();
float NewTimeStamp = Entries[NewItemIndex].Entry.TimeStamp;
}
}
void FLogVisualizer::GotoFirstItem(FName RowName)
{
FVisualLoggerDBRow& DBRow = FVisualLoggerDatabase::Get().GetRowByName(RowName);
int32 NewItemIndex = DBRow.GetCurrentItemIndex();
auto &Entries = DBRow.GetItems();
for (int32 Index = 0; Index <= DBRow.GetCurrentItemIndex(); Index++)
{
if (DBRow.IsItemVisible(Index))
{
NewItemIndex = Index;
break;
}
}
if (NewItemIndex != DBRow.GetCurrentItemIndex())
{
//DBRow.MoveTo(NewItemIndex);
TimeSliderController->CommitScrubPosition(Entries[NewItemIndex].Entry.TimeStamp, false);
}
}
void FLogVisualizer::GotoLastItem(FName RowName)
{
FVisualLoggerDBRow& DBRow = FVisualLoggerDatabase::Get().GetRowByName(RowName);
int32 NewItemIndex = DBRow.GetCurrentItemIndex();
auto &Entries = DBRow.GetItems();
for (int32 Index = Entries.Num() - 1; Index >= DBRow.GetCurrentItemIndex(); Index--)
{
if (DBRow.IsItemVisible(Index))
{
NewItemIndex = Index;
break;
}
}
if (NewItemIndex != DBRow.GetCurrentItemIndex())
{
//DBRow.MoveTo(NewItemIndex);
TimeSliderController->CommitScrubPosition(Entries[NewItemIndex].Entry.TimeStamp, false);
}
}