// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #pragma once #include "PreLoadScreen.h" #include "CoreMinimal.h" #include "Widgets/SVirtualWindow.h" #include "Widgets/SWindow.h" #include "TickableObjectRenderThread.h" #include "Containers/Ticker.h" #include "PreLoadSlateThreading.h" DECLARE_MULTICAST_DELEGATE_OneParam(FIsPreloadScreenResponsibleForRenderingMultiDelegate, bool); // Class that handles storing all registered PreLoadScreens and Playing/Stopping them class PRELOADSCREEN_API FPreLoadScreenManager { public: static FIsPreloadScreenResponsibleForRenderingMultiDelegate IsResponsibleForRenderingDelegate; //Gets the single instance of this settings object. Also creates it if needed static FPreLoadScreenManager* Get() { return Instance.Get(); } static void Create() { if (!Instance.IsValid() && ArePreLoadScreensEnabled()) { Instance = MakeShareable(new FPreLoadScreenManager()); } } static void Destroy() { if (Instance.IsValid()) { Instance->CleanUpResources(); } Instance.Reset(); } virtual ~FPreLoadScreenManager() {} void Initialize(FSlateRenderer& InSlateRenderer); void RegisterPreLoadScreen(TSharedPtr PreLoadScreen); void UnRegisterPreLoadScreen(TSharedPtr PreLoadScreen); //Plays the first found PreLoadScreen that matches the bEarlyPreLoadScreen setting passed in. void PlayFirstPreLoadScreen(EPreLoadScreenTypes PreLoadScreenTypeToPlay); void PlayPreLoadScreenAtIndex(int Index); /** Plays the PreLoadScreen with a tag that matches InTag * @returns false if no PreLoadScreen with that tag has been registered */ bool PlayPreLoadScreenWithTag(FName InTag); void StopPreLoadScreen(); void PassPreLoadScreenWindowBackToGame() const; bool IsUsingMainWindow() const; TSharedPtr GetRenderWindow(); bool HasRegisteredPreLoadScreenType(EPreLoadScreenTypes PreLoadScreenTypeToCheck) const; bool HasActivePreLoadScreenType(EPreLoadScreenTypes PreLoadScreenTypeToCheck) const; bool HasValidActivePreLoadScreen() const; void WaitForEngineLoadingScreenToFinish(); void SetEngineLoadingComplete(bool IsEngineLoadingFinished = true); bool IsEngineLoadingComplete() const { return bIsEngineLoadingComplete; } void CleanUpResources(); static void EnableRendering(bool bEnabled); static bool ShouldRender(); static bool ArePreLoadScreensEnabled(); //Creates a tick on the Render Thread that we run every virtual void RenderTick(); // Callback for handling cleaning up any resources you would like to remove after the PreLoadScreenManager cleans up // Not needed for PreLoadScreens as those have a seperate CleanUp method called. DECLARE_MULTICAST_DELEGATE(FOnPreLoadScreenManagerCleanUp); FOnPreLoadScreenManagerCleanUp OnPreLoadScreenManagerCleanUp; protected: //Default constructor. We don't want other classes to make these. Should just rely on Get() FPreLoadScreenManager() : ActivePreLoadScreenIndex(-1) , bInitialized(false) , SyncMechanism(nullptr) , bIsEngineLoadingComplete(false) {} TArray> PreLoadScreens; //Singleton Instance static TSharedPtr Instance; void BeginPlay(); /*** These functions describe the flow for an EarlyPreLoadScreen where everything is blocking waiting on a call to StopPreLoadScreen ***/ void HandleEarlyStartupPlay(); //Separate tick that handles void EarlyPlayFrameTick(); void GameLogicFrameTick(); void EarlyPlayRenderFrameTick(); void PlatformSpecificGameLogicFrameTick(); /*** These functions describe how everything is handled during an non-Early PreLoadPlay. Everything is handled asynchronously in this case with a standalone renderer ***/ void HandleEngineLoadingPlay(); IPreLoadScreen* GetActivePreLoadScreen(); const IPreLoadScreen* GetActivePreLoadScreen() const; int ActivePreLoadScreenIndex; double LastTickTime; /** Widget renderer used to tick and paint windows in a thread safe way */ TSharedPtr WidgetRenderer; /** The window that the loading screen resides in */ TWeakPtr MainWindow; /** Virtual window that we render to instead of the main slate window (for thread safety). Shares only the same backbuffer as the main window */ TSharedPtr VirtualRenderWindow; bool bInitialized; /** The threading mechanism with which we handle running slate on another thread */ class FPreLoadScreenSlateSynchMechanism* SyncMechanism; /** Critical section to allow the slate loading thread and the render thread to safely utilize the synchronization mechanism for ticking Slate. */ FCriticalSection SyncMechanismCriticalSection; static FCriticalSection RenderingEnabledCriticalSection; static bool bRenderingEnabled; bool bIsResponsibleForRendering = false; double LastRenderTickTime; float OriginalSlateSleepVariableValue; bool bIsEngineLoadingComplete; private: #if PLATFORM_ANDROID void Android_PlatformSpecificGameLogicFrameTick(); #endif //PLATFORM_ANDROID #if PLATFORM_IOS void IOS_PlatformSpecificGameLogicFrameTick(); #endif //PLATFORM_IOS };