// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. #include "MaterialEditorModule.h" #include "Materials/MaterialExpressionTextureBase.h" #include "Materials/MaterialExpressionTextureSampleParameter.h" #include "MaterialInstanceEditor.h" #include "MaterialEditor.h" #include "MaterialEditorActions.h" #include "MaterialEditorUtilities.h" #include "Editor/PropertyEditor/Public/PropertyEditorModule.h" #include "Editor/PropertyEditor/Public/IDetailsView.h" #include "Editor/PropertyEditor/Public/PropertyHandle.h" #include "MaterialEditorInstanceDetailCustomization.h" #include "Editor/WorkspaceMenuStructure/Public/WorkspaceMenuStructureModule.h" #include "EditorViewportCommands.h" #include "SDockTab.h" #include "Materials/MaterialInstanceConstant.h" #include "CanvasTypes.h" #define LOCTEXT_NAMESPACE "MaterialInstanceEditor" DEFINE_LOG_CATEGORY_STATIC(LogMaterialInstanceEditor, Log, All); const FName FMaterialInstanceEditor::PreviewTabId( TEXT( "MaterialInstanceEditor_Preview" ) ); const FName FMaterialInstanceEditor::PropertiesTabId( TEXT( "MaterialInstanceEditor_MaterialProperties" ) ); const FName FMaterialInstanceEditor::ParentsTabId( TEXT( "MaterialInstanceEditor_MaterialParents" ) ); ////////////////////////////////////////////////////////////////////////// // SMaterialTreeWidgetItem class SMaterialTreeWidgetItem : public SMultiColumnTableRow< TWeakObjectPtr > { public: SLATE_BEGIN_ARGS(SMaterialTreeWidgetItem) : _ParentIndex( -1 ) , _WidgetInfoToVisualize() {} SLATE_ARGUMENT( int32, ParentIndex ) SLATE_ARGUMENT( TWeakObjectPtr, WidgetInfoToVisualize ) SLATE_END_ARGS() /** * Construct child widgets that comprise this widget. * * @param InArgs Declaration from which to construct this widget */ void Construct( const FArguments& InArgs, const TSharedRef& InOwnerTableView ) { this->WidgetInfo = InArgs._WidgetInfoToVisualize; this->ParentIndex = InArgs._ParentIndex; SMultiColumnTableRow< TWeakObjectPtr >::Construct( FSuperRowType::FArguments(), InOwnerTableView ); } /** @return Widget based on the column name */ virtual TSharedRef GenerateWidgetForColumn( const FName& ColumnName ) override { FText Entry; FSlateFontInfo FontInfo = FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Regular.ttf"), 9 ); if ( ColumnName == "Parent" ) { if ( ParentIndex == 0 ) { Entry = NSLOCTEXT("UnrealEd", "Material", "Material"); } else if ( ParentIndex != -1 ) { FFormatNamedArguments Args; Args.Add( TEXT("Index"), ParentIndex ); Entry = FText::Format( FText::FromString("Parent {Index}"), Args ); } else { Entry = NSLOCTEXT("UnrealEd", "Current", "Current"); FontInfo = FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 9 ); } } else { Entry = FText::FromString( WidgetInfo.Get()->GetName() ); if ( ParentIndex == -1 ) { FontInfo = FSlateFontInfo( FPaths::EngineContentDir() / TEXT("Slate/Fonts/Roboto-Bold.ttf"), 9 ); } } return SNew(SHorizontalBox) +SHorizontalBox::Slot() .AutoWidth() .Padding(2) [ SNew( STextBlock ) .Text( Entry ) .Font( FontInfo ) ]; } protected: /** The info about the widget that we are visualizing */ TAttribute< TWeakObjectPtr > WidgetInfo; /** The index this material has in our parents array */ int32 ParentIndex; }; void FMaterialInstanceEditor::RegisterTabSpawners(const TSharedRef& TabManager) { WorkspaceMenuCategory = TabManager->AddLocalWorkspaceMenuCategory(LOCTEXT("WorkspaceMenu_MaterialInstanceEditor", "Material Instance Editor")); auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory.ToSharedRef(); FAssetEditorToolkit::RegisterTabSpawners(TabManager); TabManager->RegisterTabSpawner( PreviewTabId, FOnSpawnTab::CreateSP( this, &FMaterialInstanceEditor::SpawnTab_Preview ) ) .SetDisplayName( LOCTEXT( "ViewportTab", "Viewport" ) ) .SetGroup( WorkspaceMenuCategoryRef ) .SetIcon( FSlateIcon( FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Viewports" ) ); TabManager->RegisterTabSpawner( PropertiesTabId, FOnSpawnTab::CreateSP( this, &FMaterialInstanceEditor::SpawnTab_Properties ) ) .SetDisplayName( LOCTEXT( "PropertiesTab", "Details" ) ) .SetGroup( WorkspaceMenuCategoryRef ) .SetIcon( FSlateIcon( FEditorStyle::GetStyleSetName(), "LevelEditor.Tabs.Details" ) ); TabManager->RegisterTabSpawner( ParentsTabId, FOnSpawnTab::CreateSP(this, &FMaterialInstanceEditor::SpawnTab_Parents) ) .SetDisplayName( LOCTEXT("ParentsTab", "Parents") ) .SetGroup( WorkspaceMenuCategoryRef ) .SetIcon( FSlateIcon( FEditorStyle::GetStyleSetName(), "Kismet.Tabs.Palette" ) ); } void FMaterialInstanceEditor::UnregisterTabSpawners(const TSharedRef& TabManager) { FAssetEditorToolkit::UnregisterTabSpawners(TabManager); TabManager->UnregisterTabSpawner( PreviewTabId ); TabManager->UnregisterTabSpawner( PropertiesTabId ); TabManager->UnregisterTabSpawner( ParentsTabId ); } ////////////////////////////////////////////////////////////////////////// // FMaterialInstanceEditor void FMaterialInstanceEditor::InitMaterialInstanceEditor( const EToolkitMode::Type Mode, const TSharedPtr< class IToolkitHost >& InitToolkitHost, UObject* ObjectToEdit ) { GEditor->RegisterForUndo( this ); check( ObjectToEdit ); UMaterialInstanceConstant* InstanceConstant = Cast(ObjectToEdit); bShowAllMaterialParameters = false; bShowMobileStats = false; // Construct a temp holder for our instance parameters. MaterialEditorInstance = NewObject(GetTransientPackage(), NAME_None, RF_Transactional); bool bTempUseOldStyleMICEditorGroups = true; GConfig->GetBool(TEXT("/Script/UnrealEd.EditorEngine"), TEXT("UseOldStyleMICEditorGroups"), bTempUseOldStyleMICEditorGroups, GEngineIni); MaterialEditorInstance->bUseOldStyleMICEditorGroups = bTempUseOldStyleMICEditorGroups; MaterialEditorInstance->SetSourceInstance(InstanceConstant); // Register our commands. This will only register them if not previously registered FMaterialEditorCommands::Register(); CreateInternalWidgets(); BindCommands(); TSharedRef StandaloneDefaultLayout = FTabManager::NewLayout( "Standalone_MaterialInstanceEditor_Layout_v2" ) ->AddArea ( FTabManager::NewPrimaryArea() ->SetOrientation( Orient_Vertical ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient( 0.1f ) ->SetHideTabWell( true ) ->AddTab( GetToolbarTabId(), ETabState::OpenedTab ) ) ->Split ( FTabManager::NewSplitter() ->SetOrientation(Orient_Horizontal) ->SetSizeCoefficient(0.9f) ->Split ( FTabManager::NewSplitter() ->SetOrientation(Orient_Vertical) ->SetSizeCoefficient(0.27f) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.6f) ->AddTab( PropertiesTabId, ETabState::OpenedTab ) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.4f) ->AddTab( ParentsTabId, ETabState::OpenedTab ) ) ) ->Split ( FTabManager::NewStack() ->SetSizeCoefficient(0.73f) ->SetHideTabWell( true ) ->AddTab( PreviewTabId, ETabState::OpenedTab ) ) ) ); const bool bCreateDefaultStandaloneMenu = true; const bool bCreateDefaultToolbar = true; FAssetEditorToolkit::InitAssetEditor( Mode, InitToolkitHost, MaterialInstanceEditorAppIdentifier, StandaloneDefaultLayout, bCreateDefaultStandaloneMenu, bCreateDefaultToolbar, ObjectToEdit ); IMaterialEditorModule* MaterialEditorModule = &FModuleManager::LoadModuleChecked( "MaterialEditor" ); AddMenuExtender(MaterialEditorModule->GetMenuExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects())); ExtendToolbar(); RegenerateMenusAndToolbars(); // @todo toolkit world centric editing /*if( IsWorldCentricAssetEditor() ) { SpawnToolkitTab(GetToolbarTabId(), FString(), EToolkitTabSpot::ToolBar); SpawnToolkitTab(PreviewTabId, FString(), EToolkitTabSpot::Viewport); SpawnToolkitTab(PropertiesTabId, FString(), EToolkitTabSpot::Details); SpawnToolkitTab(ParentsTabId, FString(), EToolkitTabSpot::Details); }*/ // Load editor settings. LoadSettings(); // Set the preview mesh for the material. This call must occur after the toolbar is initialized. USceneThumbnailInfoWithPrimitive* ThumbnailInfoWithPrim = Cast(InstanceConstant->ThumbnailInfo); if ( ThumbnailInfoWithPrim ) { InstanceConstant->PreviewMesh = ThumbnailInfoWithPrim->PreviewMesh; } SetPreviewAssetByName(*InstanceConstant->PreviewMesh.ToString()); } FMaterialInstanceEditor::~FMaterialInstanceEditor() { GEditor->UnregisterForUndo( this ); MaterialEditorInstance = NULL; ParentList.Empty(); SaveSettings(); MaterialInstanceDetails.Reset(); MaterialInstanceParentsList.Reset(); } void FMaterialInstanceEditor::AddReferencedObjects(FReferenceCollector& Collector) { // Serialize our custom object instance Collector.AddReferencedObject(MaterialEditorInstance); // Serialize all parent material instances that are stored in the list. for (int32 Index = 0; Index < ParentList.Num(); Index++) { UMaterialInterface* Parent = ParentList[Index].Get(); Collector.AddReferencedObject(Parent); } } void FMaterialInstanceEditor::BindCommands() { const FMaterialEditorCommands& Commands = FMaterialEditorCommands::Get(); ToolkitCommands->MapAction( Commands.ShowAllMaterialParameters, FExecuteAction::CreateSP( this, &FMaterialInstanceEditor::ToggleShowAllMaterialParameters ), FCanExecuteAction(), FIsActionChecked::CreateSP( this, &FMaterialInstanceEditor::IsShowAllMaterialParametersChecked ) ); ToolkitCommands->MapAction( FEditorViewportCommands::Get().ToggleRealTime, FExecuteAction::CreateSP( PreviewVC.ToSharedRef(), &SMaterialEditorViewport::OnToggleRealtime ), FCanExecuteAction(), FIsActionChecked::CreateSP( PreviewVC.ToSharedRef(), &SMaterialEditorViewport::IsRealtime ) ); ToolkitCommands->MapAction( Commands.ToggleMobileStats, FExecuteAction::CreateSP( this, &FMaterialInstanceEditor::ToggleMobileStats ), FCanExecuteAction(), FIsActionChecked::CreateSP( this, &FMaterialInstanceEditor::IsToggleMobileStatsChecked ) ); } void FMaterialInstanceEditor::ToggleShowAllMaterialParameters() { bShowAllMaterialParameters = !bShowAllMaterialParameters; UpdatePropertyWindow(); } bool FMaterialInstanceEditor::IsShowAllMaterialParametersChecked() const { return bShowAllMaterialParameters; } void FMaterialInstanceEditor::ToggleMobileStats() { bShowMobileStats = !bShowMobileStats; UMaterialInstanceConstant* MIC = Cast(GetMaterialInterface()); if (bShowMobileStats && MIC) { UMaterial* BaseMaterial = MIC->GetBaseMaterial(); if (BaseMaterial) { FMaterialUpdateContext UpdateContext; UpdateContext.AddMaterial(BaseMaterial); do { MIC->SetFeatureLevelToCompile(ERHIFeatureLevel::ES2,bShowMobileStats); if (MIC->bHasStaticPermutationResource) { MIC->ForceRecompileForRendering(); } MIC = Cast(MIC->Parent); } while (MIC); BaseMaterial->SetFeatureLevelToCompile(ERHIFeatureLevel::ES2,bShowMobileStats); BaseMaterial->ForceRecompileForRendering(); } } PreviewVC->RefreshViewport(); } bool FMaterialInstanceEditor::IsToggleMobileStatsChecked() const { return bShowMobileStats; } void FMaterialInstanceEditor::OnOpenMaterial() { OpenSelectedParentEditor( GetSelectedParent() ); } void FMaterialInstanceEditor::OnShowInContentBrowser() { SyncSelectedParentToGB(); } void FMaterialInstanceEditor::OnInheritanceListDoubleClick( TWeakObjectPtr InMaterialInterface ) { OpenSelectedParentEditor( InMaterialInterface.Get() ); } TSharedPtr FMaterialInstanceEditor::OnInheritanceListRightClick() { UMaterialInterface* SelectedMaterialInterface = GetSelectedParent(); // Get all menu extenders for this context menu from the material editor module IMaterialEditorModule& MaterialEditor = FModuleManager::GetModuleChecked( TEXT("MaterialEditor") ); TArray MenuExtenderDelegates = MaterialEditor.GetAllMaterialDragDropContextMenuExtenders(); TArray> Extenders; for (int32 i = 0; i < MenuExtenderDelegates.Num(); ++i) { if (MenuExtenderDelegates[i].IsBound()) { Extenders.Add(MenuExtenderDelegates[i].Execute(SelectedMaterialInterface)); } } TSharedPtr MenuExtender = FExtender::Combine(Extenders); const bool bCloseAfterSelection = true; FMenuBuilder MenuBuilder( bCloseAfterSelection, NULL, MenuExtender ); MenuBuilder.BeginSection("MaterialInstanceOptions", LOCTEXT("ParentOptions", "Options") ); { // If this material isn't the currently open one, present the user an option to open it if(MaterialEditorInstance->SourceInstance!=SelectedMaterialInterface) { check(SelectedMaterialInterface != NULL ) FText Label; if(SelectedMaterialInterface->IsA(UMaterial::StaticClass())) { Label = NSLOCTEXT("UnrealEd", "MaterialEditor", "Material Editor"); } else { Label = NSLOCTEXT("UnrealEd", "MaterialInstanceEditor", "Material Instance Editor"); } MenuBuilder.AddMenuEntry( Label, LOCTEXT("OpenMaterialTooltilp", "Opens the selected material for editing"), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FMaterialInstanceEditor::OnOpenMaterial ), FCanExecuteAction() ) ); } MenuBuilder.AddMenuEntry( LOCTEXT("ShowInCB", "Find in Content Browser..."), LOCTEXT("ShowInCBTooltilp", "Finds the selected material in the Content Browser"), FSlateIcon(), FUIAction( FExecuteAction::CreateSP( this, &FMaterialInstanceEditor::OnShowInContentBrowser ), FCanExecuteAction() ) ); } MenuBuilder.EndSection(); return MenuBuilder.MakeWidget(); } TSharedRef FMaterialInstanceEditor::OnInheritanceListGenerateRow( TWeakObjectPtr InMaterialInterface, const TSharedRef& OwnerTable ) { // Find the right index to attribute to the material in the widget int32 TempIndex, Index = -1; if ( ParentList.Find( InMaterialInterface, TempIndex ) ) { if ( TempIndex == 0 ) { Index = 0; } else if ( TempIndex < ParentList.Num() - 1 ) { Index = ParentList.Num() - 1 - TempIndex; } } return SNew(SMaterialTreeWidgetItem, OwnerTable) .WidgetInfoToVisualize(InMaterialInterface) .ParentIndex( Index ); } UMaterialInterface* FMaterialInstanceEditor::GetSelectedParent() const { TArray< TWeakObjectPtr > SelectedItems = MaterialInstanceParentsList->GetSelectedItems(); UMaterialInterface* SelectedMaterialInterface = NULL; if( SelectedItems.Num() > 0 ) { check( SelectedItems.Last().IsValid() ); SelectedMaterialInterface = SelectedItems.Last().Get(); } else { SelectedMaterialInterface = MaterialEditorInstance->SourceInstance; } return SelectedMaterialInterface; } void FMaterialInstanceEditor::CreateInternalWidgets() { PreviewVC = SNew(SMaterialEditorViewport) .MaterialEditor(SharedThis(this)); FPropertyEditorModule& PropertyEditorModule = FModuleManager::GetModuleChecked( "PropertyEditor" ); const FDetailsViewArgs DetailsViewArgs( false, false, true, FDetailsViewArgs::HideNameArea, true, this ); MaterialInstanceDetails = PropertyEditorModule.CreateDetailView( DetailsViewArgs ); FOnGetDetailCustomizationInstance LayoutMICDetails = FOnGetDetailCustomizationInstance::CreateStatic( &FMaterialInstanceParameterDetails::MakeInstance, MaterialEditorInstance, FGetShowHiddenParameters::CreateSP(this, &FMaterialInstanceEditor::GetShowHiddenParameters) ); MaterialInstanceDetails->RegisterInstancedCustomPropertyLayout( UMaterialEditorInstanceConstant::StaticClass(), LayoutMICDetails ); MaterialInstanceParentsList = SNew(SListView>) .SelectionMode(ESelectionMode::Single) .ListItemsSource( &ParentList ) .OnGenerateRow( this, &FMaterialInstanceEditor::OnInheritanceListGenerateRow ) .OnContextMenuOpening(this, &FMaterialInstanceEditor::OnInheritanceListRightClick) .OnMouseButtonDoubleClick(this, &FMaterialInstanceEditor::OnInheritanceListDoubleClick) .HeaderRow ( SNew(SHeaderRow) +SHeaderRow::Column(FName(TEXT("Parent"))) .DefaultLabel(NSLOCTEXT("MaterialInstanceEditor", "Parent", "Parent")) +SHeaderRow::Column(FName(TEXT("Name"))) .DefaultLabel(NSLOCTEXT("MaterialInstanceEditor", "Name", "Name")) ); } void FMaterialInstanceEditor::ExtendToolbar() { struct Local { static void FillToolbar(FToolBarBuilder& ToolbarBuilder) { ToolbarBuilder.BeginSection("Command"); { ToolbarBuilder.AddToolBarButton(FMaterialEditorCommands::Get().ShowAllMaterialParameters); // TODO: support in material instance editor. ToolbarBuilder.AddToolBarButton(FMaterialEditorCommands::Get().ToggleMobileStats); } ToolbarBuilder.EndSection(); } }; TSharedPtr ToolbarExtender = MakeShareable(new FExtender); ToolbarExtender->AddToolBarExtension( "Asset", EExtensionHook::After, GetToolkitCommands(), FToolBarExtensionDelegate::CreateStatic( &Local::FillToolbar ) ); AddToolbarExtender(ToolbarExtender); IMaterialEditorModule* MaterialEditorModule = &FModuleManager::LoadModuleChecked( "MaterialEditor" ); AddToolbarExtender(MaterialEditorModule->GetToolBarExtensibilityManager()->GetAllExtenders(GetToolkitCommands(), GetEditingObjects())); } TSharedRef FMaterialInstanceEditor::SpawnTab_Preview( const FSpawnTabArgs& Args ) { check( Args.GetTabId().TabType == PreviewTabId ); TSharedRef SpawnedTab = SNew(SDockTab) .Label(LOCTEXT("ViewportTabTitle", "Viewport")) [ PreviewVC.ToSharedRef() ]; PreviewVC->OnAddedToTab( SpawnedTab ); AddToSpawnedToolPanels( Args.GetTabId().TabType, SpawnedTab ); return SpawnedTab; } TSharedRef FMaterialInstanceEditor::SpawnTab_Properties( const FSpawnTabArgs& Args ) { check( Args.GetTabId().TabType == PropertiesTabId ); TSharedRef SpawnedTab = SNew(SDockTab) .Icon( FEditorStyle::GetBrush("MaterialInstanceEditor.Tabs.Properties") ) .Label(LOCTEXT("MaterialPropertiesTitle", "Details")) [ SNew(SBorder) .Padding(4) [ MaterialInstanceDetails.ToSharedRef() ] ]; UpdatePropertyWindow(); AddToSpawnedToolPanels( Args.GetTabId().TabType, SpawnedTab ); return SpawnedTab; } TSharedRef FMaterialInstanceEditor::SpawnTab_Parents( const FSpawnTabArgs& Args ) { check( Args.GetTabId().TabType == ParentsTabId ); TSharedRef SpawnedTab = SNew(SDockTab) .Icon( FEditorStyle::GetBrush("MaterialInstanceEditor.Tabs.Parents") ) .Label( LOCTEXT("MaterialParentsTitle", "Instance Parents") ) [ MaterialInstanceParentsList.ToSharedRef() ]; RebuildInheritanceList(); AddToSpawnedToolPanels( Args.GetTabId().TabType, SpawnedTab ); return SpawnedTab; } void FMaterialInstanceEditor::AddToSpawnedToolPanels( const FName& TabIdentifier, const TSharedRef& SpawnedTab ) { TWeakPtr* TabSpot = SpawnedToolPanels.Find(TabIdentifier); if (!TabSpot) { SpawnedToolPanels.Add(TabIdentifier, SpawnedTab); } else { check(!TabSpot->IsValid()); *TabSpot = SpawnedTab; } } FName FMaterialInstanceEditor::GetToolkitFName() const { return FName("MaterialInstanceEditor"); } FText FMaterialInstanceEditor::GetBaseToolkitName() const { return LOCTEXT("AppLabel", "Material Instance Editor"); } FString FMaterialInstanceEditor::GetWorldCentricTabPrefix() const { return LOCTEXT("WorldCentricTabPrefix", "Material Instance ").ToString(); } FLinearColor FMaterialInstanceEditor::GetWorldCentricTabColorScale() const { return FLinearColor( 0.3f, 0.2f, 0.5f, 0.5f ); } UMaterialInterface* FMaterialInstanceEditor::GetMaterialInterface() const { return MaterialEditorInstance->SourceInstance; } void FMaterialInstanceEditor::NotifyPreChange(UProperty* PropertyThatChanged) { } void FMaterialInstanceEditor::NotifyPostChange( const FPropertyChangedEvent& PropertyChangedEvent, UProperty* PropertyThatChanged) { // Update the preview window when the user changes a property. PreviewVC->RefreshViewport(); // If they changed the parent, regenerate the parent list. if(PropertyThatChanged->GetName()==TEXT("Parent")) { bool bSetEmptyParent = false; // Check to make sure they didnt set the parent to themselves. if(MaterialEditorInstance->Parent==MaterialEditorInstance->SourceInstance) { bSetEmptyParent = true; } if (bSetEmptyParent) { MaterialEditorInstance->Parent = NULL; if(MaterialEditorInstance->SourceInstance) { MaterialEditorInstance->SourceInstance->SetParentEditorOnly(NULL); MaterialEditorInstance->SourceInstance->PostEditChange(); } } RebuildInheritanceList(); UpdatePropertyWindow(); } //rebuild the property window to account for the possibility that the item changed was //a static switch UObject* PropertyClass = PropertyThatChanged->GetOuter(); if(PropertyClass && PropertyClass->GetName() == TEXT("DEditorStaticSwitchParameterValue") && MaterialEditorInstance->Parent && MaterialEditorInstance->SourceInstance ) { TArray PreviousExpressions(MaterialEditorInstance->VisibleExpressions); MaterialEditorInstance->VisibleExpressions.Empty(); FMaterialEditorUtilities::GetVisibleMaterialParameters(MaterialEditorInstance->Parent->GetMaterial(), MaterialEditorInstance->SourceInstance, MaterialEditorInstance->VisibleExpressions); } } void FMaterialInstanceEditor::RebuildInheritanceList() { MaterialInstanceParentsList->ClearSelection(); ParentList.Empty(); // Travel up the parent chain for this material instance until we reach the root material. UMaterialInstance* InstanceConstant = MaterialEditorInstance->SourceInstance; if(InstanceConstant) { ParentList.Add(InstanceConstant); // Add all parents UMaterialInterface* Parent = InstanceConstant->Parent; while(Parent && Parent != InstanceConstant) { ParentList.Insert(Parent,0); // If the parent is a material then break. InstanceConstant = Cast(Parent); if(InstanceConstant) { Parent = InstanceConstant->Parent; } else { break; } } // MaterialInstanceParentsList->SetSelection( MaterialEditorInstance->SourceInstance ); } MaterialInstanceParentsList->RequestListRefresh(); } void FMaterialInstanceEditor::RebuildMaterialInstanceEditor() { if( MaterialEditorInstance ) { MaterialEditorInstance->RegenerateArrays(); RebuildInheritanceList(); // Required b/c recompiled parent materials result in invalid weak object pointers UpdatePropertyWindow(); } } void FMaterialInstanceEditor::DrawMessages( FViewport* Viewport, FCanvas* Canvas ) { Canvas->PushAbsoluteTransform(FMatrix::Identity); if ( MaterialEditorInstance->Parent && MaterialEditorInstance->SourceInstance ) { const FMaterialResource* MaterialResource = MaterialEditorInstance->SourceInstance->GetMaterialResource(GMaxRHIFeatureLevel); UMaterial* BaseMaterial = MaterialEditorInstance->SourceInstance->GetMaterial(); int32 DrawPositionY = 5; if ( BaseMaterial && MaterialResource ) { FMaterialEditor::DrawMaterialInfoStrings( Canvas, BaseMaterial, MaterialResource, MaterialResource->GetCompileErrors(), DrawPositionY, true ); } if (bShowMobileStats) { const FMaterialResource* MaterialResourceES2 = MaterialEditorInstance->SourceInstance->GetMaterialResource(ERHIFeatureLevel::ES2); if ( BaseMaterial && MaterialResourceES2 ) { FMaterialEditor::DrawMaterialInfoStrings( Canvas, BaseMaterial, MaterialResourceES2, MaterialResourceES2->GetCompileErrors(), DrawPositionY, true ); } } DrawSamplerWarningStrings( Canvas, DrawPositionY ); } Canvas->PopTransform(); } /** * Draws sampler/texture mismatch warning strings. * @param Canvas - The canvas on which to draw. * @param DrawPositionY - The Y position at which to draw. Upon return contains the Y value following the last line of text drawn. */ void FMaterialInstanceEditor::DrawSamplerWarningStrings(FCanvas* Canvas, int32& DrawPositionY) { if ( MaterialEditorInstance->SourceInstance ) { UMaterial* BaseMaterial = MaterialEditorInstance->SourceInstance->GetMaterial(); if ( BaseMaterial ) { UFont* FontToUse = GEngine->GetTinyFont(); const int32 SpacingBetweenLines = 13; UEnum* SamplerTypeEnum = FindObject( NULL, TEXT("/Script/Engine.EMaterialSamplerType") ); check( SamplerTypeEnum ); const int32 GroupCount = MaterialEditorInstance->ParameterGroups.Num(); for ( int32 GroupIndex = 0; GroupIndex < GroupCount; ++GroupIndex ) { const FEditorParameterGroup& Group = MaterialEditorInstance->ParameterGroups[ GroupIndex ]; const int32 ParameterCount = Group.Parameters.Num(); for ( int32 ParameterIndex = 0; ParameterIndex < ParameterCount; ++ParameterIndex ) { UDEditorTextureParameterValue* TextureParameterValue = Cast( Group.Parameters[ ParameterIndex ] ); if ( TextureParameterValue && TextureParameterValue->ExpressionId.IsValid() ) { UTexture* Texture = NULL; MaterialEditorInstance->SourceInstance->GetTextureParameterValue( TextureParameterValue->ParameterName, Texture ); if ( Texture ) { EMaterialSamplerType SamplerType = UMaterialExpressionTextureBase::GetSamplerTypeForTexture( Texture ); UMaterialExpressionTextureSampleParameter* Expression = BaseMaterial->FindExpressionByGUID( TextureParameterValue->ExpressionId ); // We want a crash report if that happens ensure(Expression); if ( Expression && Expression->SamplerType != SamplerType ) { FString SamplerTypeDisplayName; if ( SamplerTypeEnum->HasMetaData( TEXT("DisplayName"), Expression->SamplerType ) ) { SamplerTypeDisplayName = SamplerTypeEnum->GetMetaData( TEXT("DisplayName"), Expression->SamplerType ); } else { SamplerTypeDisplayName = SamplerTypeEnum->GetEnumName( Expression->SamplerType ); } Canvas->DrawShadowedString( 5, DrawPositionY, *FString::Printf( TEXT("Warning: %s samples %s as %s."), *TextureParameterValue->ParameterName.ToString(), *Texture->GetPathName(), *SamplerTypeDisplayName ), FontToUse, FLinearColor(1,1,0) ); DrawPositionY += SpacingBetweenLines; } if( Expression && ((Expression->SamplerType == (EMaterialSamplerType)TC_Normalmap || Expression->SamplerType == (EMaterialSamplerType)TC_Masks) && Texture->SRGB)) { FString SamplerTypeDisplayName; if ( SamplerTypeEnum->HasMetaData( TEXT("DisplayName"), Expression->SamplerType ) ) { SamplerTypeDisplayName = SamplerTypeEnum->GetMetaData( TEXT("DisplayName"), Expression->SamplerType ); } else { SamplerTypeDisplayName = SamplerTypeEnum->GetEnumName( Expression->SamplerType ); } Canvas->DrawShadowedString( 5, DrawPositionY, *FString::Printf( TEXT("Warning: %s samples texture as '%s'. SRGB should be disabled for '%s'."), *TextureParameterValue->ParameterName.ToString(), *SamplerTypeDisplayName, *Texture->GetPathName()), FontToUse, FLinearColor(1,1,0) ); DrawPositionY += SpacingBetweenLines; } } } } } } } } bool FMaterialInstanceEditor::SetPreviewAsset(UObject* InAsset) { if (PreviewVC.IsValid()) { return PreviewVC->SetPreviewAsset(InAsset); } return false; } bool FMaterialInstanceEditor::SetPreviewAssetByName(const TCHAR* InAssetName) { if (PreviewVC.IsValid()) { return PreviewVC->SetPreviewAssetByName(InAssetName); } return false; } void FMaterialInstanceEditor::SetPreviewMaterial(UMaterialInterface* InMaterialInterface) { if (PreviewVC.IsValid()) { PreviewVC->SetPreviewMaterial(InMaterialInterface); } } void FMaterialInstanceEditor::GetShowHiddenParameters(bool& bShowHiddenParameters) { bShowHiddenParameters = bShowAllMaterialParameters; } void FMaterialInstanceEditor::SaveSettings() { // Save the preview scene if(PreviewVC.IsValid()) { PreviewVC->PreviewScene.SaveSettings(TEXT("MaterialInstanceEditor")); } GConfig->SetBool(TEXT("MaterialInstanceEditor"), TEXT("bShowGrid"), PreviewVC->IsTogglePreviewGridChecked(), GEditorPerProjectIni); GConfig->SetBool(TEXT("MaterialInstanceEditor"), TEXT("bDrawGrid"), PreviewVC->IsRealtime(), GEditorPerProjectIni); GConfig->SetInt(TEXT("MaterialInstanceEditor"), TEXT("PrimType"), PreviewVC->PreviewPrimType, GEditorPerProjectIni); GConfig->SetBool(TEXT("MaterialInstanceEditor"), TEXT("bWantsMobileStats"), IsToggleMobileStatsChecked(), GEditorPerProjectIni); } void FMaterialInstanceEditor::LoadSettings() { bool bRealtime=false; bool bShowGrid=false; int32 PrimType=static_cast( TPT_Sphere ); bool bWantsMobileStats=false; GConfig->GetBool(TEXT("MaterialInstanceEditor"), TEXT("bShowGrid"), bShowGrid, GEditorPerProjectIni); GConfig->GetBool(TEXT("MaterialInstanceEditor"), TEXT("bDrawGrid"), bRealtime, GEditorPerProjectIni); GConfig->GetInt(TEXT("MaterialInstanceEditor"), TEXT("PrimType"), PrimType, GEditorPerProjectIni); GConfig->GetBool(TEXT("MaterialInstanceEditor"), TEXT("bWantsMobileStats"), bWantsMobileStats, GEditorPerProjectIni); if (bWantsMobileStats) { ToggleMobileStats(); } if(PreviewVC.IsValid()) { if ( bShowGrid ) { PreviewVC->TogglePreviewGrid(); } if ( bRealtime ) { PreviewVC->OnToggleRealtime(); } PreviewVC->OnSetPreviewPrimitive( static_cast(PrimType) ); // Load the preview scene PreviewVC->PreviewScene.LoadSettings(TEXT("MaterialInstanceEditor")); } } void FMaterialInstanceEditor::SyncSelectedParentToGB() { TArray< UObject* > SelectedObjects; SelectedObjects.Add( GetSelectedParent() ); GEditor->SyncBrowserToObjects(SelectedObjects); } void FMaterialInstanceEditor::OpenSelectedParentEditor(UMaterialInterface* InMaterialInterface) { ensure(InMaterialInterface); // See if its a material or material instance constant. Don't do anything if the user chose the current material instance. if(InMaterialInterface && MaterialEditorInstance->SourceInstance!=InMaterialInterface) { if(InMaterialInterface->IsA(UMaterial::StaticClass())) { // Show material editor UMaterial* Material = Cast(InMaterialInterface); FAssetEditorManager::Get().OpenEditorForAsset(Material); } else if(InMaterialInterface->IsA(UMaterialInstance::StaticClass())) { // Show material instance editor UMaterialInstance* MaterialInstance = Cast(InMaterialInterface); FAssetEditorManager::Get().OpenEditorForAsset(MaterialInstance); } } } void FMaterialInstanceEditor::UpdatePropertyWindow() { TArray SelectedObjects; SelectedObjects.Add( MaterialEditorInstance ); MaterialInstanceDetails->SetObjects( SelectedObjects, true ); } UObject* FMaterialInstanceEditor::GetSyncObject() { if (MaterialEditorInstance) { return MaterialEditorInstance->SourceInstance; } return NULL; } bool FMaterialInstanceEditor::ApproveSetPreviewAsset(UObject* InAsset) { // Default impl is to always accept. return true; } void FMaterialInstanceEditor::Refresh() { int32 TempIndex; const bool bParentChanged = !ParentList.Find( MaterialEditorInstance->Parent, TempIndex ); PreviewVC->RefreshViewport(); if( bParentChanged ) { RebuildInheritanceList(); } UpdatePropertyWindow(); } void FMaterialInstanceEditor::PostUndo( bool bSuccess ) { MaterialEditorInstance->CopyToSourceInstance(); Refresh(); } void FMaterialInstanceEditor::PostRedo( bool bSuccess ) { MaterialEditorInstance->CopyToSourceInstance(); Refresh(); } #undef LOCTEXT_NAMESPACE