2026-10-07 13:49:11 +00:00
// 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"
2026-10-21 07:36:04 +00:00
# include "LPSettingsSubsystem.h"
2026-10-07 13:49:11 +00:00
# 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 ( )
{
2026-10-21 07:36:04 +00:00
// SET1-V1b : la liste de l'instance de MainMenu qui est a l'ecran, pas la premiere trouvee (une ancienne instance,
// retiree du viewport et pas encore collectee, vient souvent avant). Aucune a l'ecran : rien a faire. Pas d'etat par
// instance a remettre a zero : la presence de LPColorBrightness se lit sur les enfants de la liste choisie, et AddRow
// rebranche les afficheurs de valeur (BrightnessValue...) sur les lignes de cette liste.
UScrollBox * Scroll = ULPSettingsSubsystem : : FindOnScreenSettingsList ( GetGameInstance ( ) ) ;
2026-10-07 13:49:11 +00:00
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 ) ) ) ;
}
2026-10-21 07:36:04 +00:00
const UUserWidget * Menu = Scroll - > GetTypedOuter < UUserWidget > ( ) ;
UE_LOG ( LogLifePlay , Display , TEXT ( " Couleur : reglages de couleur ajoutes sur %s " ) , Menu ? * Menu - > GetName ( ) : TEXT ( " ? " ) ) ;
2026-10-07 13:49:11 +00:00
}
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 ( ) ;
}