Files
Plugin/Source/SenseGlove/Private/SenseGlove/GameFramework/SGGameUserSettings.cpp
T

300 lines
11 KiB
C++

/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2026 SenseGlove
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @section DESCRIPTION
*
*
*/
#include "SenseGlove/GameFramework/SGGameUserSettings.h"
#include "Engine/Engine.h"
#include "HAL/IConsoleManager.h"
#include "Misc/ConfigCacheIni.h"
#include "Runtime/Launch/Resources/Version.h"
#include "Scalability.h"
#include "SGSettings/SGSettings.h"
struct USGGameUserSettings::FImpl
{
/************************
* Static methods
************************/
static float GetRenderScaleLevelFromQualityLevel(
int32 InQualityLevel,
Scalability::EQualityLevelBehavior Behavior = Scalability::EQualityLevelBehavior::EAbsolute);
/************************
* Owner object
************************/
USGGameUserSettings* Owner;
/************************
* Constructor / Destructor
************************/
explicit FImpl(USGGameUserSettings* InOwner);
~FImpl();
/************************
* Default copy constructor & copy assignment operator
************************/
FImpl(const FImpl& Rhs) = default;
FImpl& operator=(const FImpl& Rhs) = default;
/************************
* Methods
************************/
bool DoesCurrentSettingsMatch(ESGEngineScalabilitySettings Scalability) const;
};
float USGGameUserSettings::FImpl::GetRenderScaleLevelFromQualityLevel(
const int32 InQualityLevel, const Scalability::EQualityLevelBehavior Behavior)
{
if (!ensureAlwaysMsgf(GConfig, TEXT("Invalid GConfig!")))
{
return 0.0f;
}
TArray<FString> ResolutionValueStrings;
GConfig->GetSingleLineArray(TEXT("ScalabilitySettings"), TEXT("PerfIndexValues_ResolutionQuality"),
ResolutionValueStrings, GScalabilityIni);
if (ResolutionValueStrings.Num() == 0)
{
UE_LOG(LogConsoleResponse, Display,
TEXT("Failed to find resolution value strings in scalability ini. Falling back to the default."));
return 100.0f;
}
// No negative levels!
int32 QualityLevel = FMath::Max(0, InQualityLevel);
if (Behavior == Scalability::EQualityLevelBehavior::ERelativeToMax)
{
QualityLevel = FMath::Max(ResolutionValueStrings.Num() - 1 - QualityLevel, 0);
}
else
{
QualityLevel = FMath::Clamp(QualityLevel, 0, ResolutionValueStrings.Num() - 1);
}
return FCString::Atof(*ResolutionValueStrings[QualityLevel]);
}
USGGameUserSettings::USGGameUserSettings(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer),
Pimpl(TUniquePtr<FImpl, FImplDeleter>(new FImpl{this}, PimplDeleter))
{
}
USGGameUserSettings* USGGameUserSettings::GetInstance()
{
USGGameUserSettings* Instance{GEngine ? Cast<USGGameUserSettings>(GEngine->GetGameUserSettings()) : nullptr};
ensureAlwaysMsgf(Instance, TEXT("Invalid GameUserSettings!"));
return Instance;
}
ESGEngineScalabilitySettings USGGameUserSettings::GetEngineScalabilitySettings() const
{
const bool bDoesCurrentSettingsMatchLow = Pimpl->DoesCurrentSettingsMatch(ESGEngineScalabilitySettings::Low);
if (bDoesCurrentSettingsMatchLow)
{
return ESGEngineScalabilitySettings::Low;
}
const bool bDoesCurrentSettingsMatchMedium = Pimpl->DoesCurrentSettingsMatch(ESGEngineScalabilitySettings::Medium);
if (bDoesCurrentSettingsMatchMedium)
{
return ESGEngineScalabilitySettings::Medium;
}
const bool bDoesCurrentSettingsMatchHigh = Pimpl->DoesCurrentSettingsMatch(ESGEngineScalabilitySettings::High);
if (bDoesCurrentSettingsMatchHigh)
{
return ESGEngineScalabilitySettings::High;
}
const bool bDoesCurrentSettingsMatchEpic = Pimpl->DoesCurrentSettingsMatch(ESGEngineScalabilitySettings::Epic);
if (bDoesCurrentSettingsMatchEpic)
{
return ESGEngineScalabilitySettings::Epic;
}
const bool bDoesCurrentSettingsMatchCinematic = Pimpl->DoesCurrentSettingsMatch(
ESGEngineScalabilitySettings::Cinematic);
if (bDoesCurrentSettingsMatchCinematic)
{
return ESGEngineScalabilitySettings::Cinematic;
}
return ESGEngineScalabilitySettings::Custom;
}
void USGGameUserSettings::SetEngineScalabilitySettings(ESGEngineScalabilitySettings Scalability)
{
if (!ensureAlwaysMsgf(Scalability != ESGEngineScalabilitySettings::Custom,
TEXT("Cannot set the engine scalability directly to custom!"
" It should be either: Low, Medium, High, Epic, Cinematic,"
" or Auto (determined by hardware benchmarking)!")))
{
return;
}
const FSGHardwareBenchmarkingSettings& Settings{
USGSettings::GetInstance()->GetGameUserSettings().HardwareBenchmarkingSettings
};
if (IsDirty())
{
ValidateSettings();
ConfirmVideoMode();
}
if (Scalability != ESGEngineScalabilitySettings::Auto)
{
const int32 ScalabilityValue = static_cast<int32>(Scalability);
const float ResolutionScaleNormalized = FImpl::GetRenderScaleLevelFromQualityLevel(
ScalabilityValue, Scalability::EQualityLevelBehavior::EAbsolute);
SetResolutionScaleNormalized(ResolutionScaleNormalized);
ScalabilityQuality.SetViewDistanceQuality(ScalabilityValue);
ScalabilityQuality.SetAntiAliasingQuality(ScalabilityValue);
ScalabilityQuality.SetShadowQuality(ScalabilityValue);
ScalabilityQuality.SetGlobalIlluminationQuality(ScalabilityValue);
ScalabilityQuality.SetReflectionQuality(ScalabilityValue);
ScalabilityQuality.SetPostProcessQuality(ScalabilityValue);
ScalabilityQuality.SetTextureQuality(ScalabilityValue);
ScalabilityQuality.SetEffectsQuality(ScalabilityValue);
ScalabilityQuality.SetFoliageQuality(ScalabilityValue);
ScalabilityQuality.SetShadingQuality(ScalabilityValue);
ScalabilityQuality.SetLandscapeQuality(ScalabilityValue);
}
else
{
RunHardwareBenchmark(
Settings.WorkScale,
Settings.CPUMultiplier,
Settings.GPUMultiplier);
ApplyHardwareBenchmarkResults();
}
ConfirmVideoMode();
ApplySettings(false);
}
USGGameUserSettings::FImpl::FImpl(USGGameUserSettings* InOwner)
: Owner(InOwner)
{
}
USGGameUserSettings::FImpl::~FImpl() = default;
bool USGGameUserSettings::FImpl::DoesCurrentSettingsMatch(const ESGEngineScalabilitySettings Scalability) const
{
static const float ResolutionScaleNormalizedLow = FImpl::GetRenderScaleLevelFromQualityLevel(
static_cast<int32>(ESGEngineScalabilitySettings::Low));
static const float ResolutionScaleNormalizedMedium = FImpl::GetRenderScaleLevelFromQualityLevel(
static_cast<int32>(ESGEngineScalabilitySettings::Medium));
static const float ResolutionScaleNormalizedHigh = FImpl::GetRenderScaleLevelFromQualityLevel(
static_cast<int32>(ESGEngineScalabilitySettings::High));
static const float ResolutionScaleNormalizedEpic = FImpl::GetRenderScaleLevelFromQualityLevel(
static_cast<int32>(ESGEngineScalabilitySettings::Epic));
static const float ResolutionScaleNormalizedCinematic = FImpl::GetRenderScaleLevelFromQualityLevel(
static_cast<int32>(ESGEngineScalabilitySettings::Cinematic));
float ResolutionScaleNormalized = 0.0f;
switch (Scalability)
{
case ESGEngineScalabilitySettings::Low:
ResolutionScaleNormalized = ResolutionScaleNormalizedLow;
break;
case ESGEngineScalabilitySettings::Medium:
ResolutionScaleNormalized = ResolutionScaleNormalizedMedium;
break;
case ESGEngineScalabilitySettings::High:
ResolutionScaleNormalized = ResolutionScaleNormalizedHigh;
break;
case ESGEngineScalabilitySettings::Epic:
ResolutionScaleNormalized = ResolutionScaleNormalizedEpic;
break;
case ESGEngineScalabilitySettings::Cinematic:
ResolutionScaleNormalized = ResolutionScaleNormalizedCinematic;
break;
default:
ensureAlwaysMsgf(false, TEXT("Login Error: the execution flow should never reach here!"));
break;
}
const int32 ScalabilityValue = static_cast<int32>(Scalability);
const float CurrentResolutionScaleNormalized = FImpl::GetRenderScaleLevelFromQualityLevel(
ScalabilityValue, Scalability::EQualityLevelBehavior::EAbsolute);
const int32 CurrentViewDistanceQuality = Owner->ScalabilityQuality.ViewDistanceQuality;
const int32 CurrentAntiAliasingQuality = Owner->ScalabilityQuality.AntiAliasingQuality;
const int32 CurrentShadowQuality = Owner->ScalabilityQuality.ShadowQuality;
const int32 CurrentGlobalIlluminationQuality = Owner->ScalabilityQuality.GlobalIlluminationQuality;
const int32 CurrentReflectionQuality = Owner->ScalabilityQuality.ReflectionQuality;
const int32 CurrentPostProcessingQuality = Owner->ScalabilityQuality.PostProcessQuality;
const int32 CurrentTextureQuality = Owner->ScalabilityQuality.TextureQuality;
const int32 CurrentEffectQuality = Owner->ScalabilityQuality.EffectsQuality;
const int32 CurrentFoliageQuality = Owner->ScalabilityQuality.FoliageQuality;
const int32 CurrentShadingQuality = Owner->ScalabilityQuality.ShadingQuality;
const int32 CurrentLandscapeQuality = Owner->ScalabilityQuality.LandscapeQuality;
if (FMath::IsNearlyEqual(CurrentResolutionScaleNormalized, ResolutionScaleNormalized)
&& CurrentViewDistanceQuality == ScalabilityValue
&& CurrentAntiAliasingQuality == ScalabilityValue
&& CurrentShadowQuality == ScalabilityValue
&& CurrentGlobalIlluminationQuality == ScalabilityValue
&& CurrentReflectionQuality == ScalabilityValue
&& CurrentPostProcessingQuality == ScalabilityValue
&& CurrentTextureQuality == ScalabilityValue
&& CurrentEffectQuality == ScalabilityValue
&& CurrentFoliageQuality == ScalabilityValue
&& CurrentShadingQuality == ScalabilityValue
&& CurrentLandscapeQuality == ScalabilityValue)
{
return true;
}
return false;
}
void USGGameUserSettings::FImplDeleter::operator()(const FImpl* P) const
{
delete P;
}