|
2 | 2 |
|
3 | 3 | #include "Runtime/MovieSceneCapture/Public/MovieSceneCapture.h" |
4 | 4 |
|
| 5 | +#if WITH_EDITOR |
| 6 | + |
| 7 | +/* |
| 8 | +
|
| 9 | +This is taken as-is (more or less) from MovieSceneCaptureDialogModule.cpp |
| 10 | +to automate sequencer capturing |
| 11 | +
|
| 12 | +*/ |
| 13 | + |
| 14 | +#include "AudioDevice.h" |
| 15 | +#include "Editor/EditorEngine.h" |
| 16 | +#include "Slate/SceneViewport.h" |
| 17 | +#include "AutomatedLevelSequenceCapture.h" |
| 18 | + |
| 19 | +struct FInEditorCapture : TSharedFromThis<FInEditorCapture> |
| 20 | +{ |
| 21 | + |
| 22 | + static TWeakPtr<FInEditorCapture> CreateInEditorCapture(UMovieSceneCapture* InCaptureObject) |
| 23 | + { |
| 24 | + // FInEditorCapture owns itself, so should only be kept alive by itself, or a pinned (=> temporary) weakptr |
| 25 | + FInEditorCapture* Capture = new FInEditorCapture; |
| 26 | + Capture->Start(InCaptureObject); |
| 27 | + return Capture->AsShared(); |
| 28 | + } |
| 29 | + |
| 30 | + UWorld* GetWorld() const |
| 31 | + { |
| 32 | + return CapturingFromWorld; |
| 33 | + } |
| 34 | + |
| 35 | +private: |
| 36 | + FInEditorCapture() |
| 37 | + { |
| 38 | + CapturingFromWorld = nullptr; |
| 39 | + CaptureObject = nullptr; |
| 40 | + } |
| 41 | + |
| 42 | + void Start(UMovieSceneCapture* InCaptureObject) |
| 43 | + { |
| 44 | + check(InCaptureObject); |
| 45 | + |
| 46 | + CapturingFromWorld = nullptr; |
| 47 | + OnlyStrongReference = MakeShareable(this); |
| 48 | + |
| 49 | + CaptureObject = InCaptureObject; |
| 50 | + |
| 51 | + ULevelEditorPlaySettings* PlayInEditorSettings = GetMutableDefault<ULevelEditorPlaySettings>(); |
| 52 | + |
| 53 | + bScreenMessagesWereEnabled = GAreScreenMessagesEnabled; |
| 54 | + GAreScreenMessagesEnabled = false; |
| 55 | + |
| 56 | + if (!InCaptureObject->Settings.bEnableTextureStreaming) |
| 57 | + { |
| 58 | + const int32 UndefinedTexturePoolSize = -1; |
| 59 | + IConsoleVariable* CVarStreamingPoolSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streaming.PoolSize")); |
| 60 | + if (CVarStreamingPoolSize) |
| 61 | + { |
| 62 | + BackedUpStreamingPoolSize = CVarStreamingPoolSize->GetInt(); |
| 63 | + CVarStreamingPoolSize->Set(UndefinedTexturePoolSize, ECVF_SetByConsole); |
| 64 | + } |
| 65 | + |
| 66 | + IConsoleVariable* CVarUseFixedPoolSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streaming.UseFixedPoolSize")); |
| 67 | + if (CVarUseFixedPoolSize) |
| 68 | + { |
| 69 | + BackedUpUseFixedPoolSize = CVarUseFixedPoolSize->GetInt(); |
| 70 | + CVarUseFixedPoolSize->Set(0, ECVF_SetByConsole); |
| 71 | + } |
| 72 | + } |
| 73 | + |
| 74 | + FObjectWriter(PlayInEditorSettings, BackedUpPlaySettings); |
| 75 | + OverridePlaySettings(PlayInEditorSettings); |
| 76 | + |
| 77 | + CaptureObject->AddToRoot(); |
| 78 | + CaptureObject->OnCaptureFinished().AddRaw(this, &FInEditorCapture::OnEnd); |
| 79 | + |
| 80 | + UGameViewportClient::OnViewportCreated().AddRaw(this, &FInEditorCapture::OnStart); |
| 81 | + FEditorDelegates::EndPIE.AddRaw(this, &FInEditorCapture::OnEndPIE); |
| 82 | + |
| 83 | + FAudioDevice* AudioDevice = GEngine->GetMainAudioDevice(); |
| 84 | + if (AudioDevice != nullptr) |
| 85 | + { |
| 86 | + TransientMasterVolume = AudioDevice->GetTransientMasterVolume(); |
| 87 | + AudioDevice->SetTransientMasterVolume(0.0f); |
| 88 | + } |
| 89 | + |
| 90 | + GEditor->RequestPlaySession(true, nullptr, false); |
| 91 | + } |
| 92 | + |
| 93 | + void OverridePlaySettings(ULevelEditorPlaySettings* PlayInEditorSettings) |
| 94 | + { |
| 95 | + const FMovieSceneCaptureSettings& Settings = CaptureObject->GetSettings(); |
| 96 | + |
| 97 | + PlayInEditorSettings->NewWindowWidth = Settings.Resolution.ResX; |
| 98 | + PlayInEditorSettings->NewWindowHeight = Settings.Resolution.ResY; |
| 99 | + PlayInEditorSettings->CenterNewWindow = true; |
| 100 | + PlayInEditorSettings->LastExecutedPlayModeType = EPlayModeType::PlayMode_InEditorFloating; |
| 101 | + |
| 102 | + TSharedRef<SWindow> CustomWindow = SNew(SWindow) |
| 103 | + .Title(FText::FromString("Movie Render - Preview")) |
| 104 | + .AutoCenter(EAutoCenter::PrimaryWorkArea) |
| 105 | + .UseOSWindowBorder(true) |
| 106 | + .FocusWhenFirstShown(false) |
| 107 | + .ActivationPolicy(EWindowActivationPolicy::Never) |
| 108 | + .HasCloseButton(true) |
| 109 | + .SupportsMaximize(false) |
| 110 | + .SupportsMinimize(true) |
| 111 | + .MaxWidth(Settings.Resolution.ResX) |
| 112 | + .MaxHeight(Settings.Resolution.ResY) |
| 113 | + .SizingRule(ESizingRule::FixedSize); |
| 114 | + |
| 115 | + FSlateApplication::Get().AddWindow(CustomWindow); |
| 116 | + |
| 117 | + PlayInEditorSettings->CustomPIEWindow = CustomWindow; |
| 118 | + |
| 119 | + // Reset everything else |
| 120 | + PlayInEditorSettings->GameGetsMouseControl = false; |
| 121 | + PlayInEditorSettings->ShowMouseControlLabel = false; |
| 122 | + PlayInEditorSettings->ViewportGetsHMDControl = false; |
| 123 | + PlayInEditorSettings->ShouldMinimizeEditorOnVRPIE = true; |
| 124 | + PlayInEditorSettings->EnableGameSound = false; |
| 125 | + PlayInEditorSettings->bOnlyLoadVisibleLevelsInPIE = false; |
| 126 | + PlayInEditorSettings->bPreferToStreamLevelsInPIE = false; |
| 127 | + PlayInEditorSettings->PIEAlwaysOnTop = false; |
| 128 | + PlayInEditorSettings->DisableStandaloneSound = true; |
| 129 | + PlayInEditorSettings->AdditionalLaunchParameters = TEXT(""); |
| 130 | + PlayInEditorSettings->BuildGameBeforeLaunch = EPlayOnBuildMode::PlayOnBuild_Never; |
| 131 | + PlayInEditorSettings->LaunchConfiguration = EPlayOnLaunchConfiguration::LaunchConfig_Default; |
| 132 | + PlayInEditorSettings->SetPlayNetMode(EPlayNetMode::PIE_Standalone); |
| 133 | + PlayInEditorSettings->SetRunUnderOneProcess(true); |
| 134 | + PlayInEditorSettings->SetPlayNetDedicated(false); |
| 135 | + PlayInEditorSettings->SetPlayNumberOfClients(1); |
| 136 | + } |
| 137 | + |
| 138 | + void OnStart() |
| 139 | + { |
| 140 | + for (const FWorldContext& Context : GEngine->GetWorldContexts()) |
| 141 | + { |
| 142 | + if (Context.WorldType == EWorldType::PIE) |
| 143 | + { |
| 144 | + FSlatePlayInEditorInfo* SlatePlayInEditorSession = GEditor->SlatePlayInEditorMap.Find(Context.ContextHandle); |
| 145 | + if (SlatePlayInEditorSession) |
| 146 | + { |
| 147 | + CapturingFromWorld = Context.World(); |
| 148 | + |
| 149 | + TSharedPtr<SWindow> Window = SlatePlayInEditorSession->SlatePlayInEditorWindow.Pin(); |
| 150 | + |
| 151 | + const FMovieSceneCaptureSettings& Settings = CaptureObject->GetSettings(); |
| 152 | + |
| 153 | + SlatePlayInEditorSession->SlatePlayInEditorWindowViewport->SetViewportSize(Settings.Resolution.ResX, Settings.Resolution.ResY); |
| 154 | + |
| 155 | + FVector2D PreviewWindowSize(Settings.Resolution.ResX, Settings.Resolution.ResY); |
| 156 | + |
| 157 | + // Keep scaling down the window size while we're bigger than half the destop width/height |
| 158 | + { |
| 159 | + FDisplayMetrics DisplayMetrics; |
| 160 | + FSlateApplication::Get().GetDisplayMetrics(DisplayMetrics); |
| 161 | + |
| 162 | + while (PreviewWindowSize.X >= DisplayMetrics.PrimaryDisplayWidth*.5f || PreviewWindowSize.Y >= DisplayMetrics.PrimaryDisplayHeight*.5f) |
| 163 | + { |
| 164 | + PreviewWindowSize *= .5f; |
| 165 | + } |
| 166 | + } |
| 167 | + |
| 168 | + // Resize and move the window into the desktop a bit |
| 169 | + FVector2D PreviewWindowPosition(50, 50); |
| 170 | + Window->ReshapeWindow(PreviewWindowPosition, PreviewWindowSize); |
| 171 | + |
| 172 | + if (CaptureObject->Settings.GameModeOverride != nullptr) |
| 173 | + { |
| 174 | + CachedGameMode = CapturingFromWorld->GetWorldSettings()->DefaultGameMode; |
| 175 | + CapturingFromWorld->GetWorldSettings()->DefaultGameMode = CaptureObject->Settings.GameModeOverride; |
| 176 | + } |
| 177 | + |
| 178 | + CaptureObject->Initialize(SlatePlayInEditorSession->SlatePlayInEditorWindowViewport, Context.PIEInstance); |
| 179 | + } |
| 180 | + return; |
| 181 | + } |
| 182 | + } |
| 183 | + |
| 184 | + // todo: error? |
| 185 | + } |
| 186 | + |
| 187 | + void Shutdown() |
| 188 | + { |
| 189 | + FEditorDelegates::EndPIE.RemoveAll(this); |
| 190 | + UGameViewportClient::OnViewportCreated().RemoveAll(this); |
| 191 | + CaptureObject->OnCaptureFinished().RemoveAll(this); |
| 192 | + |
| 193 | + GAreScreenMessagesEnabled = bScreenMessagesWereEnabled; |
| 194 | + |
| 195 | + if (!CaptureObject->Settings.bEnableTextureStreaming) |
| 196 | + { |
| 197 | + IConsoleVariable* CVarStreamingPoolSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streaming.PoolSize")); |
| 198 | + if (CVarStreamingPoolSize) |
| 199 | + { |
| 200 | + CVarStreamingPoolSize->Set(BackedUpStreamingPoolSize, ECVF_SetByConsole); |
| 201 | + } |
| 202 | + |
| 203 | + IConsoleVariable* CVarUseFixedPoolSize = IConsoleManager::Get().FindConsoleVariable(TEXT("r.Streaming.UseFixedPoolSize")); |
| 204 | + if (CVarUseFixedPoolSize) |
| 205 | + { |
| 206 | + CVarUseFixedPoolSize->Set(BackedUpUseFixedPoolSize, ECVF_SetByConsole); |
| 207 | + } |
| 208 | + } |
| 209 | + |
| 210 | + if (CaptureObject->Settings.GameModeOverride != nullptr) |
| 211 | + { |
| 212 | + CapturingFromWorld->GetWorldSettings()->DefaultGameMode = CachedGameMode; |
| 213 | + } |
| 214 | + |
| 215 | + FObjectReader(GetMutableDefault<ULevelEditorPlaySettings>(), BackedUpPlaySettings); |
| 216 | + |
| 217 | + FAudioDevice* AudioDevice = GEngine->GetMainAudioDevice(); |
| 218 | + if (AudioDevice != nullptr) |
| 219 | + { |
| 220 | + AudioDevice->SetTransientMasterVolume(TransientMasterVolume); |
| 221 | + } |
| 222 | + |
| 223 | + CaptureObject->Close(); |
| 224 | + CaptureObject->RemoveFromRoot(); |
| 225 | + |
| 226 | + } |
| 227 | + void OnEndPIE(bool bIsSimulating) |
| 228 | + { |
| 229 | + Shutdown(); |
| 230 | + OnlyStrongReference = nullptr; |
| 231 | + } |
| 232 | + |
| 233 | + void OnEnd() |
| 234 | + { |
| 235 | + Shutdown(); |
| 236 | + OnlyStrongReference = nullptr; |
| 237 | + |
| 238 | + GEditor->RequestEndPlayMap(); |
| 239 | + } |
| 240 | + |
| 241 | + TSharedPtr<FInEditorCapture> OnlyStrongReference; |
| 242 | + UWorld* CapturingFromWorld; |
| 243 | + |
| 244 | + bool bScreenMessagesWereEnabled; |
| 245 | + float TransientMasterVolume; |
| 246 | + int32 BackedUpStreamingPoolSize; |
| 247 | + int32 BackedUpUseFixedPoolSize; |
| 248 | + TArray<uint8> BackedUpPlaySettings; |
| 249 | + UMovieSceneCapture* CaptureObject; |
| 250 | + |
| 251 | + TSubclassOf<AGameModeBase> CachedGameMode; |
| 252 | +}; |
| 253 | + |
| 254 | +PyObject *py_ue_in_editor_capture(ue_PyUObject * self, PyObject * args) |
| 255 | +{ |
| 256 | + ue_py_check(self); |
| 257 | + |
| 258 | + UMovieSceneCapture *capture = ue_py_check_type<UMovieSceneCapture>(self); |
| 259 | + if (!capture) |
| 260 | + return PyErr_Format(PyExc_Exception, "uobject is not a UMovieSceneCapture"); |
| 261 | + |
| 262 | + FInEditorCapture::CreateInEditorCapture(capture); |
| 263 | + |
| 264 | + Py_RETURN_NONE; |
| 265 | +} |
| 266 | + |
| 267 | +PyObject *py_ue_set_level_sequence_asset(ue_PyUObject *self, PyObject *args) |
| 268 | +{ |
| 269 | + ue_py_check(self); |
| 270 | + |
| 271 | + PyObject *py_sequence = nullptr; |
| 272 | + |
| 273 | + if (!PyArg_ParseTuple(args, "O:set_level_sequence_asset", &py_sequence)) |
| 274 | + { |
| 275 | + return nullptr; |
| 276 | + } |
| 277 | + |
| 278 | + ULevelSequence *sequence = ue_py_check_type<ULevelSequence>(py_sequence); |
| 279 | + if (!sequence) |
| 280 | + { |
| 281 | + return PyErr_Format(PyExc_Exception, "uobject is not a ULevelSequence"); |
| 282 | + } |
| 283 | + |
| 284 | + UAutomatedLevelSequenceCapture *capture = ue_py_check_type<UAutomatedLevelSequenceCapture>(self); |
| 285 | + if (!capture) |
| 286 | + return PyErr_Format(PyExc_Exception, "uobject is not a UAutomatedLevelSequenceCapture"); |
| 287 | + |
| 288 | + capture->SetLevelSequenceAsset(sequence->GetPathName()); |
| 289 | + |
| 290 | + Py_RETURN_NONE; |
| 291 | +} |
| 292 | +#endif |
5 | 293 |
|
6 | 294 | PyObject *py_ue_capture_initialize(ue_PyUObject * self, PyObject * args) |
7 | 295 | { |
@@ -39,22 +327,6 @@ PyObject *py_ue_capture_initialize(ue_PyUObject * self, PyObject * args) |
39 | 327 | } |
40 | 328 |
|
41 | 329 | } |
42 | | - else |
43 | | - { |
44 | | - for (const FWorldContext &Context : GEngine->GetWorldContexts()) |
45 | | - { |
46 | | - if (Context.WorldType == EWorldType::PIE) |
47 | | - { |
48 | | - if (Context.GameViewport) |
49 | | - { |
50 | | - UE_LOG(LogPython, Error, TEXT("Found Viewport at %p"), Context.GameViewport); |
51 | | - FSlatePlayInEditorInfo *SlatePIEInfo = GEditor->SlatePlayInEditorMap.Find(Context.ContextHandle); |
52 | | - |
53 | | - capture->Initialize(SlatePIEInfo->SlatePlayInEditorWindowViewport); |
54 | | - } |
55 | | - } |
56 | | - } |
57 | | - } |
58 | 330 | #endif |
59 | 331 | Py_RETURN_NONE; |
60 | 332 | } |
|
0 commit comments