Added support for DPI scaling in ImGui, with scaling in Slate remaining as an alternative:

- The old DPI Scale setting was replaced by DPI Scaling Info, which contains information about scale and method of scaling.
- ImGui Context Manager handles scaling in ImGui by scaling all styles, rebuilding fonts using a different size, and raising OnFontAtlasBuilt event.
- ImGui Module Manager uses OnFontAtlasBuilt event to rebuild font textures.
- The update policy in Texture Manager was loosened to update existing resources rather than throwing an exception. This is less strict but it is now more useful since our main texture can now change. The throwing behavior used in the public interface is now handled before calling to the Texture Manager.
This commit is contained in:
Sebastian 2020-06-07 21:58:48 +01:00
parent 8de65f3d34
commit 9d4eb74bf0
13 changed files with 254 additions and 93 deletions

View File

@ -6,6 +6,7 @@
#include "ImGuiDelegatesContainer.h"
#include "ImGuiImplementation.h"
#include "ImGuiModuleSettings.h"
#include "Utilities/ScopeGuards.h"
#include "Utilities/WorldContext.h"
#include "Utilities/WorldContextIndex.h"
@ -59,11 +60,13 @@ namespace
#endif // WITH_EDITOR
}
FImGuiContextManager::FImGuiContextManager()
FImGuiContextManager::FImGuiContextManager(FImGuiModuleSettings& InSettings)
: Settings(InSettings)
{
unsigned char* Pixels;
int Width, Height, Bpp;
FontAtlas.GetTexDataAsRGBA32(&Pixels, &Width, &Height, &Bpp);
Settings.OnDPIScaleChangedDelegate.AddRaw(this, &FImGuiContextManager::SetDPIScale);
SetDPIScale(Settings.GetDPIScaleInfo());
BuildFontAtlas();
FWorldDelegates::OnWorldTickStart.AddRaw(this, &FImGuiContextManager::OnWorldTickStart);
#if ENGINE_COMPATIBILITY_WITH_WORLD_POST_ACTOR_TICK
@ -73,6 +76,8 @@ FImGuiContextManager::FImGuiContextManager()
FImGuiContextManager::~FImGuiContextManager()
{
Settings.OnDPIScaleChangedDelegate.RemoveAll(this);
// Order matters because contexts can be created during World Tick Start events.
FWorldDelegates::OnWorldTickStart.RemoveAll(this);
#if ENGINE_COMPATIBILITY_WITH_WORLD_POST_ACTOR_TICK
@ -98,6 +103,13 @@ void FImGuiContextManager::Tick(float DeltaSeconds)
FImGuiDelegatesContainer::Get().OnWorldDebug(Pair.Key).Clear();
}
}
// Once all context tick they should use new fonts and we can release the old resources. Extra countdown is added
// wait for contexts that ticked outside of this function, before rebuilding fonts.
if (FontResourcesReleaseCountdown > 0 && !--FontResourcesReleaseCountdown)
{
FontResourcesToRelease.Empty();
}
}
#if ENGINE_COMPATIBILITY_LEGACY_WORLD_ACTOR_TICK
@ -142,8 +154,8 @@ FImGuiContextManager::FContextData& FImGuiContextManager::GetEditorContextData()
if (UNLIKELY(!Data))
{
Data = &Contexts.Emplace(Utilities::EDITOR_CONTEXT_INDEX, FContextData{ GetEditorContextName(), Utilities::EDITOR_CONTEXT_INDEX, DrawMultiContextEvent, FontAtlas, -1 });
ContextProxyCreatedEvent.Broadcast(Utilities::EDITOR_CONTEXT_INDEX, *Data->ContextProxy);
Data = &Contexts.Emplace(Utilities::EDITOR_CONTEXT_INDEX, FContextData{ GetEditorContextName(), Utilities::EDITOR_CONTEXT_INDEX, OnDrawMultiContext, FontAtlas, -1 });
OnContextProxyCreated.Broadcast(Utilities::EDITOR_CONTEXT_INDEX, *Data->ContextProxy);
}
return *Data;
@ -199,8 +211,8 @@ FImGuiContextManager::FContextData& FImGuiContextManager::GetWorldContextData(co
#if WITH_EDITOR
if (UNLIKELY(!Data))
{
Data = &Contexts.Emplace(Index, FContextData{ GetWorldContextName(World), Index, DrawMultiContextEvent, FontAtlas, WorldContext->PIEInstance });
ContextProxyCreatedEvent.Broadcast(Index, *Data->ContextProxy);
Data = &Contexts.Emplace(Index, FContextData{ GetWorldContextName(World), Index, OnDrawMultiContext, FontAtlas, WorldContext->PIEInstance });
OnContextProxyCreated.Broadcast(Index, *Data->ContextProxy);
}
else
{
@ -221,3 +233,95 @@ FImGuiContextManager::FContextData& FImGuiContextManager::GetWorldContextData(co
}
return *Data;
}
struct FGuardContext
{
FGuardContext()
: OldContext(ImGui::GetCurrentContext())
{
}
~FGuardContext()
{
if (bRestore)
{
ImGui::SetCurrentContext(OldContext);
}
}
FGuardContext(FGuardContext&& Other)
: OldContext(MoveTemp(Other.OldContext))
{
Other.bRestore = false;
}
FGuardContext& operator=(FGuardContext&&) = delete;
FGuardContext(const FGuardContext&) = delete;
FGuardContext& operator=(const FGuardContext&) = delete;
private:
ImGuiContext* OldContext = nullptr;
bool bRestore = true;
};
void FImGuiContextManager::SetDPIScale(const FImGuiDPIScaleInfo& ScaleInfo)
{
const float Scale = ScaleInfo.GetImGuiScale();
if (DPIScale != Scale)
{
DPIScale = Scale;
// Only rebuild font atlas if it is already built. Otherwise allow the other logic to pick a moment.
if (FontAtlas.IsBuilt())
{
RebuildFontAtlas();
}
for (auto& Pair : Contexts)
{
if (Pair.Value.ContextProxy)
{
ImGuiStyle NewStyle = ImGuiStyle();
NewStyle.ScaleAllSizes(DPIScale);
FGuardContext GuardContext;
Pair.Value.ContextProxy->SetAsCurrent();
ImGui::GetStyle() = MoveTemp(NewStyle);
}
}
}
}
void FImGuiContextManager::BuildFontAtlas()
{
if (!FontAtlas.IsBuilt())
{
ImFontConfig FontConfig = {};
FontConfig.SizePixels = FMath::RoundFromZero(13.f * DPIScale);
FontAtlas.AddFontDefault(&FontConfig);
unsigned char* Pixels;
int Width, Height, Bpp;
FontAtlas.GetTexDataAsRGBA32(&Pixels, &Width, &Height, &Bpp);
OnFontAtlasBuilt.Broadcast();
}
}
void FImGuiContextManager::RebuildFontAtlas()
{
if (FontAtlas.IsBuilt())
{
// Keep the old resources alive for a few frames to give all contexts a chance to bind to new ones.
FontResourcesToRelease.Add(TUniquePtr<ImFontAtlas>(new ImFontAtlas()));
Swap(*FontResourcesToRelease.Last(), FontAtlas);
// Typically, one frame should be enough but since we allow for custom ticking, we need at least to frames to
// wait for contexts that already ticked and will not do that before the end of the next tick of this manager.
FontResourcesReleaseCountdown = 3;
}
BuildFontAtlas();
}

View File

@ -5,6 +5,8 @@
#include "ImGuiContextProxy.h"
class FImGuiModuleSettings;
// TODO: It might be useful to broadcast FContextProxyCreatedDelegate to users, to support similar cases to our ImGui
// demo, but we would need to remove from that interface internal classes.
@ -18,7 +20,7 @@ class FImGuiContextManager
{
public:
FImGuiContextManager();
FImGuiContextManager(FImGuiModuleSettings& InSettings);
FImGuiContextManager(const FImGuiContextManager&) = delete;
FImGuiContextManager& operator=(const FImGuiContextManager&) = delete;
@ -31,7 +33,6 @@ public:
ImFontAtlas& GetFontAtlas() { return FontAtlas; }
const ImFontAtlas& GetFontAtlas() const { return FontAtlas; }
#if WITH_EDITOR
// Get or create editor ImGui context proxy.
FORCEINLINE FImGuiContextProxy& GetEditorContextProxy() { return *GetEditorContextData().ContextProxy; }
@ -57,10 +58,13 @@ public:
// Delegate called for all contexts in manager, right after calling context specific draw event. Allows listeners
// draw the same content to multiple contexts.
FSimpleMulticastDelegate& OnDrawMultiContext() { return DrawMultiContextEvent; }
FSimpleMulticastDelegate OnDrawMultiContext;
// Delegate called when new context proxy is created.
FContextProxyCreatedDelegate& OnContextProxyCreated() { return ContextProxyCreatedEvent; }
// Delegate called when a new context proxy is created.
FContextProxyCreatedDelegate OnContextProxyCreated;
// Delegate called after font atlas is built.
FSimpleMulticastDelegate OnFontAtlasBuilt;
void Tick(float DeltaSeconds);
@ -99,11 +103,17 @@ private:
FContextData& GetWorldContextData(const UWorld& World, int32* OutContextIndex = nullptr);
void SetDPIScale(const FImGuiDPIScaleInfo& ScaleInfo);
void BuildFontAtlas();
void RebuildFontAtlas();
TMap<int32, FContextData> Contexts;
FSimpleMulticastDelegate DrawMultiContextEvent;
FContextProxyCreatedDelegate ContextProxyCreatedEvent;
ImFontAtlas FontAtlas;
TArray<TUniquePtr<ImFontAtlas>> FontResourcesToRelease;
FImGuiModuleSettings& Settings;
float DPIScale = -1.f;
int32 FontResourcesReleaseCountdown = 0;
};

View File

@ -95,7 +95,7 @@ FImGuiDelegateHandle FImGuiModule::AddMultiContextImGuiDelegate(const FImGuiDele
#else
checkf(ImGuiModuleManager, TEXT("Null pointer to internal module implementation. Is module available?"));
return { ImGuiModuleManager->GetContextManager().OnDrawMultiContext().Add(Delegate), EDelegateCategory::MultiContext };
return { ImGuiModuleManager->GetContextManager().OnDrawMultiContext.Add(Delegate), EDelegateCategory::MultiContext };
#endif
}
@ -115,7 +115,7 @@ void FImGuiModule::RemoveImGuiDelegate(const FImGuiDelegateHandle& Handle)
{
if (Handle.Category == EDelegateCategory::MultiContext)
{
ImGuiModuleManager->GetContextManager().OnDrawMultiContext().Remove(Handle.Handle);
ImGuiModuleManager->GetContextManager().OnDrawMultiContext.Remove(Handle.Handle);
}
else if (auto* Proxy = ImGuiModuleManager->GetContextManager().GetContextProxy(Handle.Index))
{
@ -135,7 +135,13 @@ FImGuiTextureHandle FImGuiModule::FindTextureHandle(const FName& Name)
FImGuiTextureHandle FImGuiModule::RegisterTexture(const FName& Name, class UTexture2D* Texture, bool bMakeUnique)
{
const TextureIndex Index = ImGuiModuleManager->GetTextureManager().CreateTextureResources(Name, Texture, bMakeUnique);
FTextureManager& TextureManager = ImGuiModuleManager->GetTextureManager();
checkf(!bMakeUnique || TextureManager.FindTextureIndex(Name) == INDEX_NONE,
TEXT("Trying to register a texture with a name '%s' that is already used. Chose a different name ")
TEXT("or use bMakeUnique false, to update existing texture resources."), *Name.ToString());
const TextureIndex Index = TextureManager.CreateTextureResources(Name, Texture);
return FImGuiTextureHandle{ Name, ImGuiInterops::ToImTextureID(Index) };
}

View File

@ -15,14 +15,18 @@
// High enough z-order guarantees that ImGui output is rendered on top of the game UI.
constexpr int32 IMGUI_WIDGET_Z_ORDER = 10000;
// Module texture names.
const static FName PlainTextureName = "ImGuiModule_Plain";
const static FName FontAtlasTextureName = "ImGuiModule_FontAtlas";
FImGuiModuleManager::FImGuiModuleManager()
: Commands(Properties)
, Settings(Properties, Commands)
, ImGuiDemo(Properties)
, ContextManager(Settings)
{
// Register in context manager to get information whenever a new context proxy is created.
ContextManager.OnContextProxyCreated().AddRaw(this, &FImGuiModuleManager::OnContextProxyCreated);
ContextManager.OnContextProxyCreated.AddRaw(this, &FImGuiModuleManager::OnContextProxyCreated);
// Typically we will use viewport created events to add widget to new game viewports.
ViewportCreatedHandle = UGameViewportClient::OnViewportCreated().AddRaw(this, &FImGuiModuleManager::OnViewportCreated);
@ -43,6 +47,8 @@ FImGuiModuleManager::FImGuiModuleManager()
FImGuiModuleManager::~FImGuiModuleManager()
{
ContextManager.OnFontAtlasBuilt.RemoveAll(this);
// We are no longer interested with adding widgets to viewports.
if (ViewportCreatedHandle.IsValid())
{
@ -80,8 +86,17 @@ void FImGuiModuleManager::LoadTextures()
TextureManager.InitializeErrorTexture(FColor::Magenta);
// Create an empty texture at index 0. We will use it for ImGui outputs with null texture id.
TextureManager.CreatePlainTexture(FName{ "ImGuiModule_Plain" }, 2, 2, FColor::White);
TextureManager.CreatePlainTexture(PlainTextureName, 2, 2, FColor::White);
// Register for atlas built events, so we can rebuild textures.
ContextManager.OnFontAtlasBuilt.AddRaw(this, &FImGuiModuleManager::BuildFontAtlasTexture);
BuildFontAtlasTexture();
}
}
void FImGuiModuleManager::BuildFontAtlasTexture()
{
// Create a font atlas texture.
ImFontAtlas& Fonts = ContextManager.GetFontAtlas();
@ -89,11 +104,10 @@ void FImGuiModuleManager::LoadTextures()
int Width, Height, Bpp;
Fonts.GetTexDataAsRGBA32(&Pixels, &Width, &Height, &Bpp);
TextureIndex FontsTexureIndex = TextureManager.CreateTexture(FName{ "ImGuiModule_FontAtlas" }, Width, Height, Bpp, Pixels);
const TextureIndex FontsTexureIndex = TextureManager.CreateTexture(FontAtlasTextureName, Width, Height, Bpp, Pixels);
// Set font texture index in ImGui.
// Set the font texture index in the ImGui.
Fonts.TexID = ImGuiInterops::ToImTextureID(FontsTexureIndex);
}
}
void FImGuiModuleManager::RegisterTick()

View File

@ -46,6 +46,7 @@ private:
FImGuiModuleManager& operator=(FImGuiModuleManager&&) = delete;
void LoadTextures();
void BuildFontAtlasTexture();
bool IsTickRegistered() { return TickDelegateHandle.IsValid(); }
void RegisterTick();

View File

@ -104,7 +104,7 @@ void FImGuiModuleSettings::UpdateSettings()
SetUseSoftwareCursor(SettingsObject->bUseSoftwareCursor);
SetToggleInputKey(SettingsObject->ToggleInput);
SetCanvasSizeInfo(SettingsObject->CanvasSize);
SetDPIScale(SettingsObject->DPIScale);
SetDPIScaleInfo(SettingsObject->DPIScale);
}
}
@ -167,16 +167,16 @@ void FImGuiModuleSettings::SetCanvasSizeInfo(const FImGuiCanvasSizeInfo& CanvasS
if (CanvasSize != CanvasSizeInfo)
{
CanvasSize = CanvasSizeInfo;
OnCanvasSizeInfoChangeDelegate.Broadcast(CanvasSize);
OnCanvasSizeChangedDelegate.Broadcast(CanvasSize);
}
}
void FImGuiModuleSettings::SetDPIScale(float Scale)
void FImGuiModuleSettings::SetDPIScaleInfo(const FImGuiDPIScaleInfo& ScaleInfo)
{
if (DPIScale != Scale)
if (DPIScale != ScaleInfo)
{
DPIScale = Scale;
OnDPIScaleChangeDelegate.Broadcast(DPIScale);
DPIScale = ScaleInfo;
OnDPIScaleChangedDelegate.Broadcast(DPIScale);
}
}

View File

@ -88,6 +88,49 @@ struct FImGuiCanvasSizeInfo
bool operator!=(const FImGuiCanvasSizeInfo& Other) const { return !(*this == Other); }
};
UENUM(BlueprintType)
enum class EImGuiDPIScaleMethod : uint8
{
ImGui UMETA(DisplayName = "ImGui", ToolTip = "Scale ImGui fonts and styles."),
Slate UMETA(ToolTip = "Scale in Slate. ImGui canvas size will be adjusted to get the screen size that is the same as defined in the Canvas Size property.")
};
/**
* Struct with DPI scale data.
*/
USTRUCT()
struct FImGuiDPIScaleInfo
{
GENERATED_BODY()
protected:
// Whether to scale in ImGui or in Slate. Scaling in ImGui gives better looking results but Slate might be a better
// option when layouts do not account for different fonts and styles. When scaling in Slate, ImGui canvas size will
// be adjusted to get the screen size that is the same as defined in the Canvas Size property.
UPROPERTY(EditAnywhere, Category = "DPI Scale")
EImGuiDPIScaleMethod ScalingMethod = EImGuiDPIScaleMethod::ImGui;
// Fixed scale.
UPROPERTY(EditAnywhere, Category = "DPI Scale", meta = (ClampMin = 0, UIMin = 0))
float Scale = 1.f;
public:
float GetImGuiScale() const { return ShouldScaleInSlate() ? 1.f : Scale; }
float GetSlateScale() const { return ShouldScaleInSlate() ? Scale : 1.f; }
bool ShouldScaleInSlate() const { return ScalingMethod == EImGuiDPIScaleMethod::Slate; }
bool operator==(const FImGuiDPIScaleInfo& Other) const
{
return (Scale == Other.Scale) && (ScalingMethod == Other.ScalingMethod);
}
bool operator!=(const FImGuiDPIScaleInfo& Other) const { return !(*this == Other); }
};
// UObject used for loading and saving ImGui settings. To access actual settings use FImGuiModuleSettings interface.
UCLASS(config=ImGui, defaultconfig)
class UImGuiSettings : public UObject
@ -148,13 +191,9 @@ protected:
UPROPERTY(EditAnywhere, config, Category = "Canvas Size")
FImGuiCanvasSizeInfo CanvasSize;
// DPI scale for the ImGui widgets.
//
// Note that when this scale is other than 1.0, canvas size will be scaled before it is passed to the ImGui.
// It will be scaled to keep the same screen size as defined by the Canvas Size property. If the default
// canvas size is 3840x2160 and the DPI scale is 2.0, the size passed to the ImGui will be 1920x1080.
UPROPERTY(EditAnywhere, Category = "DPI Scale", meta = (ClampMin = 0, UIMin = 0))
float DPIScale = 1.f;
// Setup DPI Scale.
UPROPERTY(EditAnywhere, config, Category = "DPI Scale", Meta = (ShowOnlyInnerProperties))
FImGuiDPIScaleInfo DPIScale;
// Deprecated name for ToggleInput. Kept temporarily to automatically move old configuration.
UPROPERTY(config)
@ -178,9 +217,9 @@ public:
// Generic delegate used to notify changes of boolean properties.
DECLARE_MULTICAST_DELEGATE_OneParam(FBoolChangeDelegate, bool);
DECLARE_MULTICAST_DELEGATE_OneParam(FFloatChangeDelegate, float);
DECLARE_MULTICAST_DELEGATE_OneParam(FStringClassReferenceChangeDelegate, const FStringClassReference&);
DECLARE_MULTICAST_DELEGATE_OneParam(FImGuiCanvasSizeInfoChangeDelegate, const FImGuiCanvasSizeInfo&);
DECLARE_MULTICAST_DELEGATE_OneParam(FImGuiDPIScaleInfoChangeDelegate, const FImGuiDPIScaleInfo&);
// Constructor for ImGui module settings. It will bind to instances of module properties and commands and will
// update them every time when settings are changed.
@ -206,8 +245,8 @@ public:
// Get the information how to calculate the canvas size.
const FImGuiCanvasSizeInfo& GetCanvasSizeInfo() const { return CanvasSize; }
// Get the DPI Scale.
float GetDPIScale() const { return DPIScale; }
// Get the DPI Scale information.
const FImGuiDPIScaleInfo& GetDPIScaleInfo() const { return DPIScale; }
// Delegate raised when ImGui Input Handle is changed.
FStringClassReferenceChangeDelegate OnImGuiInputHandlerClassChanged;
@ -216,10 +255,10 @@ public:
FBoolChangeDelegate OnUseSoftwareCursorChanged;
// Delegate raised when information how to calculate the canvas size is changed.
FImGuiCanvasSizeInfoChangeDelegate OnCanvasSizeInfoChangeDelegate;
FImGuiCanvasSizeInfoChangeDelegate OnCanvasSizeChangedDelegate;
// Delegate raised when the DPI scale is changed.
FFloatChangeDelegate OnDPIScaleChangeDelegate;
FImGuiDPIScaleInfoChangeDelegate OnDPIScaleChangedDelegate;
private:
@ -232,7 +271,7 @@ private:
void SetUseSoftwareCursor(bool bUse);
void SetToggleInputKey(const FImGuiKeyInfo& KeyInfo);
void SetCanvasSizeInfo(const FImGuiCanvasSizeInfo& CanvasSizeInfo);
void SetDPIScale(float DPIScale);
void SetDPIScaleInfo(const FImGuiDPIScaleInfo& ScaleInfo);
#if WITH_EDITOR
void OnPropertyChanged(class UObject* ObjectBeingModified, struct FPropertyChangedEvent& PropertyChangedEvent);
@ -244,7 +283,7 @@ private:
FStringClassReference ImGuiInputHandlerClass;
FImGuiKeyInfo ToggleInputKey;
FImGuiCanvasSizeInfo CanvasSize;
float DPIScale = 1.f;
FImGuiDPIScaleInfo DPIScale;
bool bShareKeyboardInput = false;
bool bShareGamepadInput = false;
bool bShareMouseInput = false;

View File

@ -15,7 +15,6 @@ void FTextureManager::InitializeErrorTexture(const FColor& Color)
TextureIndex FTextureManager::CreateTexture(const FName& Name, int32 Width, int32 Height, uint32 SrcBpp, uint8* SrcData, TFunction<void(uint8*)> SrcDataCleanup)
{
checkf(Name != NAME_None, TEXT("Trying to create a texture with a name 'NAME_None' is not allowed."));
checkf(FindTextureIndex(Name) == INDEX_NONE, TEXT("Trying to create texture using name '%s' that is already registered."), *Name.ToString());
return CreateTextureInternal(Name, Width, Height, SrcBpp, SrcData, SrcDataCleanup);
}
@ -23,24 +22,17 @@ TextureIndex FTextureManager::CreateTexture(const FName& Name, int32 Width, int3
TextureIndex FTextureManager::CreatePlainTexture(const FName& Name, int32 Width, int32 Height, FColor Color)
{
checkf(Name != NAME_None, TEXT("Trying to create a texture with a name 'NAME_None' is not allowed."));
checkf(FindTextureIndex(Name) == INDEX_NONE, TEXT("Trying to create texture using name '%s' that is already registered."), *Name.ToString());
return CreatePlainTextureInternal(Name, Width, Height, Color);
}
TextureIndex FTextureManager::CreateTextureResources(const FName& Name, UTexture2D* Texture, bool bMakeUnique)
TextureIndex FTextureManager::CreateTextureResources(const FName& Name, UTexture2D* Texture)
{
checkf(Name != NAME_None, TEXT("Trying to create texture resources with a name 'NAME_None' is not allowed."));
checkf(Texture, TEXT("Null Texture."));
if (bMakeUnique)
{
checkf(FindTextureIndex(Name) == INDEX_NONE, TEXT("Trying to create texture resources using name '%s' that is already registered.")
TEXT(" Consider using different name or set bMakeUnique parameter to false."), *Name.ToString());
}
// Create an entry for the texture.
return AddTextureEntry(Name, Texture, false, true);
return AddTextureEntry(Name, Texture, false);
}
void FTextureManager::ReleaseTextureResources(TextureIndex Index)
@ -75,7 +67,7 @@ TextureIndex FTextureManager::CreateTextureInternal(const FName& Name, int32 Wid
}
else
{
return AddTextureEntry(Name, Texture, true, false);
return AddTextureEntry(Name, Texture, true);
}
}
@ -94,18 +86,18 @@ TextureIndex FTextureManager::CreatePlainTextureInternal(const FName& Name, int3
return CreateTextureInternal(Name, Width, Height, Bpp, SrcData, SrcDataCleanup);
}
TextureIndex FTextureManager::AddTextureEntry(const FName& Name, UTexture2D* Texture, bool bAddToRoot, bool bUpdate)
TextureIndex FTextureManager::AddTextureEntry(const FName& Name, UTexture2D* Texture, bool bAddToRoot)
{
// If we update try to find entry with that name.
TextureIndex Index = bUpdate ? FindTextureIndex(Name) : INDEX_NONE;
// Try to find an entry with that name.
TextureIndex Index = FindTextureIndex(Name);
// If we didn't find, try to find and entry to reuse.
// If this is a new name, try to find an entry to reuse.
if (Index == INDEX_NONE)
{
Index = FindTextureIndex(NAME_None);
}
// Either update/reuse entry or add a new one.
// Either update/reuse an entry or add a new one.
if (Index != INDEX_NONE)
{
TextureResources[Index] = { Name, Texture, bAddToRoot };

View File

@ -60,7 +60,7 @@ public:
return IsValidTexture(Index) ? TextureResources[Index].ResourceHandle : ErrorTexture.ResourceHandle;
}
// Create a texture from raw data. Throws exception if there is already a texture with that name.
// Create a texture from raw data.
// @param Name - The texture name
// @param Width - The texture width
// @param Height - The texture height
@ -70,7 +70,7 @@ public:
// @returns The index of a texture that was created
TextureIndex CreateTexture(const FName& Name, int32 Width, int32 Height, uint32 SrcBpp, uint8* SrcData, TFunction<void(uint8*)> SrcDataCleanup = [](uint8*) {});
// Create a plain texture. Throws exception if there is already a texture with that name.
// Create a plain texture.
// @param Name - The texture name
// @param Width - The texture width
// @param Height - The texture height
@ -78,16 +78,11 @@ public:
// @returns The index of a texture that was created
TextureIndex CreatePlainTexture(const FName& Name, int32 Width, int32 Height, FColor Color);
// Create Slate resources to an existing texture, managed externally. As part of an external interface it allows
// to loosen resource verification policy. By default (consistently with other create function) it protects from
// creating resources with name that is already registered. If bMakeUnique is false, then existing resources are
// updated/replaced. Throws exception, if name argument is NAME_None or texture is null.
// Create Slate resources to an existing texture, managed externally.
// @param Name - The texture name
// @param Texture - The texture
// @param bMakeUnique - If true (default) and there is already a texture with given name, then exception is thrown,
// otherwise existing resources are updated.
// @returns The index to created/updated texture resources
TextureIndex CreateTextureResources(const FName& Name, UTexture2D* Texture, bool bMakeUnique = true);
TextureIndex CreateTextureResources(const FName& Name, UTexture2D* Texture);
// Release resources for given texture. Ignores invalid indices.
// @param Index - The index of a texture resources
@ -110,7 +105,7 @@ private:
// @param Texture - The texture
// @param bAddToRoot - If true, we should add texture to root to prevent garbage collection (use for own textures)
// @returns The index of the entry that we created or reused
TextureIndex AddTextureEntry(const FName& Name, UTexture2D* Texture, bool bAddToRoot, bool bUpdate);
TextureIndex AddTextureEntry(const FName& Name, UTexture2D* Texture, bool bAddToRoot);
// Check whether index is in range allocated for TextureResources (it doesn't mean that resources are valid).
FORCEINLINE bool IsInRange(TextureIndex Index) const

View File

@ -23,10 +23,10 @@ void SImGuiLayout::Construct(const FArguments& InArgs)
if (ModuleManager)
{
auto& Settings = ModuleManager->GetSettings();
SetDPIScale(Settings.GetDPIScale());
if (!Settings.OnDPIScaleChangeDelegate.IsBoundToObject(this))
SetDPIScale(Settings.GetDPIScaleInfo());
if (!Settings.OnDPIScaleChangedDelegate.IsBoundToObject(this))
{
Settings.OnDPIScaleChangeDelegate.AddRaw(this, &SImGuiLayout::SetDPIScale);
Settings.OnDPIScaleChangedDelegate.AddRaw(this, &SImGuiLayout::SetDPIScale);
}
}
@ -71,7 +71,7 @@ SImGuiLayout::~SImGuiLayout()
{
if (ModuleManager)
{
ModuleManager->GetSettings().OnDPIScaleChangeDelegate.RemoveAll(this);
ModuleManager->GetSettings().OnDPIScaleChangedDelegate.RemoveAll(this);
}
}

View File

@ -31,8 +31,7 @@ public:
private:
float GetDPIScale() const { return DPIScale; }
void SetDPIScale(float Scale) { DPIScale = Scale; }
void SetDPIScale(const FImGuiDPIScaleInfo& ScaleInfo) { DPIScale = ScaleInfo.GetSlateScale(); }
FImGuiModuleManager* ModuleManager = nullptr;
TWeakObjectPtr<UGameViewportClient> GameViewport;

View File

@ -84,7 +84,7 @@ void SImGuiWidget::Construct(const FArguments& InArgs)
const auto& Settings = ModuleManager->GetSettings();
SetHideMouseCursor(Settings.UseSoftwareCursor());
CreateInputHandler(Settings.GetImGuiInputHandlerClass());
SetDPIScale(Settings.GetDPIScale());
SetDPIScale(Settings.GetDPIScaleInfo());
SetCanvasSizeInfo(Settings.GetCanvasSizeInfo());
// Initialize state.
@ -284,13 +284,13 @@ void SImGuiWidget::RegisterImGuiSettingsDelegates()
{
Settings.OnUseSoftwareCursorChanged.AddRaw(this, &SImGuiWidget::SetHideMouseCursor);
}
if (!Settings.OnDPIScaleChangeDelegate.IsBoundToObject(this))
if (!Settings.OnDPIScaleChangedDelegate.IsBoundToObject(this))
{
Settings.OnDPIScaleChangeDelegate.AddRaw(this, &SImGuiWidget::SetDPIScale);
Settings.OnDPIScaleChangedDelegate.AddRaw(this, &SImGuiWidget::SetDPIScale);
}
if (!Settings.OnCanvasSizeInfoChangeDelegate.IsBoundToObject(this))
if (!Settings.OnCanvasSizeChangedDelegate.IsBoundToObject(this))
{
Settings.OnCanvasSizeInfoChangeDelegate.AddRaw(this, &SImGuiWidget::SetCanvasSizeInfo);
Settings.OnCanvasSizeChangedDelegate.AddRaw(this, &SImGuiWidget::SetCanvasSizeInfo);
}
}
@ -300,8 +300,8 @@ void SImGuiWidget::UnregisterImGuiSettingsDelegates()
Settings.OnImGuiInputHandlerClassChanged.RemoveAll(this);
Settings.OnUseSoftwareCursorChanged.RemoveAll(this);
Settings.OnDPIScaleChangeDelegate.RemoveAll(this);
Settings.OnCanvasSizeInfoChangeDelegate.RemoveAll(this);
Settings.OnDPIScaleChangedDelegate.RemoveAll(this);
Settings.OnCanvasSizeChangedDelegate.RemoveAll(this);
}
void SImGuiWidget::SetHideMouseCursor(bool bHide)
@ -509,8 +509,9 @@ void SImGuiWidget::HandleWindowFocusLost()
}
}
void SImGuiWidget::SetDPIScale(float Scale)
void SImGuiWidget::SetDPIScale(const FImGuiDPIScaleInfo& ScaleInfo)
{
const float Scale = ScaleInfo.GetSlateScale();
if (DPIScale != Scale)
{
DPIScale = Scale;

View File

@ -103,7 +103,7 @@ private:
void UpdateTransparentMouseInput(const FGeometry& AllottedGeometry);
void HandleWindowFocusLost();
void SetDPIScale(float Scale);
void SetDPIScale(const FImGuiDPIScaleInfo& ScaleInfo);
void SetCanvasSizeInfo(const FImGuiCanvasSizeInfo& CanvasSizeInfo);
void UpdateCanvasSize();