// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "Layout/Visibility.h" #include "Input/Reply.h" #include "Widgets/SWidget.h" #include "Widgets/SBoxPanel.h" #include "EngineDefines.h" #include "Engine/SkeletalMesh.h" #include "PropertyHandle.h" #include "IDetailCustomNodeBuilder.h" #include "IDetailCustomization.h" #include "SkeletalMeshReductionSettings.h" #include "Widgets/Input/SComboBox.h" DECLARE_LOG_CATEGORY_EXTERN(LogSkeletalMeshPersonaMeshDetail, Log, All); struct FAssetData; class FNaniteSkeletalMeshLayout; class FDetailWidgetRow; class FPersonaMeshDetails; class IDetailChildrenBuilder; class IDetailLayoutBuilder; class IPersonaToolkit; class SUniformGridPanel; struct FSectionLocalizer; class IDetailCategoryBuilder; class IDetailGroup; //The parameter is the LOD index so we know which LOD need to be rebuild DECLARE_DELEGATE_RetVal_OneParam(bool, FIsLODSettingsEnabledDelegate, int32) DECLARE_DELEGATE_OneParam(FModifyMeshLODSettingsDelegate, int32) /** * Struct to uniquely identify clothing applied to a material section * Contains index into the ClothingAssets array and the submesh index. */ struct FClothAssetSubmeshIndex { FClothAssetSubmeshIndex(int32 InAssetIndex, int32 InSubmeshIndex) : AssetIndex(InAssetIndex) , SubmeshIndex(InSubmeshIndex) {} int32 AssetIndex; int32 SubmeshIndex; bool operator==(const FClothAssetSubmeshIndex& Other) const { return (AssetIndex == Other.AssetIndex && SubmeshIndex == Other.SubmeshIndex ); } }; struct FClothingComboInfo { /* Per-material clothing combo boxes, array size must be same to # of sections */ TArray> ClothingComboBoxes; /* Clothing combo box strings */ TArray > ClothingComboStrings; /* Mapping from a combo box string to the asset and submesh it was generated from */ TMap ClothingComboStringReverseLookup; /* The currently-selected index from each clothing combo box */ TArray ClothingComboSelectedIndices; }; struct FSectionLocalizer { FSectionLocalizer(int32 InLODIndex, int32 InSectionIndex) : LODIndex(InLODIndex) , SectionIndex(InSectionIndex) {} bool operator==(const FSectionLocalizer& Other) const { return (LODIndex == Other.LODIndex && SectionIndex == Other.SectionIndex); } bool operator!=(const FSectionLocalizer& Other) const { return !((*this) == Other); } int32 LODIndex; int32 SectionIndex; }; class FSkeletalMeshReductionSettingsLayout : public IDetailCustomNodeBuilder, public TSharedFromThis { public: FSkeletalMeshReductionSettingsLayout(FSkeletalMeshOptimizationSettings& InReductionettings, bool InbIsLODModelbuildDataAvailable, int32 InLODIndex, FIsLODSettingsEnabledDelegate InIsLODSettingsEnabledDelegate, FModifyMeshLODSettingsDelegate InModifyMeshLODSettingsDelegate); virtual ~FSkeletalMeshReductionSettingsLayout() {}; enum EImportanceType { ID_Silhouette, ID_Texture, ID_Shading, ID_Skinning }; DECLARE_DELEGATE_RetVal(float, FGetFloatDelegate); DECLARE_DELEGATE_OneParam(FSetFloatDelegate, float); DECLARE_DELEGATE_RetVal(int32, FGetIntegerDelegate); DECLARE_DELEGATE_OneParam(FSetIntegerDelegate, int32); DECLARE_DELEGATE_RetVal(uint32, FGetUnsignedIntegerDelegate); DECLARE_DELEGATE_OneParam(FSetUnsignedIntegerDelegate, uint32); DECLARE_DELEGATE_RetVal(ECheckBoxState, FGetCheckBoxStateDelegate); DECLARE_DELEGATE_OneParam(FSetCheckBoxStateDelegate, ECheckBoxState); void UnbindReductionSettings() { IsLODSettingsEnabledDelegate.Unbind(); } private: /** IDetailCustomNodeBuilder Interface*/ virtual void SetOnRebuildChildren(FSimpleDelegate InOnRegenerateChildren) override {} virtual void GenerateHeaderRowContent(FDetailWidgetRow& NodeRow) override; virtual void GenerateChildContent(IDetailChildrenBuilder& ChildrenBuilder) override; virtual void Tick(float DeltaTime) override {} virtual bool RequiresTick() const override { return false; } virtual FName GetName() const override { static FName MeshReductionSettings("SkeletalMeshOptimizationSettings"); return MeshReductionSettings; } virtual bool InitiallyCollapsed() const override { return true; } bool IsReductionEnabled() const; //Custom Row Add utilities FDetailWidgetRow& AddFloatRow(IDetailChildrenBuilder& ChildrenBuilder, const FText RowTitleText, const FText RowNameContentText, const FText RowNameContentTootlipText, FName RowTag, const float MinSliderValue, const float MaxSliderValue, FGetFloatDelegate GetterDelegate, FSetFloatDelegate SetterDelegate); FDetailWidgetRow& AddBoolRow(IDetailChildrenBuilder& ChildrenBuilder, const FText RowTitleText, const FText RowNameContentText, const FText RowNameContentToolitipText, FName RowTag, FGetCheckBoxStateDelegate GetterDelegate, FSetCheckBoxStateDelegate SetterDelegate); FDetailWidgetRow& AddIntegerRow(IDetailChildrenBuilder& ChildrenBuilder, const FText RowTitleText, const FText RowNameContentText, const FText RowNameContentTootlipText, FName RowTag, const int32 MinSliderValue, const int32 MaxSliderValue, FGetIntegerDelegate GetterDelegate, FSetIntegerDelegate SetterDelegate); FDetailWidgetRow& AddUnsignedIntegerRow(IDetailChildrenBuilder& ChildrenBuilder, const FText RowTitleText, const FText RowNameContentText, const FText RowNameContentTootlipText, FName RowTag, const uint32 MinSliderValue, const uint32 MaxSliderValue, FGetUnsignedIntegerDelegate GetterDelegate, FSetUnsignedIntegerDelegate SetterDelegate); void AddBaseLODRow(IDetailChildrenBuilder& ChildrenBuilder); void SetPercentAndAbsoluteVisibility(FDetailWidgetRow& Row, SkeletalMeshTerminationCriterion FirstCriterion, SkeletalMeshTerminationCriterion SecondCriterion); int32 GetBaseLODValue() const { return ReductionSettings.BaseLOD; } void SetBaseLODValue(int32 Value) { ReductionSettings.BaseLOD = Value; } TSharedRef FillReductionMethodMenu(); FText GetReductionMethodText() const; TSharedRef FillReductionImportanceMenu(const EImportanceType Importance); FText GetReductionImportanceText(const EImportanceType Importance) const; TSharedRef FillReductionTerminationCriterionMenu(); FText GetReductionTerminationCriterionText() const; float GetNumTrianglesPercentage() const; void SetNumTrianglesPercentage(float Value); float GetNumVerticesPercentage() const; void SetNumVerticesPercentage(float Value); int32 GetNumMaxTrianglesCount() const; void SetNumMaxTrianglesCount(int32 Value); int32 GetNumMaxVerticesCount() const; void SetNumMaxVerticesCount(int32 Value); uint32 GetNumMaxTrianglesPercentageCount() const; void SetNumMaxTrianglesPercentageCount(uint32 Value); uint32 GetNumMaxVerticesPercentageCount() const; void SetNumMaxVerticesPercentageCount(uint32 Value); float GetAccuracyPercentage() const; void SetAccuracyPercentage(float Value); ECheckBoxState ShouldRecomputeNormals() const; void OnRecomputeNormalsChanged(ECheckBoxState NewState); float GetNormalsThreshold() const; void SetNormalsThreshold(float Value); float GetWeldingThreshold() const; void SetWeldingThreshold(float Value); ECheckBoxState GetLockEdges() const; void SetLockEdges(ECheckBoxState NewState); ECheckBoxState GetLockColorBounaries() const; void SetLockColorBounaries(ECheckBoxState NewState); ECheckBoxState GetImproveTrianglesForCloth() const; void SetImproveTrianglesForCloth(ECheckBoxState NewState); ECheckBoxState GetEnforceBoneBoundaries() const; void SetEnforceBoneBoundaries(ECheckBoxState NewState); ECheckBoxState GetMergeCoincidentVertBones() const; void SetMergeCoincidentVertBones(ECheckBoxState NewState); float GetVolumeImportance() const; void SetVolumeImportance(float Value); ECheckBoxState GetRemapMorphTargets() const; void SetRemapMorphTargets(ECheckBoxState NewState); int32 GetMaxBonesPerVertex() const; void SetMaxBonesPerVertex(int32 Value); // Used the the thrid-party UI. EVisibility GetVisibiltyIfCurrentReductionMethodIsNot(SkeletalMeshOptimizationType ReductionType) const; // Used by the native tool UI. EVisibility ShowIfCurrentCriterionIs(TArray TerminationCriterionArray) const; /** Detect usage of thirdparty vs native tool */ bool UseNativeLODTool() const; bool UseNativeReductionTool() const; /** Used to hide parameters that only make sense for the third party tool. @return EVisibility::Visible if we are using the simplygon tool, otherwise EVisibility::Hidden */ EVisibility GetVisibilityForThirdPartyTool() const; private: FSkeletalMeshOptimizationSettings& ReductionSettings; bool bIsLODModelbuildDataAvailable; int32 LODIndex; FIsLODSettingsEnabledDelegate IsLODSettingsEnabledDelegate; FModifyMeshLODSettingsDelegate ModifyMeshLODSettingsDelegate; UEnum* EnumReductionMethod; UEnum* EnumImportance; UEnum* EnumTerminationCriterion; //Use this data to keep a valid reference so the helper lambda can have persistent data //Helper lambda are use with spinner to not do a transaction when spinning with mouse movement struct FSliderStateData { float MovementValueFloat = 0.0f; int32 MovementValueInt = 0; uint32 MovementValueUnsignedInt = 0; bool bSliderActiveMode = false; }; TArray SliderStateDataArray; }; class FSkeletalMeshBuildSettingsLayout : public IDetailCustomNodeBuilder, public TSharedFromThis { public: FSkeletalMeshBuildSettingsLayout(FSkeletalMeshBuildSettings& InBuildSettings, int32 InLODIndex, FIsLODSettingsEnabledDelegate InIsBuildSettingsEnabledDelegate, FModifyMeshLODSettingsDelegate InModifyMeshLODSettingsDelegate); virtual ~FSkeletalMeshBuildSettingsLayout() {}; DECLARE_DELEGATE_RetVal(float, FGetFloatDelegate); DECLARE_DELEGATE_OneParam(FSetFloatDelegate, float); DECLARE_DELEGATE_RetVal(int32, FGetIntegerDelegate); DECLARE_DELEGATE_OneParam(FSetIntegerDelegate, int32); void UnbindBuildSettings() { IsBuildSettingsEnabledDelegate.Unbind(); } private: /** IDetailCustomNodeBuilder Interface*/ virtual void SetOnRebuildChildren(FSimpleDelegate InOnRegenerateChildren) override {} virtual void GenerateHeaderRowContent(FDetailWidgetRow& NodeRow) override; virtual void GenerateChildContent(IDetailChildrenBuilder& ChildrenBuilder) override; virtual void Tick(float DeltaTime) override {} virtual bool RequiresTick() const override { return false; } virtual FName GetName() const override { static FName MeshBuildSettings("MeshBuildSettings"); return MeshBuildSettings; } virtual bool InitiallyCollapsed() const override { return true; } bool IsBuildEnabled() const; //Custom Row Add utilities FDetailWidgetRow& AddFloatRow(IDetailChildrenBuilder& ChildrenBuilder, const FText RowTitleText, const FText RowNameContentText, const FText RowNameContentTootlipText, const float MinSliderValue, const float MaxSliderValue, FGetFloatDelegate GetterDelegate, FSetFloatDelegate SetterDelegate); FDetailWidgetRow& AddIntegerRow( IDetailChildrenBuilder& ChildrenBuilder, const FText& RowTitleText, const FText& RowNameContentText, const FText& RowNameContentTooltipText, FName RowTag, const int32 MinSliderValue, const int32 MaxSliderValue, const FGetIntegerDelegate& GetterDelegate, const FSetIntegerDelegate& SetterDelegate); float GetThresholdPosition() const; void SetThresholdPosition(float Value); float GetThresholdTangentNormal() const; void SetThresholdTangentNormal(float Value); float GetThresholdUV() const; void SetThresholdUV(float Value); float GetMorphThresholdPosition() const; void SetMorphThresholdPosition(float Value); int32 GetBoneInfluenceLimit() const; void SetBoneInfluenceLimit(int32 Value); ECheckBoxState ShouldRecomputeNormals() const; ECheckBoxState ShouldRecomputeTangents() const; ECheckBoxState ShouldUseMikkTSpace() const; ECheckBoxState ShouldComputeWeightedNormals() const; ECheckBoxState ShouldRemoveDegenerates() const; ECheckBoxState ShouldUseHighPrecisionTangentBasis() const; ECheckBoxState ShouldUseHighPrecisionSkinWeights() const; ECheckBoxState ShouldUseFullPrecisionUVs() const; ECheckBoxState ShouldUseBackwardsCompatibleF16TruncUVs() const; void OnRecomputeNormalsChanged(ECheckBoxState NewState); void OnRecomputeTangentsChanged(ECheckBoxState NewState); void OnUseMikkTSpaceChanged(ECheckBoxState NewState); void OnComputeWeightedNormalsChanged(ECheckBoxState NewState); void OnRemoveDegeneratesChanged(ECheckBoxState NewState); void OnUseHighPrecisionTangentBasisChanged(ECheckBoxState NewState); void OnUseHighPrecisionSkinWeightsChanged(ECheckBoxState NewState); void OnUseFullPrecisionUVsChanged(ECheckBoxState NewState); void OnUseBackwardsCompatibleF16TruncUVsChanged(ECheckBoxState NewState); private: FSkeletalMeshBuildSettings& BuildSettings; int32 LODIndex; FIsLODSettingsEnabledDelegate IsBuildSettingsEnabledDelegate; FModifyMeshLODSettingsDelegate ModifyMeshLODSettingsDelegate; //Use this data to keep a valid reference so the helper lambda can have persistent data //Helper lambda are use with spinner to not do a transaction when spinning with mouse movement struct FSliderStateData { float MovementValueFloat = 0.0f; int32 MovementValueInt = 0; bool bSliderActiveMode = false; }; TArray SliderStateDataArray; }; class FPersonaMeshDetails : public IDetailCustomization { public: FPersonaMeshDetails(TSharedRef InPersonaToolkit); ~FPersonaMeshDetails(); /** Makes a new instance of this detail layout class for a specific detail view requesting it */ static TSharedRef MakeInstance(TWeakPtr InPersonaToolkit); /** IDetailCustomization interface */ virtual void CustomizeDetails( IDetailLayoutBuilder& DetailLayout ) override; public: void ForceLayoutRebuild(); void RequestLayoutUpdate(); private: //Prevent attribute change calling post edit change void OnAttributePreChangePreventPostEditChange(int32 LODIndex, FName LODInfoPropertyName) const; void OnAttributeChangedPreventPostEditChange(const int32 LODIndex, const FName LODInfoPropertyName, const bool bForceComponentRefresh) const; void PreventAttributePostEditChange(TSharedPtr AttributeHandle, const int32 LODIndex, const FName PropertyName, const bool bForceComponentRefresh) const; //This function customize the LODInfo temporary object void CustomizeLODInfoSetingsDetails(IDetailLayoutBuilder& DetailLayout, class ULODInfoUILayout* LODInfoUILayout, TSharedRef LODInfoProperty, IDetailCategoryBuilder& LODCategory); FReply AddMaterialSlot(); FText GetMaterialArrayText() const; /** * Called by the material list widget when we need to get new materials for the list * * @param OutMaterials Handle to a material list builder that materials should be added to */ void OnGetSectionsForView( class ISectionListBuilder& OutSections, int32 LODIndex ); /** * Called when a user drags a new material over a list item to replace it * * @param NewMaterial The material that should replace the existing material * @param PrevMaterial The material that should be replaced * @param SlotIndex The index of the slot on the component where materials should be replaces * @param bReplaceAll If true all materials in the slot should be replaced not just ones using PrevMaterial */ void OnSectionChanged(int32 LODIndex, int32 SectionIndex, int32 NewMaterialSlotIndex, FName NewMaterialSlotName); /** * Called by the material list widget when we need to get new materials for the list * * @param OutMaterials Handle to a material list builder that materials should be added to */ void OnGetMaterialsForArray(class IMaterialListBuilder& OutMaterials, int32 LODIndex); /** * Called when a user drags a new material over a list item to replace it * * @param NewMaterial The material that should replace the existing material * @param PrevMaterial The material that should be replaced * @param SlotIndex The index of the slot on the component where materials should be replaces * @param bReplaceAll If true all materials in the slot should be replaced not just ones using PrevMaterial */ void OnMaterialArrayChanged(UMaterialInterface* NewMaterial, UMaterialInterface* PrevMaterial, int32 SlotIndex, bool bReplaceAll, int32 LODIndex); /** * Called by the material list widget on generating each name widget * * @param Material The material that is being displayed * @param SlotIndex The index of the material slot */ TSharedRef OnGenerateCustomNameWidgetsForSection(int32 LodIndex, int32 SectionIndex); /** * Called by the material list widget on generating each thumbnail widget * * @param Material The material that is being displayed * @param SlotIndex The index of the material slot */ TSharedRef OnGenerateCustomSectionWidgetsForSection(int32 LODIndex, int32 SectionIndex); bool IsSectionEnabled(int32 LodIndex, int32 SectionIndex) const; EVisibility ShowEnabledSectionDetail(int32 LodIndex, int32 SectionIndex) const; EVisibility ShowDisabledSectionDetail(int32 LodIndex, int32 SectionIndex) const; void OnSectionEnabledChanged(int32 LodIndex, int32 SectionIndex, bool bEnable); TOptional GetSectionGenerateUpToValue(int32 LodIndex, int32 SectionIndex) const; void SetSectionGenerateUpToValue(int8 Value, int32 LodIndex, int32 SectionIndex); void SetSectionGenerateUpToValueCommitted(int8 Value, ETextCommit::Type CommitInfo, int32 LodIndex, int32 SectionIndex); EVisibility ShowSectionGenerateUpToSlider(int32 LodIndex, int32 SectionIndex) const; ECheckBoxState IsGenerateUpToSectionEnabled(int32 LodIndex, int32 SectionIndex) const; void OnSectionGenerateUpToChanged(ECheckBoxState NewState, int32 LodIndex, int32 SectionIndex); TSharedRef OnGenerateLodComboBoxForLodPicker(); EVisibility LodComboBoxVisibilityForLodPicker() const; bool IsLodComboBoxEnabledForLodPicker() const; /* * Generate the context menu to choose the LOD we will display the picker list */ TSharedRef OnGenerateLodMenuForLodPicker(); FText GetCurrentLodName() const; FText GetCurrentLodTooltip() const; static bool GetAutoLod(USkeletalMeshComponent* InMeshComponent); static int32 GetCurrentDisplayLODIndex(USkeletalMeshComponent* InMeshComponent); void SetCurrentLOD(int32 NewLodIndex); void UpdateLODCategoryVisibility() const; FText GetMaterialNameText(int32 MaterialIndex)const ; void OnMaterialNameCommitted(const FText& InValue, ETextCommit::Type CommitType, int32 MaterialIndex); FText GetOriginalImportMaterialNameText(int32 MaterialIndex)const; /** * Called by the material list widget on generating name side content * * @param Material The material that is being displayed * @param MaterialIndex The index of the material slot */ TSharedRef OnGenerateCustomNameWidgetsForMaterialArray(UMaterialInterface* Material, int32 MaterialIndex); /** * Called by the material list widget on generating each thumbnail widget * * @param Material The material that is being displayed * @param MaterialIndex The index of the material slot */ TSharedRef OnGenerateCustomMaterialWidgetsForMaterialArray(UMaterialInterface* Material, int32 MaterialIndex, int32 LODIndex); /** * Called by the material list widget on generating each thumbnail widget * Those generated widget will be stack under the material list row * * @param Material The material that is being displayed * @param MaterialIndex The index of the material slot */ TSharedRef OnGenerateMaterialListExtraBottomWidget(UMaterialInterface* Material, int32 MaterialIndex, int32 LODIndex); /* If the material list is dirty this function will return true */ bool OnMaterialListDirty(); bool CanDeleteMaterialSlot(int32 MaterialIndex) const; void OnDeleteMaterialSlot(int32 MaterialIndex); /* Call when user change the material slot overlay material. */ void OnMaterialSlotOverlayMaterialChanged(UMaterialInterface* NewOverlayMaterial, int32 MaterialIndex); /** * Handler for check box display based on whether the material is highlighted * * @param MaterialIndex The material index that is being selected */ ECheckBoxState IsMaterialSelected(int32 MaterialIndex) const; /** * Handler for changing highlight status on a material * * @param MaterialIndex The material index that is being selected */ void OnMaterialSelectedChanged(ECheckBoxState NewState, int32 MaterialIndex); /** * Handler for check box display based on whether the material is isolated * * @param MaterialIndex The material index that is being isolate */ ECheckBoxState IsIsolateMaterialEnabled(int32 MaterialIndex) const; /** * Handler for changing isolated status on a material * * @param MaterialIndex The material index that is being isolate */ void OnMaterialIsolatedChanged(ECheckBoxState NewState, int32 MaterialIndex); /** * Handler for check box display based on whether the material is highlighted * * @param SectionIndex The material section that is being tested */ ECheckBoxState IsSectionSelected(int32 SectionIndex) const; /** * Handler for changing highlight status on a material * * @param SectionIndex The material section that is being tested */ void OnSectionSelectedChanged(ECheckBoxState NewState, int32 SectionIndex); /** * Handler for check box display based on whether the material is isolated * * @param SectionIndex The material section that is being tested */ ECheckBoxState IsIsolateSectionEnabled(int32 SectionIndex) const; /** * Handler for changing isolated status on a material * * @param SectionIndex The material section that is being tested */ void OnSectionIsolatedChanged(ECheckBoxState NewState, int32 SectionIndex); /** * Handler for check box display based on whether the material has shadow casting enabled * * @param LODIndex The LODIndex we want to change * @param SectionIndex The SectionIndex we change the ShadowCasting flag */ ECheckBoxState IsSectionShadowCastingEnabled(int32 LODIndex, int32 SectionIndex) const; /** * Handler for changing shadow casting status on a section * * @param LODIndex The LODIndex we want to change * @param SectionIndex The SectionIndex we change the ShadowCasting flag */ void OnSectionShadowCastingChanged(ECheckBoxState NewState, int32 LODIndex, int32 SectionIndex); /** * Handler for check box display based on whether the material has VisibleInRayTracing enabled * * @param LODIndex The LODIndex we want to change * @param SectionIndex The SectionIndex we change the VisibleInRayTracing flag */ ECheckBoxState IsSectionVisibleInRayTracingEnabled(int32 LODIndex, int32 SectionIndex) const; /** * Handler for changing VisibleInRayTracing status on a section * * @param LODIndex The LODIndex we want to change * @param SectionIndex The SectionIndex we change the VisibleInRayTracing flag */ void OnSectionVisibleInRayTracingChanged(ECheckBoxState NewState, int32 LODIndex, int32 SectionIndex); /** * Handler for selecting which vertex color to mask the blending of recomputing tangents * * @param LODIndex The LODIndex we want to change * @param SectionIndex The SectionIndex we change the RecomputeTangent */ TSharedRef OnGenerateRecomputeTangentsSetting(int32 LODIndex, int32 SectionIndex); FText GetCurrentRecomputeTangentsSetting(int32 LODIndex, int32 SectionIndex) const; void SetCurrentRecomputeTangentsSetting(int32 LODIndex, int32 SectionIndex, int32 Index); /** * Handler for enabling delete button on materials * * @param SectionIndex - index of the section to check */ bool CanDeleteMaterialElement(int32 LODIndex, int32 SectionIndex) const; /** Creates the UI for Current LOD panel */ void AddLODLevelCategories(IDetailLayoutBuilder& DetailLayout); /** Get a material index from LOD index and section index */ int32 GetMaterialIndex(int32 LODIndex, int32 SectionIndex) const; /** for LOD settings category */ void CustomizeLODSettingsCategories(IDetailLayoutBuilder& DetailLayout); /** Called when a LOD is imported. Refreshes the UI. */ void OnAssetPostLODImported(UObject* InObject, int32 InLODIndex); void OnAssetReimport(UObject* InObject); /** Called from the PersonalMeshDetails UI to import a LOD. */ void OnImportLOD(TSharedPtr NewValue, ESelectInfo::Type SelectInfo, IDetailLayoutBuilder* DetailLayout); void UpdateLODNames(); int32 GetLODCount() const; void OnLODCountChanged(int32 NewValue); void OnLODCountCommitted(int32 InValue, ETextCommit::Type CommitInfo); FText GetLODCountTooltip() const; FText GetLODImportedText(int32 LODIndex) const; FText GetMaterialSlotNameText(int32 MaterialIndex) const; void OnNoRefStreamingLODBiasChanged(int32 NewValue, FName QualityLevel); void OnNoRefStreamingLODBiasCommitted(int32 InValue, ETextCommit::Type CommitInfo, FName QualityLevel); int32 GetNoRefStreamingLODBias(FName QualityLevel) const; TSharedRef GetNoRefStreamingLODBiasWidget(FName QualityLevelName) const; bool AddNoRefStreamingLODBiasOverride(FName QualityLevelName); bool RemoveNoRefStreamingLODBiasOverride(FName QualityLevelName); TArray GetNoRefStreamingLODBiasOverrideNames() const; FText GetNoRefStreamingLODBiasTooltip() const; void OnMinQualityLevelLodChanged(int32 NewValue, FName QualityLevel); void OnMinQualityLevelLodCommitted(int32 InValue, ETextCommit::Type CommitInfo, FName QualityLevel); int32 GetMinQualityLevelLod(FName QualityLevel) const; TSharedRef GetMinQualityLevelLodWidget(FName QualityLevelName) const; bool AddMinLodQualityLevelOverride(FName QualityLevelName); bool RemoveMinLodQualityLevelOverride(FName QualityLevelName); TArray GetMinQualityLevelLodOverrideNames() const; FReply ResetToDefault(); FPerPlatformInt GetMinLod(); /** apply LOD changes if the user modified LOD reduction settings */ FReply OnApplyChanges(); /** regenerate one specific LOD Index no dependencies*/ void RegenerateOneLOD(int32 LODIndex); /** regenerate the specific all LODs dependent of InLODIndex. This is not regenerating the InLODIndex*/ void RegenerateDependentLODs(int32 LODIndex); /** Apply specified LOD Index */ FReply ApplyLODChanges(int32 LODIndex); /** Apply specified LOD Index */ FReply RegenerateLOD(int32 LODIndex); /** Removes the specified lod from the skeletal mesh */ FReply RemoveOneLOD(int32 LODIndex); /** Removes any editable geometry from the given LOD, making it auto-generated */ FReply RemoveGeometryFromLOD(int32 LODIndex); /** Restore the LOD imported data if the LOD is no longer reduced */ void RestoreNonReducedLOD(int32 LODIndex); /** hide properties which don't need to be showed to end users */ void HideUnnecessaryProperties(IDetailLayoutBuilder& DetailLayout); // Handling functions for post process blueprint selection combo box void OnPostProcessBlueprintChanged(IDetailLayoutBuilder* DetailBuilder); FString GetCurrentPostProcessBlueprintPath() const; bool OnShouldFilterPostProcessBlueprint(const FAssetData& AssetData) const; void OnSetPostProcessBlueprint(const FAssetData& AssetData, TSharedRef BlueprintProperty); /** Access the persona toolkit ptr. It should always be valid in the lifetime of this customization */ TSharedRef GetPersonaToolkit() const { check(PersonaToolkitPtr.IsValid()); return PersonaToolkitPtr.Pin().ToSharedRef(); } bool HasValidPersonaToolkit() const { return PersonaToolkitPtr.IsValid(); } EVisibility GetOverrideUVDensityVisibililty() const; ECheckBoxState IsUVDensityOverridden(int32 MaterialIndex) const; void OnOverrideUVDensityChanged(ECheckBoxState NewState, int32 MaterialIndex); EVisibility GetUVDensityVisibility(int32 MaterialIndex, int32 UVChannelIndex) const; TOptional GetUVDensityValue(int32 MaterialIndex, int32 UVChannelIndex) const; void SetUVDensityValue(float InDensity, ETextCommit::Type CommitType, int32 MaterialIndex, int32 UVChannelIndex); SVerticalBox::FSlot& GetUVDensitySlot(int32 MaterialIndex, int32 UVChannelIndex) const; // Used to control the type of reimport to do with a named parameter enum class EReimportButtonType : uint8 { Reimport, ReimportWithNewFile }; // Handler for reimport buttons in LOD details FReply OnReimportLodClicked(EReimportButtonType InReimportType, int32 InLODIndex); void OnCopySectionList(int32 LODIndex); bool OnCanCopySectionList(int32 LODIndex) const; void OnPasteSectionList(int32 LODIndex); void OnCopySectionItem(int32 LODIndex, int32 SectionIndex); bool OnCanCopySectionItem(int32 LODIndex, int32 SectionIndex) const; void OnPasteSectionItem(int32 LODIndex, int32 SectionIndex); void OnCopyMaterialList(); bool OnCanCopyMaterialList() const; void OnPasteMaterialList(); void OnCopyMaterialItem(int32 CurrentSlot); bool OnCanCopyMaterialItem(int32 CurrentSlot) const; void OnPasteMaterialItem(int32 CurrentSlot); void OnPreviewMeshChanged(USkeletalMesh* OldSkeletalMesh, USkeletalMesh* NewMesh); bool FilterOutBakePose(const struct FAssetData& AssetData, USkeleton* Skeleton) const; bool FilterOutBakePose(const struct FAssetData& AssetData, TObjectPtr Skeleton) const { return FilterOutBakePose(AssetData, Skeleton.Get()); } FText GetLODCustomModeNameContent(int32 LODIndex) const; ECheckBoxState IsLODCustomModeCheck(int32 LODIndex) const; void SetLODCustomModeCheck(ECheckBoxState NewState, int32 LODIndex); bool IsLODCustomModeEnable(int32 LODIndex) const; /** Gets the max LOD that can be set from the lod count slider (current num plus an interval) */ TOptional GetLodSliderMaxValue() const; void CustomizeSkinWeightProfiles(IDetailLayoutBuilder& DetailLayout); TSharedRef CreateSkinWeightProfileMenuContent(); public: bool IsApplyNeeded() const; bool IsGenerateAvailable() const; void ApplyChanges(); FText GetApplyButtonText() const; private: // Container for the objects to display TWeakObjectPtr SkeletalMeshPtr; // Reference the persona toolkit TWeakPtr PersonaToolkitPtr; /** Nanite settings for the details panel. */ TSharedPtr NaniteSettings; IDetailLayoutBuilder* MeshDetailLayout; //This is the mockup UObjects to modify a copy of the LODInfo TArray LODInfoUILayouts; TArray> LODInfoUILayoutDetailsViews; /** LOD import options */ TArray > LODNames; /** Helper value that corresponds to the 'Number of LODs' spinbox.*/ int32 LODCount; /* This is to know if material are used by any LODs sections. */ TMap> MaterialUsedMap; TArray LodCategories; IDetailCategoryBuilder* LodCustomCategory; bool CustomLODEditMode; TArray DetailDisplayLODs; /* * Helper to keep the old GenerateUpTo slider value to register transaction correctly. * The key is the union of LOD index and section index. */ TMap OldGenerateUpToSliderValues; /* * This prevent showing the delete material slot warning dialog more then once per editor session */ bool bDeleteWarningConsumed; private: // info about clothing combo boxes for multiple LOD TArray ClothingComboLODInfos; TArray ClothingSelectedSubmeshIndices; // Menu entry for clothing dropdown struct FClothingEntry { // Asset index inside the mesh int32 AssetIndex; // LOD index inside the clothing asset int32 AssetLodIndex; // Pointer back to the asset for this clothing entry TWeakObjectPtr Asset; }; // Cloth combo box tracking for refreshes post-import/creation typedef SComboBox> SClothComboBox; typedef TSharedPtr SClothComboBoxPtr; TArray ClothComboBoxes; // Clothing entries available to bind to the mesh TArray> NewClothingAssetEntries; // Cached item in above array that is used as the "None" entry in the list TSharedPtr ClothingNoneEntry; // Update the list of valid entries void UpdateClothingEntries(); // Refreshes clothing combo boxes that are currently active void RefreshClothingComboBoxes(); // Called as clothing combo boxes open to validate option entries void OnClothingComboBoxOpening(); // Generate a widget for the clothing details panel TSharedRef OnGenerateWidgetForClothingEntry(TSharedPtr InEntry); // Get the current text for the clothing selection combo box for the specified LOD and section FText OnGetClothingComboText(int32 InLodIdx, int32 InSectionIdx) const; // Callback when the clothing asset is changed void OnClothingSelectionChanged(TSharedPtr InNewEntry, ESelectInfo::Type InSelectType, int32 BoxIndex, int32 InLodIdx, int32 InSectionIdx); // If the clothing details widget is editable bool IsClothingPanelEnabled() const; /* Generate slate UI for Clothing category */ void CustomizeClothingProperties(class IDetailLayoutBuilder& DetailLayout, class IDetailCategoryBuilder& ClothingFilesCategory); /* Generate each ClothingAsset array entry */ void OnGenerateElementForClothingAsset( TSharedRef ElementProperty, int32 ElementIndex, IDetailChildrenBuilder& ChildrenBuilder, IDetailLayoutBuilder* DetailLayout ); /* Make uniform grid widget for Apex details */ TSharedRef MakeClothingDetailsWidget(int32 AssetIndex) const; /* Removes a clothing asset */ FReply OnRemoveClothingAssetClicked(int32 AssetIndex, IDetailLayoutBuilder* DetailLayout); /* Create LOD setting assets from current setting */ FReply OnSaveLODSettings(); /** LOD Settings Selected */ void OnLODSettingsSelected(const FAssetData& AssetData); /** LOD Info editing is enabled? LODIndex == -1, then it just verifies if the asset exists */ bool IsLODInfoEditingEnabled(int32 LODIndex) const; bool IsMinLodEnable() const; bool IsQualityLevelMinLodEnable() const; void ModifyMeshLODSettings(int32 LODIndex); TMap> BuildSettingsWidgetsPerLOD; TMap> ReductionSettingsWidgetsPerLOD; // Property handle used to determine if the VertexColorImportOverride property should be enabled. TSharedPtr VertexColorImportOptionHandle; // Property handle used during UI construction TSharedPtr VertexColorImportOverrideHandle; // Delegate implementation of FOnInstancedPropertyIteration used during DataImport UI construction void OnInstancedFbxSkeletalMeshImportDataPropertyIteration(IDetailCategoryBuilder& BaseCategory, IDetailGroup* PropertyGroup, TSharedRef& Property) const; // Delegate used at runtime to determine the state of the VertexOverrideColor property bool GetVertexOverrideColorEnabledState() const; // Called when the skeletal mesh has finished rebuilding. This may affect some settings, such as vertex attributes. void OnMeshRebuildCompleted(USkeletalMesh* InMesh); };