// Copyright Epic Games, Inc. All Rights Reserved. #include "HierarchicalSimplificationCustomizations.h" #include "Containers/Map.h" #include "CoreTypes.h" #include "Delegates/Delegate.h" #include "DetailWidgetRow.h" #include "GameFramework/WorldSettings.h" #include "IDetailChildrenBuilder.h" #include "IDetailGroup.h" #include "IDetailPropertyRow.h" #include "IGeometryProcessingInterfacesModule.h" #include "IMeshReductionInterfaces.h" #include "Internationalization/Internationalization.h" #include "Internationalization/Text.h" #include "Misc/AssertionMacros.h" #include "Misc/Attribute.h" #include "Modules/ModuleManager.h" #include "PropertyHandle.h" #include "PropertyRestriction.h" #include "UObject/Class.h" #include "UObject/NameTypes.h" #include "UObject/UnrealNames.h" #include "UObject/UnrealType.h" #define LOCTEXT_NAMESPACE "HierarchicalSimplificationCustomizations" TSharedRef FHierarchicalSimplificationCustomizations::MakeInstance() { return MakeShareable( new FHierarchicalSimplificationCustomizations ); } void FHierarchicalSimplificationCustomizations::CustomizeHeader(TSharedRef StructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { FFormatOrderedArguments Args; Args.Add(StructPropertyHandle->GetPropertyDisplayName()); FText Name = FText::Format(LOCTEXT("HLODLevelName", "HLOD Level {0}"), Args); HeaderRow. NameContent() [ StructPropertyHandle->CreatePropertyNameWidget(Name) ] .ValueContent() [ StructPropertyHandle->CreatePropertyValueWidget(false) ]; } void FHierarchicalSimplificationCustomizations::CustomizeChildren( TSharedRef StructPropertyHandle, class IDetailChildrenBuilder& ChildBuilder, IPropertyTypeCustomizationUtils& StructCustomizationUtils ) { // Retrieve structure's child properties uint32 NumChildren; StructPropertyHandle->GetNumChildren( NumChildren ); TMap > PropertyHandles; for( uint32 ChildIndex = 0; ChildIndex < NumChildren; ++ChildIndex ) { TSharedRef ChildHandle = StructPropertyHandle->GetChildHandle( ChildIndex ).ToSharedRef(); const FName PropertyName = ChildHandle->GetProperty()->GetFName(); PropertyHandles.Add(PropertyName, ChildHandle); } // Create two sub-settings groups for clean overview IDetailGroup& ClusterGroup = ChildBuilder.AddGroup(NAME_None, FText::FromString("Cluster generation settings")); IDetailGroup& MergeGroup = ChildBuilder.AddGroup(NAME_None, FText::FromString("Mesh generation settings")); // Retrieve special case properties SimplificationMethodPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FHierarchicalSimplification, SimplificationMethod)); TSharedPtr< IPropertyHandle > ProxyMeshSettingPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FHierarchicalSimplification, ProxySetting)); TSharedPtr< IPropertyHandle > MergeMeshSettingPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FHierarchicalSimplification, MergeSetting)); TSharedPtr< IPropertyHandle > ApproximateMeshSettingsPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FHierarchicalSimplification, ApproximateSettings)); TSharedPtr< IPropertyHandle > TransitionScreenSizePropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FHierarchicalSimplification, TransitionScreenSize)); TSharedPtr< IPropertyHandle > OverrideDrawDistancePropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FHierarchicalSimplification, OverrideDrawDistance)); TSharedPtr< IPropertyHandle > ReusePreviousLevelClustersPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FHierarchicalSimplification, bReusePreviousLevelClusters)); for (auto Iter(PropertyHandles.CreateConstIterator()); Iter; ++Iter) { // Handle special property cases (done inside the loop to maintain order according to the struct if (Iter.Value() == SimplificationMethodPropertyHandle) { IDetailPropertyRow& SimplifyMeshRow = MergeGroup.AddPropertyRow(SimplificationMethodPropertyHandle.ToSharedRef()); AddResetToDefaultOverrides(SimplifyMeshRow); static const UEnum* HLODSimplificationMethodEnum = StaticEnum(); // Determine whether or not there is a mesh merging interface available (SimplygonMeshReduction/SimplygonSwarm) IMeshReductionModule* ReductionModule = FModuleManager::Get().LoadModulePtr("MeshReductionInterface"); if (ReductionModule == nullptr || ReductionModule->GetMeshMergingInterface() == nullptr) { static FText RestrictReason = LOCTEXT("SimplifySimplificationMethodUnavailable", "Simplify method is not available, MeshReductionInterface module is missing"); TSharedPtr EnumRestriction = MakeShared(RestrictReason); EnumRestriction->AddHiddenValue(HLODSimplificationMethodEnum->GetNameStringByValue((int64)EHierarchicalSimplificationMethod::Simplify)); SimplificationMethodPropertyHandle->AddRestriction(EnumRestriction.ToSharedRef()); } IGeometryProcessingInterfacesModule* GeometryProcessingInterfacesModule = FModuleManager::Get().LoadModulePtr("GeometryProcessingInterfaces"); if (GeometryProcessingInterfacesModule == nullptr || GeometryProcessingInterfacesModule->GetApproximateActorsImplementation() == nullptr) { static FText RestrictReason = LOCTEXT("ApproximateSimplificationMethodUnavailable", "Approximate method is not available, GeometryProcessingInterfaces module is missing"); TSharedPtr EnumRestriction = MakeShared(RestrictReason); EnumRestriction->AddHiddenValue(HLODSimplificationMethodEnum->GetNameStringByValue((int64)EHierarchicalSimplificationMethod::Approximate)); SimplificationMethodPropertyHandle->AddRestriction(EnumRestriction.ToSharedRef()); } } else if (Iter.Value() == ProxyMeshSettingPropertyHandle) { IDetailPropertyRow& SettingsRow = MergeGroup.AddPropertyRow(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(SettingsRow); SettingsRow.Visibility(TAttribute(this, &FHierarchicalSimplificationCustomizations::IsProxyMeshSettingVisible)); } else if (Iter.Value() == MergeMeshSettingPropertyHandle) { IDetailPropertyRow& SettingsRow = MergeGroup.AddPropertyRow(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(SettingsRow); SettingsRow.Visibility(TAttribute(this, &FHierarchicalSimplificationCustomizations::IsMergeMeshSettingVisible)); } else if (Iter.Value() == ApproximateMeshSettingsPropertyHandle) { IDetailPropertyRow& SettingsRow = MergeGroup.AddPropertyRow(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(SettingsRow); SettingsRow.Visibility(TAttribute(this, &FHierarchicalSimplificationCustomizations::IsApproximateMeshSettingVisible)); } else if (Iter.Value() == TransitionScreenSizePropertyHandle) { IDetailPropertyRow& SettingsRow = MergeGroup.AddPropertyRow(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(SettingsRow); } else if (Iter.Value() == OverrideDrawDistancePropertyHandle) { IDetailPropertyRow& SettingsRow = MergeGroup.AddPropertyRow(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(SettingsRow); } else if (Iter.Value() == ReusePreviousLevelClustersPropertyHandle) { IDetailPropertyRow& SettingsRow = ClusterGroup.AddPropertyRow(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(SettingsRow); uint32 Index = StructPropertyHandle->GetIndexInArray(); // Hide the property for HLOD level 0 SettingsRow.Visibility(TAttribute::Create([Index]() { return (Index == INDEX_NONE || Index > 0) ? EVisibility::Visible : EVisibility::Collapsed; })); } else { IDetailPropertyRow& SettingsRow = ClusterGroup.AddPropertyRow(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(SettingsRow); } } } EHierarchicalSimplificationMethod FHierarchicalSimplificationCustomizations::GetSelectedSimplificationMethod() const { uint8 SimplificationMethod = 0; if (SimplificationMethodPropertyHandle) { SimplificationMethodPropertyHandle->GetValue(SimplificationMethod); } return (EHierarchicalSimplificationMethod)SimplificationMethod; } EVisibility FHierarchicalSimplificationCustomizations::IsProxyMeshSettingVisible() const { return GetSelectedSimplificationMethod() == EHierarchicalSimplificationMethod::Simplify ? EVisibility::Visible : EVisibility::Hidden; } EVisibility FHierarchicalSimplificationCustomizations::IsMergeMeshSettingVisible() const { return GetSelectedSimplificationMethod() == EHierarchicalSimplificationMethod::Merge ? EVisibility::Visible : EVisibility::Hidden; } EVisibility FHierarchicalSimplificationCustomizations::IsApproximateMeshSettingVisible() const { return GetSelectedSimplificationMethod() == EHierarchicalSimplificationMethod::Approximate ? EVisibility::Visible : EVisibility::Hidden; } #undef LOCTEXT_NAMESPACE