VRTowerDef/Plugins/MetaXR/Source/OculusXRHMD/Private/OculusXRHMDRuntimeSettings.cpp

300 lines
13 KiB
C++

// @lint-ignore-every LICENSELINT
// Copyright Epic Games, Inc. All Rights Reserved.
#include "OculusXRHMDRuntimeSettings.h"
//////////////////////////////////////////////////////////////////////////
// UOculusXRHMDRuntimeSettings
#include "OculusXRHMD_Settings.h"
UOculusXRHMDRuntimeSettings::UOculusXRHMDRuntimeSettings(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, bAutoEnabled(false)
{
#if OCULUS_HMD_SUPPORTED_PLATFORMS
// FSettings is the sole source of truth for Oculus default settings
OculusXRHMD::FSettings DefaultSettings;
SystemSplashBackground = DefaultSettings.SystemSplashBackground;
bSupportsDash = DefaultSettings.Flags.bSupportsDash;
bCompositesDepth = DefaultSettings.Flags.bCompositeDepth;
bHQDistortion = DefaultSettings.Flags.bHQDistortion;
SuggestedCpuPerfLevel = DefaultSettings.SuggestedCpuPerfLevel;
SuggestedGpuPerfLevel = DefaultSettings.SuggestedGpuPerfLevel;
FoveatedRenderingMethod = DefaultSettings.FoveatedRenderingMethod;
FoveatedRenderingLevel = DefaultSettings.FoveatedRenderingLevel;
bDynamicFoveatedRendering = DefaultSettings.bDynamicFoveatedRendering;
bSupportEyeTrackedFoveatedRendering = DefaultSettings.bSupportEyeTrackedFoveatedRendering;
PixelDensityMin = DefaultSettings.PixelDensityMin;
PixelDensityMax = DefaultSettings.PixelDensityMax;
bFocusAware = DefaultSettings.Flags.bFocusAware;
bDynamicResolution = DefaultSettings.Flags.bPixelDensityAdaptive;
XrApi = DefaultSettings.XrApi;
ColorSpace = DefaultSettings.ColorSpace;
ControllerPoseAlignment = DefaultSettings.ControllerPoseAlignment;
bRequiresSystemKeyboard = DefaultSettings.Flags.bRequiresSystemKeyboard;
HandTrackingSupport = DefaultSettings.HandTrackingSupport;
HandTrackingFrequency = DefaultSettings.HandTrackingFrequency;
HandTrackingVersion = DefaultSettings.HandTrackingVersion;
bInsightPassthroughEnabled = DefaultSettings.Flags.bInsightPassthroughEnabled;
bBodyTrackingEnabled = DefaultSettings.Flags.bBodyTrackingEnabled;
bEyeTrackingEnabled = DefaultSettings.Flags.bEyeTrackingEnabled;
bFaceTrackingEnabled = DefaultSettings.Flags.bFaceTrackingEnabled;
bSupportExperimentalFeatures = DefaultSettings.bSupportExperimentalFeatures;
bAnchorSupportEnabled = DefaultSettings.Flags.bAnchorSupportEnabled;
bAnchorSharingEnabled = DefaultSettings.Flags.bAnchorSharingEnabled;
bSceneSupportEnabled = DefaultSettings.Flags.bSceneSupportEnabled;
ProcessorFavor = DefaultSettings.ProcessorFavor;
bTileTurnOffEnabled = DefaultSettings.Flags.bTileTurnOffEnabled;
FaceTrackingDataSource.Empty(static_cast<int8>(EFaceTrackingDataSourceConfig::MAX));
FaceTrackingDataSource.Append(DefaultSettings.FaceTrackingDataSource);
// Default this to false, FSettings doesn't have a separate composite depth flag for mobile
bCompositeDepthMobile = false;
#else
// Some set of reasonable defaults, since blueprints are still available on non-Oculus platforms.
SystemSplashBackground = ESystemSplashBackgroundType::Black;
bSupportsDash = false;
bCompositesDepth = false;
bHQDistortion = false;
SuggestedCpuPerfLevel = EOculusXRProcessorPerformanceLevel::SustainedLow;
SuggestedGpuPerfLevel = EOculusXRProcessorPerformanceLevel::SustainedHigh;
FoveatedRenderingMethod = EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering;
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Off;
bDynamicFoveatedRendering = false;
bSupportEyeTrackedFoveatedRendering = false;
PixelDensityMin = 0.8f;
PixelDensityMax = 1.2f;
bDynamicResolution = false;
bCompositeDepthMobile = false;
bFocusAware = true;
XrApi = EOculusXRXrApi::OVRPluginOpenXR;
bLateLatching = false;
ColorSpace = EOculusXRColorSpace::P3;
ControllerPoseAlignment = EOculusXRControllerPoseAlignment::Default;
bRequiresSystemKeyboard = false;
HandTrackingSupport = EOculusXRHandTrackingSupport::ControllersOnly;
HandTrackingFrequency = EOculusXRHandTrackingFrequency::Low;
HandTrackingVersion = EOculusXRHandTrackingVersion::Default;
bInsightPassthroughEnabled = false;
bSupportExperimentalFeatures = false;
bBodyTrackingEnabled = false;
bEyeTrackingEnabled = false;
bFaceTrackingEnabled = false;
bAnchorSupportEnabled = false;
bAnchorSharingEnabled = false;
bSceneSupportEnabled = false;
ProcessorFavor = EProcessorFavor::FavorEqually;
bTileTurnOffEnabled = false;
#endif
LoadFromIni();
}
#if WITH_EDITOR
bool UOculusXRHMDRuntimeSettings::CanEditChange(const FProperty* InProperty) const
{
bool bIsEditable = Super::CanEditChange(InProperty);
if (bIsEditable && InProperty)
{
const FName PropertyName = InProperty->GetFName();
if (PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, XrApi) && !FModuleManager::Get().IsModuleLoaded("OpenXRHMD"))
{
bIsEditable = false;
}
// Disable settings for marketplace release that are only compatible with the Oculus engine fork
#ifndef WITH_OCULUS_BRANCH
if (PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingMethod) || PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bSupportEyeTrackedFoveatedRendering) || PropertyName == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bDynamicResolution))
{
bIsEditable = false;
}
#endif // WITH_OCULUS_BRANCH
}
return bIsEditable;
}
void UOculusXRHMDRuntimeSettings::PostEditChangeProperty(struct FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
if (PropertyChangedEvent.Property != nullptr)
{
// Automatically switch to Fixed Foveated Rendering when removing Eye Tracked Foveated rendering support
if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bSupportEyeTrackedFoveatedRendering) && !bSupportEyeTrackedFoveatedRendering)
{
FoveatedRenderingMethod = EOculusXRFoveatedRenderingMethod::FixedFoveatedRendering;
UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingMethod)), GetDefaultConfigFilename());
}
// Automatically enable support for eye tracked foveated rendering when selecting the Eye Tracked Foveated Rendering method
if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingMethod) && FoveatedRenderingMethod == EOculusXRFoveatedRenderingMethod::EyeTrackedFoveatedRendering)
{
bSupportEyeTrackedFoveatedRendering = true;
UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, bSupportEyeTrackedFoveatedRendering)), GetDefaultConfigFilename());
}
if (PropertyChangedEvent.Property->GetFName() == GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, SupportedDevices))
{
if (PropertyChangedEvent.ChangeType == EPropertyChangeType::ArrayAdd)
{
// Get a list of all available devices
TArray<EOculusXRSupportedDevices> deviceList;
#define OCULUS_DEVICE_LOOP(device) deviceList.Add(device);
FOREACH_ENUM_EOCULUSXRSUPPORTEDDEVICES(OCULUS_DEVICE_LOOP);
#undef OCULUS_DEVICE_LOOP
// Add last device that isn't already in the list
for (int i = deviceList.Num() - 1; i >= 0; --i)
{
if (!SupportedDevices.Contains(deviceList[i]))
{
SupportedDevices.Last() = deviceList[i];
break;
}
// Just add another copy of the first device if nothing was available
SupportedDevices.Last() = deviceList[deviceList.Num() - 1];
}
}
}
}
}
#endif // WITH_EDITOR
void UOculusXRHMDRuntimeSettings::PostInitProperties()
{
Super::PostInitProperties();
RenameProperties();
const TCHAR* OculusSettings = TEXT("/Script/OculusXRHMD.OculusXRHMDRuntimeSettings");
if (!FModuleManager::Get().IsModuleLoaded("OpenXRHMD"))
{
XrApi = EOculusXRXrApi::OVRPluginOpenXR;
UpdateSinglePropertyInConfigFile(GetClass()->FindPropertyByName(GET_MEMBER_NAME_CHECKED(UOculusXRHMDRuntimeSettings, XrApi)), GetDefaultConfigFilename());
}
}
void UOculusXRHMDRuntimeSettings::LoadFromIni()
{
const TCHAR* OculusSettings = TEXT("Oculus.Settings");
bool v;
float f;
FVector vec;
if (GConfig->GetFloat(OculusSettings, TEXT("PixelDensityMax"), f, GEngineIni))
{
check(!FMath::IsNaN(f));
PixelDensityMax = f;
}
if (GConfig->GetFloat(OculusSettings, TEXT("PixelDensityMin"), f, GEngineIni))
{
check(!FMath::IsNaN(f));
PixelDensityMin = f;
}
if (GConfig->GetBool(OculusSettings, TEXT("bHQDistortion"), v, GEngineIni))
{
bHQDistortion = v;
}
if (GConfig->GetBool(OculusSettings, TEXT("bCompositeDepth"), v, GEngineIni))
{
bCompositesDepth = v;
}
}
/** This essentially acts like redirects for plugin settings saved in the engine config.
Anything added here should check for the current setting in the config so that if the dev changes the setting manually, we don't overwrite it with the old setting.
Note: Do not use UpdateSinglePropertyInConfigFile() here, since that uses a temp config to save the single property,
it'll get overwritten when GConfig->RemoveKey() marks the main config as dirty and it gets saved again **/
void UOculusXRHMDRuntimeSettings::RenameProperties()
{
const TCHAR* OculusSettings = TEXT("/Script/OculusXRHMD.OculusXRHMDRuntimeSettings");
bool v = false;
FString str;
// FFRLevel was renamed to FoveatedRenderingLevel
if (!GConfig->GetString(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingLevel), str, GetDefaultConfigFilename()) && GConfig->GetString(OculusSettings, TEXT("FFRLevel"), str, GetDefaultConfigFilename()))
{
if (str.Equals(TEXT("FFR_Off")))
{
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Off;
}
else if (str.Equals(TEXT("FFR_Low")))
{
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Low;
}
else if (str.Equals(TEXT("FFR_Medium")))
{
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::Medium;
}
else if (str.Equals(TEXT("FFR_High")))
{
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::High;
}
else if (str.Equals(TEXT("FFR_HighTop")))
{
FoveatedRenderingLevel = EOculusXRFoveatedRenderingLevel::HighTop;
}
// Use GetNameStringByValue() here because GetValueAsString() includes the type name as well
GConfig->SetString(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, FoveatedRenderingLevel), *StaticEnum<EOculusXRFoveatedRenderingLevel>()->GetNameStringByValue((int64)FoveatedRenderingLevel), GetDefaultConfigFilename());
GConfig->RemoveKey(OculusSettings, TEXT("FFRLevel"), GetDefaultConfigFilename());
}
// FFRDynamic was renamed to bDynamicFoveatedRendering
if (!GConfig->GetString(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, bDynamicFoveatedRendering), str, GetDefaultConfigFilename()) && GConfig->GetBool(OculusSettings, TEXT("FFRDynamic"), v, GetDefaultConfigFilename()))
{
bDynamicFoveatedRendering = v;
GConfig->SetBool(OculusSettings, GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, bDynamicFoveatedRendering), bDynamicFoveatedRendering, GetDefaultConfigFilename());
GConfig->RemoveKey(OculusSettings, TEXT("FFRDynamic"), GetDefaultConfigFilename());
}
const FString Quest = TEXT("Quest");
#ifndef WITH_OCULUS_BRANCH
const TCHAR* AndroidSettings = TEXT("/Script/AndroidRuntimeSettings.AndroidRuntimeSettings");
TArray<FString> PackageList;
const TCHAR* PackageForMobileKey = TEXT("+PackageForOculusMobile");
if (GConfig->GetArray(AndroidSettings, PackageForMobileKey, PackageList, GetDefaultConfigFilename()))
{
const FString Quest2 = TEXT("Quest2");
if (PackageList.Contains(Quest))
{
PackageList.Remove(Quest);
if (!PackageList.Contains(Quest2))
{
PackageList.Add(Quest2);
}
GConfig->SetArray(AndroidSettings, PackageForMobileKey, PackageList, GetDefaultConfigFilename());
}
}
#endif // WITH_OCULUS_BRANCH
TArray<FString> DeviceList;
const TCHAR* SupportedDevicesKey = *FString("+").Append(GET_MEMBER_NAME_STRING_CHECKED(UOculusXRHMDRuntimeSettings, SupportedDevices));
if (GConfig->GetArray(OculusSettings, SupportedDevicesKey, DeviceList, GetDefaultConfigFilename()))
{
const EOculusXRSupportedDevices LastSupportedDevice = EOculusXRSupportedDevices::Quest2;
const FString LastSupportedDeviceString = StaticEnum<EOculusXRSupportedDevices>()->GetNameStringByValue((int64)LastSupportedDevice);
if (DeviceList.Contains(Quest))
{
DeviceList.Remove(Quest);
if (!DeviceList.Contains(LastSupportedDeviceString))
{
DeviceList.Add(LastSupportedDeviceString);
}
GConfig->SetArray(OculusSettings, SupportedDevicesKey, DeviceList, GetDefaultConfigFilename());
// Reflect the config changes in the Project Settings UI
SupportedDevices.Remove((EOculusXRSupportedDevices)0); // Enums that don't exist just have a value of 0
if (!SupportedDevices.Contains(LastSupportedDevice))
{
SupportedDevices.Add(LastSupportedDevice);
}
}
}
}