606 lines
19 KiB
C++
606 lines
19 KiB
C++
|
|
// Voir LPVideoQualitySubsystem.h.
|
||
|
|
|
||
|
|
#include "LPVideoQualitySubsystem.h"
|
||
|
|
|
||
|
|
#include "Blueprint/UserWidget.h"
|
||
|
|
#include "Components/Button.h"
|
||
|
|
#include "Components/ButtonSlot.h"
|
||
|
|
#include "Components/HorizontalBox.h"
|
||
|
|
#include "Components/HorizontalBoxSlot.h"
|
||
|
|
#include "Components/PanelWidget.h"
|
||
|
|
#include "Components/ScrollBox.h"
|
||
|
|
#include "Components/ScrollBoxSlot.h"
|
||
|
|
#include "Components/SizeBox.h"
|
||
|
|
#include "Components/Slider.h"
|
||
|
|
#include "Components/TextBlock.h"
|
||
|
|
#include "Engine/GameInstance.h"
|
||
|
|
#include "Engine/World.h"
|
||
|
|
#include "HAL/IConsoleManager.h"
|
||
|
|
#include "LifePlay.h"
|
||
|
|
#include "Misc/ConfigCacheIni.h"
|
||
|
|
#include "Misc/Paths.h"
|
||
|
|
#include "DynamicRHI.h"
|
||
|
|
#include "RHI.h"
|
||
|
|
#include "RHIStats.h"
|
||
|
|
#include "Scalability.h"
|
||
|
|
#include "Styling/CoreStyle.h"
|
||
|
|
#include "Styling/SlateTypes.h"
|
||
|
|
|
||
|
|
namespace LPVideoQuality
|
||
|
|
{
|
||
|
|
constexpr int32 MaxLevel = 3;
|
||
|
|
// Niveau retenu quand la VRAM est inconnue (0 ou -1) : High.
|
||
|
|
constexpr int32 RecommendedUnknownLevel = 2;
|
||
|
|
|
||
|
|
// VRAM dediee en octets, 0 si inconnue (RHI absent, -nullrhi, valeur non renseignee).
|
||
|
|
int64 QueryDedicatedVideoMemoryBytes()
|
||
|
|
{
|
||
|
|
if (!GDynamicRHI)
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
FTextureMemoryStats Stats;
|
||
|
|
RHIGetTextureMemoryStats(Stats);
|
||
|
|
return FMath::Max<int64>(Stats.DedicatedVideoMemory, 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
// <4 Go Low, <6 Med, <10 High, sinon Epic ; 0 Go (inconnu) = High.
|
||
|
|
int32 LevelFromVramGB(double VramGB)
|
||
|
|
{
|
||
|
|
if (VramGB <= 0.0)
|
||
|
|
{
|
||
|
|
return RecommendedUnknownLevel;
|
||
|
|
}
|
||
|
|
if (VramGB < 4.0)
|
||
|
|
{
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
if (VramGB < 6.0)
|
||
|
|
{
|
||
|
|
return 1;
|
||
|
|
}
|
||
|
|
if (VramGB < 10.0)
|
||
|
|
{
|
||
|
|
return 2;
|
||
|
|
}
|
||
|
|
return 3;
|
||
|
|
}
|
||
|
|
|
||
|
|
FString IniPath()
|
||
|
|
{
|
||
|
|
return FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("Config/Windows/LPVideoQuality.ini"));
|
||
|
|
}
|
||
|
|
|
||
|
|
FSlateFontInfo MenuFont()
|
||
|
|
{
|
||
|
|
FSlateFontInfo Font = FCoreStyle::GetDefaultFontStyle("Regular", 20);
|
||
|
|
Font.OutlineSettings.OutlineSize = 2;
|
||
|
|
Font.OutlineSettings.bApplyOutlineToDropShadows = true;
|
||
|
|
Font.OutlineSettings.OutlineColor = FLinearColor(0.f, 0.f, 0.f, 0.8f);
|
||
|
|
return Font;
|
||
|
|
}
|
||
|
|
|
||
|
|
void FindLook(UWidget* Widget, UTextBlock*& OutText, USlider*& OutSlider)
|
||
|
|
{
|
||
|
|
if (!Widget || (OutText && OutSlider))
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (!OutText)
|
||
|
|
{
|
||
|
|
OutText = Cast<UTextBlock>(Widget);
|
||
|
|
}
|
||
|
|
if (!OutSlider)
|
||
|
|
{
|
||
|
|
OutSlider = Cast<USlider>(Widget);
|
||
|
|
}
|
||
|
|
if (UUserWidget* User = Cast<UUserWidget>(Widget))
|
||
|
|
{
|
||
|
|
FindLook(User->GetRootWidget(), OutText, OutSlider);
|
||
|
|
}
|
||
|
|
if (UPanelWidget* Panel = Cast<UPanelWidget>(Widget))
|
||
|
|
{
|
||
|
|
for (int32 Index = 0; Index < Panel->GetChildrenCount() && !(OutText && OutSlider); ++Index)
|
||
|
|
{
|
||
|
|
FindLook(Panel->GetChildAt(Index), OutText, OutSlider);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int32 ClampLevel(int32 Level)
|
||
|
|
{
|
||
|
|
return FMath::Clamp(Level, 0, MaxLevel);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
FLPVideoLevels FLPVideoLevels::FromOverall(int32 Level)
|
||
|
|
{
|
||
|
|
const int32 Clamped = LPVideoQuality::ClampLevel(Level);
|
||
|
|
FLPVideoLevels Result;
|
||
|
|
Result.Overall = Clamped;
|
||
|
|
Result.Shadows = Clamped;
|
||
|
|
Result.Textures = Clamped;
|
||
|
|
Result.Effects = Clamped;
|
||
|
|
Result.AA = Clamped;
|
||
|
|
return Result;
|
||
|
|
}
|
||
|
|
|
||
|
|
void FLPVideoLevels::Normalize()
|
||
|
|
{
|
||
|
|
Shadows = LPVideoQuality::ClampLevel(Shadows);
|
||
|
|
Textures = LPVideoQuality::ClampLevel(Textures);
|
||
|
|
Effects = LPVideoQuality::ClampLevel(Effects);
|
||
|
|
AA = LPVideoQuality::ClampLevel(AA);
|
||
|
|
Overall = (Shadows == Textures && Textures == Effects && Effects == AA) ? Shadows : -1;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool FLPVideoLevels::operator==(const FLPVideoLevels& Other) const
|
||
|
|
{
|
||
|
|
return Overall == Other.Overall && Shadows == Other.Shadows && Textures == Other.Textures && Effects == Other.Effects && AA == Other.AA;
|
||
|
|
}
|
||
|
|
|
||
|
|
FString ULPVideoQualitySubsystem::LevelLabel(int32 Level)
|
||
|
|
{
|
||
|
|
switch (Level)
|
||
|
|
{
|
||
|
|
case 0: return TEXT("Low");
|
||
|
|
case 1: return TEXT("Med");
|
||
|
|
case 2: return TEXT("High");
|
||
|
|
case 3: return TEXT("Epic");
|
||
|
|
default: return TEXT("Custom");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||
|
|
{
|
||
|
|
Super::Initialize(Collection);
|
||
|
|
Load();
|
||
|
|
ApplyToScalability();
|
||
|
|
TickHandle = FTSTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateUObject(this, &ULPVideoQualitySubsystem::Tick), 0.5f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::Deinitialize()
|
||
|
|
{
|
||
|
|
FTSTicker::GetCoreTicker().RemoveTicker(TickHandle);
|
||
|
|
Super::Deinitialize();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ULPVideoQualitySubsystem::Tick(float DeltaTime)
|
||
|
|
{
|
||
|
|
(void)DeltaTime;
|
||
|
|
UWorld* World = GetWorld();
|
||
|
|
if (World && World->IsGameWorld() && LastAppliedWorld.Get() != World)
|
||
|
|
{
|
||
|
|
// Le Blueprint peut reappliquer ses valeurs au chargement d'un niveau.
|
||
|
|
LastAppliedWorld = World;
|
||
|
|
ApplyToScalability();
|
||
|
|
}
|
||
|
|
EnsureControls();
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::ReadFromScalability()
|
||
|
|
{
|
||
|
|
const Scalability::FQualityLevels Current = Scalability::GetQualityLevels();
|
||
|
|
Levels.Shadows = Current.ShadowQuality;
|
||
|
|
Levels.Textures = Current.TextureQuality;
|
||
|
|
Levels.Effects = Current.EffectsQuality;
|
||
|
|
Levels.AA = Current.AntiAliasingQuality;
|
||
|
|
Levels.Normalize();
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::Load()
|
||
|
|
{
|
||
|
|
// Valeurs de repli : etat Scalability courant (premier lancement).
|
||
|
|
ReadFromScalability();
|
||
|
|
const FString Ini = LPVideoQuality::IniPath();
|
||
|
|
FConfigFile File;
|
||
|
|
File.Read(Ini);
|
||
|
|
bool bAnyKey = false;
|
||
|
|
auto Read = [&File, &bAnyKey](const TCHAR* Key, int32& Out)
|
||
|
|
{
|
||
|
|
FString Text;
|
||
|
|
if (File.GetString(TEXT("LPVideoQuality"), Key, Text))
|
||
|
|
{
|
||
|
|
Out = FCString::Atoi(*Text);
|
||
|
|
bAnyKey = true;
|
||
|
|
}
|
||
|
|
};
|
||
|
|
// Overall est relu pour la trace mais ignore : Normalize() le recalcule.
|
||
|
|
int32 StoredOverall = Levels.Overall;
|
||
|
|
Read(TEXT("Overall"), StoredOverall);
|
||
|
|
Read(TEXT("Shadows"), Levels.Shadows);
|
||
|
|
Read(TEXT("Textures"), Levels.Textures);
|
||
|
|
Read(TEXT("Effects"), Levels.Effects);
|
||
|
|
Read(TEXT("AA"), Levels.AA);
|
||
|
|
Levels.Normalize();
|
||
|
|
if (bAnyKey)
|
||
|
|
{
|
||
|
|
bConfigured = true;
|
||
|
|
UE_LOG(LogLifePlay, Display, TEXT("Video : relu Overall %d, Shadows %d, Textures %d, Effects %d, AA %d depuis %s"), Levels.Overall, Levels.Shadows, Levels.Textures, Levels.Effects, Levels.AA, *Ini);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
bConfigured = false;
|
||
|
|
UE_LOG(LogLifePlay, Display, TEXT("Video : pas de %s, niveaux lus depuis Scalability (Overall %d, Shadows %d, Textures %d, Effects %d, AA %d)"), *Ini, Levels.Overall, Levels.Shadows, Levels.Textures, Levels.Effects, Levels.AA);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::Save() const
|
||
|
|
{
|
||
|
|
const FString Ini = LPVideoQuality::IniPath();
|
||
|
|
FConfigFile File;
|
||
|
|
File.Read(Ini);
|
||
|
|
auto Write = [&File](const TCHAR* Key, int32 Value)
|
||
|
|
{
|
||
|
|
File.SetString(TEXT("LPVideoQuality"), Key, *FString::FromInt(Value));
|
||
|
|
};
|
||
|
|
Write(TEXT("Version"), 1);
|
||
|
|
Write(TEXT("Overall"), Levels.Overall);
|
||
|
|
Write(TEXT("Shadows"), Levels.Shadows);
|
||
|
|
Write(TEXT("Textures"), Levels.Textures);
|
||
|
|
Write(TEXT("Effects"), Levels.Effects);
|
||
|
|
Write(TEXT("AA"), Levels.AA);
|
||
|
|
File.Write(Ini);
|
||
|
|
UE_LOG(LogLifePlay, Display, TEXT("Video : Overall %d, Shadows %d, Textures %d, Effects %d, AA %d enregistres dans %s"), Levels.Overall, Levels.Shadows, Levels.Textures, Levels.Effects, Levels.AA, *Ini);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::ApplyToScalability()
|
||
|
|
{
|
||
|
|
if (!bConfigured)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
// Ecrire uniquement les 4 sg.* en SetByConsole : SetQualityLevels appliquerait aussi
|
||
|
|
// r.ScreenPercentage / r.Streaming.PoolSize / r.SSS.Scale (souvent deja poses par le BP
|
||
|
|
// en SetByConsole) et spamait des warnings "SetByScalability ignored".
|
||
|
|
auto SetSg = [](const TCHAR* Name, int32 Value)
|
||
|
|
{
|
||
|
|
if (IConsoleVariable* Variable = IConsoleManager::Get().FindConsoleVariable(Name))
|
||
|
|
{
|
||
|
|
Variable->Set(Value, ECVF_SetByConsole);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
SetSg(TEXT("sg.ShadowQuality"), Levels.Shadows);
|
||
|
|
SetSg(TEXT("sg.TextureQuality"), Levels.Textures);
|
||
|
|
SetSg(TEXT("sg.EffectsQuality"), Levels.Effects);
|
||
|
|
SetSg(TEXT("sg.AntiAliasingQuality"), Levels.AA);
|
||
|
|
UE_LOG(LogLifePlay, Display, TEXT("Video : qualite appliquee (sg.ShadowQuality %d, sg.TextureQuality %d, sg.EffectsQuality %d, sg.AntiAliasingQuality %d)"), Levels.Shadows, Levels.Textures, Levels.Effects, Levels.AA);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::SetLevels(FLPVideoLevels NewLevels, bool bFromOverall)
|
||
|
|
{
|
||
|
|
if (bFromOverall && NewLevels.Overall >= 0)
|
||
|
|
{
|
||
|
|
NewLevels = FLPVideoLevels::FromOverall(NewLevels.Overall);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
NewLevels.Normalize();
|
||
|
|
}
|
||
|
|
Levels = NewLevels;
|
||
|
|
bConfigured = true;
|
||
|
|
ApplyToScalability();
|
||
|
|
RefreshWidgets();
|
||
|
|
Save();
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::RefreshWidgets()
|
||
|
|
{
|
||
|
|
if (bRefreshing)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
bRefreshing = true;
|
||
|
|
const int32 Values[NumRows] = {
|
||
|
|
Levels.Overall >= 0 ? Levels.Overall : LPVideoQuality::ClampLevel(FMath::RoundToInt((Levels.Shadows + Levels.Textures + Levels.Effects + Levels.AA) * 0.25f)),
|
||
|
|
Levels.Shadows, Levels.Textures, Levels.Effects, Levels.AA
|
||
|
|
};
|
||
|
|
for (int32 Index = 0; Index < NumRows; ++Index)
|
||
|
|
{
|
||
|
|
if (USlider* Slider = Rows[Index].Slider.Get())
|
||
|
|
{
|
||
|
|
Slider->SetValue(static_cast<float>(Values[Index]));
|
||
|
|
}
|
||
|
|
if (UTextBlock* Readout = Rows[Index].Readout.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LevelLabel(Index == RowOverall ? Levels.Overall : Values[Index])));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
bRefreshing = false;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::OnOverallChanged(float Value)
|
||
|
|
{
|
||
|
|
if (bRefreshing)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
SetLevels(FLPVideoLevels::FromOverall(FMath::RoundToInt(Value)), true);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::OnShadowsChanged(float Value)
|
||
|
|
{
|
||
|
|
if (bRefreshing)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
FLPVideoLevels L = Levels;
|
||
|
|
L.Shadows = LPVideoQuality::ClampLevel(FMath::RoundToInt(Value));
|
||
|
|
SetLevels(L, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::OnTexturesChanged(float Value)
|
||
|
|
{
|
||
|
|
if (bRefreshing)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
FLPVideoLevels L = Levels;
|
||
|
|
L.Textures = LPVideoQuality::ClampLevel(FMath::RoundToInt(Value));
|
||
|
|
SetLevels(L, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::OnEffectsChanged(float Value)
|
||
|
|
{
|
||
|
|
if (bRefreshing)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
FLPVideoLevels L = Levels;
|
||
|
|
L.Effects = LPVideoQuality::ClampLevel(FMath::RoundToInt(Value));
|
||
|
|
SetLevels(L, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::OnAAChanged(float Value)
|
||
|
|
{
|
||
|
|
if (bRefreshing)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
FLPVideoLevels L = Levels;
|
||
|
|
L.AA = LPVideoQuality::ClampLevel(FMath::RoundToInt(Value));
|
||
|
|
SetLevels(L, false);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::OnRecommendedClicked()
|
||
|
|
{
|
||
|
|
const int64 VramBytes = LPVideoQuality::QueryDedicatedVideoMemoryBytes();
|
||
|
|
const double VramGB = static_cast<double>(VramBytes) / (1024.0 * 1024.0 * 1024.0);
|
||
|
|
const int32 Level = LPVideoQuality::LevelFromVramGB(VramGB);
|
||
|
|
if (VramBytes > 0)
|
||
|
|
{
|
||
|
|
UE_LOG(LogLifePlay, Display, TEXT("Video : Recommended = %s (niveau %d), VRAM dediee detectee %.1f Go"), *LevelLabel(Level), Level, VramGB);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
UE_LOG(LogLifePlay, Display, TEXT("Video : Recommended = %s (niveau %d), VRAM dediee inconnue (0 Go), defaut High"), *LevelLabel(Level), Level);
|
||
|
|
}
|
||
|
|
SetLevels(FLPVideoLevels::FromOverall(Level), true);
|
||
|
|
}
|
||
|
|
|
||
|
|
USlider* ULPVideoQualitySubsystem::AddRow(ERow Row, UScrollBox* Scroll, UWidget*& OutRow, const TCHAR* Name, const TCHAR* Label, FName Handler, const TCHAR* Tip, const FSlateFontInfo& Font, const FSlateColor& Color, const FSliderStyle* SliderStyle)
|
||
|
|
{
|
||
|
|
UHorizontalBox* Box = NewObject<UHorizontalBox>(Scroll, Name);
|
||
|
|
UTextBlock* Caption = NewObject<UTextBlock>(Box);
|
||
|
|
Caption->SetText(FText::FromString(Label));
|
||
|
|
Caption->SetFont(Font);
|
||
|
|
Caption->SetColorAndOpacity(Color);
|
||
|
|
USizeBox* CaptionBox = NewObject<USizeBox>(Box);
|
||
|
|
CaptionBox->SetWidthOverride(220.f);
|
||
|
|
CaptionBox->AddChild(Caption);
|
||
|
|
USlider* Slider = NewObject<USlider>(Box);
|
||
|
|
if (SliderStyle)
|
||
|
|
{
|
||
|
|
Slider->SetWidgetStyle(*SliderStyle);
|
||
|
|
}
|
||
|
|
Slider->SetMinValue(0.f);
|
||
|
|
Slider->SetMaxValue(static_cast<float>(LPVideoQuality::MaxLevel));
|
||
|
|
Slider->SetStepSize(1.f);
|
||
|
|
Slider->SetLocked(false);
|
||
|
|
Slider->SetValue(0.f);
|
||
|
|
UTextBlock* Readout = NewObject<UTextBlock>(Box);
|
||
|
|
Readout->SetFont(Font);
|
||
|
|
Readout->SetColorAndOpacity(Color);
|
||
|
|
if (UHorizontalBoxSlot* Slot = Box->AddChildToHorizontalBox(CaptionBox))
|
||
|
|
{
|
||
|
|
Slot->SetVerticalAlignment(VAlign_Center);
|
||
|
|
Slot->SetPadding(FMargin(10.f, 0.f, 20.f, 0.f));
|
||
|
|
}
|
||
|
|
if (UHorizontalBoxSlot* Slot = Box->AddChildToHorizontalBox(Slider))
|
||
|
|
{
|
||
|
|
Slot->SetSize(FSlateChildSize(ESlateSizeRule::Fill));
|
||
|
|
Slot->SetVerticalAlignment(VAlign_Center);
|
||
|
|
Slot->SetPadding(FMargin(0.f, 0.f, 20.f, 0.f));
|
||
|
|
}
|
||
|
|
if (UHorizontalBoxSlot* Slot = Box->AddChildToHorizontalBox(Readout))
|
||
|
|
{
|
||
|
|
Slot->SetVerticalAlignment(VAlign_Center);
|
||
|
|
Slot->SetPadding(FMargin(0.f, 0.f, 10.f, 0.f));
|
||
|
|
}
|
||
|
|
Box->SetToolTipText(FText::FromString(Tip));
|
||
|
|
FScriptDelegate Delegate;
|
||
|
|
Delegate.BindUFunction(this, Handler);
|
||
|
|
Slider->OnValueChanged.Add(Delegate);
|
||
|
|
Rows[Row].Slider = Slider;
|
||
|
|
Rows[Row].Readout = Readout;
|
||
|
|
OutRow = Box;
|
||
|
|
return Slider;
|
||
|
|
}
|
||
|
|
|
||
|
|
UWidget* ULPVideoQualitySubsystem::MakeRecommendedRow(UScrollBox* Scroll, const FSlateFontInfo& Font, const FSlateColor& Color)
|
||
|
|
{
|
||
|
|
UHorizontalBox* Box = NewObject<UHorizontalBox>(Scroll, TEXT("LPVideoRecommended"));
|
||
|
|
UButton* Button = NewObject<UButton>(Box);
|
||
|
|
UTextBlock* Caption = NewObject<UTextBlock>(Button);
|
||
|
|
Caption->SetText(FText::FromString(TEXT("Recommended")));
|
||
|
|
Caption->SetFont(Font);
|
||
|
|
Caption->SetColorAndOpacity(Color);
|
||
|
|
Button->SetContent(Caption);
|
||
|
|
if (UButtonSlot* ContentSlot = Cast<UButtonSlot>(Caption->Slot))
|
||
|
|
{
|
||
|
|
ContentSlot->SetHorizontalAlignment(HAlign_Left);
|
||
|
|
ContentSlot->SetVerticalAlignment(VAlign_Center);
|
||
|
|
ContentSlot->SetPadding(FMargin(10.f));
|
||
|
|
}
|
||
|
|
FScriptDelegate Delegate;
|
||
|
|
Delegate.BindUFunction(this, GET_FUNCTION_NAME_CHECKED(ULPVideoQualitySubsystem, OnRecommendedClicked));
|
||
|
|
Button->OnClicked.Add(Delegate);
|
||
|
|
if (UHorizontalBoxSlot* Slot = Box->AddChildToHorizontalBox(Button))
|
||
|
|
{
|
||
|
|
Slot->SetVerticalAlignment(VAlign_Center);
|
||
|
|
Slot->SetHorizontalAlignment(HAlign_Left);
|
||
|
|
Slot->SetPadding(FMargin(10.f, 0.f, 0.f, 0.f));
|
||
|
|
}
|
||
|
|
Box->SetToolTipText(FText::FromString(TEXT("Apply the recommended preset for this PC.")));
|
||
|
|
RecommendedButton = Button;
|
||
|
|
return Box;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPVideoQualitySubsystem::EnsureControls()
|
||
|
|
{
|
||
|
|
UScrollBox* Scroll = nullptr;
|
||
|
|
for (TObjectIterator<UScrollBox> It; It; ++It)
|
||
|
|
{
|
||
|
|
UScrollBox* Candidate = *It;
|
||
|
|
if (!Candidate || Candidate->GetFName() != TEXT("SettingsScrollBox") || Candidate->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject))
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
const UUserWidget* Owner = Candidate->GetTypedOuter<UUserWidget>();
|
||
|
|
if (!Owner || Owner->HasAnyFlags(RF_ClassDefaultObject) || Owner->GetGameInstance() != GetGameInstance())
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
Scroll = Candidate;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (!Scroll)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
int32 InsertAt = INDEX_NONE;
|
||
|
|
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
||
|
|
{
|
||
|
|
if (UWidget* Child = Scroll->GetChildAt(Index))
|
||
|
|
{
|
||
|
|
if (Child->GetFName() == TEXT("LPVideoOverall"))
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (InsertAt == INDEX_NONE && Child->GetName().StartsWith(TEXT("LPColor")))
|
||
|
|
{
|
||
|
|
InsertAt = Index;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
UTextBlock* SampleText = nullptr;
|
||
|
|
USlider* SampleSlider = nullptr;
|
||
|
|
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
||
|
|
{
|
||
|
|
LPVideoQuality::FindLook(Scroll->GetChildAt(Index), SampleText, SampleSlider);
|
||
|
|
}
|
||
|
|
const FSlateFontInfo Font = SampleText ? SampleText->GetFont() : LPVideoQuality::MenuFont();
|
||
|
|
const FSlateColor Color = SampleText ? SampleText->GetColorAndOpacity() : FSlateColor(FLinearColor(1.f, 1.f, 1.f, 0.95f));
|
||
|
|
const FSliderStyle* SliderStyle = SampleSlider ? &SampleSlider->GetWidgetStyle() : nullptr;
|
||
|
|
|
||
|
|
// Nouvelle instance du menu : on repart de l'etat moteur tant que le joueur n'a rien choisi.
|
||
|
|
if (!bConfigured)
|
||
|
|
{
|
||
|
|
ReadFromScalability();
|
||
|
|
}
|
||
|
|
|
||
|
|
UWidget* Built[NumRows + 1] = { nullptr };
|
||
|
|
AddRow(RowOverall, Scroll, Built[0], TEXT("LPVideoOverall"), TEXT("Overall Quality"), GET_FUNCTION_NAME_CHECKED(ULPVideoQualitySubsystem, OnOverallChanged), TEXT("Preset applied to shadows, textures, effects and anti-aliasing. Custom when they differ."), Font, Color, SliderStyle);
|
||
|
|
AddRow(RowShadows, Scroll, Built[1], TEXT("LPVideoShadows"), TEXT("Shadows"), GET_FUNCTION_NAME_CHECKED(ULPVideoQualitySubsystem, OnShadowsChanged), TEXT("Shadow resolution and distance."), Font, Color, SliderStyle);
|
||
|
|
AddRow(RowTextures, Scroll, Built[2], TEXT("LPVideoTextures"), TEXT("Textures"), GET_FUNCTION_NAME_CHECKED(ULPVideoQualitySubsystem, OnTexturesChanged), TEXT("Texture filtering and streaming budget."), Font, Color, SliderStyle);
|
||
|
|
AddRow(RowEffects, Scroll, Built[3], TEXT("LPVideoEffects"), TEXT("Effects"), GET_FUNCTION_NAME_CHECKED(ULPVideoQualitySubsystem, OnEffectsChanged), TEXT("Translucency, refraction, subsurface scattering and particles."), Font, Color, SliderStyle);
|
||
|
|
AddRow(RowAA, Scroll, Built[4], TEXT("LPVideoAA"), TEXT("Anti-Aliasing"), GET_FUNCTION_NAME_CHECKED(ULPVideoQualitySubsystem, OnAAChanged), TEXT("Anti-aliasing quality. The method itself is fixed."), Font, Color, SliderStyle);
|
||
|
|
Built[5] = MakeRecommendedRow(Scroll, Font, Color);
|
||
|
|
|
||
|
|
bool bInserted = false;
|
||
|
|
if (InsertAt != INDEX_NONE)
|
||
|
|
{
|
||
|
|
bInserted = true;
|
||
|
|
for (int32 Index = 0; Index < NumRows + 1; ++Index)
|
||
|
|
{
|
||
|
|
UPanelSlot* PanelSlot = Scroll->InsertChildAt(InsertAt + Index, Built[Index]);
|
||
|
|
if (!PanelSlot)
|
||
|
|
{
|
||
|
|
bInserted = false;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
if (UScrollBoxSlot* Slot = Cast<UScrollBoxSlot>(PanelSlot))
|
||
|
|
{
|
||
|
|
Slot->SetPadding(FMargin(0.f, 0.f, 0.f, 10.f));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (!bInserted)
|
||
|
|
{
|
||
|
|
if (InsertAt != INDEX_NONE)
|
||
|
|
{
|
||
|
|
// Repli : InsertChildAt a echoue. On retire ce qui a pu etre insere, on ajoute en fin
|
||
|
|
// puis on remet les LPColor* derriere en conservant leurs objets.
|
||
|
|
UE_LOG(LogLifePlay, Warning, TEXT("Video : InsertChildAt a echoue, repli par AddChild et reordonnancement des reglages de couleur"));
|
||
|
|
for (UWidget* Row : Built)
|
||
|
|
{
|
||
|
|
if (Row && Row->GetParent() == Scroll)
|
||
|
|
{
|
||
|
|
Scroll->RemoveChild(Row);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for (UWidget* Row : Built)
|
||
|
|
{
|
||
|
|
if (UScrollBoxSlot* Slot = Cast<UScrollBoxSlot>(Scroll->AddChild(Row)))
|
||
|
|
{
|
||
|
|
Slot->SetPadding(FMargin(0.f, 0.f, 0.f, 10.f));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (InsertAt != INDEX_NONE)
|
||
|
|
{
|
||
|
|
TArray<UWidget*> Colors;
|
||
|
|
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
||
|
|
{
|
||
|
|
UWidget* Child = Scroll->GetChildAt(Index);
|
||
|
|
if (Child && Child->GetName().StartsWith(TEXT("LPColor")))
|
||
|
|
{
|
||
|
|
Colors.Add(Child);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for (UWidget* Child : Colors)
|
||
|
|
{
|
||
|
|
Scroll->RemoveChild(Child);
|
||
|
|
}
|
||
|
|
for (UWidget* Child : Colors)
|
||
|
|
{
|
||
|
|
if (UScrollBoxSlot* Slot = Cast<UScrollBoxSlot>(Scroll->AddChild(Child)))
|
||
|
|
{
|
||
|
|
Slot->SetPadding(FMargin(0.f, 0.f, 0.f, 10.f));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Les curseurs Blueprint remplaces par LPVideo* sont replies tout de suite ;
|
||
|
|
// LPSettingsSubsystem les garde replies au changement d'onglet.
|
||
|
|
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
||
|
|
{
|
||
|
|
if (UWidget* Child = Scroll->GetChildAt(Index))
|
||
|
|
{
|
||
|
|
const FName ChildName = Child->GetFName();
|
||
|
|
if (ChildName == TEXT("ShadowQuality") || ChildName == TEXT("PostProcessQuality") || ChildName == TEXT("PostProcessAAQuality"))
|
||
|
|
{
|
||
|
|
Child->SetVisibility(ESlateVisibility::Collapsed);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
RefreshWidgets();
|
||
|
|
// Nouvelle instance du menu : le Blueprint a pu reappliquer ses propres valeurs.
|
||
|
|
ApplyToScalability();
|
||
|
|
UE_LOG(LogLifePlay, Display, TEXT("Video : controles ajoutes avant les reglages de couleur"));
|
||
|
|
}
|