// Copyright Epic Games, Inc. All Rights Reserved. #include "MuCOE/SMutableObjectViewer.h" #include "Framework/MultiBox/MultiBoxBuilder.h" #include "Framework/Views/TableViewMetadata.h" #include "Interfaces/ITargetPlatform.h" #include "Interfaces/ITargetPlatformManagerModule.h" #include "MuCO/CustomizableObject.h" #include "MuCOE/CustomizableObjectCompileRunnable.h" #include "MuCOE/CustomizableObjectEditorStyle.h" #include "MuCOE/SMutableCodeViewer.h" #include "MuCOE/SMutableGraphViewer.h" #include "Widgets/Docking/SDockTab.h" #include "Widgets/Input/STextComboBox.h" #include "Widgets/Input/SNumericDropDown.h" #include "Widgets/Views/STreeView.h" class FExtender; class FUICommandList; class ITableRow; class SWidget; struct FSlateBrush; #define LOCTEXT_NAMESPACE "SMutableDebugger" void SMutableObjectViewer::AddReferencedObjects(FReferenceCollector& Collector) { Collector.AddReferencedObject(CustomizableObject); } FString SMutableObjectViewer::GetReferencerName() const { return TEXT("SMutableObjectViewer"); } void SMutableObjectViewer::Construct(const FArguments& InArgs, UCustomizableObject* InObject) { check(InObject); CustomizableObject = InObject; // Initialize the debugger compile options CompileOptions = InObject->GetPrivate()->GetCompileOptions(); { ITargetPlatformManagerModule* TPM = GetTargetPlatformManager(); const TArray& Platforms = TPM->GetActiveTargetPlatforms(); CompileOptions.TargetPlatform = Platforms.IsEmpty() ? nullptr : Platforms[0]; } FToolBarBuilder ToolbarBuilder(TSharedPtr(), FMultiBoxCustomization::None, TSharedPtr(), true); ToolbarBuilder.SetLabelVisibility(EVisibility::Visible); ToolbarBuilder.SetStyle(&FAppStyle::Get(), "SlimToolBar"); ToolbarBuilder.BeginSection("Compilation"); ToolbarBuilder.AddToolBarButton( FUIAction(FExecuteAction::CreateSP(this, &SMutableObjectViewer::GenerateMutableGraphPressed)), NAME_None, LOCTEXT("GenerateMutableGraph", "Unreal to Mutable Graph"), LOCTEXT("GenerateMutableGraphTooltip", "Generate a mutable graph from the customizable object source graph."), FSlateIcon(FCustomizableObjectEditorStyle::Get().GetStyleSetName(), "CustomizableObjectDebugger.GenerateMutableGraph", "CustomizableObjectDebugger.GenerateMutableGraph.Small"), EUserInterfaceActionType::Button ); ToolbarBuilder.AddToolBarButton( FUIAction(FExecuteAction::CreateSP(this, &SMutableObjectViewer::CompileMutableCodePressed)), NAME_None, LOCTEXT("GenerateMutableCode", "Unreal to Mutable Code"), LOCTEXT("GenerateMutableCodeTooltipFromGraph", "Generate a mutable code from the customizable object source graph."), FSlateIcon(FCustomizableObjectEditorStyle::Get().GetStyleSetName(), "CustomizableObjectDebugger.CompileMutableCode", "CustomizableObjectDebugger.CompileMutableCode.Small"), EUserInterfaceActionType::Button ); ToolbarBuilder.AddComboButton( FUIAction(), FOnGetContent::CreateSP(this, &SMutableObjectViewer::GenerateCompileOptionsMenuContent), LOCTEXT("Compile_Options_Label", "Compile Options"), LOCTEXT("Compile_Options_Tooltip", "Change Compile Options"), TAttribute(), true); ToolbarBuilder.EndSection(); ChildSlot [ SNew(SVerticalBox) + SVerticalBox::Slot() .AutoHeight() .VAlign(VAlign_Center) [ ToolbarBuilder.MakeWidget() ] + SVerticalBox::Slot() .FillHeight(1.0f) [ SAssignNew(DebuggerContentsBox, SBorder) ] ]; } void SMutableObjectViewer::GenerateMutableGraphPressed() { // Convert from Unreal graph to Mutable graph. TSharedRef Compiler = MakeShared(); TArray> RuntimeTextures; TArray CompilerTextures; TArray> RuntimeMeshes; TArray CompilerMeshes; mu::Ptr RootNode = Compiler->Export(CustomizableObject, CompileOptions, RuntimeTextures, CompilerTextures, RuntimeMeshes, CompilerMeshes); if (!RootNode) { // TODO: Show errors return; } FString DataTag = FString::Printf(TEXT("Mutable Graph : %s"), *CompileOptions.TargetPlatform->PlatformName()); TSharedRef GraphViewer = SNew(SMutableGraphViewer, RootNode) .DataTag(DataTag) .ReferencedRuntimeTextures(RuntimeTextures) .ReferencedCompileTextures(CompilerTextures) .ReferencedRuntimeMeshes(RuntimeMeshes) .ReferencedCompileMeshes(CompilerMeshes); DebuggerContentsBox->ClearContent(); DebuggerContentsBox->SetContent(GraphViewer); } void SMutableObjectViewer::CompileMutableCodePressed() { TArray> RuntimeTextures; TArray CompilerTextures; TArray> RuntimeMeshes; TArray CompilerMeshes; if (CompileOptions.bForceLargeLODBias) { // Debug compile with many different biases constexpr int32 MaxBias = 15; for (int32 Bias = 0; Bias < MaxBias; ++Bias) { CompileOptions.DebugBias = Bias; TSharedRef Compiler = MakeShared(); RuntimeTextures.Empty(); CompilerTextures.Empty(); RuntimeMeshes.Empty(); CompilerMeshes.Empty(); mu::NodePtr RootNode = Compiler->Export(CustomizableObject, CompileOptions, RuntimeTextures, CompilerTextures, RuntimeMeshes, CompilerMeshes); if (!RootNode) { // TODO: Show errors ensure(false); return; } // Do the compilation to Mutable Code synchronously. TSharedPtr CompileTask = MakeShareable(new FCustomizableObjectCompileRunnable(RootNode, Compiler)); CompileTask->Options = CompileOptions; CompileTask->ReferencedTextures = CompilerTextures; CompileTask->ReferencedMeshes = CompilerMeshes; CompileTask->Init(); CompileTask->Run(); } } // Convert from Unreal graph to Mutable graph. TSharedRef Compiler = MakeShared(); RuntimeTextures.Empty(); CompilerTextures.Empty(); RuntimeMeshes.Empty(); CompilerMeshes.Empty(); mu::NodePtr RootNode = Compiler->Export(CustomizableObject, CompileOptions, RuntimeTextures, CompilerTextures, RuntimeMeshes, CompilerMeshes); if (!RootNode) { // TODO: Show errors ensure(false); return; } // Do the compilation to Mutable Code synchronously. TSharedPtr CompileTask = MakeShareable(new FCustomizableObjectCompileRunnable(RootNode, Compiler)); CompileTask->Options = CompileOptions; CompileTask->ReferencedTextures = CompilerTextures; CompileTask->ReferencedMeshes = CompilerMeshes; CompileTask->Init(); CompileTask->Run(); FString DataTag = FString::Printf( TEXT("Mutable Code : %s opt %d"), *CompileOptions.TargetPlatform->PlatformName(), CompileOptions.OptimizationLevel ); TSharedRef CodeViewer = SNew(SMutableCodeViewer, CompileTask->Model, RuntimeTextures, RuntimeMeshes) .DataTag(DataTag); DebuggerContentsBox->ClearContent(); DebuggerContentsBox->SetContent(CodeViewer); } TSharedRef SMutableObjectViewer::GenerateCompileOptionsMenuContent() { const bool bShouldCloseWindowAfterMenuSelection = false; FMenuBuilder MenuBuilder(bShouldCloseWindowAfterMenuSelection, nullptr); // settings MenuBuilder.BeginSection("Optimization", LOCTEXT("MutableCompileOptimizationHeading", "Optimization")); { // Unreal Graph to Mutable Graph options //----------------------------------- // Platform DebugPlatformStrings.Empty(); TSharedPtr SelectedPlatform; { ITargetPlatformManagerModule* TPM = GetTargetPlatformManager(); check(TPM); ITargetPlatform* CurrentPlatform = NULL; const TArray& Platforms = TPM->GetTargetPlatforms(); for (const ITargetPlatform* Platform : Platforms) { TSharedPtr ThisPlatform = MakeShareable(new FString(Platform->PlatformName())); DebugPlatformStrings.Add(ThisPlatform); if (Platform == CompileOptions.TargetPlatform) { SelectedPlatform = ThisPlatform; } } } if (!SelectedPlatform.IsValid() && DebugPlatformStrings.Num()) { SelectedPlatform = DebugPlatformStrings[0]; } DebugPlatformCombo = SNew(STextComboBox) .OptionsSource(&DebugPlatformStrings) .InitiallySelectedItem(SelectedPlatform) .OnSelectionChanged(this, &SMutableObjectViewer::OnChangeDebugPlatform) ; MenuBuilder.AddWidget(DebugPlatformCombo.ToSharedRef(), LOCTEXT("MutableDebugPlatform", "Target Platform")); // Compilation options //----------------------------------- // Optimisation level CompileOptimizationStrings.Empty(); CompileOptimizationStrings.Add(MakeShareable(new FString(LOCTEXT("OptimizationNone", "None").ToString()))); CompileOptimizationStrings.Add(MakeShareable(new FString(LOCTEXT("OptimizationMin", "Minimal").ToString()))); CompileOptimizationStrings.Add(MakeShareable(new FString(LOCTEXT("OptimizationMax", "Maximum").ToString()))); CompileOptions.OptimizationLevel = FMath::Min(CompileOptions.OptimizationLevel, CompileOptimizationStrings.Num() - 1); CompileOptimizationCombo = SNew(STextComboBox) .OptionsSource(&CompileOptimizationStrings) .InitiallySelectedItem(CompileOptimizationStrings[CompileOptions.OptimizationLevel]) .OnSelectionChanged(this, &SMutableObjectViewer::OnChangeCompileOptimizationLevel) ; MenuBuilder.AddWidget(CompileOptimizationCombo.ToSharedRef(), LOCTEXT("MutableCompileOptimizationLevel", "Optimization Level")); { CompileTextureCompressionStrings.Empty(); CompileTextureCompressionStrings.Add(MakeShareable(new FString(LOCTEXT("MutableTextureCompressionNone", "None").ToString()))); CompileTextureCompressionStrings.Add(MakeShareable(new FString(LOCTEXT("MutableTextureCompressionFast", "Fast").ToString()))); CompileTextureCompressionStrings.Add(MakeShareable(new FString(LOCTEXT("MutableTextureCompressionHighQuality", "High Quality").ToString()))); int32 SelectedCompression = FMath::Clamp(int32(CompileOptions.TextureCompression), 0, CompileTextureCompressionStrings.Num() - 1); CompileTextureCompressionCombo = SNew(STextComboBox) .OptionsSource(&CompileTextureCompressionStrings) .InitiallySelectedItem(CompileTextureCompressionStrings[SelectedCompression]) .OnSelectionChanged(this, &SMutableObjectViewer::OnChangeCompileTextureCompressionType) ; MenuBuilder.AddWidget(CompileTextureCompressionCombo.ToSharedRef(), LOCTEXT("MutableCompileTextureCompressionType", "Texture Compression")); } // Image tiling // Unfortunately SNumericDropDown doesn't work with integers at the time of writing. TArray::FNamedValue> TilingOptions; TilingOptions.Add(SNumericDropDown::FNamedValue(0, FText::FromString(TEXT("0")), FText::FromString(TEXT("Disabled")))); TilingOptions.Add(SNumericDropDown::FNamedValue(64, FText::FromString(TEXT("64")), FText::FromString(TEXT("64")))); TilingOptions.Add(SNumericDropDown::FNamedValue(128, FText::FromString(TEXT("128")), FText::FromString(TEXT("128")))); TilingOptions.Add(SNumericDropDown::FNamedValue(256, FText::FromString(TEXT("256")), FText::FromString(TEXT("256")))); TilingOptions.Add(SNumericDropDown::FNamedValue(512, FText::FromString(TEXT("512")), FText::FromString(TEXT("512")))); CompileTilingCombo = SNew(SNumericDropDown) .DropDownValues(TilingOptions) .Value_Lambda( [&]() { return float(CompileOptions.ImageTiling); }) .OnValueChanged_Lambda( [&](float Value) { CompileOptions.ImageTiling = int32(Value); } ) ; MenuBuilder.AddWidget(CompileTilingCombo.ToSharedRef(), LOCTEXT("MutableCompileImageTiling", "Image Tiling")); // Disk as cache MenuBuilder.AddMenuEntry( LOCTEXT("Generate_MutableUseDisk", "Enable compiling using the disk as memory."), LOCTEXT("Generate_MutableUseDiskTooltip", "This is very slow but supports compiling huge objects. It requires a lot of free space in the OS disk."), FSlateIcon(), FUIAction( FExecuteAction::CreateLambda([this]() { CompileOptions.bUseDiskCompilation = !CompileOptions.bUseDiskCompilation; }), FCanExecuteAction(), FIsActionChecked::CreateLambda([this]() { return CompileOptions.bUseDiskCompilation; })), NAME_None, EUserInterfaceActionType::ToggleButton ); // Debug LODBias MenuBuilder.AddMenuEntry( LOCTEXT("ForceLargeLODBias", "Force a large texture LODBias."), LOCTEXT("ForceLargeLODBiasTooltip", "This is useful to test compilation of special cook modes."), FSlateIcon(), FUIAction( FExecuteAction::CreateLambda([this]() { CompileOptions.bForceLargeLODBias = !CompileOptions.bForceLargeLODBias; }), FCanExecuteAction(), FIsActionChecked::CreateLambda([this]() { return CompileOptions.bForceLargeLODBias; })), NAME_None, EUserInterfaceActionType::ToggleButton ); } MenuBuilder.EndSection(); return MenuBuilder.MakeWidget(); } void SMutableObjectViewer::OnChangeCompileOptimizationLevel(TSharedPtr NewSelection, ESelectInfo::Type SelectInfo) { CompileOptions.OptimizationLevel = CompileOptimizationStrings.Find(NewSelection); } void SMutableObjectViewer::OnChangeCompileTextureCompressionType(TSharedPtr NewSelection, ESelectInfo::Type) { CompileOptions.TextureCompression = ECustomizableObjectTextureCompression(CompileTextureCompressionStrings.Find(NewSelection)); } void SMutableObjectViewer::OnChangeDebugPlatform(TSharedPtr NewSelection, ESelectInfo::Type SelectInfo) { if (!CustomizableObject) return; CompileOptions.TargetPlatform = nullptr; ITargetPlatformManagerModule* TPM = GetTargetPlatformManager(); check(TPM); const TArray& Platforms = TPM->GetTargetPlatforms(); check(Platforms.Num()); CompileOptions.TargetPlatform = Platforms[0]; for (int32 Index = 1; Index < Platforms.Num(); Index++) { if (Platforms[Index]->PlatformName() == *NewSelection) { CompileOptions.TargetPlatform = Platforms[Index]; break; } } } #undef LOCTEXT_NAMESPACE