// Copyright Epic Games, Inc. All Rights Reserved. #include "MeshProxySettingsCustomizations.h" #include "Algo/AnyOf.h" #include "Containers/Map.h" #include "Containers/UnrealString.h" #include "Delegates/Delegate.h" #include "HAL/Platform.h" #include "IDetailChildrenBuilder.h" #include "IDetailGroup.h" #include "IDetailPropertyRow.h" #include "IMeshReductionInterfaces.h" #include "IMeshReductionManagerModule.h" #include "Internationalization/Text.h" #include "Misc/AssertionMacros.h" #include "Misc/Attribute.h" #include "Modules/ModuleManager.h" #include "PropertyHandle.h" #include "UObject/NameTypes.h" #include "UObject/UnrealNames.h" #include "UObject/UnrealType.h" #include "WorldPartition/HLOD/HLODLayer.h" #define LOCTEXT_NAMESPACE "MeshProxySettingsCustomizations" void FMeshProxySettingsCustomizations::CustomizeHeader(TSharedRef StructPropertyHandle, FDetailWidgetRow& HeaderRow, IPropertyTypeCustomizationUtils& StructCustomizationUtils) { } TSharedRef FMeshProxySettingsCustomizations::MakeInstance() { return MakeShareable(new FMeshProxySettingsCustomizations); } bool FMeshProxySettingsCustomizations::UseNativeProxyLODTool() const { IMeshMerging* MergeModule = FModuleManager::Get().LoadModuleChecked("MeshReductionInterface").GetMeshMergingInterface(); return MergeModule && MergeModule->GetName().Equals("ProxyLODMeshMerging"); } void FMeshProxySettingsCustomizations::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); } TArray OutersList; StructPropertyHandle->GetOuterObjects(OutersList); bIsEditingHLODLayer = Algo::AnyOf(OutersList, [](UObject* Outer) { return Outer->IsInA(UHLODLayer::StaticClass()); }); // Determine if we are using our native module If so, we will supress some of the options used by the current thirdparty tool (simplygon). IMeshReductionManagerModule& ModuleManager = FModuleManager::Get().LoadModuleChecked("MeshReductionInterface"); IMeshMerging* MergeModule = ModuleManager.GetMeshMergingInterface(); // Respect the ShowInnerProperties property from the struct property. static const FName ShowOnlyInners("ShowOnlyInnerProperties"); bool bCreateSettingsGroup = !StructPropertyHandle->HasMetaData(ShowOnlyInners); IDetailGroup* MeshSettingsGroup = nullptr; if (bCreateSettingsGroup) { MeshSettingsGroup = &ChildBuilder.AddGroup(NAME_None, FText::FromString("Proxy Settings")); } auto AddPropertyToGroup = [bCreateSettingsGroup, &ChildBuilder, &MeshSettingsGroup](const TSharedRef& prop) -> IDetailPropertyRow& { if (bCreateSettingsGroup) { return MeshSettingsGroup->AddPropertyRow(prop); } else { return ChildBuilder.AddProperty(prop); } }; TSharedPtr< IPropertyHandle > HardAngleThresholdPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FMeshProxySettings, HardAngleThreshold)); TSharedPtr< IPropertyHandle > NormalCalcMethodPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FMeshProxySettings, NormalCalculationMethod)); TSharedPtr< IPropertyHandle > MaxRayCastDistdPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FMeshProxySettings, MaxRayCastDist)); TSharedPtr< IPropertyHandle > RecalculateNormalsPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FMeshProxySettings, bRecalculateNormals)); TSharedPtr< IPropertyHandle > UseLandscapeCullingPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FMeshProxySettings, bUseLandscapeCulling)); TSharedPtr< IPropertyHandle > LandscapeCullingPrecisionPropertyHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FMeshProxySettings, LandscapeCullingPrecision)); TSharedPtr< IPropertyHandle > MergeDistanceHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FMeshProxySettings, MergeDistance)); TSharedPtr< IPropertyHandle > UnresolvedGeometryColorHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FMeshProxySettings, UnresolvedGeometryColor)); TSharedPtr< IPropertyHandle > VoxelSizeHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FMeshProxySettings, VoxelSize)); TSharedPtr< IPropertyHandle > ScreenSizeHandle = PropertyHandles.FindChecked(GET_MEMBER_NAME_CHECKED(FMeshProxySettings, ScreenSize)); 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() == HardAngleThresholdPropertyHandle) { IDetailPropertyRow& MeshProxySettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(MeshProxySettingsRow); MeshProxySettingsRow.ToolTip(FText::FromString(FString("Angle at which a hard edge is introduced between faces. Note: Increases vertex count and may introduce additional UV seams. It is only recommended if not using normals maps"))); MeshProxySettingsRow.Visibility(TAttribute(this, &FMeshProxySettingsCustomizations::IsHardAngleThresholdVisible)); } else if (Iter.Value() == NormalCalcMethodPropertyHandle) { IDetailPropertyRow& MeshProxySettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(MeshProxySettingsRow); MeshProxySettingsRow.Visibility(TAttribute(this, &FMeshProxySettingsCustomizations::IsNormalCalcMethodVisible)); } else if (Iter.Value() == MaxRayCastDistdPropertyHandle) { IDetailPropertyRow& MeshProxySettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(MeshProxySettingsRow); MeshProxySettingsRow.Visibility(TAttribute(this, &FMeshProxySettingsCustomizations::IsSearchDistanceVisible)); } else if (Iter.Value() == RecalculateNormalsPropertyHandle) { IDetailPropertyRow& MeshProxySettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(MeshProxySettingsRow); MeshProxySettingsRow.Visibility(TAttribute(this, &FMeshProxySettingsCustomizations::IsRecalculateNormalsVisible)); } else if (Iter.Value() == UseLandscapeCullingPropertyHandle) { IDetailPropertyRow& MeshProxySettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(MeshProxySettingsRow); MeshProxySettingsRow.DisplayName(FText::FromString(FString("Enable Volume Culling"))); MeshProxySettingsRow.ToolTip(FText::FromString(FString("Allow culling volumes to exclude geometry."))); MeshProxySettingsRow.Visibility(TAttribute(this, &FMeshProxySettingsCustomizations::IsUseLandscapeCullingVisible)); } else if (Iter.Value() == LandscapeCullingPrecisionPropertyHandle) { IDetailPropertyRow& MeshProxySettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(MeshProxySettingsRow); MeshProxySettingsRow.Visibility(TAttribute(this, &FMeshProxySettingsCustomizations::IsUseLandscapeCullingPrecisionVisible)); } else if (Iter.Value() == MergeDistanceHandle) { IDetailPropertyRow& MeshProxySettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(MeshProxySettingsRow); MeshProxySettingsRow.Visibility(TAttribute(this, &FMeshProxySettingsCustomizations::IsMergeDistanceVisible)); } else if (Iter.Value() == UnresolvedGeometryColorHandle) { IDetailPropertyRow& MeshProxySettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(MeshProxySettingsRow); MeshProxySettingsRow.Visibility(TAttribute(this, &FMeshProxySettingsCustomizations::IsUnresolvedGeometryColorVisible)); } else if (Iter.Value() == VoxelSizeHandle) { IDetailPropertyRow& MeshProxySettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(MeshProxySettingsRow); MeshProxySettingsRow.Visibility(TAttribute(this, &FMeshProxySettingsCustomizations::IsVoxelSizeVisible)); } else if (Iter.Value() == ScreenSizeHandle) { IDetailPropertyRow& MeshProxySettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(MeshProxySettingsRow); MeshProxySettingsRow.Visibility(TAttribute(this, &FMeshProxySettingsCustomizations::IsScreenSizeVisible)); } else { IDetailPropertyRow& SettingsRow = AddPropertyToGroup(Iter.Value().ToSharedRef()); AddResetToDefaultOverrides(SettingsRow); } } } EVisibility FMeshProxySettingsCustomizations::IsThirdPartySpecificVisible() const { // Static assignment. The tool can only change during editor restart. static bool bUseNativeTool = UseNativeProxyLODTool(); if (bUseNativeTool) { return EVisibility::Hidden; } return EVisibility::Visible; } EVisibility FMeshProxySettingsCustomizations::IsProxyLODSpecificVisible() const { // Static assignment. The tool can only change during editor restart. static bool bUseNativeTool = UseNativeProxyLODTool(); if (bUseNativeTool) { return EVisibility::Visible; } return EVisibility::Hidden; } EVisibility FMeshProxySettingsCustomizations::IsHardAngleThresholdVisible() const { // Only proxyLOD actually uses this setting. Historically, it has been exposed for // simplygon, but it was not actually connected! return IsProxyLODSpecificVisible(); } EVisibility FMeshProxySettingsCustomizations::IsNormalCalcMethodVisible() const { // Only ProxyLOD return IsProxyLODSpecificVisible(); } EVisibility FMeshProxySettingsCustomizations::IsRecalculateNormalsVisible() const { return IsThirdPartySpecificVisible(); } EVisibility FMeshProxySettingsCustomizations::IsUseLandscapeCullingVisible() const { return EVisibility::Visible; } EVisibility FMeshProxySettingsCustomizations::IsUseLandscapeCullingPrecisionVisible() const { return IsThirdPartySpecificVisible(); } EVisibility FMeshProxySettingsCustomizations::IsMergeDistanceVisible() const { return EVisibility::Visible; } EVisibility FMeshProxySettingsCustomizations::IsUnresolvedGeometryColorVisible() const { // visible for proxylod but not third party tool (e.g. simplygon) return IsProxyLODSpecificVisible(); } EVisibility FMeshProxySettingsCustomizations::IsSearchDistanceVisible() const { return IsProxyLODSpecificVisible(); } EVisibility FMeshProxySettingsCustomizations::IsVoxelSizeVisible() const { return IsProxyLODSpecificVisible(); } EVisibility FMeshProxySettingsCustomizations::IsScreenSizeVisible() const { return bIsEditingHLODLayer ? EVisibility::Hidden : IsProxyLODSpecificVisible(); } #undef LOCTEXT_NAMESPACE