// Copyright Epic Games, Inc. All Rights Reserved. #include "AssetDefinition_StaticMesh.h" #include "Algo/Accumulate.h" #include "EditorSupportDelegates.h" #include "Engine/StaticMeshSourceData.h" #include "StaticMeshEditorModule.h" #include "FbxMeshUtils.h" #include "Misc/MessageDialog.h" #include "StaticMeshCompiler.h" #include "ThumbnailRendering/SceneThumbnailInfo.h" #include "ToolMenu.h" #include "ToolMenus.h" #include "ContentBrowserMenuContexts.h" #include "ToolMenuSection.h" #define LOCTEXT_NAMESPACE "UAssetDefinition_StaticMesh" UThumbnailInfo* UAssetDefinition_StaticMesh::LoadThumbnailInfo(const FAssetData& InAssetData) const { return UE::Editor::FindOrCreateThumbnailInfo(InAssetData.GetAsset(), USceneThumbnailInfo::StaticClass()); } FAssetOpenSupport UAssetDefinition_StaticMesh::GetAssetOpenSupport(const FAssetOpenSupportArgs& OpenSupportArgs) const { return FAssetOpenSupport(OpenSupportArgs.OpenMethod,OpenSupportArgs.OpenMethod == EAssetOpenMethod::Edit || OpenSupportArgs.OpenMethod == EAssetOpenMethod::View); } EAssetCommandResult UAssetDefinition_StaticMesh::OpenAssets(const FAssetOpenArgs& OpenArgs) const { IStaticMeshEditorModule* StaticMeshEditorModule = &FModuleManager::LoadModuleChecked( "StaticMeshEditor" ); for (UStaticMesh* Mesh : OpenArgs.LoadObjects()) { StaticMeshEditorModule->CreateStaticMeshEditor(OpenArgs.GetToolkitMode(), OpenArgs.ToolkitHost, Mesh); } return EAssetCommandResult::Handled; } // Menu Extensions //-------------------------------------------------------------------- namespace MenuExtension_StaticMesh { // When copying and pasting LOD data between meshes, we don't actually put the data onto the clipboard it's just // data stored here and referenced when executing paste. static TWeakObjectPtr LODCopyMesh; static TAutoConsoleVariable CVarEnableSaveGeneratedLODsInPackage( TEXT("r.StaticMesh.EnableSaveGeneratedLODsInPackage"), 0, TEXT("Enables saving generated LODs in the Package.\n") \ TEXT("0 - Do not save (and hide this menu option) [default].\n") \ TEXT("1 - Enable this option and save the LODs in the Package.\n"), ECVF_Default ); static void ExecuteSaveGeneratedLODsInPackage(const FToolMenuContext& InContext) { if (const UContentBrowserAssetContextMenuContext* CBContext = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext)) { for (UStaticMesh* StaticMesh : CBContext->LoadSelectedObjects()) { StaticMesh->GenerateLodsInPackage(); } } } static void ExecuteRemoveVertexColors(const FToolMenuContext& InContext) { const FText WarningMessage = LOCTEXT("Warning_RemoveVertexColors", "Are you sure you want to remove vertex colors from all selected meshes? There is no undo available."); if (FMessageDialog::Open(EAppMsgType::YesNo, WarningMessage) == EAppReturnType::Yes) { FScopedSlowTask SlowTask(1.0f, LOCTEXT("RemovingVertexColors", "Removing Vertex Colors")); if (const UContentBrowserAssetContextMenuContext* CBContext = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext)) { for (UStaticMesh* StaticMesh : CBContext->LoadSelectedObjects()) { StaticMesh->RemoveVertexColors(); } } } } // Nanite Section //================================================================= const static FName NAME_NaniteEnabled("NaniteEnabled"); static bool IsNaniteEnabled(const FAssetData& StaticMeshAsset) { bool bNaniteEnabled = false; return StaticMeshAsset.GetTagValue(NAME_NaniteEnabled, bNaniteEnabled) && bNaniteEnabled; } void ModifyNaniteEnable(const TArray& Objects, bool bNaniteEnable) { TArray Meshes; Meshes.Reserve(Objects.Num()); for (UStaticMesh* Mesh: Objects) { if (Mesh && Mesh->NaniteSettings.bEnabled != bNaniteEnable) { Meshes.Add(Mesh); } } FStaticMeshCompilingManager::FFinishCompilationOptions FinishCompilationOptions; FinishCompilationOptions.bIncludeDependentMeshes = true; FStaticMeshCompilingManager::Get().FinishCompilation(Meshes, FinishCompilationOptions); for (UStaticMesh* Mesh : Meshes) { Mesh->NaniteSettings.bEnabled = bNaniteEnable; } UStaticMesh::BatchBuild(Meshes); for (UStaticMesh* Mesh : Meshes) { Mesh->MarkPackageDirty(); Mesh->OnMeshChanged.Broadcast(); } } void ExecuteNaniteEnable(const FToolMenuContext& InContext) { const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext); TArray RegularMeshes = Context->LoadSelectedObjectsIf([](const FAssetData& AssetData) { return !IsNaniteEnabled(AssetData); }); ModifyNaniteEnable(RegularMeshes, true); } void ExecuteNaniteDisable(const FToolMenuContext& InContext) { const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext); TArray NaniteMeshes = Context->LoadSelectedObjectsIf([](const FAssetData& AssetData) { return IsNaniteEnabled(AssetData); }); ModifyNaniteEnable(NaniteMeshes, false); } static void GetNaniteMenu(UToolMenu* Menu) { const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(*Menu); FToolMenuSection& Section = Menu->FindOrAddSection("NaniteActions"); { const TAttribute Label = LOCTEXT("StaticMesh_NaniteToggle", "Nanite"); const TAttribute ToolTip = LOCTEXT("StaticMesh_NaniteToggleTooltip", "Toggle Nanite support on the selected meshes."); const FSlateIcon Icon = FSlateIcon(); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateLambda([](const FToolMenuContext& InContext) { if (const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext)) { const bool bContainsTrue = Context->SelectedAssets.ContainsByPredicate([](const FAssetData& InAsset) { return IsNaniteEnabled(InAsset); }); const bool bContainsFalse = Context->SelectedAssets.ContainsByPredicate([](const FAssetData& InAsset) { return !IsNaniteEnabled(InAsset); }); if ((bContainsTrue && bContainsFalse) || bContainsTrue) { ExecuteNaniteDisable(InContext); } else { ExecuteNaniteEnable(InContext); } } }); UIAction.GetActionCheckState = FToolMenuGetActionCheckState::CreateLambda([](const FToolMenuContext& InContext) { if (const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext)) { const bool bContainsTrue = Context->SelectedAssets.ContainsByPredicate([](const FAssetData& InAsset) { return IsNaniteEnabled(InAsset); }); const bool bContainsFalse = Context->SelectedAssets.ContainsByPredicate([](const FAssetData& InAsset) { return !IsNaniteEnabled(InAsset); }); return bContainsTrue && bContainsFalse ? ECheckBoxState::Undetermined : (bContainsTrue ? ECheckBoxState::Checked : ECheckBoxState::Unchecked); } return ECheckBoxState::Undetermined; }); Section.AddMenuEntry("StaticMesh_NaniteToggle", Label, ToolTip, Icon, UIAction, EUserInterfaceActionType::ToggleButton); } Section.AddSeparator("Nanite_EnableDisableOptions"); const int32 NaniteMeshes = Algo::Accumulate(Context->SelectedAssets, 0, [](int32 Value, const FAssetData& StaticMeshAsset) { bool bNaniteEnabled = false; return (StaticMeshAsset.GetTagValue(NAME_NaniteEnabled, bNaniteEnabled) && bNaniteEnabled) ? Value + 1 : Value; }); { const int32 RegularMeshes = Context->SelectedAssets.Num() - NaniteMeshes; const TAttribute Label = FText::Format(LOCTEXT("StaticMesh_NaniteEnableAll", "Enable Nanite ({0} Meshes)"), RegularMeshes); const TAttribute ToolTip = LOCTEXT("StaticMesh_NaniteEnableAllTooltip", "Enables support for Nanite on the selected meshes."); const FSlateIcon Icon = FSlateIcon(); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteNaniteEnable); UIAction.CanExecuteAction.BindLambda([RegularMeshes](const FToolMenuContext&) { return RegularMeshes > 0; }); Section.AddMenuEntry("StaticMesh_EnableNanite", Label, ToolTip, Icon, UIAction); } { const TAttribute Label = FText::Format(LOCTEXT("StaticMesh_NaniteDisableAll", "Disable Nanite ({0} Meshes)"), NaniteMeshes); const TAttribute ToolTip = LOCTEXT("StaticMesh_NaniteDisableAllTooltip", "Disables support for Nanite on the selected meshes."); const FSlateIcon Icon = FSlateIcon(); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteNaniteDisable); UIAction.CanExecuteAction.BindLambda([NaniteMeshes](const FToolMenuContext&) { return NaniteMeshes > 0; }); Section.AddMenuEntry("StaticMesh_DisableNanite", Label, ToolTip, Icon, UIAction); } } // LOD Section //================================================================= static void ExecuteImportMeshLOD(const FToolMenuContext&, FAssetData StaticMeshAsset, int32 LOD, bool bReimportWithNewFile) { if (UStaticMesh* Mesh = Cast(StaticMeshAsset.GetAsset())) { FbxMeshUtils::ImportMeshLODDialog(Mesh, LOD, true, bReimportWithNewFile); } } static void ExecuteImportHiResMesh(const FToolMenuContext& InContext) { if (UStaticMesh* StaticMesh = UContentBrowserAssetContextMenuContext::LoadSingleSelectedAsset(InContext)) { if (FbxMeshUtils::ImportStaticMeshHiResSourceModelDialog(StaticMesh)) { FEditorDelegates::RefreshEditor.Broadcast(); FEditorSupportDelegates::RedrawAllViewports.Broadcast(); } } } static void ExecuteReimportHiResMeshWithNewFile(const FToolMenuContext& InContext) { if (UStaticMesh* StaticMesh = UContentBrowserAssetContextMenuContext::LoadSingleSelectedAsset(InContext)) { StaticMesh->GetHiResSourceModel().SourceImportFilename = FString(); if (FbxMeshUtils::ImportStaticMeshHiResSourceModelDialog(StaticMesh)) { FEditorDelegates::RefreshEditor.Broadcast(); FEditorSupportDelegates::RedrawAllViewports.Broadcast(); } } } static void ExecuteRemoveHiResMesh(const FToolMenuContext& InContext) { if (UStaticMesh* StaticMesh = UContentBrowserAssetContextMenuContext::LoadSingleSelectedAsset(InContext)) { if (FbxMeshUtils::RemoveStaticMeshHiRes(StaticMesh)) { FEditorDelegates::RefreshEditor.Broadcast(); FEditorSupportDelegates::RedrawAllViewports.Broadcast(); } } } const static FName NAME_HasHiResMesh("HasHiResMesh"); static TOptional HasHiResMesh(const FAssetData& StaticMeshAsset) { bool bHasHiResMesh = false; if (StaticMeshAsset.GetTagValue(NAME_HasHiResMesh, bHasHiResMesh)) { return bHasHiResMesh; } return TOptional(); } static void GetImportHiResMenu(UToolMenu* Menu) { const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(*Menu); check(Context->SelectedAssets.Num() == 1); const FAssetData& StaticMeshAsset = Context->SelectedAssets[0]; FToolMenuSection& Section = Menu->FindOrAddSection("HighResMeshActions"); const TOptional bHasHighResMesh = HasHiResMesh(StaticMeshAsset); // Import / Reimport { if (!bHasHighResMesh.Get(false)) { const TAttribute Label = LOCTEXT("Import_HighRes", "Import High Res..."); const TAttribute ToolTip = LOCTEXT("Import_HighResTip", "Adds a high resolution version of the mesh. Used instead of LOD0 by systems that can benefit from more detailed geometry (Nanite, modeling, etc.)."); const FSlateIcon Icon = FSlateIcon(); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteImportHiResMesh); Section.AddMenuEntry("Import_HighRes", Label, ToolTip, Icon, UIAction); } else { { const TAttribute Label = LOCTEXT("Reimport_HighRes", "Reimport High Res"); const TAttribute ToolTip = LOCTEXT("Reimport_HighRes_Tip", "Reimport over existing the existing high res mesh."); const FSlateIcon Icon = FSlateIcon(); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteImportHiResMesh); Section.AddMenuEntry("Reimport_HighRes", Label, ToolTip, Icon, UIAction); } { const TAttribute Label = LOCTEXT("Reimport_HighRes_WithNewFile", "Reimport High Res with new file..."); const TAttribute ToolTip = LOCTEXT("Reimport_HighRes_WithNewFileTip", "Reimport the high resolution version of the mesh with a new file."); const FSlateIcon Icon = FSlateIcon(); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteReimportHiResMeshWithNewFile); Section.AddMenuEntry("Reimport_HighRes_WithNewFile", Label, ToolTip, Icon, UIAction); } } } // Remove { const TAttribute Label = LOCTEXT("Remove_HighRes", "Remove High Res"); const TAttribute ToolTip = LOCTEXT("Remove_HighRes_Tip", "Remove the high res version of the mesh"); const FSlateIcon Icon = FSlateIcon(); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteRemoveHiResMesh); UIAction.CanExecuteAction = FToolMenuCanExecuteAction::CreateLambda([bHasHighResMesh](const FToolMenuContext& Context) { return bHasHighResMesh.Get(true); }); Section.AddMenuEntry("Remove_HighRes", Label, ToolTip, Icon, UIAction); } } static void ExecuteCopyLODSettings(const FToolMenuContext& InContext) { if (UStaticMesh* StaticMesh = UContentBrowserAssetContextMenuContext::LoadSingleSelectedAsset(InContext)) { LODCopyMesh = StaticMesh; } } static void ExecutePasteLODSettings(const FToolMenuContext& InContext) { if (!LODCopyMesh.IsValid()) { return; } // Retrieve LOD settings from source mesh struct FLODSettings { FMeshReductionSettings ReductionSettings; float ScreenSize; }; TArray LODSettings; LODSettings.AddZeroed(LODCopyMesh->GetNumSourceModels()); for (int32 i = 0; i < LODCopyMesh->GetNumSourceModels(); i++) { LODSettings[i].ReductionSettings = LODCopyMesh->GetSourceModel(i).ReductionSettings; LODSettings[i].ScreenSize = LODCopyMesh->GetSourceModel(i).ScreenSize.Default; } const bool bAutoComputeLODScreenSize = LODCopyMesh->bAutoComputeLODScreenSize; const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InContext); // Copy LOD settings over to selected objects in content browser (meshes) for (UStaticMesh* Mesh : Context->LoadSelectedObjects()) { const int32 LODCount = LODSettings.Num(); Mesh->SetNumSourceModels(LODCount); for (int32 i = 0; i < LODCount; i++) { FStaticMeshSourceModel& SrcModel = Mesh->GetSourceModel(i); SrcModel.ReductionSettings = LODSettings[i].ReductionSettings; SrcModel.ScreenSize.Default = LODSettings[i].ScreenSize; } Mesh->bAutoComputeLODScreenSize = bAutoComputeLODScreenSize; Mesh->PostEditChange(); Mesh->MarkPackageDirty(); } } static bool CanPasteLODSettings(const FToolMenuContext& InContext) { return LODCopyMesh.IsValid(); } const static FName NAME_LODs("LODs"); static int32 GetNumberOfLODs(const FAssetData& StaticMeshAsset) { int32 NumberOfLODs = 0; return StaticMeshAsset.GetTagValue(NAME_LODs, NumberOfLODs) ? NumberOfLODs : 0; } static void GetImportLODMenu(UToolMenu* Menu, bool bReimportWithNewFile) { const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(*Menu); check(Context->SelectedAssets.Num() == 1); FToolMenuSection& Section = Menu->FindOrAddSection("ImportLODMenu"); const FAssetData& StaticMeshAsset = Context->SelectedAssets[0]; //Add 1 so we can Add LOD when we are not in "Reimport With New File" submenu const int32 OriginalLodCount = GetNumberOfLODs(StaticMeshAsset); const int32 LodCount = OriginalLodCount+ (bReimportWithNewFile ? 0 : 1); for (int32 LOD = 1; LOD < LodCount; ++LOD) { FText Label = FText::Format(LOCTEXT("Reimport LOD (number)", "Reimport LOD {0}"), LOD); FText ToolTip = LOCTEXT("ReimportTip", "Reimport over existing LOD"); if (LOD == OriginalLodCount) { Label = FText::Format(LOCTEXT("Add LOD (number)", "Add LOD {0}"), LOD); ToolTip = LOCTEXT("NewImportTip", "Import new LOD"); } { const FSlateIcon Icon = FSlateIcon(); const FToolMenuExecuteAction UIAction = FToolMenuExecuteAction::CreateStatic(&ExecuteImportMeshLOD, StaticMeshAsset, LOD, bReimportWithNewFile); Section.AddMenuEntry(*FString::Printf(TEXT("LOD_%d"), LOD), Label, ToolTip, Icon, UIAction); } } } static void GetLODMenu(UToolMenu* Menu) { const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(*Menu); FToolMenuSection& Section = Menu->FindOrAddSection("LODActions"); if (Context->SelectedAssets.Num() == 1) { constexpr bool bReimportWithNewFile = true; Section.AddSubMenu( "ImportLODsMenu", NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_ImportLOD", "Import LOD"), NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_ImportLODtooltip", "Imports meshes into the LODs"), FNewToolMenuDelegate::CreateStatic(&GetImportLODMenu, !bReimportWithNewFile) ); Section.AddSubMenu( "ReimportLODsWithNewFileMenu", NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_ImportLODWithNewFile", "Reimport LOD With New File"), NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_ImportLODWithNewFiletooltip", "Reimports meshes LODs with new file."), FNewToolMenuDelegate::CreateStatic(&GetImportLODMenu, bReimportWithNewFile) ); } Section.AddSeparator("CopyPaste"); { const TAttribute Label = LOCTEXT("StaticMesh_CopyLOD", "Copy LOD"); const TAttribute ToolTip = LOCTEXT("StaticMesh_CopyLODTooltip", "Copies the LOD settings from the selected mesh."); const FSlateIcon Icon = FSlateIcon(); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteCopyLODSettings); UIAction.CanExecuteAction.BindLambda([](const FToolMenuContext& Context) { return UContentBrowserAssetContextMenuContext::GetNumAssetsSelected(Context) == 1; }); Section.AddMenuEntry("StaticMesh_CopyLOD", Label, ToolTip, Icon, UIAction); } { FText Label = FText(LOCTEXT("StaticMesh_PasteLOD", "Paste LOD")); if (LODCopyMesh.IsValid()) { Label = FText::Format(LOCTEXT("StaticMesh_PasteLODWithName", "Paste LOD from {0}"), FText::FromString(LODCopyMesh->GetName())); } const TAttribute ToolTip = LOCTEXT("StaticMesh_PasteLODToltip", "Pastes LOD settings to the selected mesh(es)."); const FSlateIcon Icon = FSlateIcon(); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecutePasteLODSettings); UIAction.CanExecuteAction = FToolMenuCanExecuteAction::CreateStatic(&CanPasteLODSettings); Section.AddMenuEntry("StaticMesh_PasteLOD", Label, ToolTip, Icon, UIAction); } if (Context->SelectedAssets.Num() == 1) { Section.AddSeparator("HighRes"); Section.AddSubMenu( "ImportHighResMenu", NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_HiRes", "High Res"), NSLOCTEXT("AssetTypeActions_StaticMesh", "StaticMesh_HiRestooltip", "High resolution version of the mesh. Used instead of LOD0 by systems that can benefit from more detailed geometry (Nanite, modeling, etc.)"), FNewToolMenuDelegate::CreateStatic(&GetImportHiResMenu) ); } } static FDelayedAutoRegisterHelper DelayedAutoRegister(EDelayedRegisterRunPhase::EndOfEngineInit, []{ UToolMenus::RegisterStartupCallback(FSimpleMulticastDelegate::FDelegate::CreateLambda([]() { FToolMenuOwnerScoped OwnerScoped(UE_MODULE_NAME); UToolMenu* Menu = UE::ContentBrowser::ExtendToolMenu_AssetContextMenu(UStaticMesh::StaticClass()); FToolMenuSection& Section = Menu->FindOrAddSection("GetAssetActions"); Section.AddDynamicEntry(NAME_None, FNewToolMenuSectionDelegate::CreateLambda([](FToolMenuSection& InSection) { const UContentBrowserAssetContextMenuContext* Context = UContentBrowserAssetContextMenuContext::FindContextWithAssets(InSection); if (Context && Context->bCanBeModified) { if (CVarEnableSaveGeneratedLODsInPackage.GetValueOnGameThread() != 0) { const TAttribute Label = LOCTEXT("ObjectContext_SaveGeneratedLODsInPackage", "Save Generated LODs"); const TAttribute ToolTip = LOCTEXT("ObjectContext_SaveGeneratedLODsInPackageTooltip", "Run the mesh reduce and save the generated LODs as part of the package."); const FSlateIcon Icon = FSlateIcon(); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteSaveGeneratedLODsInPackage); InSection.AddMenuEntry("ObjectContext_SaveGeneratedLODsInPackage", Label, ToolTip, Icon, UIAction); } { const TAttribute Label = LOCTEXT("ObjectContext_ClearVertexColors", "Remove Vertex Colors"); const TAttribute ToolTip = LOCTEXT("ObjectContext_ClearVertexColorsTooltip", "Removes vertex colors from all LODS in all selected meshes."); const FSlateIcon Icon = FSlateIcon(FAppStyle::GetAppStyleSetName(), "ContentBrowser.AssetActions.RemoveVertexColors"); FToolUIAction UIAction; UIAction.ExecuteAction = FToolMenuExecuteAction::CreateStatic(&ExecuteRemoveVertexColors); InSection.AddMenuEntry("ObjectContext_ClearVertexColors", Label, ToolTip, Icon, UIAction); } { InSection.AddSubMenu( "StaticMesh_NaniteMenu", LOCTEXT("StaticMesh_NaniteMenu", "Nanite"), LOCTEXT("StaticMesh_NaniteTooltip", "Nanite Options and Tools"), FNewToolMenuDelegate::CreateStatic(&GetNaniteMenu), false, FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.Adjust") ); } { InSection.AddSubMenu( "StaticMesh_LODMenu", LOCTEXT("StaticMesh_LODMenu", "Level Of Detail"), LOCTEXT("StaticMesh_LODTooltip", "LOD Options and Tools"), FNewToolMenuDelegate::CreateStatic(&GetLODMenu), false, FSlateIcon(FAppStyle::GetAppStyleSetName(), "Icons.LOD") ); } } })); })); }); } #undef LOCTEXT_NAMESPACE