From ffe515e874680da015e377cc141a28e4228c8fc7 Mon Sep 17 00:00:00 2001 From: Nicolas Lebedenco Date: Sat, 26 Nov 2016 22:18:52 -0500 Subject: [PATCH 01/13] Corrected and rephrased comment about PlaybackType --- Source/LoadingScreen/Private/LoadingScreenSettings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/LoadingScreen/Private/LoadingScreenSettings.h b/Source/LoadingScreen/Private/LoadingScreenSettings.h index 252e642..e9b82db 100644 --- a/Source/LoadingScreen/Private/LoadingScreenSettings.h +++ b/Source/LoadingScreen/Private/LoadingScreenSettings.h @@ -30,7 +30,7 @@ struct LOADINGSCREEN_API FLoadingScreenDescription UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) bool bWaitForManualStop; - /** Should we just play back, loop, etc. NOTE: if the playback type is MT_LoopLast, then bAutoCompleteWhenLoadingCompletes will be togged on when the last movie is hit*/ + /** Should we just play back, loop, etc. NOTE: if playback type is MT_LoadingLoop, then MoviePlayer will auto complete when in the last movie and load finishes regardless of bAutoCompleteWhenLoadingCompletes */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) TEnumAsByte PlaybackType; From 0daeb432b0184ecf3acd2b873ce157552e5da952 Mon Sep 17 00:00:00 2001 From: Nicolas Lebedenco Date: Wed, 18 Jan 2017 17:47:37 -0500 Subject: [PATCH 02/13] Fix configuration to indicate the engine that a Content folder is not used. --- LoadingScreen.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LoadingScreen.uplugin b/LoadingScreen.uplugin index 5d74547..0c5d79f 100644 --- a/LoadingScreen.uplugin +++ b/LoadingScreen.uplugin @@ -9,7 +9,7 @@ "CreatedByURL": "http://nickdarnell.com", "EngineVersion" : "4.12.0", "EnabledByDefault" : false, - "CanContainContent": true, + "CanContainContent": false, "Modules" : [ From adf32c8d20e6cb179727e5b85624744f7ca85c9d Mon Sep 17 00:00:00 2001 From: Nicolas Lebedenco Date: Sun, 12 Nov 2017 23:21:57 -0500 Subject: [PATCH 03/13] Bumped to 4.18 --- LoadingScreen.uplugin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LoadingScreen.uplugin b/LoadingScreen.uplugin index 60a4395..c0a36ac 100644 --- a/LoadingScreen.uplugin +++ b/LoadingScreen.uplugin @@ -10,7 +10,7 @@ "CreatedByURL": "https://www.epicgames.com", "DocsURL": "https://github.com/ue4plugins/LoadingScreen", "SupportURL": "https://github.com/ue4plugins/LoadingScreen/issues", - "EngineVersion": "4.16.0", + "EngineVersion": "4.18.0", "EnabledByDefault": false, "CanContainContent": true, From 7f6430a71c05af65a0af13d4961ed37821509def Mon Sep 17 00:00:00 2001 From: Nicolas Lebedenco Date: Sat, 2 Dec 2017 20:00:15 -0500 Subject: [PATCH 04/13] Fixed Editor crash during a HotReload due to FObjectFinder being used inside FLoadingScreenDescription constructor. It's only allowed inside UObjects. Also modified SSimpleLoadingScreen to actually use TipFont and LoadingFont. --- Source/LoadingScreen/Private/LoadingScreenSettings.cpp | 6 +----- Source/LoadingScreen/Private/LoadingScreenSettings.h | 8 ++++---- Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp | 10 +++++----- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/Source/LoadingScreen/Private/LoadingScreenSettings.cpp b/Source/LoadingScreen/Private/LoadingScreenSettings.cpp index a1bef51..72a215c 100644 --- a/Source/LoadingScreen/Private/LoadingScreenSettings.cpp +++ b/Source/LoadingScreen/Private/LoadingScreenSettings.cpp @@ -15,11 +15,6 @@ FLoadingScreenDescription::FLoadingScreenDescription() , LoadingText(LOCTEXT("Loading", "LOADING")) , ImageStretch(EStretch::ScaleToFit) { - if ( !IsRunningDedicatedServer() ) - { - static ConstructorHelpers::FObjectFinder RobotoFontObj(TEXT("/Engine/EngineFonts/Roboto")); - LoadingFont = FSlateFontInfo(RobotoFontObj.Object, 32, FName("Bold")); - } } ULoadingScreenSettings::ULoadingScreenSettings(const FObjectInitializer& Initializer) @@ -31,6 +26,7 @@ ULoadingScreenSettings::ULoadingScreenSettings(const FObjectInitializer& Initial { static ConstructorHelpers::FObjectFinder RobotoFontObj(TEXT("/Engine/EngineFonts/Roboto")); TipFont = FSlateFontInfo(RobotoFontObj.Object, 20, FName("Normal")); + LoadingFont = FSlateFontInfo(RobotoFontObj.Object, 32, FName("Bold")); } } diff --git a/Source/LoadingScreen/Private/LoadingScreenSettings.h b/Source/LoadingScreen/Private/LoadingScreenSettings.h index 3ce51ec..0c83509 100644 --- a/Source/LoadingScreen/Private/LoadingScreenSettings.h +++ b/Source/LoadingScreen/Private/LoadingScreenSettings.h @@ -45,10 +45,6 @@ struct LOADINGSCREEN_API FLoadingScreenDescription UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Display) FText LoadingText; - /** */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Display) - FSlateFontInfo LoadingFont; - /** The movie paths local to the game's Content/Movies/ directory we will play. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Movies) TArray MoviePaths; @@ -84,6 +80,10 @@ class LOADINGSCREEN_API ULoadingScreenSettings : public UDeveloperSettings UPROPERTY(config, EditAnywhere, BlueprintReadWrite, Category=Advice) FSlateFontInfo TipFont; + /** The font to display on loading. */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Display) + FSlateFontInfo LoadingFont; + /** The size of the tip before it's wrapped to the next line. */ UPROPERTY(config, EditAnywhere, BlueprintReadWrite, Category=Advice) float TipWrapAt; diff --git a/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp b/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp index 0f5fd38..f45905d 100644 --- a/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp +++ b/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp @@ -26,8 +26,8 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr const ULoadingScreenSettings* Settings = GetDefault(); - //Settings->TipFont; - //InScreenDescription.LoadingFont.GetCompositeFont()->SubTypefaces[0]->Typeface.Fonts[0].Font.BulkDataPtr->GetLinker()->GetOwnerThreadId() + const FSlateFontInfo& TipFont = Settings->TipFont; + const FSlateFontInfo& LoadingFont = Settings->LoadingFont; TSharedRef Root = SNew(SOverlay); @@ -63,7 +63,7 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr TipWidget = SNew(STextBlock) .WrapTextAt(Settings->TipWrapAt) - //.Font(Settings->TipFont) + .Font(TipFont) .Text(Settings->Tips[TipIndex]); } @@ -94,7 +94,7 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr [ SNew(SCircularThrobber) // Convert font size to pixels, pixel_size = point_size * resolution / 72, then half it to get radius - .Radius((InScreenDescription.LoadingFont.Size * 96.0f/72.0f) / 2.0f) + .Radius((LoadingFont.Size * 96.0f/72.0f) / 2.0f) ] + SHorizontalBox::Slot() @@ -104,7 +104,7 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr [ SNew(STextBlock) .Text(InScreenDescription.LoadingText) - //.Font(InScreenDescription.LoadingFont) + .Font(LoadingFont) ] + SHorizontalBox::Slot() From 0a4a508b126fa28f9b35a252baf3998b56b158ac Mon Sep 17 00:00:00 2001 From: Nicolas Lebedenco Date: Sun, 4 Feb 2018 12:00:51 -0500 Subject: [PATCH 05/13] Improved comments and property grouping. --- .../Private/LoadingScreenSettings.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Source/LoadingScreen/Private/LoadingScreenSettings.h b/Source/LoadingScreen/Private/LoadingScreenSettings.h index 0c83509..10fa16a 100644 --- a/Source/LoadingScreen/Private/LoadingScreenSettings.h +++ b/Source/LoadingScreen/Private/LoadingScreenSettings.h @@ -20,15 +20,15 @@ struct LOADINGSCREEN_API FLoadingScreenDescription /** The minimum time that a loading screen should be opened for, -1 if there is no minimum time. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) float MinimumLoadingScreenDisplayTime; - - /** If true, the loading screen will disappear as soon as all movies are played and loading is done. */ + + /** If true, the loading screen will disappear as soon as loading is done. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) bool bAutoCompleteWhenLoadingCompletes; - + /** If true, movies can be skipped by clicking the loading screen as long as loading is done. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) bool bMoviesAreSkippable; - + /** If true, movie playback continues until Stop is called. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) bool bWaitForManualStop; @@ -37,18 +37,18 @@ struct LOADINGSCREEN_API FLoadingScreenDescription UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) TEnumAsByte PlaybackType; + /** The movie paths local to the game's Content/Movies/ directory without extension. */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Movies) + TArray MoviePaths; + /** Should we show the images/tips/loading text? Generally you'll want to set this to false if you just want to show a movie. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Display) bool bShowUIOverlay; - /** */ + /** Text displayed beside the animated icon */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Display) FText LoadingText; - /** The movie paths local to the game's Content/Movies/ directory we will play. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Movies) - TArray MoviePaths; - /** The texture display while in the loading screen on top of the movie. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Images, meta=(AllowedClasses="Texture2D")) TArray Images; From 079e3ff321c50c7e7117338ebb3bb0785b631bbc Mon Sep 17 00:00:00 2001 From: Nicolas Lebedenco Date: Tue, 3 Apr 2018 12:21:39 -0400 Subject: [PATCH 06/13] Bumped to 4.19 --- LoadingScreen.uplugin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LoadingScreen.uplugin b/LoadingScreen.uplugin index c0a36ac..8d8128f 100644 --- a/LoadingScreen.uplugin +++ b/LoadingScreen.uplugin @@ -10,7 +10,7 @@ "CreatedByURL": "https://www.epicgames.com", "DocsURL": "https://github.com/ue4plugins/LoadingScreen", "SupportURL": "https://github.com/ue4plugins/LoadingScreen/issues", - "EngineVersion": "4.18.0", + "EngineVersion": "4.19.0", "EnabledByDefault": false, "CanContainContent": true, @@ -21,4 +21,4 @@ "LoadingPhase": "PreLoadingScreen" } ] -} \ No newline at end of file +} From 8d81df50debf618f2de81888a8cc8a89b392b059 Mon Sep 17 00:00:00 2001 From: Nicolas Lebedenco Date: Thu, 19 Jul 2018 03:06:47 -0400 Subject: [PATCH 07/13] Updated for 4.20 --- LoadingScreen.uplugin | 2 +- Source/LoadingScreen/LoadingScreen.Build.cs | 3 +-- Source/LoadingScreen/Private/SSimpleLoadingScreen.h | 5 +++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LoadingScreen.uplugin b/LoadingScreen.uplugin index 8d8128f..fe84f09 100644 --- a/LoadingScreen.uplugin +++ b/LoadingScreen.uplugin @@ -10,7 +10,7 @@ "CreatedByURL": "https://www.epicgames.com", "DocsURL": "https://github.com/ue4plugins/LoadingScreen", "SupportURL": "https://github.com/ue4plugins/LoadingScreen/issues", - "EngineVersion": "4.19.0", + "EngineVersion": "4.20.0", "EnabledByDefault": false, "CanContainContent": true, diff --git a/Source/LoadingScreen/LoadingScreen.Build.cs b/Source/LoadingScreen/LoadingScreen.Build.cs index 6824151..f495416 100644 --- a/Source/LoadingScreen/LoadingScreen.Build.cs +++ b/Source/LoadingScreen/LoadingScreen.Build.cs @@ -21,8 +21,7 @@ public LoadingScreen(ReadOnlyTargetRules Target) "SlateCore", "InputCore", "Engine" - } - ); + }); } } } diff --git a/Source/LoadingScreen/Private/SSimpleLoadingScreen.h b/Source/LoadingScreen/Private/SSimpleLoadingScreen.h index cc81737..3ea40f2 100644 --- a/Source/LoadingScreen/Private/SSimpleLoadingScreen.h +++ b/Source/LoadingScreen/Private/SSimpleLoadingScreen.h @@ -17,9 +17,10 @@ struct FLoadingScreenBrush : public FSlateDynamicImageBrush, public FGCObject virtual void AddReferencedObjects(FReferenceCollector& Collector) override { - if ( ResourceObject ) + UObject* Object = GetResourceObject(); + if (Object) { - Collector.AddReferencedObject(ResourceObject); + Collector.AddReferencedObject(Object); } } }; From ece5fdb294ae9c88e2fa63180907e6551d5e6bac Mon Sep 17 00:00:00 2001 From: gamerpcx <32440829+gamerpcx@users.noreply.github.com> Date: Fri, 27 Jul 2018 09:52:35 -0700 Subject: [PATCH 08/13] Copyright date The copyright date needs to be updated --- Source/LoadingScreen/Public/ILoadingScreenModule.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/LoadingScreen/Public/ILoadingScreenModule.h b/Source/LoadingScreen/Public/ILoadingScreenModule.h index 99aa65c..69e84ee 100644 --- a/Source/LoadingScreen/Public/ILoadingScreenModule.h +++ b/Source/LoadingScreen/Public/ILoadingScreenModule.h @@ -1,4 +1,4 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. #pragma once From e764e5a47075bd507eacebf0f3101d82b229c993 Mon Sep 17 00:00:00 2001 From: gamerpcx <32440829+gamerpcx@users.noreply.github.com> Date: Sat, 19 Jan 2019 13:12:14 -0500 Subject: [PATCH 09/13] Updated to 2019 Copyright date 2019 copyright date changed. --- Source/LoadingScreen/Public/ILoadingScreenModule.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/LoadingScreen/Public/ILoadingScreenModule.h b/Source/LoadingScreen/Public/ILoadingScreenModule.h index 69e84ee..b5b5294 100644 --- a/Source/LoadingScreen/Public/ILoadingScreenModule.h +++ b/Source/LoadingScreen/Public/ILoadingScreenModule.h @@ -1,4 +1,4 @@ -// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #pragma once From 97e7c7e7949c6b9bea0cd9489fc142ef49b75eea Mon Sep 17 00:00:00 2001 From: gamerpcx <32440829+gamerpcx@users.noreply.github.com> Date: Sat, 19 Jan 2019 13:13:10 -0500 Subject: [PATCH 10/13] Updated the Copyright year to 2019 Updated year to 2019. --- Source/LoadingScreen/LoadingScreen.Build.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/LoadingScreen/LoadingScreen.Build.cs b/Source/LoadingScreen/LoadingScreen.Build.cs index f495416..0742db4 100644 --- a/Source/LoadingScreen/LoadingScreen.Build.cs +++ b/Source/LoadingScreen/LoadingScreen.Build.cs @@ -1,4 +1,4 @@ -// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. namespace UnrealBuildTool.Rules { From 2dea2ccf534cffa14c137c19a529cab6a456cbc2 Mon Sep 17 00:00:00 2001 From: morskoyzmey Date: Thu, 31 Jan 2019 06:52:49 +0500 Subject: [PATCH 11/13] LoadingFont config not-saving fix --- Source/LoadingScreen/Private/LoadingScreenSettings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/LoadingScreen/Private/LoadingScreenSettings.h b/Source/LoadingScreen/Private/LoadingScreenSettings.h index 10fa16a..ac4903f 100644 --- a/Source/LoadingScreen/Private/LoadingScreenSettings.h +++ b/Source/LoadingScreen/Private/LoadingScreenSettings.h @@ -81,7 +81,7 @@ class LOADINGSCREEN_API ULoadingScreenSettings : public UDeveloperSettings FSlateFontInfo TipFont; /** The font to display on loading. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Display) + UPROPERTY(config, EditAnywhere, BlueprintReadWrite, Category = Display) FSlateFontInfo LoadingFont; /** The size of the tip before it's wrapped to the next line. */ From ccb162fc36c59076543247f1ddd29da92168b1a3 Mon Sep 17 00:00:00 2001 From: NickDarnell Date: Sat, 4 May 2019 08:39:30 -0400 Subject: [PATCH 12/13] Upgrading the project to be 4.22 ready, adding a few more options for background color options, fixing some rare crashes due to cross thread access to the SNullContentWidget. --- Docs/plugins.png | Bin 44379 -> 0 bytes LoadingScreen.uplugin | 4 +- README.md | 12 +--- .../Private/LoadingScreenModule.cpp | 3 +- .../Private/LoadingScreenSettings.cpp | 10 +--- .../Private/LoadingScreenSettings.h | 38 +++++++----- .../Private/SSimpleLoadingScreen.cpp | 56 ++++++++++++------ .../Private/SSimpleLoadingScreen.h | 22 +------ 8 files changed, 72 insertions(+), 73 deletions(-) delete mode 100644 Docs/plugins.png diff --git a/Docs/plugins.png b/Docs/plugins.png deleted file mode 100644 index 2cdaebe25d8e1fb4b57296511a1273390bd0c8bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44379 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 diff --git a/LoadingScreen.uplugin b/LoadingScreen.uplugin index fe84f09..d120ee7 100644 --- a/LoadingScreen.uplugin +++ b/LoadingScreen.uplugin @@ -10,8 +10,8 @@ "CreatedByURL": "https://www.epicgames.com", "DocsURL": "https://github.com/ue4plugins/LoadingScreen", "SupportURL": "https://github.com/ue4plugins/LoadingScreen/issues", - "EngineVersion": "4.20.0", - "EnabledByDefault": false, + "EngineVersion": "4.22", + "EnabledByDefault": true, "CanContainContent": true, "Modules": [ diff --git a/README.md b/README.md index 5052f4a..a897293 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ time to avoid needing to write a new loading screen manually. ## Supported Platforms -This plug-in was last built against **Unreal Engine 4.16**. It works on all platforms (probably). +This plug-in was last built against **Unreal Engine 4.22**. It works on all platforms (probably). ## Dependencies @@ -33,15 +33,7 @@ If you use it as a project plug-in, clone this repository into your project's */Plugins* directory and compile your game in Visual Studio. A C++ code project is required for this to work. -If you use it as an Engine plug-in, clone this repository into the -*/Engine/Plugins/Media* directory and compile your game. Full Unreal Engine 4 -source code from GitHub (4.12 or higher) is required for this. - -After compiling the plug-in, you have to **enable it** in Unreal Editor's -plug-in browser. - -![plugin](Docs/plugins.png) - +The plug-in configured to be enabled by default once it's in your game's plug-in directory. ## Support diff --git a/Source/LoadingScreen/Private/LoadingScreenModule.cpp b/Source/LoadingScreen/Private/LoadingScreenModule.cpp index 856b240..fa72a55 100644 --- a/Source/LoadingScreen/Private/LoadingScreenModule.cpp +++ b/Source/LoadingScreen/Private/LoadingScreenModule.cpp @@ -1,4 +1,4 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #include "ILoadingScreenModule.h" #include "LoadingScreenSettings.h" @@ -43,6 +43,7 @@ void FLoadingScreenModule::StartupModule() { Ref.TryLoad(); } + for ( const FStringAssetReference& Ref : Settings->DefaultScreen.Images ) { Ref.TryLoad(); diff --git a/Source/LoadingScreen/Private/LoadingScreenSettings.cpp b/Source/LoadingScreen/Private/LoadingScreenSettings.cpp index 72a215c..6cabe7f 100644 --- a/Source/LoadingScreen/Private/LoadingScreenSettings.cpp +++ b/Source/LoadingScreen/Private/LoadingScreenSettings.cpp @@ -1,4 +1,4 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #include "LoadingScreenSettings.h" #include "UObject/ConstructorHelpers.h" @@ -7,13 +7,7 @@ #define LOCTEXT_NAMESPACE "LoadingScreen" FLoadingScreenDescription::FLoadingScreenDescription() - : MinimumLoadingScreenDisplayTime(-1) - , bAutoCompleteWhenLoadingCompletes(true) - , bMoviesAreSkippable(true) - , bWaitForManualStop(false) - , bShowUIOverlay(true) - , LoadingText(LOCTEXT("Loading", "LOADING")) - , ImageStretch(EStretch::ScaleToFit) + : LoadingText(LOCTEXT("Loading", "LOADING")) { } diff --git a/Source/LoadingScreen/Private/LoadingScreenSettings.h b/Source/LoadingScreen/Private/LoadingScreenSettings.h index ac4903f..8667be7 100644 --- a/Source/LoadingScreen/Private/LoadingScreenSettings.h +++ b/Source/LoadingScreen/Private/LoadingScreenSettings.h @@ -1,4 +1,4 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #pragma once @@ -18,21 +18,21 @@ struct LOADINGSCREEN_API FLoadingScreenDescription FLoadingScreenDescription(); /** The minimum time that a loading screen should be opened for, -1 if there is no minimum time. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) - float MinimumLoadingScreenDisplayTime; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Loading) + float MinimumLoadingScreenDisplayTime = -1; /** If true, the loading screen will disappear as soon as loading is done. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) - bool bAutoCompleteWhenLoadingCompletes; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Loading) + bool bAutoCompleteWhenLoadingCompletes = true; /** If true, movies can be skipped by clicking the loading screen as long as loading is done. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) - bool bMoviesAreSkippable; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Loading) + bool bMoviesAreSkippable = true; /** If true, movie playback continues until Stop is called. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) - bool bWaitForManualStop; - + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Loading) + bool bWaitForManualStop = false; + /** Should we just play back, loop, etc. NOTE: if playback type is MT_LoadingLoop, then MoviePlayer will auto complete when in the last movie and load finishes regardless of bAutoCompleteWhenLoadingCompletes */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Loading) TEnumAsByte PlaybackType; @@ -42,8 +42,8 @@ struct LOADINGSCREEN_API FLoadingScreenDescription TArray MoviePaths; /** Should we show the images/tips/loading text? Generally you'll want to set this to false if you just want to show a movie. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Display) - bool bShowUIOverlay; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Display) + bool bShowUIOverlay = true; /** Text displayed beside the animated icon */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Display) @@ -51,11 +51,19 @@ struct LOADINGSCREEN_API FLoadingScreenDescription /** The texture display while in the loading screen on top of the movie. */ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Images, meta=(AllowedClasses="Texture2D")) - TArray Images; + TArray Images; /** The scaling type to apply to images. */ - UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Images) - TEnumAsByte ImageStretch; + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Images) + TEnumAsByte ImageStretch = EStretch::ScaleToFit; + + /** The background color to use */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Images) + FLinearColor BackgroundColor = FLinearColor::Black; + + /** The background color to use for tips */ + UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Images) + FLinearColor TipBackgroundColor = FLinearColor(0, 0, 0, 0.75f); }; /** diff --git a/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp b/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp index f45905d..2598df9 100644 --- a/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp +++ b/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp @@ -1,25 +1,36 @@ -// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved. +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. #include "SSimpleLoadingScreen.h" -#include "SScaleBox.h" -#include "Widgets/Images/SImage.h" -#include "Widgets/Layout/SSpacer.h" #include "Widgets/SOverlay.h" #include "Widgets/SBoxPanel.h" -#include "Widgets/Text/STextBlock.h" +#include "Widgets/Layout/SScaleBox.h" +#include "Widgets/Layout/SSpacer.h" #include "Widgets/Layout/SBorder.h" -#include "SSafeZone.h" -#include "SThrobber.h" -#include "SDPIScaler.h" +#include "Widgets/Layout/SSafeZone.h" +#include "Widgets/Layout/SDPIScaler.h" +#include "Widgets/Text/STextBlock.h" +#include "Widgets/Images/SImage.h" +#include "Widgets/Images/SThrobber.h" #include "Engine/Texture2D.h" #include "Engine/UserInterfaceSettings.h" +#include "Slate/DeferredCleanupSlateBrush.h" #define LOCTEXT_NAMESPACE "LoadingScreen" ///////////////////////////////////////////////////// // SSimpleLoadingScreen +static float PointSizeToSlateUnits(float PointSize) +{ + //FreeTypeConstants::HorizontalDPI = 96; + const float SlateFreeTypeHorizontalResolutionDPI = 96.0f; + const float FreeTypeNativeDPI = 72.0f; + const float PixelSize = PointSize * (SlateFreeTypeHorizontalResolutionDPI / FreeTypeNativeDPI); + + return PixelSize; +} + void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScreenDescription& InScreenDescription) { LastComputedDPIScale = 1.0f; @@ -39,18 +50,24 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr UObject* ImageObject = ImageAsset.TryLoad(); if ( UTexture2D* LoadingImage = Cast(ImageObject) ) { - FVector2D Size = FVector2D(LoadingImage->GetSizeX(), LoadingImage->GetSizeY()); - LoadingScreenBrush = MakeShareable(new FLoadingScreenBrush(LoadingImage, Size, FName(*ImageAsset.ToString()))); + LoadingScreenBrush = FDeferredCleanupSlateBrush::CreateBrush(LoadingImage); Root->AddSlot() .HAlign(HAlign_Fill) .VAlign(VAlign_Fill) [ - SNew(SScaleBox) - .Stretch(InScreenDescription.ImageStretch) + SNew(SBorder) + .HAlign(HAlign_Fill) + .VAlign(VAlign_Fill) + .BorderBackgroundColor(InScreenDescription.BackgroundColor) + .BorderImage(FCoreStyle::Get().GetBrush("WhiteBrush")) [ - SNew(SImage) - .Image(LoadingScreenBrush.Get()) + SNew(SScaleBox) + .Stretch(InScreenDescription.ImageStretch) + [ + SNew(SImage) + .Image(LoadingScreenBrush.IsValid() ? LoadingScreenBrush->GetSlateBrush() : nullptr) + ] ] ]; } @@ -66,6 +83,12 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr .Font(TipFont) .Text(Settings->Tips[TipIndex]); } + else + { + // Need to use a spacer when being rendered on another thread, incrementing the SNullWidget will + // lead to shared ptr crashes. + TipWidget = SNew(SSpacer); + } Root->AddSlot() .HAlign(HAlign_Fill) @@ -74,7 +97,7 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr SNew(SBorder) .HAlign(HAlign_Fill) .VAlign(VAlign_Fill) - .BorderBackgroundColor(FLinearColor(0, 0, 0, 0.75)) + .BorderBackgroundColor(InScreenDescription.TipBackgroundColor) .BorderImage(FCoreStyle::Get().GetBrush("WhiteBrush")) [ SNew(SSafeZone) @@ -93,8 +116,7 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr .AutoWidth() [ SNew(SCircularThrobber) - // Convert font size to pixels, pixel_size = point_size * resolution / 72, then half it to get radius - .Radius((LoadingFont.Size * 96.0f/72.0f) / 2.0f) + .Radius(PointSizeToSlateUnits(LoadingFont.Size) / 2.0f) ] + SHorizontalBox::Slot() diff --git a/Source/LoadingScreen/Private/SSimpleLoadingScreen.h b/Source/LoadingScreen/Private/SSimpleLoadingScreen.h index 3ea40f2..d0b9a52 100644 --- a/Source/LoadingScreen/Private/SSimpleLoadingScreen.h +++ b/Source/LoadingScreen/Private/SSimpleLoadingScreen.h @@ -5,25 +5,7 @@ #include "SCompoundWidget.h" #include "LoadingScreenSettings.h" -/** -* Special brush to prevent garbage collection -*/ -struct FLoadingScreenBrush : public FSlateDynamicImageBrush, public FGCObject -{ - FLoadingScreenBrush(class UTexture2D* InTexture, const FVector2D& InImageSize, const FName InImagePath) - : FSlateDynamicImageBrush(InTexture, InImageSize, InImagePath) - { - } - - virtual void AddReferencedObjects(FReferenceCollector& Collector) override - { - UObject* Object = GetResourceObject(); - if (Object) - { - Collector.AddReferencedObject(Object); - } - } -}; +class FDeferredCleanupSlateBrush; class SSimpleLoadingScreen : public SCompoundWidget { @@ -41,6 +23,6 @@ class SSimpleLoadingScreen : public SCompoundWidget float GetDPIScale() const; private: - TSharedPtr LoadingScreenBrush; + TSharedPtr LoadingScreenBrush; float LastComputedDPIScale; }; From deed02422eb662a18eb99bd443d8d06581e61c1f Mon Sep 17 00:00:00 2001 From: NickDarnell Date: Sat, 4 May 2019 09:04:32 -0400 Subject: [PATCH 13/13] const correctness, making the tips multiline, simplifying the DPI scaling logic. --- .../Private/LoadingScreenSettings.h | 2 +- .../Private/SSimpleLoadingScreen.cpp | 23 ++++--------------- .../Private/SSimpleLoadingScreen.h | 3 --- 3 files changed, 6 insertions(+), 22 deletions(-) diff --git a/Source/LoadingScreen/Private/LoadingScreenSettings.h b/Source/LoadingScreen/Private/LoadingScreenSettings.h index 8667be7..ceb6936 100644 --- a/Source/LoadingScreen/Private/LoadingScreenSettings.h +++ b/Source/LoadingScreen/Private/LoadingScreenSettings.h @@ -97,6 +97,6 @@ class LOADINGSCREEN_API ULoadingScreenSettings : public UDeveloperSettings float TipWrapAt; /** The tips to display on the load screen. */ - UPROPERTY(config, EditAnywhere, BlueprintReadWrite, Category=Advice) + UPROPERTY(config, EditAnywhere, BlueprintReadWrite, Category=Advice, meta = (MultiLine = "true")) TArray Tips; }; diff --git a/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp b/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp index 2598df9..b80a27c 100644 --- a/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp +++ b/Source/LoadingScreen/Private/SSimpleLoadingScreen.cpp @@ -33,8 +33,6 @@ static float PointSizeToSlateUnits(float PointSize) void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScreenDescription& InScreenDescription) { - LastComputedDPIScale = 1.0f; - const ULoadingScreenSettings* Settings = GetDefault(); const FSlateFontInfo& TipFont = Settings->TipFont; @@ -45,7 +43,7 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr // If there's an image defined if ( InScreenDescription.Images.Num() > 0 ) { - int32 ImageIndex = FMath::RandRange(0, InScreenDescription.Images.Num() - 1); + const int32 ImageIndex = FMath::RandRange(0, InScreenDescription.Images.Num() - 1); const FStringAssetReference& ImageAsset = InScreenDescription.Images[ImageIndex]; UObject* ImageObject = ImageAsset.TryLoad(); if ( UTexture2D* LoadingImage = Cast(ImageObject) ) @@ -76,7 +74,7 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr TSharedRef TipWidget = SNullWidget::NullWidget; if ( Settings->Tips.Num() > 0 ) { - int32 TipIndex = FMath::RandRange(0, Settings->Tips.Num() - 1); + const int32 TipIndex = FMath::RandRange(0, Settings->Tips.Num() - 1); TipWidget = SNew(STextBlock) .WrapTextAt(Settings->TipWrapAt) @@ -156,22 +154,11 @@ void SSimpleLoadingScreen::Construct(const FArguments& InArgs, const FLoadingScr ]; } -void SSimpleLoadingScreen::Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) -{ - const FVector2D& LocalSize = AllottedGeometry.GetLocalSize(); - FIntPoint Size((int32)LocalSize.X, (int32)LocalSize.Y); - const float NewScale = GetDefault()->GetDPIScaleBasedOnSize(Size); - - if ( NewScale != LastComputedDPIScale ) - { - LastComputedDPIScale = NewScale; - SlatePrepass(1.0f); - } -} - float SSimpleLoadingScreen::GetDPIScale() const { - return LastComputedDPIScale; + const FVector2D& DrawSize = GetCachedGeometry().ToPaintGeometry().GetLocalSize(); + const FIntPoint Size((int32)DrawSize.X, (int32)DrawSize.Y); + return GetDefault()->GetDPIScaleBasedOnSize(Size); } #undef LOCTEXT_NAMESPACE diff --git a/Source/LoadingScreen/Private/SSimpleLoadingScreen.h b/Source/LoadingScreen/Private/SSimpleLoadingScreen.h index d0b9a52..91fab88 100644 --- a/Source/LoadingScreen/Private/SSimpleLoadingScreen.h +++ b/Source/LoadingScreen/Private/SSimpleLoadingScreen.h @@ -17,12 +17,9 @@ class SSimpleLoadingScreen : public SCompoundWidget void Construct(const FArguments& InArgs, const FLoadingScreenDescription& ScreenDescription); - virtual void Tick(const FGeometry& AllottedGeometry, const double InCurrentTime, const float InDeltaTime) override; - private: float GetDPIScale() const; private: TSharedPtr LoadingScreenBrush; - float LastComputedDPIScale; };