2016-01-07 08:17:16 -05:00
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
2014-09-09 12:16:36 -04:00
# include "HardwareTargetingPrivatePCH.h"
# include "HardwareTargetingModule.h"
# include "HardwareTargetingSettings.h"
# include "Internationalization.h"
2014-10-27 07:53:18 -04:00
# include "ISettingsModule.h"
# include "ModuleManager.h"
2014-09-09 12:16:36 -04:00
# include "SDecoratedEnumCombo.h"
2014-09-18 01:29:26 -04:00
# include "Runtime/Engine/Classes/Engine/RendererSettings.h"
2014-09-19 18:15:39 -04:00
# include "Editor/Documentation/Public/IDocumentation.h"
2015-04-10 03:30:54 -04:00
# include "GameFramework/InputSettings.h"
# include "GameMapsSettings.h"
2015-05-12 01:55:22 -04:00
# include "EditorProjectSettings.h"
2014-10-27 07:53:18 -04:00
2014-09-09 12:16:36 -04:00
# define LOCTEXT_NAMESPACE "HardwareTargeting"
2014-10-27 07:53:18 -04:00
2014-09-18 01:29:26 -04:00
//////////////////////////////////////////////////////////////////////////
// FMetaSettingGatherer
struct FMetaSettingGatherer
{
FTextBuilder DescriptionBuffer ;
2014-09-18 22:10:53 -04:00
TMap < UObject * , FTextBuilder > DescriptionBuffers ;
TMap < UObject * , FText > CategoryNames ;
2014-09-18 01:29:26 -04:00
// Are we just displaying what would change, or actually changing things?
bool bReadOnly ;
2014-09-18 22:10:53 -04:00
bool bIncludeUnmodifiedProperties ;
2014-09-18 01:29:26 -04:00
FMetaSettingGatherer ( )
: bReadOnly ( false )
2014-09-18 22:10:53 -04:00
, bIncludeUnmodifiedProperties ( false )
2014-09-18 01:29:26 -04:00
{
}
void AddEntry ( UObject * SettingsObject , UProperty * Property , FText NewValue , bool bModified )
{
2014-09-18 22:10:53 -04:00
if ( bModified | | bIncludeUnmodifiedProperties )
2014-09-18 01:29:26 -04:00
{
2015-03-06 15:13:38 -05:00
FTextBuilder & SettingsDescriptionBuffer = DescriptionBuffers . FindOrAdd ( SettingsObject ) ;
2014-09-18 01:29:26 -04:00
2014-09-18 22:10:53 -04:00
if ( ! bReadOnly )
{
2014-11-07 19:36:09 -05:00
FPropertyChangedEvent ChangeEvent ( Property , EPropertyChangeType : : ValueSet ) ;
2014-09-18 22:10:53 -04:00
SettingsObject - > PostEditChangeProperty ( ChangeEvent ) ;
}
else
{
FText SettingDisplayName = Property - > GetDisplayNameText ( ) ;
2014-09-18 01:29:26 -04:00
2014-09-18 22:10:53 -04:00
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " SettingName " ) , SettingDisplayName ) ;
Args . Add ( TEXT ( " SettingValue " ) , NewValue ) ;
2014-09-18 01:29:26 -04:00
2014-09-18 22:10:53 -04:00
FText FormatString = bModified ?
LOCTEXT ( " MetaSettingDisplayStringModified " , " {SettingName} is {SettingValue} <HardwareTargets.Strong>(modified)</> " ) :
LOCTEXT ( " MetaSettingDisplayStringUnmodified " , " {SettingName} is {SettingValue} " ) ;
2014-09-18 01:29:26 -04:00
2015-03-06 15:13:38 -05:00
SettingsDescriptionBuffer . AppendLine ( FText : : Format ( FormatString , Args ) ) ;
2014-09-18 22:10:53 -04:00
}
2014-09-18 01:29:26 -04:00
}
}
template < typename ValueType >
static FText ValueToString ( ValueType Value ) ;
2014-09-22 09:41:38 -04:00
bool Finalize ( )
2014-09-18 01:29:26 -04:00
{
check ( ! bReadOnly ) ;
2014-09-22 09:41:38 -04:00
bool bSuccess = true ;
2014-09-18 22:10:53 -04:00
for ( auto & Pair : DescriptionBuffers )
2014-09-18 01:29:26 -04:00
{
2014-09-22 09:41:38 -04:00
const FString Filename = Pair . Key - > GetDefaultConfigFilename ( ) ;
const FDateTime BeforeTime = IFileManager : : Get ( ) . GetTimeStamp ( * Filename ) ;
2014-09-18 22:10:53 -04:00
Pair . Key - > UpdateDefaultConfigFile ( ) ;
2014-09-22 09:41:38 -04:00
const FDateTime AfterTime = IFileManager : : Get ( ) . GetTimeStamp ( * Filename ) ;
bSuccess = BeforeTime ! = AfterTime & & bSuccess ;
2014-09-18 01:29:26 -04:00
}
2014-09-22 09:41:38 -04:00
return bSuccess ;
2014-09-18 01:29:26 -04:00
}
} ;
template < >
FText FMetaSettingGatherer : : ValueToString ( bool Value )
{
return Value ? LOCTEXT ( " BoolEnabled " , " enabled " ) : LOCTEXT ( " BoolDisabled " , " disabled " ) ;
}
template < >
FText FMetaSettingGatherer : : ValueToString ( EAntiAliasingMethodUI : : Type Value )
{
switch ( Value )
{
case EAntiAliasingMethodUI : : AAM_None :
return LOCTEXT ( " AA_None " , " None " ) ;
case EAntiAliasingMethodUI : : AAM_FXAA :
return LOCTEXT ( " AA_FXAA " , " FXAA " ) ;
case EAntiAliasingMethodUI : : AAM_TemporalAA :
return LOCTEXT ( " AA_TemporalAA " , " Temporal AA " ) ;
default :
return FText : : AsNumber ( ( int32 ) Value ) ;
}
}
# define UE_META_SETTING_ENTRY(Builder, Class, PropertyName, TargetValue) \
{ \
Class * SettingsObject = GetMutableDefault < Class > ( ) ; \
bool bModified = SettingsObject - > PropertyName ! = ( TargetValue ) ; \
if ( ! Builder . bReadOnly ) { SettingsObject - > PropertyName = ( TargetValue ) ; } \
Builder . AddEntry ( SettingsObject , FindFieldChecked < UProperty > ( Class : : StaticClass ( ) , GET_MEMBER_NAME_CHECKED ( Class , PropertyName ) ) , FMetaSettingGatherer : : ValueToString ( TargetValue ) , bModified ) ; \
}
//////////////////////////////////////////////////////////////////////////
// FHardwareTargetingModule
2014-09-09 12:16:36 -04:00
class FHardwareTargetingModule : public IHardwareTargetingModule
{
2014-09-18 01:29:26 -04:00
public :
2014-09-09 12:16:36 -04:00
// IModuleInterface interface
virtual void StartupModule ( ) override ;
virtual void ShutdownModule ( ) override ;
// End of IModuleInterface interface
2014-09-18 01:29:26 -04:00
// IHardwareTargetingModule interface
virtual void ApplyHardwareTargetingSettings ( ) override ;
2014-09-18 22:10:53 -04:00
virtual TArray < FModifiedDefaultConfig > GetPendingSettingsChanges ( ) override ;
2014-09-09 12:16:36 -04:00
virtual TSharedRef < SWidget > MakeHardwareClassTargetCombo ( FOnHardwareClassChanged OnChanged , TAttribute < EHardwareClass : : Type > SelectedEnum ) override ;
virtual TSharedRef < SWidget > MakeGraphicsPresetTargetCombo ( FOnGraphicsPresetChanged OnChanged , TAttribute < EGraphicsPreset : : Type > SelectedEnum ) override ;
2014-09-18 01:29:26 -04:00
// End of IHardwareTargetingModule interface
private :
void GatherSettings ( FMetaSettingGatherer & Builder ) ;
2014-09-09 12:16:36 -04:00
} ;
void FHardwareTargetingModule : : StartupModule ( )
{
2014-10-27 07:53:18 -04:00
ISettingsModule * SettingsModule = FModuleManager : : GetModulePtr < ISettingsModule > ( " Settings " ) ;
2014-09-09 12:16:36 -04:00
2014-10-27 07:53:18 -04:00
if ( SettingsModule ! = nullptr )
{
SettingsModule - > RegisterSettings ( " Project " , " Project " , " HardwareTargeting " ,
LOCTEXT ( " HardwareTargetingSettingsName " , " Target Hardware " ) ,
LOCTEXT ( " HardwareTargetingSettingsDescription " , " Options for choosing which class of hardware to target " ) ,
GetMutableDefault < UHardwareTargetingSettings > ( )
) ;
}
2014-09-09 12:16:36 -04:00
// Apply any settings on startup if necessary
ApplyHardwareTargetingSettings ( ) ;
}
void FHardwareTargetingModule : : ShutdownModule ( )
{
}
2014-09-18 01:29:26 -04:00
2014-09-18 22:10:53 -04:00
TArray < FModifiedDefaultConfig > FHardwareTargetingModule : : GetPendingSettingsChanges ( )
2014-09-18 01:29:26 -04:00
{
// Gather and stringify the modified settings
FMetaSettingGatherer Gatherer ;
Gatherer . bReadOnly = true ;
2014-09-18 22:10:53 -04:00
Gatherer . bIncludeUnmodifiedProperties = true ;
2014-09-18 01:29:26 -04:00
GatherSettings ( Gatherer ) ;
2014-09-18 22:10:53 -04:00
TArray < FModifiedDefaultConfig > OutArray ;
for ( auto & Pair : Gatherer . DescriptionBuffers )
{
FModifiedDefaultConfig ModifiedConfig ;
ModifiedConfig . SettingsObject = Pair . Key ;
ModifiedConfig . Description = Pair . Value . ToText ( ) ;
ModifiedConfig . CategoryHeading = Gatherer . CategoryNames . FindChecked ( Pair . Key ) ;
2014-09-18 01:29:26 -04:00
2014-09-18 22:10:53 -04:00
OutArray . Add ( ModifiedConfig ) ;
}
return OutArray ;
}
2014-09-09 12:16:36 -04:00
2014-09-18 01:29:26 -04:00
void FHardwareTargetingModule : : GatherSettings ( FMetaSettingGatherer & Builder )
{
UHardwareTargetingSettings * Settings = GetMutableDefault < UHardwareTargetingSettings > ( ) ;
2014-09-18 22:10:53 -04:00
if ( Builder . bReadOnly )
{
// Force the category order and give nice descriptions
Builder . CategoryNames . Add ( GetMutableDefault < URendererSettings > ( ) , LOCTEXT ( " RenderingCategoryHeader " , " Engine - Rendering " ) ) ;
Builder . CategoryNames . Add ( GetMutableDefault < UInputSettings > ( ) , LOCTEXT ( " InputCategoryHeader " , " Engine - Input " ) ) ;
Builder . CategoryNames . Add ( GetMutableDefault < UGameMapsSettings > ( ) , LOCTEXT ( " MapsAndModesCategoryHeader " , " Project - Maps & Modes " ) ) ;
2015-05-12 01:55:22 -04:00
Builder . CategoryNames . Add ( GetMutableDefault < ULevelEditor2DSettings > ( ) , LOCTEXT ( " EditorSettings2D " , " Editor - 2D " ) ) ;
2014-09-18 22:10:53 -04:00
}
2014-09-18 01:29:26 -04:00
const bool bLowEndMobile = ( Settings - > TargetedHardwareClass = = EHardwareClass : : Mobile ) & & ( Settings - > DefaultGraphicsPerformance = = EGraphicsPreset : : Scalable ) ;
const bool bAnyMobile = ( Settings - > TargetedHardwareClass = = EHardwareClass : : Mobile ) ;
const bool bHighEndMobile = ( Settings - > TargetedHardwareClass = = EHardwareClass : : Mobile ) & & ( Settings - > DefaultGraphicsPerformance = = EGraphicsPreset : : Maximum ) ;
const bool bAnyPC = ( Settings - > TargetedHardwareClass = = EHardwareClass : : Desktop ) ;
const bool bHighEndPC = ( Settings - > TargetedHardwareClass = = EHardwareClass : : Desktop ) & & ( Settings - > DefaultGraphicsPerformance = = EGraphicsPreset : : Maximum ) ;
2015-05-12 01:55:22 -04:00
const bool bAnyScalable = Settings - > DefaultGraphicsPerformance = = EGraphicsPreset : : Scalable ;
2014-09-18 01:29:26 -04:00
{
// Based roughly on https://docs.unrealengine.com/latest/INT/Platforms/Mobile/PostProcessEffects/index.html
UE_META_SETTING_ENTRY ( Builder , URendererSettings , bMobileHDR , ! bLowEndMobile ) ;
// Bloom works and isn't terribly expensive on anything beyond low-end
UE_META_SETTING_ENTRY ( Builder , URendererSettings , bDefaultFeatureBloom , ! bLowEndMobile ) ;
// Separate translucency does nothing in the ES2 renderer
UE_META_SETTING_ENTRY ( Builder , URendererSettings , bSeparateTranslucency , ! bAnyMobile ) ;
2015-07-22 17:08:37 -04:00
// Motion blur, auto-exposure, and ambient occlusion don't work in the ES2 renderer
2014-09-18 01:29:26 -04:00
UE_META_SETTING_ENTRY ( Builder , URendererSettings , bDefaultFeatureMotionBlur , bHighEndPC ) ;
UE_META_SETTING_ENTRY ( Builder , URendererSettings , bDefaultFeatureAutoExposure , bHighEndPC ) ;
UE_META_SETTING_ENTRY ( Builder , URendererSettings , bDefaultFeatureAmbientOcclusion , bAnyPC ) ;
2015-07-22 17:08:37 -04:00
// lens flare doesn't work in the ES2 renderer, the quality is low and the feature is controversial
UE_META_SETTING_ENTRY ( Builder , URendererSettings , bDefaultFeatureLensFlare , false ) ;
2014-09-18 01:29:26 -04:00
// DOF and AA work on mobile but are expensive, keeping them off by default
//@TODO: DOF setting doesn't exist yet
// UE_META_SETTING_ENTRY(Builder, URendererSettings, bDefaultFeatureDepthOfField, bHighEndPC);
UE_META_SETTING_ENTRY ( Builder , URendererSettings , DefaultFeatureAntiAliasing , bHighEndPC ? EAntiAliasingMethodUI : : AAM_TemporalAA : EAntiAliasingMethodUI : : AAM_None ) ;
}
{
// Mobile uses touch
UE_META_SETTING_ENTRY ( Builder , UInputSettings , bUseMouseForTouch , bAnyMobile ) ;
//@TODO: Use bAlwaysShowTouchInterface (sorta implied by bUseMouseForTouch)?
}
{
// Tablets or phones are usually shared-screen multiplayer instead of split-screen
UE_META_SETTING_ENTRY ( Builder , UGameMapsSettings , bUseSplitscreen , bAnyPC ) ;
}
}
2014-09-09 12:16:36 -04:00
void FHardwareTargetingModule : : ApplyHardwareTargetingSettings ( )
{
UHardwareTargetingSettings * Settings = GetMutableDefault < UHardwareTargetingSettings > ( ) ;
2014-09-18 01:29:26 -04:00
// Apply the settings if they've changed
if ( Settings - > HasPendingChanges ( ) )
2014-09-09 12:16:36 -04:00
{
2014-09-18 01:29:26 -04:00
// Gather and apply the modified settings
FMetaSettingGatherer Builder ;
Builder . bReadOnly = false ;
GatherSettings ( Builder ) ;
2014-09-22 09:41:38 -04:00
const bool bSuccess = Builder . Finalize ( ) ;
2014-09-09 12:16:36 -04:00
2014-09-18 01:29:26 -04:00
// Write out the 'did we apply' values
2014-09-22 09:41:38 -04:00
if ( bSuccess )
{
2014-10-01 05:58:03 -04:00
Settings - > AppliedTargetedHardwareClass = Settings - > TargetedHardwareClass ;
Settings - > AppliedDefaultGraphicsPerformance = Settings - > DefaultGraphicsPerformance ;
Settings - > UpdateDefaultConfigFile ( ) ;
2014-09-22 09:41:38 -04:00
}
2014-09-09 12:16:36 -04:00
}
}
TSharedRef < SWidget > FHardwareTargetingModule : : MakeHardwareClassTargetCombo ( FOnHardwareClassChanged OnChanged , TAttribute < EHardwareClass : : Type > SelectedEnum )
{
TArray < SDecoratedEnumCombo < EHardwareClass : : Type > : : FComboOption > HardwareClassInfo ;
2014-09-30 12:18:05 -04:00
HardwareClassInfo . Add ( SDecoratedEnumCombo < EHardwareClass : : Type > : : FComboOption (
EHardwareClass : : Unspecified , FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " HardwareTargeting.HardwareUnspecified " ) , LOCTEXT ( " UnspecifiedCaption " , " Unspecified " ) , false ) ) ;
2014-09-09 12:16:36 -04:00
HardwareClassInfo . Add ( SDecoratedEnumCombo < EHardwareClass : : Type > : : FComboOption (
EHardwareClass : : Desktop , FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " HardwareTargeting.DesktopPlatform " ) , LOCTEXT ( " DesktopCaption " , " Desktop / Console " ) ) ) ;
HardwareClassInfo . Add ( SDecoratedEnumCombo < EHardwareClass : : Type > : : FComboOption (
EHardwareClass : : Mobile , FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " HardwareTargeting.MobilePlatform " ) , LOCTEXT ( " MobileCaption " , " Mobile / Tablet " ) ) ) ;
return SNew ( SDecoratedEnumCombo < EHardwareClass : : Type > , MoveTemp ( HardwareClassInfo ) )
. SelectedEnum ( SelectedEnum )
2014-09-19 18:15:39 -04:00
. OnEnumChanged ( OnChanged )
. ToolTip ( IDocumentation : : Get ( ) - > CreateToolTip ( LOCTEXT ( " HardwareClassTooltip " , " Choose the overall class of hardware to target (desktop/console or mobile/tablet). " ) , NULL , TEXT ( " Shared/Editor/Settings/TargetHardware " ) , TEXT ( " HardwareClass " ) ) ) ;
2014-09-09 12:16:36 -04:00
}
TSharedRef < SWidget > FHardwareTargetingModule : : MakeGraphicsPresetTargetCombo ( FOnGraphicsPresetChanged OnChanged , TAttribute < EGraphicsPreset : : Type > SelectedEnum )
{
TArray < SDecoratedEnumCombo < EGraphicsPreset : : Type > : : FComboOption > GraphicsPresetInfo ;
2014-09-30 12:18:05 -04:00
GraphicsPresetInfo . Add ( SDecoratedEnumCombo < EGraphicsPreset : : Type > : : FComboOption (
EGraphicsPreset : : Unspecified , FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " HardwareTargeting.GraphicsUnspecified " ) , LOCTEXT ( " UnspecifiedCaption " , " Unspecified " ) , false ) ) ;
2014-09-09 12:16:36 -04:00
GraphicsPresetInfo . Add ( SDecoratedEnumCombo < EGraphicsPreset : : Type > : : FComboOption (
EGraphicsPreset : : Maximum , FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " HardwareTargeting.MaximumQuality " ) , LOCTEXT ( " MaximumCaption " , " Maximum Quality " ) ) ) ;
GraphicsPresetInfo . Add ( SDecoratedEnumCombo < EGraphicsPreset : : Type > : : FComboOption (
EGraphicsPreset : : Scalable , FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " HardwareTargeting.ScalableQuality " ) , LOCTEXT ( " ScalableCaption " , " Scalable 3D or 2D " ) ) ) ;
return SNew ( SDecoratedEnumCombo < EGraphicsPreset : : Type > , MoveTemp ( GraphicsPresetInfo ) )
. SelectedEnum ( SelectedEnum )
2014-09-19 18:15:39 -04:00
. OnEnumChanged ( OnChanged )
. ToolTip ( IDocumentation : : Get ( ) - > CreateToolTip ( LOCTEXT ( " GraphicsPresetTooltip " , " Choose the graphical level to target (high-end only or scalable from low-end on up). " ) , NULL , TEXT ( " Shared/Editor/Settings/TargetHardware " ) , TEXT ( " GraphicalLevel " ) ) ) ;
2014-09-09 12:16:36 -04:00
}
IHardwareTargetingModule & IHardwareTargetingModule : : Get ( )
{
static FHardwareTargetingModule Instance ;
return Instance ;
}
2014-09-18 01:29:26 -04:00
IMPLEMENT_MODULE ( FHardwareTargetingModule , HardwareTarget ) ;
2014-09-09 12:16:36 -04:00
2014-09-18 01:29:26 -04:00
# undef UE_META_SETTING_ENTRY
2014-09-09 12:16:36 -04:00
# undef LOCTEXT_NAMESPACE