You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden
Change 2777555 on 2015/11/23 by Antony.Carter
Friend List Sub Menu restyling to new designs
#RB Nicholas.Davies
#TESTS Check 3 sub menus of friends list (Online Status, Friends List, Settings) still function correctly with new styling.
Change 2777506 on 2015/11/23 by Andrew.Rodham
Sequencer: Copy/Paste command binding is no longer active if the seuqnece widget is not focused
This addresses UE-23423
#tests Tested copy/paste inside and outside of sequencer
#codereview Max.Chen
#rb Max.Chen
Change 2777505 on 2015/11/23 by Andrew.Rodham
Sequencer: Undoing the addition of a spawnable now ensures its actor instance is deleted correctly
This addresses UE-23450
#tests tested the repro steps on the bug
#codereview Max.Chen
#rb Max.Chen
Change 2777489 on 2015/11/23 by Andrew.Rodham
Sequencer: Workflow optimizations for spawnables
- Editing a property on an instance of a spawnable now automatically propagates to the spawnable defaults, provided the property is not keyed
- Fixed a few cases where spawnables were left lingering around while scrubbing or switching between sub-sequences
- Fixed the root sequence instance being evaluated when there was a sub-sequence focused.
- Selection states are now remembered for spawnable objects when they are destroyed/re-spawned
#codereview Max.Chen
#tests tested loks of object types as spawnables in PIE and in editor
#rb Max.Chen
Change 2777321 on 2015/11/23 by Terence.Burns
Updated the usage of World->UpdateStreamingLevels to FlushStreaming levels on the advice of Dmitriy. Need this to ensure that the streaming is completed before we send it off to lightmass.
#rb Dmitriy.Dyomin
#Tests Run the RebuildLightmaps UAT script.
Change 2777091 on 2015/11/22 by Andrew.Grant
Changed "inappropriate outmost" warning on package load to an error. At the very least we want this for a day or two on Orion to surface errors quickly, but may be a good thing to make a standard error since it indicates something that's likely broken.
#rb none
#tests Golden path in game, cooked content
#codereview Nick.Penwarden, Michael.Noland
Change 2777037 on 2015/11/22 by Laurent.Delayen
Additional debug info to track down https://jira.ol.epicgames.net/browse/OR-9675
#rb martin.wilson
#codereview martin.wilson
#tests Golden path (PIE) + compiled for PS4
Change 2777030 on 2015/11/22 by Sam.Zamani
#online,externalui,ps4
- added footer option for closing the embedded web browser
#rb none
#tests exec command to try on ps4
Change 2777019 on 2015/11/22 by Marcus.Wassmer
Possible fix for OR-9851
#rb none
#test GoldenPath, PS4
#codereview Nick.Darnell,Matt.Kuhlenschmidt
Change 2776932 on 2015/11/22 by Max.Chen
Sequencer: Fix editor selection so that it's not modified in response to the sequencer outliner tree node changing selection if the user is not explicitly selecting in the tree.
#RB none
#tests Select an actor that Sequencer doesn't control and it shouldn't deselect.
Change 2776900 on 2015/11/21 by Marcus.Wassmer
HighQuality particle lights.
#rb Brian.Karis
#test GoldenPath, HQ Particles w/wo ShadowCasting.
#codereview Olaf.Piesche, Simon.Tovey, Tim.Elek
Change 2776868 on 2015/11/21 by Brian.Karis
Reduced temporal aa responsiveness back where it was.
Change 2776867 on 2015/11/21 by Brian.Karis
Removed shading terminator bias meant for shadow map acne but it made character faces look worse.
Change 2776840 on 2015/11/21 by Brian.Karis
Hair indirect lighting implemented.
Improvements to hair shading model. No longer uses backlit parameter.
#rb marcus.wassmer
#tests editor
Change 2776748 on 2015/11/21 by Max.Preussner
Sequencer: Continued to implement track label editor
Note: still disabled, because there are a couple remaining issues
#codereview: max.chen
#rb: max.chen
#test: Editor, Runtime
Change 2776493 on 2015/11/20 by Max.Preussner
Sequencer: Wrapped the node tree context menu actions for editing in an 'Edit' section
#codereview: max.chen
#rb: max.chen
312 lines
9.3 KiB
C++
312 lines
9.3 KiB
C++
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "MovieSceneCapturePCH.h"
|
|
|
|
#include "LevelSequencePlayer.h"
|
|
#include "AutomatedLevelSequenceCapture.h"
|
|
#include "ErrorCodes.h"
|
|
#include "ActiveMovieSceneCaptures.h"
|
|
|
|
UAutomatedLevelSequenceCapture::UAutomatedLevelSequenceCapture(const FObjectInitializer& Init)
|
|
: Super(Init)
|
|
{
|
|
#if WITH_EDITORONLY_DATA == 0
|
|
if (!HasAnyFlags(RF_ClassDefaultObject))
|
|
{
|
|
checkf(false, TEXT("Automated level sequence captures can only be used in editor builds."));
|
|
}
|
|
#else
|
|
bUseCustomStartFrame = false;
|
|
StartFrame = 0;
|
|
bUseCustomEndFrame = false;
|
|
EndFrame = 1;
|
|
WarmUpFrameCount = 0;
|
|
DelayBeforeWarmUp = 0.0f;
|
|
|
|
RemainingDelaySeconds = 0.0f;
|
|
RemainingWarmUpFrames = 0;
|
|
#endif
|
|
}
|
|
|
|
#if WITH_EDITORONLY_DATA
|
|
|
|
void UAutomatedLevelSequenceCapture::SetLevelSequenceAsset(FString AssetPath)
|
|
{
|
|
LevelSequenceAsset = MoveTemp(AssetPath);
|
|
}
|
|
|
|
void UAutomatedLevelSequenceCapture::SetLevelSequenceActor(ALevelSequenceActor* InActor)
|
|
{
|
|
LevelSequenceActor = InActor;
|
|
LevelSequenceActorId = LevelSequenceActor.GetUniqueID().GetGuid();
|
|
}
|
|
|
|
void UAutomatedLevelSequenceCapture::Initialize(TWeakPtr<FSceneViewport> InViewport)
|
|
{
|
|
// Apply command-line overrides from parent class first. This needs to be called before setting up the capture strategy with the desired frame rate.
|
|
Super::Initialize(InViewport);
|
|
|
|
// Apply command-line overrides
|
|
{
|
|
FString LevelSequenceAssetPath;
|
|
if( FParse::Value( FCommandLine::Get(), TEXT( "-LevelSequence=" ), LevelSequenceAssetPath ) )
|
|
{
|
|
LevelSequenceAsset.SetPath( LevelSequenceAssetPath );
|
|
LevelSequenceActorId = FGuid();
|
|
}
|
|
|
|
int32 StartFrameOverride;
|
|
if( FParse::Value( FCommandLine::Get(), TEXT( "-MovieStartFrame=" ), StartFrameOverride ) )
|
|
{
|
|
bUseCustomStartFrame = true;
|
|
StartFrame = StartFrameOverride;
|
|
}
|
|
|
|
int32 EndFrameOverride;
|
|
if( FParse::Value( FCommandLine::Get(), TEXT( "-MovieEndFrame=" ), EndFrameOverride ) )
|
|
{
|
|
bUseCustomEndFrame = true;
|
|
EndFrame = EndFrameOverride;
|
|
}
|
|
|
|
int32 WarmUpFrameCountOverride;
|
|
if( FParse::Value( FCommandLine::Get(), TEXT( "-MovieWarmUpFrames=" ), WarmUpFrameCountOverride ) )
|
|
{
|
|
WarmUpFrameCount = WarmUpFrameCountOverride;
|
|
}
|
|
|
|
float DelayBeforeWarmUpOverride;
|
|
if( FParse::Value( FCommandLine::Get(), TEXT( "-MovieDelayBeforeWarmUp=" ), DelayBeforeWarmUpOverride ) )
|
|
{
|
|
DelayBeforeWarmUp = DelayBeforeWarmUpOverride;
|
|
}
|
|
}
|
|
|
|
// Ensure the LevelSequence is up to date with the LevelSequenceActorId (Level sequence is only there for a nice UI)
|
|
LevelSequenceActor = FUniqueObjectGuid(LevelSequenceActorId);
|
|
|
|
ALevelSequenceActor* Actor = LevelSequenceActor.Get();
|
|
|
|
// If we don't have a valid actor, attempt to find a level sequence actor in the world that references this asset
|
|
if( Actor == nullptr )
|
|
{
|
|
if( LevelSequenceAsset.IsValid() )
|
|
{
|
|
ULevelSequence* Asset = Cast<ULevelSequence>( LevelSequenceAsset.TryLoad() );
|
|
if( Asset != nullptr )
|
|
{
|
|
for( auto It = TActorIterator<ALevelSequenceActor>( InViewport.Pin()->GetClient()->GetWorld() ); It; ++It )
|
|
{
|
|
if( It->LevelSequence == LevelSequenceAsset )
|
|
{
|
|
// Found it!
|
|
Actor = *It;
|
|
this->LevelSequenceActor = Actor;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Actor)
|
|
{
|
|
// Make sure we're not playing yet (in case AutoPlay was called from BeginPlay)
|
|
if( Actor->SequencePlayer != nullptr && Actor->SequencePlayer->IsPlaying() )
|
|
{
|
|
Actor->SequencePlayer->Stop();
|
|
}
|
|
Actor->bAutoPlay = false;
|
|
|
|
// Bind to the event so we know when to capture a frame
|
|
if( Actor->SequencePlayer != nullptr )
|
|
{
|
|
OnPlayerUpdatedBinding = Actor->SequencePlayer->OnSequenceUpdated().AddUObject( this, &UAutomatedLevelSequenceCapture::SequenceUpdated );
|
|
}
|
|
}
|
|
|
|
CaptureState = ELevelSequenceCaptureState::DelayBeforeWarmUp;
|
|
RemainingDelaySeconds = FMath::Max( 0.0f, DelayBeforeWarmUp );
|
|
CaptureStrategy = MakeShareable(new FFixedTimeStepCaptureStrategy(Settings.FrameRate));
|
|
}
|
|
|
|
|
|
void UAutomatedLevelSequenceCapture::SetupFrameRange()
|
|
{
|
|
ALevelSequenceActor* Actor = LevelSequenceActor.Get();
|
|
if( Actor )
|
|
{
|
|
ULevelSequence* LevelSequence = Cast<ULevelSequence>( Actor->LevelSequence.TryLoad() );
|
|
if( LevelSequence != nullptr )
|
|
{
|
|
UMovieScene* MovieScene = LevelSequence->GetMovieScene();
|
|
if( MovieScene != nullptr )
|
|
{
|
|
const int32 SequenceStartFrame = FMath::RoundToInt( MovieScene->GetPlaybackRange().GetLowerBoundValue() * Settings.FrameRate );
|
|
const int32 SequenceEndFrame = FMath::Max( SequenceStartFrame, FMath::RoundToInt( MovieScene->GetPlaybackRange().GetUpperBoundValue() * Settings.FrameRate ) );
|
|
|
|
// Default to playing back the sequence's stored playback range
|
|
int32 PlaybackStartFrame = SequenceStartFrame;
|
|
int32 PlaybackEndFrame = SequenceEndFrame;
|
|
|
|
if( bUseCustomStartFrame )
|
|
{
|
|
PlaybackStartFrame = Settings.bUseRelativeFrameNumbers ? ( SequenceStartFrame + StartFrame ) : StartFrame;
|
|
}
|
|
|
|
if( !Settings.bUseRelativeFrameNumbers )
|
|
{
|
|
// NOTE: The frame number will be an offset from the first frame that we start capturing on, not the frame
|
|
// that we start playback at (in the case of WarmUpFrameCount being non-zero). So we'll cache out frame
|
|
// number offset before adjusting for the warm up frames.
|
|
this->FrameNumberOffset = PlaybackStartFrame;
|
|
}
|
|
|
|
if( bUseCustomEndFrame )
|
|
{
|
|
PlaybackEndFrame = FMath::Max( PlaybackStartFrame, Settings.bUseRelativeFrameNumbers ? ( SequenceEndFrame + EndFrame ) : EndFrame );
|
|
}
|
|
|
|
// We always add 1 to the number of frames we want to capture, because we want to capture both the start and end frames (which if the play range is 0, would still yield a single frame)
|
|
this->FrameCount = ( PlaybackEndFrame - PlaybackStartFrame ) + 1;
|
|
|
|
RemainingWarmUpFrames = FMath::Max( WarmUpFrameCount, 0 );
|
|
if( RemainingWarmUpFrames > 0 )
|
|
{
|
|
// We were asked to playback additional frames before we start capturing
|
|
PlaybackStartFrame -= RemainingWarmUpFrames;
|
|
}
|
|
|
|
// Override the movie scene's playback range
|
|
Actor->SequencePlayer->SetPlaybackRange(
|
|
(float)PlaybackStartFrame / (float)Settings.FrameRate,
|
|
(float)PlaybackEndFrame / (float)Settings.FrameRate );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void UAutomatedLevelSequenceCapture::Tick(float DeltaSeconds)
|
|
{
|
|
const bool bAnyFramesToCapture = OutstandingFrameCount > 0;
|
|
Super::Tick(DeltaSeconds);
|
|
|
|
ALevelSequenceActor* Actor = LevelSequenceActor.Get();
|
|
|
|
if (!Actor)
|
|
{
|
|
ULevelSequence* Asset = Cast<ULevelSequence>(LevelSequenceAsset.TryLoad());
|
|
if (Asset)
|
|
{
|
|
// Spawn a new actor
|
|
Actor = GWorld->SpawnActor<ALevelSequenceActor>();
|
|
Actor->SetSequence(Asset);
|
|
// Ensure it doesn't loop (-1 is indefinite)
|
|
Actor->PlaybackSettings.LoopCount = 0;
|
|
|
|
LevelSequenceActor = Actor;
|
|
}
|
|
else
|
|
{
|
|
FPlatformMisc::RequestExit(FMovieSceneCaptureExitCodes::AssetNotFound);
|
|
}
|
|
}
|
|
|
|
if (Actor && Actor->SequencePlayer)
|
|
{
|
|
// First off we'll stage the sequence. This just means we'll play the first frame of the animation
|
|
// and then pause it immediately
|
|
if( CaptureState == ELevelSequenceCaptureState::Staging )
|
|
{
|
|
Actor->SequencePlayer->Play();
|
|
Actor->SequencePlayer->Pause();
|
|
|
|
CaptureState = ELevelSequenceCaptureState::DelayBeforeWarmUp;
|
|
}
|
|
|
|
// Then we'll just wait a little bit. We'll delay the specified number of seconds before capturing to allow any
|
|
// textures to stream in or post processing effects to settle.
|
|
if( CaptureState == ELevelSequenceCaptureState::DelayBeforeWarmUp )
|
|
{
|
|
RemainingDelaySeconds -= DeltaSeconds;
|
|
if( RemainingDelaySeconds <= 0.0f )
|
|
{
|
|
RemainingDelaySeconds = 0.0f;
|
|
|
|
// Start warming up. Even if we're not capturing yet, this will make sure we're rendering at a
|
|
// fixed frame rate.
|
|
StartWarmup();
|
|
|
|
// Wait a frame to go by after we've set the fixed time step, so that the animation starts
|
|
// playback at a consistent time
|
|
CaptureState = ELevelSequenceCaptureState::ReadyToWarmUp;
|
|
}
|
|
}
|
|
else if( CaptureState == ELevelSequenceCaptureState::ReadyToWarmUp )
|
|
{
|
|
Actor->SequencePlayer->Play();
|
|
CaptureState = ELevelSequenceCaptureState::WarmingUp;
|
|
}
|
|
|
|
|
|
if( CaptureState == ELevelSequenceCaptureState::WarmingUp )
|
|
{
|
|
// Count down our warm up frames
|
|
if( RemainingWarmUpFrames == 0 )
|
|
{
|
|
CaptureState = ELevelSequenceCaptureState::FinishedWarmUp;
|
|
|
|
// It's time to start capturing!
|
|
StartCapture();
|
|
}
|
|
else
|
|
{
|
|
// Not ready to capture just yet
|
|
--RemainingWarmUpFrames;
|
|
}
|
|
}
|
|
|
|
|
|
if( bAnyFramesToCapture && OutstandingFrameCount == 0 )
|
|
{
|
|
// If we hit this, then we've rendered out the last frame and can stop!
|
|
StopCapture();
|
|
}
|
|
}
|
|
}
|
|
|
|
void UAutomatedLevelSequenceCapture::OnCaptureStopped()
|
|
{
|
|
ALevelSequenceActor* Actor = LevelSequenceActor.Get();
|
|
if( Actor != nullptr )
|
|
{
|
|
if( Actor->SequencePlayer != nullptr )
|
|
{
|
|
Actor->SequencePlayer->OnSequenceUpdated().Remove( OnPlayerUpdatedBinding );
|
|
}
|
|
}
|
|
|
|
Close();
|
|
FPlatformMisc::RequestExit(0);
|
|
}
|
|
|
|
void UAutomatedLevelSequenceCapture::SequenceUpdated(const ULevelSequencePlayer& Player, float CurrentTime, float PreviousTime)
|
|
{
|
|
if( bCapturing )
|
|
{
|
|
// Save the previous rendered frame
|
|
CaptureFrame( LastFrameDelta );
|
|
|
|
// Get ready to capture the next rendered frame
|
|
PrepareForScreenshot();
|
|
}
|
|
}
|
|
|
|
void UAutomatedLevelSequenceCapture::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
|
|
{
|
|
LevelSequenceActorId = LevelSequenceActor.GetUniqueID().GetGuid();
|
|
}
|
|
|
|
#endif |