379 lines
12 KiB
C++
379 lines
12 KiB
C++
|
|
// Voir LPColorGradeSubsystem.h.
|
||
|
|
|
||
|
|
#include "LPColorGradeSubsystem.h"
|
||
|
|
|
||
|
|
#include "Blueprint/UserWidget.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/PostProcessVolume.h"
|
||
|
|
#include "Engine/World.h"
|
||
|
|
#include "LifePlay.h"
|
||
|
|
#include "Misc/ConfigCacheIni.h"
|
||
|
|
#include "Misc/Paths.h"
|
||
|
|
#include "Styling/CoreStyle.h"
|
||
|
|
#include "Styling/SlateTypes.h"
|
||
|
|
|
||
|
|
namespace LPColorGrade
|
||
|
|
{
|
||
|
|
FString IniPath()
|
||
|
|
{
|
||
|
|
return FPaths::Combine(FPaths::ProjectSavedDir(), TEXT("Config/Windows/LPColorGrade.ini"));
|
||
|
|
}
|
||
|
|
|
||
|
|
FString FormatValue(float Value, int32 Decimals)
|
||
|
|
{
|
||
|
|
return FString::Printf(TEXT("%.*f"), Decimals, Value);
|
||
|
|
}
|
||
|
|
|
||
|
|
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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
||
|
|
{
|
||
|
|
Super::Initialize(Collection);
|
||
|
|
Load();
|
||
|
|
TickHandle = FTSTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateUObject(this, &ULPColorGradeSubsystem::Tick), 0.5f);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::Deinitialize()
|
||
|
|
{
|
||
|
|
FTSTicker::GetCoreTicker().RemoveTicker(TickHandle);
|
||
|
|
Super::Deinitialize();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool ULPColorGradeSubsystem::Tick(float DeltaTime)
|
||
|
|
{
|
||
|
|
(void)DeltaTime;
|
||
|
|
EnsureVolume();
|
||
|
|
EnsureControls();
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::Load()
|
||
|
|
{
|
||
|
|
const FString Ini = LPColorGrade::IniPath();
|
||
|
|
FConfigFile File;
|
||
|
|
File.Read(Ini);
|
||
|
|
auto Read = [&File](const TCHAR* Key, float& Out)
|
||
|
|
{
|
||
|
|
FString Text;
|
||
|
|
if (File.GetString(TEXT("LPColorGrade"), Key, Text))
|
||
|
|
{
|
||
|
|
Out = FCString::Atof(*Text);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
Read(TEXT("Brightness"), Brightness);
|
||
|
|
Read(TEXT("Saturation"), Saturation);
|
||
|
|
Read(TEXT("Contrast"), Contrast);
|
||
|
|
Read(TEXT("WhiteBalance"), WhiteBalance);
|
||
|
|
Read(TEXT("Tint"), Tint);
|
||
|
|
Brightness = FMath::Clamp(Brightness, -2.f, 2.f);
|
||
|
|
Saturation = FMath::Clamp(Saturation, 0.f, 2.f);
|
||
|
|
Contrast = FMath::Clamp(Contrast, 0.f, 2.f);
|
||
|
|
WhiteBalance = FMath::Clamp(WhiteBalance, 1500.f, 15000.f);
|
||
|
|
Tint = FMath::Clamp(Tint, -1.f, 1.f);
|
||
|
|
UE_LOG(LogLifePlay, Display, TEXT("Couleur : relu Brightness %.2f, Saturation %.2f, Contrast %.2f, White Balance %.0f, Tint %.2f depuis %s"), Brightness, Saturation, Contrast, WhiteBalance, Tint, *Ini);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::Save() const
|
||
|
|
{
|
||
|
|
const FString Ini = LPColorGrade::IniPath();
|
||
|
|
FConfigFile File;
|
||
|
|
File.Read(Ini);
|
||
|
|
auto Write = [&File](const TCHAR* Key, float Value)
|
||
|
|
{
|
||
|
|
File.SetString(TEXT("LPColorGrade"), Key, *FString::SanitizeFloat(Value));
|
||
|
|
};
|
||
|
|
Write(TEXT("Brightness"), Brightness);
|
||
|
|
Write(TEXT("Saturation"), Saturation);
|
||
|
|
Write(TEXT("Contrast"), Contrast);
|
||
|
|
Write(TEXT("WhiteBalance"), WhiteBalance);
|
||
|
|
Write(TEXT("Tint"), Tint);
|
||
|
|
File.Write(Ini);
|
||
|
|
UE_LOG(LogLifePlay, Display, TEXT("Couleur : Brightness %.2f, Saturation %.2f, Contrast %.2f, White Balance %.0f, Tint %.2f enregistres dans %s"), Brightness, Saturation, Contrast, WhiteBalance, Tint, *Ini);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::ApplyGrade()
|
||
|
|
{
|
||
|
|
APostProcessVolume* Volume = GradeVolume.Get();
|
||
|
|
if (!Volume)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
FPostProcessSettings& Settings = Volume->Settings;
|
||
|
|
Settings.bOverride_AutoExposureBias = true;
|
||
|
|
Settings.AutoExposureBias = Brightness;
|
||
|
|
Settings.bOverride_ColorSaturation = true;
|
||
|
|
Settings.ColorSaturation = FVector4(Saturation, Saturation, Saturation, 1.f);
|
||
|
|
Settings.bOverride_ColorContrast = true;
|
||
|
|
Settings.ColorContrast = FVector4(Contrast, Contrast, Contrast, 1.f);
|
||
|
|
Settings.bOverride_TemperatureType = true;
|
||
|
|
Settings.TemperatureType = TEMP_WhiteBalance;
|
||
|
|
Settings.bOverride_WhiteTemp = true;
|
||
|
|
Settings.WhiteTemp = WhiteBalance;
|
||
|
|
Settings.bOverride_WhiteTint = true;
|
||
|
|
Settings.WhiteTint = Tint;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::EnsureVolume()
|
||
|
|
{
|
||
|
|
UWorld* World = GetWorld();
|
||
|
|
if (!World || !World->IsGameWorld())
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
if (GradeVolume.IsValid() && GradeVolume->GetWorld() == World)
|
||
|
|
{
|
||
|
|
ApplyGrade();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
FActorSpawnParameters Params;
|
||
|
|
Params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
|
||
|
|
Params.ObjectFlags |= RF_Transient;
|
||
|
|
APostProcessVolume* Volume = World->SpawnActor<APostProcessVolume>(APostProcessVolume::StaticClass(), Params);
|
||
|
|
if (!Volume)
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
Volume->bUnbound = true;
|
||
|
|
Volume->bEnabled = true;
|
||
|
|
Volume->BlendWeight = 1.f;
|
||
|
|
Volume->Priority = 100.f;
|
||
|
|
GradeVolume = Volume;
|
||
|
|
ApplyGrade();
|
||
|
|
UE_LOG(LogLifePlay, Display, TEXT("Couleur : exposition, saturation, contraste et balance des blancs"));
|
||
|
|
}
|
||
|
|
|
||
|
|
USlider* ULPColorGradeSubsystem::AddRow(UScrollBox* Scroll, const TCHAR* Name, const TCHAR* Label, float Min, float Max, float Step, float Value, FName Handler, const TCHAR* Tip, const FSlateFontInfo& Font, const FSlateColor& Color, const FSliderStyle* SliderStyle)
|
||
|
|
{
|
||
|
|
UHorizontalBox* Row = NewObject<UHorizontalBox>(Scroll, Name);
|
||
|
|
UTextBlock* Caption = NewObject<UTextBlock>(Row);
|
||
|
|
Caption->SetText(FText::FromString(Label));
|
||
|
|
Caption->SetFont(Font);
|
||
|
|
Caption->SetColorAndOpacity(Color);
|
||
|
|
USizeBox* CaptionBox = NewObject<USizeBox>(Row);
|
||
|
|
CaptionBox->SetWidthOverride(220.f);
|
||
|
|
CaptionBox->AddChild(Caption);
|
||
|
|
USlider* Slider = NewObject<USlider>(Row);
|
||
|
|
if (SliderStyle)
|
||
|
|
{
|
||
|
|
Slider->SetWidgetStyle(*SliderStyle);
|
||
|
|
}
|
||
|
|
Slider->SetMinValue(Min);
|
||
|
|
Slider->SetMaxValue(Max);
|
||
|
|
Slider->SetStepSize(Step);
|
||
|
|
Slider->SetValue(Value);
|
||
|
|
UTextBlock* Readout = NewObject<UTextBlock>(Row);
|
||
|
|
Readout->SetFont(Font);
|
||
|
|
Readout->SetColorAndOpacity(Color);
|
||
|
|
if (UHorizontalBoxSlot* Slot = Row->AddChildToHorizontalBox(CaptionBox))
|
||
|
|
{
|
||
|
|
Slot->SetVerticalAlignment(VAlign_Center);
|
||
|
|
Slot->SetPadding(FMargin(10.f, 0.f, 20.f, 0.f));
|
||
|
|
}
|
||
|
|
if (UHorizontalBoxSlot* Slot = Row->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 = Row->AddChildToHorizontalBox(Readout))
|
||
|
|
{
|
||
|
|
Slot->SetVerticalAlignment(VAlign_Center);
|
||
|
|
Slot->SetPadding(FMargin(0.f, 0.f, 10.f, 0.f));
|
||
|
|
}
|
||
|
|
if (UScrollBoxSlot* Slot = Cast<UScrollBoxSlot>(Scroll->AddChild(Row)))
|
||
|
|
{
|
||
|
|
Slot->SetPadding(FMargin(0.f, 0.f, 0.f, 10.f));
|
||
|
|
}
|
||
|
|
Row->SetToolTipText(FText::FromString(Tip));
|
||
|
|
FScriptDelegate Delegate;
|
||
|
|
Delegate.BindUFunction(this, Handler);
|
||
|
|
Slider->OnValueChanged.Add(Delegate);
|
||
|
|
if (Name == FString(TEXT("LPColorBrightness")))
|
||
|
|
{
|
||
|
|
BrightnessValue = Readout;
|
||
|
|
}
|
||
|
|
else if (Name == FString(TEXT("LPColorSaturation")))
|
||
|
|
{
|
||
|
|
SaturationValue = Readout;
|
||
|
|
}
|
||
|
|
else if (Name == FString(TEXT("LPColorContrast")))
|
||
|
|
{
|
||
|
|
ContrastValue = Readout;
|
||
|
|
}
|
||
|
|
else if (Name == FString(TEXT("LPColorWhiteBalance")))
|
||
|
|
{
|
||
|
|
WhiteBalanceValue = Readout;
|
||
|
|
}
|
||
|
|
else if (Name == FString(TEXT("LPColorTint")))
|
||
|
|
{
|
||
|
|
TintValue = Readout;
|
||
|
|
}
|
||
|
|
return Slider;
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::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;
|
||
|
|
}
|
||
|
|
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
||
|
|
{
|
||
|
|
if (UWidget* Child = Scroll->GetChildAt(Index))
|
||
|
|
{
|
||
|
|
if (Child->GetFName() == TEXT("LPColorBrightness"))
|
||
|
|
{
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
UTextBlock* SampleText = nullptr;
|
||
|
|
USlider* SampleSlider = nullptr;
|
||
|
|
for (int32 Index = 0; Index < Scroll->GetChildrenCount(); ++Index)
|
||
|
|
{
|
||
|
|
LPColorGrade::FindLook(Scroll->GetChildAt(Index), SampleText, SampleSlider);
|
||
|
|
}
|
||
|
|
const FSlateFontInfo Font = SampleText ? SampleText->GetFont() : LPColorGrade::MenuFont();
|
||
|
|
const FSlateColor Color = SampleText ? SampleText->GetColorAndOpacity() : FSlateColor(FLinearColor(1.f, 1.f, 1.f, 0.95f));
|
||
|
|
const FSliderStyle* SliderStyle = SampleSlider ? &SampleSlider->GetWidgetStyle() : nullptr;
|
||
|
|
AddRow(Scroll, TEXT("LPColorBrightness"), TEXT("Brightness"), -2.f, 2.f, 0.05f, Brightness, GET_FUNCTION_NAME_CHECKED(ULPColorGradeSubsystem, OnBrightnessChanged), TEXT("Exposure compensation. -1 is twice as dark, +1 is twice as bright."), Font, Color, SliderStyle);
|
||
|
|
AddRow(Scroll, TEXT("LPColorSaturation"), TEXT("Saturation"), 0.f, 2.f, 0.05f, Saturation, GET_FUNCTION_NAME_CHECKED(ULPColorGradeSubsystem, OnSaturationChanged), TEXT("Color intensity. 1 is unchanged, 0 is gray."), Font, Color, SliderStyle);
|
||
|
|
AddRow(Scroll, TEXT("LPColorContrast"), TEXT("Contrast"), 0.f, 2.f, 0.05f, Contrast, GET_FUNCTION_NAME_CHECKED(ULPColorGradeSubsystem, OnContrastChanged), TEXT("Range between light and dark. 1 is unchanged."), Font, Color, SliderStyle);
|
||
|
|
AddRow(Scroll, TEXT("LPColorWhiteBalance"), TEXT("White Balance"), 1500.f, 15000.f, 50.f, WhiteBalance, GET_FUNCTION_NAME_CHECKED(ULPColorGradeSubsystem, OnWhiteBalanceChanged), TEXT("Color temperature in kelvin. 6500 is daylight."), Font, Color, SliderStyle);
|
||
|
|
AddRow(Scroll, TEXT("LPColorTint"), TEXT("Tint"), -1.f, 1.f, 0.01f, Tint, GET_FUNCTION_NAME_CHECKED(ULPColorGradeSubsystem, OnTintChanged), TEXT("Magenta to green. 0 is unchanged."), Font, Color, SliderStyle);
|
||
|
|
if (UTextBlock* Readout = BrightnessValue.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Brightness, 2)));
|
||
|
|
}
|
||
|
|
if (UTextBlock* Readout = SaturationValue.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Saturation, 2)));
|
||
|
|
}
|
||
|
|
if (UTextBlock* Readout = ContrastValue.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Contrast, 2)));
|
||
|
|
}
|
||
|
|
if (UTextBlock* Readout = WhiteBalanceValue.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(WhiteBalance, 0)));
|
||
|
|
}
|
||
|
|
if (UTextBlock* Readout = TintValue.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Tint, 2)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::OnBrightnessChanged(float Value)
|
||
|
|
{
|
||
|
|
Brightness = Value;
|
||
|
|
if (UTextBlock* Readout = BrightnessValue.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Value, 2)));
|
||
|
|
}
|
||
|
|
ApplyGrade();
|
||
|
|
Save();
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::OnSaturationChanged(float Value)
|
||
|
|
{
|
||
|
|
Saturation = Value;
|
||
|
|
if (UTextBlock* Readout = SaturationValue.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Value, 2)));
|
||
|
|
}
|
||
|
|
ApplyGrade();
|
||
|
|
Save();
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::OnContrastChanged(float Value)
|
||
|
|
{
|
||
|
|
Contrast = Value;
|
||
|
|
if (UTextBlock* Readout = ContrastValue.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Value, 2)));
|
||
|
|
}
|
||
|
|
ApplyGrade();
|
||
|
|
Save();
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::OnWhiteBalanceChanged(float Value)
|
||
|
|
{
|
||
|
|
WhiteBalance = Value;
|
||
|
|
if (UTextBlock* Readout = WhiteBalanceValue.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Value, 0)));
|
||
|
|
}
|
||
|
|
ApplyGrade();
|
||
|
|
Save();
|
||
|
|
}
|
||
|
|
|
||
|
|
void ULPColorGradeSubsystem::OnTintChanged(float Value)
|
||
|
|
{
|
||
|
|
Tint = Value;
|
||
|
|
if (UTextBlock* Readout = TintValue.Get())
|
||
|
|
{
|
||
|
|
Readout->SetText(FText::FromString(LPColorGrade::FormatValue(Value, 2)));
|
||
|
|
}
|
||
|
|
ApplyGrade();
|
||
|
|
Save();
|
||
|
|
}
|