2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "MaterialEditorModule.h"
2014-05-22 11:33:54 -04:00
2014-10-07 16:39:44 -04:00
# include "MaterialGraph/MaterialGraphNode_Comment.h"
2014-05-22 11:33:54 -04:00
# include "Materials/MaterialExpressionBreakMaterialAttributes.h"
# include "Materials/MaterialExpressionCollectionParameter.h"
# include "Materials/MaterialExpressionComment.h"
# include "Materials/MaterialExpressionComponentMask.h"
# include "Materials/MaterialExpressionConstant.h"
# include "Materials/MaterialExpressionConstant2Vector.h"
# include "Materials/MaterialExpressionConstant3Vector.h"
# include "Materials/MaterialExpressionConstant4Vector.h"
2014-07-21 04:33:11 -04:00
# include "Materials/MaterialExpressionDynamicParameter.h"
2014-05-22 11:33:54 -04:00
# include "Materials/MaterialExpressionFontSampleParameter.h"
# include "Materials/MaterialExpressionFunctionInput.h"
# include "Materials/MaterialExpressionFunctionOutput.h"
# include "Materials/MaterialExpressionParameter.h"
# include "Materials/MaterialExpressionParticleSubUV.h"
# include "Materials/MaterialExpressionRotateAboutAxis.h"
# include "Materials/MaterialExpressionScalarParameter.h"
# include "Materials/MaterialExpressionStaticComponentMaskParameter.h"
# include "Materials/MaterialExpressionTextureSampleParameter.h"
# include "Materials/MaterialExpressionTextureObject.h"
# include "Materials/MaterialExpressionTextureSampleParameter2D.h"
# include "Materials/MaterialExpressionTextureSampleParameterCube.h"
# include "Materials/MaterialExpressionTextureSampleParameterSubUV.h"
# include "Materials/MaterialExpressionTransformPosition.h"
# include "Materials/MaterialExpressionVectorParameter.h"
# include "Materials/MaterialFunction.h"
2015-04-10 03:30:54 -04:00
# include "Materials/MaterialParameterCollection.h"
2014-05-22 11:33:54 -04:00
2014-03-14 14:13:41 -04:00
# include "MaterialEditorActions.h"
# include "MaterialExpressionClasses.h"
# include "MaterialCompiler.h"
2014-05-21 10:00:58 -04:00
# include "EditorSupportDelegates.h"
2014-03-14 14:13:41 -04:00
# include "Toolkits/IToolkitHost.h"
# include "Editor/EditorWidgets/Public/EditorWidgets.h"
# include "AssetRegistryModule.h"
# include "AssetToolsModule.h"
# include "SMaterialEditorViewport.h"
# include "SMaterialEditorTitleBar.h"
# include "PreviewScene.h"
# include "ScopedTransaction.h"
# include "BusyCursor.h"
# include "Editor/PropertyEditor/Public/PropertyEditorModule.h"
# include "Editor/PropertyEditor/Public/IDetailsView.h"
# include "MaterialEditorDetailCustomization.h"
# include "MaterialInstanceEditor.h"
# include "Editor/WorkspaceMenuStructure/Public/WorkspaceMenuStructureModule.h"
# include "EditorViewportCommands.h"
# include "GraphEditor.h"
# include "GraphEditorActions.h"
# include "BlueprintEditorUtils.h"
# include "EdGraphUtilities.h"
# include "SNodePanel.h"
# include "MaterialEditorUtilities.h"
# include "SMaterialPalette.h"
2014-04-23 18:30:12 -04:00
# include "FindInMaterial.h"
2014-08-27 20:35:19 -04:00
# include "SColorPicker.h"
2014-09-05 08:25:23 -04:00
# include "EditorClassUtils.h"
# include "IDocumentation.h"
2014-10-14 22:50:06 -04:00
# include "SDockTab.h"
2014-03-14 14:13:41 -04:00
# include "Developer/MessageLog/Public/MessageLogModule.h"
2014-05-29 17:02:05 -04:00
# include "Particles/ParticleSystemComponent.h"
2014-10-14 22:50:06 -04:00
# include "GenericCommands.h"
2015-04-10 03:30:54 -04:00
# include "CanvasTypes.h"
# include "Engine/Selection.h"
# include "Engine/TextureCube.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "MaterialEditor"
DEFINE_LOG_CATEGORY_STATIC ( LogMaterialEditor , Log , All ) ;
2014-08-26 14:02:18 -04:00
static TAutoConsoleVariable < int32 > CVarMaterialEdUseDevShaders (
TEXT ( " r.MaterialEditor.UseDevShaders " ) ,
0 ,
TEXT ( " Toggles whether the material editor will use shaders that include extra overhead incurred by the editor. Material editor must be re-opened if changed at runtime. " ) ,
ECVF_RenderThreadSafe ) ;
2014-03-14 14:13:41 -04:00
const FName FMaterialEditor : : PreviewTabId ( TEXT ( " MaterialEditor_Preview " ) ) ;
const FName FMaterialEditor : : GraphCanvasTabId ( TEXT ( " MaterialEditor_GraphCanvas " ) ) ;
const FName FMaterialEditor : : PropertiesTabId ( TEXT ( " MaterialEditor_MaterialProperties " ) ) ;
const FName FMaterialEditor : : HLSLCodeTabId ( TEXT ( " MaterialEditor_HLSLCode " ) ) ;
const FName FMaterialEditor : : PaletteTabId ( TEXT ( " MaterialEditor_Palette " ) ) ;
const FName FMaterialEditor : : StatsTabId ( TEXT ( " MaterialEditor_Stats " ) ) ;
2014-04-23 18:21:07 -04:00
const FName FMaterialEditor : : FindTabId ( TEXT ( " MaterialEditor_Find " ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-02 18:09:23 -04:00
///////////////////////////
// FMatExpressionPreview //
///////////////////////////
2014-03-14 14:13:41 -04:00
bool FMatExpressionPreview : : ShouldCache ( EShaderPlatform Platform , const FShaderType * ShaderType , const FVertexFactoryType * VertexFactoryType ) const
{
if ( VertexFactoryType = = FindVertexFactoryType ( FName ( TEXT ( " FLocalVertexFactory " ) , FNAME_Find ) ) )
{
// we only need the non-light-mapped, base pass, local vertex factory shaders for drawing an opaque Material Tile
// @todo: Added a FindShaderType by fname or something"
2014-08-25 14:41:54 -04:00
if ( IsMobilePlatform ( Platform ) )
2014-03-14 14:13:41 -04:00
{
2014-07-10 10:39:54 -04:00
if ( FCString : : Stristr ( ShaderType - > GetName ( ) , TEXT ( " BasePassForForwardShadingVSFNoLightMapPolicy " ) ) | |
FCString : : Stristr ( ShaderType - > GetName ( ) , TEXT ( " BasePassForForwardShadingPSFNoLightMapPolicy " ) ) )
{
return true ;
}
2014-03-14 14:13:41 -04:00
}
2014-07-10 10:39:54 -04:00
else
2014-03-14 14:13:41 -04:00
{
2014-07-10 10:39:54 -04:00
if ( FCString : : Stristr ( ShaderType - > GetName ( ) , TEXT ( " BasePassVSFNoLightMapPolicy " ) ) | |
FCString : : Stristr ( ShaderType - > GetName ( ) , TEXT ( " BasePassHSFNoLightMapPolicy " ) ) | |
FCString : : Stristr ( ShaderType - > GetName ( ) , TEXT ( " BasePassDSFNoLightMapPolicy " ) ) )
{
return true ;
}
else if ( FCString : : Stristr ( ShaderType - > GetName ( ) , TEXT ( " BasePassPSFNoLightMapPolicy " ) ) )
{
return true ;
}
2014-03-14 14:13:41 -04:00
}
}
return false ;
}
2015-01-13 19:47:46 -05:00
int32 FMatExpressionPreview : : CompilePropertyAndSetMaterialProperty ( EMaterialProperty Property , FMaterialCompiler * Compiler , EShaderFrequency OverrideShaderFrequency , bool bUsePreviousFrameTime ) const
2014-03-14 14:13:41 -04:00
{
2014-07-11 15:14:35 -04:00
// needs to be called in this function!!
2015-01-13 19:47:46 -05:00
Compiler - > SetMaterialProperty ( Property , OverrideShaderFrequency , bUsePreviousFrameTime ) ;
2014-07-11 15:14:35 -04:00
int32 Ret = INDEX_NONE ;
2014-03-14 14:13:41 -04:00
if ( Property = = MP_EmissiveColor & & Expression . IsValid ( ) )
{
// Hardcoding output 0 as we don't have the UI to specify any other output
const int32 OutputIndex = 0 ;
// Get back into gamma corrected space, as DrawTile does not do this adjustment.
2014-07-11 15:14:35 -04:00
Ret = Compiler - > Power ( Compiler - > Max ( Expression - > CompilePreview ( Compiler , OutputIndex , - 1 ) , Compiler - > Constant ( 0 ) ) , Compiler - > Constant ( 1.f / 2.2f ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-13 19:47:46 -05:00
else if ( Property = = MP_WorldPositionOffset )
2014-03-14 14:13:41 -04:00
{
//set to 0 to prevent off by 1 pixel errors
2014-07-11 15:14:35 -04:00
Ret = Compiler - > Constant ( 0.0f ) ;
2014-03-14 14:13:41 -04:00
}
else if ( Property > = MP_CustomizedUVs0 & & Property < = MP_CustomizedUVs7 )
{
const int32 TextureCoordinateIndex = Property - MP_CustomizedUVs0 ;
2014-07-11 15:14:35 -04:00
Ret = Compiler - > TextureCoordinate ( TextureCoordinateIndex , false , false ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2014-07-11 15:14:35 -04:00
Ret = Compiler - > Constant ( 1.0f ) ;
2014-03-14 14:13:41 -04:00
}
2014-07-11 15:14:35 -04:00
// output should always be the right type for this property
return Compiler - > ForceCast ( Ret , GetMaterialPropertyType ( Property ) ) ;
2014-03-14 14:13:41 -04:00
}
void FMatExpressionPreview : : NotifyCompilationFinished ( )
{
if ( Expression . IsValid ( ) & & Expression - > GraphNode )
{
CastChecked < UMaterialGraphNode > ( Expression - > GraphNode ) - > bPreviewNeedsUpdate = true ;
}
}
2014-04-02 18:09:23 -04:00
/////////////////////
// FMaterialEditor //
/////////////////////
2014-03-14 14:13:41 -04:00
void FMaterialEditor : : RegisterTabSpawners ( const TSharedRef < class FTabManager > & TabManager )
{
2014-10-23 15:11:28 -04:00
WorkspaceMenuCategory = TabManager - > AddLocalWorkspaceMenuCategory ( LOCTEXT ( " WorkspaceMenu_MaterialEditor " , " Material Editor " ) ) ;
2014-10-09 12:34:55 -04:00
auto WorkspaceMenuCategoryRef = WorkspaceMenuCategory . ToSharedRef ( ) ;
2014-03-14 14:13:41 -04:00
FAssetEditorToolkit : : RegisterTabSpawners ( TabManager ) ;
2014-10-09 12:34:55 -04:00
2014-03-14 14:13:41 -04:00
TabManager - > RegisterTabSpawner ( PreviewTabId , FOnSpawnTab : : CreateSP ( this , & FMaterialEditor : : SpawnTab_Preview ) )
. SetDisplayName ( LOCTEXT ( " ViewportTab " , " Viewport " ) )
2014-10-09 12:34:55 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
. SetIcon ( FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " LevelEditor.Tabs.Viewports " ) ) ;
2014-03-14 14:13:41 -04:00
TabManager - > RegisterTabSpawner ( GraphCanvasTabId , FOnSpawnTab : : CreateSP ( this , & FMaterialEditor : : SpawnTab_GraphCanvas ) )
. SetDisplayName ( LOCTEXT ( " GraphCanvasTab " , " Graph " ) )
2014-10-09 12:34:55 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
. SetIcon ( FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " GraphEditor.EventGraph_16x " ) ) ;
2014-03-14 14:13:41 -04:00
TabManager - > RegisterTabSpawner ( PropertiesTabId , FOnSpawnTab : : CreateSP ( this , & FMaterialEditor : : SpawnTab_MaterialProperties ) )
. SetDisplayName ( LOCTEXT ( " DetailsTab " , " Details " ) )
2014-10-09 12:34:55 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
. SetIcon ( FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " LevelEditor.Tabs.Details " ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
TabManager - > RegisterTabSpawner ( PaletteTabId , FOnSpawnTab : : CreateSP ( this , & FMaterialEditor : : SpawnTab_Palette ) )
. SetDisplayName ( LOCTEXT ( " PaletteTab " , " Palette " ) )
2014-10-09 12:34:55 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
. SetIcon ( FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " Kismet.Tabs.Palette " ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
TabManager - > RegisterTabSpawner ( StatsTabId , FOnSpawnTab : : CreateSP ( this , & FMaterialEditor : : SpawnTab_Stats ) )
. SetDisplayName ( LOCTEXT ( " StatsTab " , " Stats " ) )
2014-10-09 12:34:55 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
. SetIcon ( FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " LevelEditor.Tabs.StatsViewer " ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
TabManager - > RegisterTabSpawner ( FindTabId , FOnSpawnTab : : CreateSP ( this , & FMaterialEditor : : SpawnTab_Find ) )
. SetDisplayName ( LOCTEXT ( " FindTab " , " Find Results " ) )
2014-10-09 12:34:55 -04:00
. SetGroup ( WorkspaceMenuCategoryRef )
. SetIcon ( FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " Kismet.Tabs.FindResults " ) ) ;
2014-04-23 18:21:07 -04:00
2014-03-14 14:13:41 -04:00
TabManager - > RegisterTabSpawner ( HLSLCodeTabId , FOnSpawnTab : : CreateSP ( this , & FMaterialEditor : : SpawnTab_HLSLCode ) )
. SetDisplayName ( LOCTEXT ( " HLSLCodeTab " , " HLSL Code " ) )
2014-10-09 12:34:55 -04:00
. SetGroup ( WorkspaceMenuCategoryRef ) ;
2014-03-14 14:13:41 -04:00
}
void FMaterialEditor : : UnregisterTabSpawners ( const TSharedRef < class FTabManager > & TabManager )
{
FAssetEditorToolkit : : UnregisterTabSpawners ( TabManager ) ;
TabManager - > UnregisterTabSpawner ( PreviewTabId ) ;
TabManager - > UnregisterTabSpawner ( GraphCanvasTabId ) ;
TabManager - > UnregisterTabSpawner ( PropertiesTabId ) ;
2014-04-23 18:21:07 -04:00
TabManager - > UnregisterTabSpawner ( PaletteTabId ) ;
TabManager - > UnregisterTabSpawner ( StatsTabId ) ;
TabManager - > UnregisterTabSpawner ( FindTabId ) ;
2014-03-14 14:13:41 -04:00
TabManager - > UnregisterTabSpawner ( HLSLCodeTabId ) ;
}
void FMaterialEditor : : InitEditorForMaterial ( UMaterial * InMaterial )
{
check ( InMaterial ) ;
OriginalMaterial = InMaterial ;
MaterialFunction = NULL ;
OriginalMaterialObject = InMaterial ;
ExpressionPreviewMaterial = NULL ;
// Create a copy of the material for preview usage (duplicating to a different class than original!)
// Propagate all object flags except for RF_Standalone, otherwise the preview material won't GC once
// the material editor releases the reference.
Material = ( UMaterial * ) StaticDuplicateObject ( OriginalMaterial , GetTransientPackage ( ) , NULL , ~ RF_Standalone , UPreviewMaterial : : StaticClass ( ) ) ;
2014-08-26 14:02:18 -04:00
Material - > CancelOutstandingCompilation ( ) ; //The material is compiled later on anyway so no need to do it in Duplication/PostLoad.
//I'm hackily canceling the jobs here but we should really not add the jobs in the first place. <<--- TODO
Material - > bAllowDevelopmentShaderCompile = CVarMaterialEdUseDevShaders . GetValueOnGameThread ( ) ;
2014-03-14 14:13:41 -04:00
// Remove NULL entries, so the rest of the material editor can assume all entries of Material->Expressions are valid
// This can happen if an expression class was removed
for ( int32 ExpressionIndex = Material - > Expressions . Num ( ) - 1 ; ExpressionIndex > = 0 ; ExpressionIndex - - )
{
if ( ! Material - > Expressions [ ExpressionIndex ] )
{
Material - > Expressions . RemoveAt ( ExpressionIndex ) ;
}
}
}
void FMaterialEditor : : InitEditorForMaterialFunction ( UMaterialFunction * InMaterialFunction )
{
check ( InMaterialFunction ) ;
Material = NULL ;
MaterialFunction = InMaterialFunction ;
OriginalMaterialObject = InMaterialFunction ;
ExpressionPreviewMaterial = NULL ;
// Create a temporary material to preview the material function
2015-02-09 05:43:45 -05:00
Material = NewObject < UMaterial > ( ) ;
2014-03-14 14:13:41 -04:00
{
2014-07-28 17:01:21 -04:00
FArchiveUObject DummyArchive ;
2014-03-14 14:13:41 -04:00
// Hack: serialize the new material with an archive that does nothing so that its material resources are created
Material - > Serialize ( DummyArchive ) ;
}
2014-05-30 07:55:38 -04:00
Material - > SetShadingModel ( MSM_Unlit ) ;
2014-03-14 14:13:41 -04:00
// Propagate all object flags except for RF_Standalone, otherwise the preview material function won't GC once
// the material editor releases the reference.
MaterialFunction = ( UMaterialFunction * ) StaticDuplicateObject ( InMaterialFunction , GetTransientPackage ( ) , NULL , ~ RF_Standalone , UMaterialFunction : : StaticClass ( ) ) ;
MaterialFunction - > ParentFunction = InMaterialFunction ;
OriginalMaterial = Material ;
}
void FMaterialEditor : : InitMaterialEditor ( const EToolkitMode : : Type Mode , const TSharedPtr < class IToolkitHost > & InitToolkitHost , UObject * ObjectToEdit )
{
EditorOptions = NULL ;
bMaterialDirty = false ;
bStatsFromPreviewMaterial = false ;
ColorPickerObject = NULL ;
2014-04-23 18:21:07 -04:00
// Support undo/redo
Material - > SetFlags ( RF_Transactional ) ;
2014-04-02 18:09:23 -04:00
2014-04-23 18:21:07 -04:00
GEditor - > RegisterForUndo ( this ) ;
2014-04-02 18:09:23 -04:00
2014-04-23 18:21:07 -04:00
if ( ! Material - > MaterialGraph )
{
Material - > MaterialGraph = CastChecked < UMaterialGraph > ( FBlueprintEditorUtils : : CreateNewGraph ( Material , NAME_None , UMaterialGraph : : StaticClass ( ) , UMaterialGraphSchema : : StaticClass ( ) ) ) ;
}
Material - > MaterialGraph - > Material = Material ;
Material - > MaterialGraph - > MaterialFunction = MaterialFunction ;
Material - > MaterialGraph - > RealtimeDelegate . BindSP ( this , & FMaterialEditor : : IsToggleRealTimeExpressionsChecked ) ;
Material - > MaterialGraph - > MaterialDirtyDelegate . BindSP ( this , & FMaterialEditor : : SetMaterialDirty ) ;
Material - > MaterialGraph - > ToggleCollapsedDelegate . BindSP ( this , & FMaterialEditor : : ToggleCollapsed ) ;
2014-03-14 14:13:41 -04:00
// copy material usage
for ( int32 Usage = 0 ; Usage < MATUSAGE_MAX ; Usage + + )
{
const EMaterialUsage UsageEnum = ( EMaterialUsage ) Usage ;
if ( OriginalMaterial - > GetUsageByFlag ( UsageEnum ) )
{
bool bNeedsRecompile = false ;
Material - > SetMaterialUsage ( bNeedsRecompile , UsageEnum ) ;
}
}
// Manually copy bUsedAsSpecialEngineMaterial as it is duplicate transient to prevent accidental creation of new special engine materials
Material - > bUsedAsSpecialEngineMaterial = OriginalMaterial - > bUsedAsSpecialEngineMaterial ;
// Register our commands. This will only register them if not previously registered
FGraphEditorCommands : : Register ( ) ;
FMaterialEditorCommands : : Register ( ) ;
FMaterialEditorSpawnNodeCommands : : Register ( ) ;
FEditorSupportDelegates : : MaterialUsageFlagsChanged . AddRaw ( this , & FMaterialEditor : : OnMaterialUsageFlagsChanged ) ;
2014-10-23 21:38:06 -04:00
FEditorSupportDelegates : : VectorParameterDefaultChanged . AddRaw ( this , & FMaterialEditor : : OnVectorParameterDefaultChanged ) ;
FEditorSupportDelegates : : ScalarParameterDefaultChanged . AddRaw ( this , & FMaterialEditor : : OnScalarParameterDefaultChanged ) ;
2015-03-08 15:25:46 -04:00
FEditorDelegates : : OnAssetPostImport . AddRaw ( this , & FMaterialEditor : : OnAssetPostImport ) ;
2014-03-14 14:13:41 -04:00
FAssetRegistryModule & AssetRegistryModule = FModuleManager : : GetModuleChecked < FAssetRegistryModule > ( TEXT ( " AssetRegistry " ) ) ;
AssetRegistryModule . Get ( ) . OnAssetRenamed ( ) . AddSP ( this , & FMaterialEditor : : RenameAssetFromRegistry ) ;
CreateInternalWidgets ( ) ;
2014-04-02 18:09:23 -04:00
// Do setup previously done in SMaterialEditorCanvas
2014-04-23 18:21:07 -04:00
SetPreviewMaterial ( Material ) ;
Material - > bIsPreviewMaterial = true ;
FMaterialEditorUtilities : : InitExpressions ( Material ) ;
2014-03-14 14:13:41 -04:00
BindCommands ( ) ;
2014-04-23 18:21:07 -04:00
const TSharedRef < FTabManager : : FLayout > StandaloneDefaultLayout = FTabManager : : NewLayout ( " Standalone_MaterialEditor_Layout_v5 " )
2014-03-14 14:13:41 -04:00
- > 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.2f )
- > Split
(
FTabManager : : NewStack ( )
- > SetHideTabWell ( true )
- > AddTab ( PreviewTabId , ETabState : : OpenedTab )
)
- > Split
(
FTabManager : : NewStack ( )
- > AddTab ( PropertiesTabId , ETabState : : OpenedTab )
)
)
- > Split
(
FTabManager : : NewSplitter ( ) - > SetOrientation ( Orient_Vertical )
- > SetSizeCoefficient ( 0.80f )
- > Split
(
FTabManager : : NewStack ( )
- > SetSizeCoefficient ( 0.8f )
- > SetHideTabWell ( true )
- > AddTab ( GraphCanvasTabId , ETabState : : OpenedTab )
)
- > Split
(
FTabManager : : NewStack ( )
- > SetSizeCoefficient ( 0.20f )
- > AddTab ( StatsTabId , ETabState : : ClosedTab )
2014-04-23 18:21:07 -04:00
- > AddTab ( FindTabId , ETabState : : ClosedTab )
2014-03-14 14:13:41 -04:00
)
)
- > Split
(
FTabManager : : NewSplitter ( ) - > SetOrientation ( Orient_Horizontal ) - > SetSizeCoefficient ( 0.2f )
- > Split
(
FTabManager : : NewStack ( )
- > AddTab ( PaletteTabId , ETabState : : OpenedTab )
)
)
)
) ;
const bool bCreateDefaultStandaloneMenu = true ;
const bool bCreateDefaultToolbar = true ;
// Add the preview material to the objects being edited, so that we can find this editor from the temporary material graph
TArray < UObject * > ObjectsToEdit ;
ObjectsToEdit . Add ( ObjectToEdit ) ;
ObjectsToEdit . Add ( Material ) ;
FAssetEditorToolkit : : InitAssetEditor ( Mode , InitToolkitHost , MaterialEditorAppIdentifier , StandaloneDefaultLayout , bCreateDefaultStandaloneMenu , bCreateDefaultToolbar , ObjectsToEdit , false ) ;
2014-10-09 12:34:55 -04:00
2014-03-14 14:13:41 -04:00
IMaterialEditorModule * MaterialEditorModule = & FModuleManager : : LoadModuleChecked < IMaterialEditorModule > ( " 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 ( GraphCanvasTabId , FString ( ) , EToolkitTabSpot : : Document ) ;
SpawnToolkitTab ( PropertiesTabId , FString ( ) , EToolkitTabSpot : : Details ) ;
} */
// Load editor settings from disk.
LoadEditorSettings ( ) ;
// Set the preview mesh for the material. This call must occur after the toolbar is initialized.
2015-02-19 00:33:19 -05:00
if ( ! SetPreviewAssetByName ( * Material - > PreviewMesh . ToString ( ) ) )
2014-03-14 14:13:41 -04:00
{
// The material preview mesh couldn't be found or isn't loaded. Default to the one of the primitive types.
2015-02-19 00:33:19 -05:00
SetPreviewAsset ( GUnrealEd - > GetThumbnailManager ( ) - > EditorSphere ) ;
2014-03-14 14:13:41 -04:00
}
// Initialize expression previews.
if ( MaterialFunction )
{
Material - > Expressions = MaterialFunction - > FunctionExpressions ;
Material - > EditorComments = MaterialFunction - > FunctionEditorComments ;
// Remove NULL entries, so the rest of the material editor can assume all entries of Material->Expressions are valid
// This can happen if an expression class was removed
for ( int32 ExpressionIndex = Material - > Expressions . Num ( ) - 1 ; ExpressionIndex > = 0 ; ExpressionIndex - - )
{
if ( ! Material - > Expressions [ ExpressionIndex ] )
{
Material - > Expressions . RemoveAt ( ExpressionIndex ) ;
}
}
if ( Material - > Expressions . Num ( ) = = 0 )
{
// If this is an empty functions, create an output by default and start previewing it
2014-04-02 18:09:23 -04:00
if ( GraphEditor . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
UMaterialExpression * Expression = CreateNewMaterialExpression ( UMaterialExpressionFunctionOutput : : StaticClass ( ) , FVector2D ( 200 , 300 ) , false , true ) ;
SetPreviewExpression ( Expression ) ;
}
}
else
{
bool bSetPreviewExpression = false ;
UMaterialExpressionFunctionOutput * FirstOutput = NULL ;
for ( int32 ExpressionIndex = Material - > Expressions . Num ( ) - 1 ; ExpressionIndex > = 0 ; ExpressionIndex - - )
{
UMaterialExpression * Expression = Material - > Expressions [ ExpressionIndex ] ;
// Setup the expression to be used with the preview material instead of the function
Expression - > Function = NULL ;
Expression - > Material = Material ;
UMaterialExpressionFunctionOutput * FunctionOutput = Cast < UMaterialExpressionFunctionOutput > ( Expression ) ;
if ( FunctionOutput )
{
FirstOutput = FunctionOutput ;
if ( FunctionOutput - > bLastPreviewed )
{
bSetPreviewExpression = true ;
// Preview the last output previewed
2014-04-23 18:21:07 -04:00
SetPreviewExpression ( FunctionOutput ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-04-23 18:21:07 -04:00
}
2014-03-14 14:13:41 -04:00
if ( ! bSetPreviewExpression & & FirstOutput )
{
2014-04-23 18:21:07 -04:00
SetPreviewExpression ( FirstOutput ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-04-23 18:06:41 -04:00
}
2014-03-14 14:13:41 -04:00
2014-09-11 08:13:08 -04:00
// Store the name of this material (for the tutorial widget meta)
Material - > MaterialGraph - > OriginalMaterialFullName = OriginalMaterial - > GetName ( ) ;
2014-04-23 18:21:07 -04:00
Material - > MaterialGraph - > RebuildGraph ( ) ;
RecenterEditor ( ) ;
2014-07-08 10:58:56 -04:00
//Make sure the preview material is initialized.
UpdatePreviewMaterial ( true ) ;
RegenerateCodeView ( true ) ;
2014-04-23 18:21:07 -04:00
ForceRefreshExpressionPreviews ( ) ;
}
2014-03-14 14:13:41 -04:00
FMaterialEditor : : FMaterialEditor ( )
: bMaterialDirty ( false )
, bStatsFromPreviewMaterial ( false )
, Material ( NULL )
, OriginalMaterial ( NULL )
, ExpressionPreviewMaterial ( NULL )
2014-04-23 20:20:58 -04:00
, EmptyMaterial ( NULL )
2014-03-14 14:13:41 -04:00
, PreviewExpression ( NULL )
, MaterialFunction ( NULL )
, OriginalMaterialObject ( NULL )
, EditorOptions ( NULL )
, ScopedTransaction ( NULL )
, bAlwaysRefreshAllPreviews ( false )
, bHideUnusedConnectors ( false )
2014-07-08 10:58:56 -04:00
, bLivePreview ( true )
2014-03-14 14:13:41 -04:00
, bIsRealtime ( false )
, bShowStats ( true )
2014-04-23 20:20:58 -04:00
, bShowBuiltinStats ( false )
2014-03-14 14:13:41 -04:00
, bShowMobileStats ( false )
{
}
FMaterialEditor : : ~ FMaterialEditor ( )
{
2014-10-23 21:38:06 -04:00
for ( int32 ParameterIndex = 0 ; ParameterIndex < OverriddenVectorParametersToRevert . Num ( ) ; ParameterIndex + + )
{
SetVectorParameterDefaultOnDependentMaterials ( OverriddenVectorParametersToRevert [ ParameterIndex ] , FLinearColor : : Black , false ) ;
}
for ( int32 ParameterIndex = 0 ; ParameterIndex < OverriddenScalarParametersToRevert . Num ( ) ; ParameterIndex + + )
{
SetScalarParameterDefaultOnDependentMaterials ( OverriddenScalarParametersToRevert [ ParameterIndex ] , 0 , false ) ;
}
2014-03-14 14:13:41 -04:00
// Unregister this delegate
FEditorSupportDelegates : : MaterialUsageFlagsChanged . RemoveAll ( this ) ;
2014-10-23 21:38:06 -04:00
FEditorSupportDelegates : : VectorParameterDefaultChanged . RemoveAll ( this ) ;
FEditorSupportDelegates : : ScalarParameterDefaultChanged . RemoveAll ( this ) ;
2015-03-08 15:25:46 -04:00
FEditorDelegates : : OnAssetPostImport . RemoveAll ( this ) ;
2014-03-14 14:13:41 -04:00
// Null out the expression preview material so they can be GC'ed
ExpressionPreviewMaterial = NULL ;
// Save editor settings to disk.
SaveEditorSettings ( ) ;
MaterialDetailsView . Reset ( ) ;
2014-04-23 18:21:07 -04:00
{
SCOPED_SUSPEND_RENDERING_THREAD ( true ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ExpressionPreviews . Empty ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:21:07 -04:00
check ( ! ScopedTransaction ) ;
GEditor - > UnregisterForUndo ( this ) ;
}
2014-03-14 14:13:41 -04:00
void FMaterialEditor : : GetAllMaterialExpressionGroups ( TArray < FString > * OutGroups )
{
for ( int32 MaterialExpressionIndex = 0 ; MaterialExpressionIndex < Material - > Expressions . Num ( ) ; + + MaterialExpressionIndex )
{
UMaterialExpression * MaterialExpression = Material - > Expressions [ MaterialExpressionIndex ] ;
UMaterialExpressionParameter * Switch = Cast < UMaterialExpressionParameter > ( MaterialExpression ) ;
UMaterialExpressionTextureSampleParameter * TextureS = Cast < UMaterialExpressionTextureSampleParameter > ( MaterialExpression ) ;
UMaterialExpressionFontSampleParameter * FontS = Cast < UMaterialExpressionFontSampleParameter > ( MaterialExpression ) ;
if ( Switch )
{
OutGroups - > AddUnique ( Switch - > Group . ToString ( ) ) ;
}
if ( TextureS )
{
OutGroups - > AddUnique ( TextureS - > Group . ToString ( ) ) ;
}
if ( FontS )
{
OutGroups - > AddUnique ( FontS - > Group . ToString ( ) ) ;
}
}
}
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void FMaterialEditor : : CreateInternalWidgets ( )
{
Viewport = SNew ( SMaterialEditorViewport )
. MaterialEditor ( SharedThis ( this ) ) ;
FPropertyEditorModule & PropertyEditorModule = FModuleManager : : GetModuleChecked < FPropertyEditorModule > ( " PropertyEditor " ) ;
2014-04-23 18:21:07 -04:00
GraphEditor = CreateGraphEditorWidget ( ) ;
// Manually set zoom level to avoid deferred zooming
GraphEditor - > SetViewLocation ( FVector2D : : ZeroVector , 1 ) ;
2015-01-26 17:14:50 -05:00
const FDetailsViewArgs DetailsViewArgs ( false , false , true , FDetailsViewArgs : : HideNameArea , true , this ) ;
2014-04-23 18:21:07 -04:00
MaterialDetailsView = PropertyEditorModule . CreateDetailView ( DetailsViewArgs ) ;
2014-03-14 14:13:41 -04:00
FOnGetDetailCustomizationInstance LayoutExpressionParameterDetails = FOnGetDetailCustomizationInstance : : CreateStatic (
& FMaterialExpressionParameterDetails : : MakeInstance , FOnCollectParameterGroups : : CreateSP ( this , & FMaterialEditor : : GetAllMaterialExpressionGroups ) ) ;
MaterialDetailsView - > RegisterInstancedCustomPropertyLayout (
UMaterialExpressionParameter : : StaticClass ( ) ,
LayoutExpressionParameterDetails
) ;
MaterialDetailsView - > RegisterInstancedCustomPropertyLayout (
UMaterialExpressionFontSampleParameter : : StaticClass ( ) ,
LayoutExpressionParameterDetails
) ;
MaterialDetailsView - > RegisterInstancedCustomPropertyLayout (
UMaterialExpressionTextureSampleParameter : : StaticClass ( ) ,
LayoutExpressionParameterDetails
) ;
FOnGetDetailCustomizationInstance LayoutCollectionParameterDetails = FOnGetDetailCustomizationInstance : : CreateStatic ( & FMaterialExpressionCollectionParameterDetails : : MakeInstance ) ;
MaterialDetailsView - > RegisterInstancedCustomPropertyLayout (
UMaterialExpressionCollectionParameter : : StaticClass ( ) ,
LayoutCollectionParameterDetails
) ;
2014-04-23 18:21:07 -04:00
Palette = SNew ( SMaterialPalette , SharedThis ( this ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
FMessageLogModule & MessageLogModule = FModuleManager : : LoadModuleChecked < FMessageLogModule > ( " MessageLog " ) ;
FMessageLogInitializationOptions LogOptions ;
// Show Pages so that user is never allowed to clear log messages
2014-08-26 14:02:18 -04:00
LogOptions . bShowPages = false ;
LogOptions . bShowFilters = false ; //TODO - Provide custom filters? E.g. "Critical Errors" vs "Errors" needed for materials?
LogOptions . bAllowClear = false ;
2014-04-23 18:21:07 -04:00
LogOptions . MaxPageCount = 1 ;
StatsListing = MessageLogModule . CreateLogListing ( " MaterialEditorStats " , LogOptions ) ;
2014-03-14 14:13:41 -04:00
2014-09-16 13:46:20 -04:00
Stats = MessageLogModule . CreateLogListingWidget ( StatsListing . ToSharedRef ( ) ) ;
2014-04-23 18:21:07 -04:00
FindResults =
SNew ( SFindInMaterial , SharedThis ( this ) ) ;
2014-03-14 14:13:41 -04:00
CodeViewUtility =
SNew ( SVerticalBox )
// Copy Button
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 2.0f , 0.0f )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Left )
[
SNew ( SButton )
2014-04-23 18:06:41 -04:00
. Text ( LOCTEXT ( " CopyHLSLButton " , " Copy " ) )
. ToolTipText ( LOCTEXT ( " CopyHLSLButtonToolTip " , " Copies all HLSL code to the clipboard. " ) )
2014-03-14 14:13:41 -04:00
. ContentPadding ( 3 )
. OnClicked ( this , & FMaterialEditor : : CopyCodeViewTextToClipboard )
]
]
// Separator
+ SVerticalBox : : Slot ( )
. FillHeight ( 1 )
[
SNew ( SSeparator )
] ;
CodeView =
SNew ( SScrollBox )
+ SScrollBox : : Slot ( ) . Padding ( 5 )
[
SNew ( STextBlock )
. Text ( this , & FMaterialEditor : : GetCodeViewText )
] ;
RegenerateCodeView ( ) ;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
FName FMaterialEditor : : GetToolkitFName ( ) const
{
return FName ( " MaterialEditor " ) ;
}
FText FMaterialEditor : : GetBaseToolkitName ( ) const
{
return LOCTEXT ( " AppLabel " , " Material Editor " ) ;
}
FText FMaterialEditor : : GetToolkitName ( ) const
{
const UObject * EditingObject = GetEditingObjects ( ) [ 0 ] ;
const bool bDirtyState = EditingObject - > GetOutermost ( ) - > IsDirty ( ) ;
// Overridden to accommodate editing of multiple objects (original and preview materials)
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " ObjectName " ) , FText : : FromString ( EditingObject - > GetName ( ) ) ) ;
Args . Add ( TEXT ( " DirtyState " ) , bDirtyState ? FText : : FromString ( TEXT ( " * " ) ) : FText : : GetEmpty ( ) ) ;
return FText : : Format ( LOCTEXT ( " MaterialEditorAppLabel " , " {ObjectName}{DirtyState} " ) , Args ) ;
}
FString FMaterialEditor : : GetWorldCentricTabPrefix ( ) const
{
return LOCTEXT ( " WorldCentricTabPrefix " , " Material " ) . ToString ( ) ;
}
FLinearColor FMaterialEditor : : GetWorldCentricTabColorScale ( ) const
{
return FLinearColor ( 0.3f , 0.2f , 0.5f , 0.5f ) ;
}
void FMaterialEditor : : Tick ( float InDeltaTime )
{
2014-04-23 18:21:07 -04:00
UpdateMaterialInfoList ( ) ;
UpdateGraphNodeStates ( ) ;
}
2014-03-14 14:13:41 -04:00
TStatId FMaterialEditor : : GetStatId ( ) const
{
RETURN_QUICK_DECLARE_CYCLE_STAT ( FMaterialEditor , STATGROUP_Tickables ) ;
}
void FMaterialEditor : : UpdateThumbnailInfoPreviewMesh ( UMaterialInterface * MatInterface )
{
if ( MatInterface )
{
FAssetToolsModule & AssetToolsModule = FModuleManager : : LoadModuleChecked < FAssetToolsModule > ( " AssetTools " ) ;
TWeakPtr < IAssetTypeActions > AssetTypeActions = AssetToolsModule . Get ( ) . GetAssetTypeActionsForClass ( MatInterface - > GetClass ( ) ) ;
if ( AssetTypeActions . IsValid ( ) )
{
USceneThumbnailInfoWithPrimitive * OriginalThumbnailInfo = Cast < USceneThumbnailInfoWithPrimitive > ( AssetTypeActions . Pin ( ) - > GetThumbnailInfo ( MatInterface ) ) ;
if ( OriginalThumbnailInfo )
{
OriginalThumbnailInfo - > PreviewMesh = MatInterface - > PreviewMesh ;
MatInterface - > PostEditChange ( ) ;
}
}
}
}
void FMaterialEditor : : ExtendToolbar ( )
{
struct Local
{
2014-04-23 18:21:07 -04:00
static void FillToolbar ( FToolBarBuilder & ToolbarBuilder )
2014-03-14 14:13:41 -04:00
{
ToolbarBuilder . BeginSection ( " Apply " ) ;
{
ToolbarBuilder . AddToolBarButton ( FMaterialEditorCommands : : Get ( ) . Apply ) ;
}
ToolbarBuilder . EndSection ( ) ;
2014-04-23 18:21:07 -04:00
ToolbarBuilder . BeginSection ( " Search " ) ;
{
ToolbarBuilder . AddToolBarButton ( FMaterialEditorCommands : : Get ( ) . FindInMaterial ) ;
}
ToolbarBuilder . EndSection ( ) ;
2014-03-14 14:13:41 -04:00
ToolbarBuilder . BeginSection ( " Graph " ) ;
{
ToolbarBuilder . AddToolBarButton ( FMaterialEditorCommands : : Get ( ) . CameraHome ) ;
ToolbarBuilder . AddToolBarButton ( FMaterialEditorCommands : : Get ( ) . CleanUnusedExpressions ) ;
2014-07-03 09:13:33 -04:00
ToolbarBuilder . AddToolBarButton ( FMaterialEditorCommands : : Get ( ) . ShowHideConnectors ) ;
ToolbarBuilder . AddToolBarButton ( FMaterialEditorCommands : : Get ( ) . ToggleLivePreview ) ;
2014-03-14 14:13:41 -04:00
ToolbarBuilder . AddToolBarButton ( FMaterialEditorCommands : : Get ( ) . ToggleRealtimeExpressions ) ;
ToolbarBuilder . AddToolBarButton ( FMaterialEditorCommands : : Get ( ) . AlwaysRefreshAllPreviews ) ;
ToolbarBuilder . AddToolBarButton ( FMaterialEditorCommands : : Get ( ) . ToggleMaterialStats ) ;
ToolbarBuilder . AddToolBarButton ( FMaterialEditorCommands : : Get ( ) . ToggleMobileStats ) ;
}
ToolbarBuilder . EndSection ( ) ;
}
} ;
TSharedPtr < FExtender > ToolbarExtender = MakeShareable ( new FExtender ) ;
ToolbarExtender - > AddToolBarExtension (
" Asset " ,
EExtensionHook : : After ,
GetToolkitCommands ( ) ,
2014-04-23 18:21:07 -04:00
FToolBarExtensionDelegate : : CreateStatic ( & Local : : FillToolbar )
2014-03-14 14:13:41 -04:00
) ;
AddToolbarExtender ( ToolbarExtender ) ;
IMaterialEditorModule * MaterialEditorModule = & FModuleManager : : LoadModuleChecked < IMaterialEditorModule > ( " MaterialEditor " ) ;
AddToolbarExtender ( MaterialEditorModule - > GetToolBarExtensibilityManager ( ) - > GetAllExtenders ( GetToolkitCommands ( ) , GetEditingObjects ( ) ) ) ;
}
UMaterialInterface * FMaterialEditor : : GetMaterialInterface ( ) const
{
return Material ;
}
2015-02-19 00:33:19 -05:00
bool FMaterialEditor : : ApproveSetPreviewAsset ( UObject * InAsset )
2014-03-14 14:13:41 -04:00
{
bool bApproved = true ;
2015-02-19 00:33:19 -05:00
2014-03-14 14:13:41 -04:00
// Only permit the use of a skeletal mesh if the material has bUsedWithSkeltalMesh.
2015-02-19 00:33:19 -05:00
if ( USkeletalMesh * SkeletalMesh = Cast < USkeletalMesh > ( InAsset ) )
2014-03-14 14:13:41 -04:00
{
2015-02-19 00:33:19 -05:00
if ( ! Material - > bUsedWithSkeletalMesh )
{
FMessageDialog : : Open ( EAppMsgType : : Ok , NSLOCTEXT ( " UnrealEd " , " Error_MaterialEditor_CantPreviewOnSkelMesh " , " Can't preview on the specified skeletal mesh because the material has not been compiled with bUsedWithSkeletalMesh. " ) ) ;
bApproved = false ;
}
2014-03-14 14:13:41 -04:00
}
2015-02-19 00:33:19 -05:00
2014-03-14 14:13:41 -04:00
return bApproved ;
}
void FMaterialEditor : : SaveAsset_Execute ( )
{
UE_LOG ( LogMaterialEditor , Log , TEXT ( " Saving and Compiling material %s " ) , * GetEditingObjects ( ) [ 0 ] - > GetName ( ) ) ;
2015-01-30 16:12:10 -05:00
if ( bMaterialDirty )
{
UpdateOriginalMaterial ( ) ;
}
2014-03-14 14:13:41 -04:00
UPackage * Package = OriginalMaterial - > GetOutermost ( ) ;
if ( MaterialFunction ! = NULL & & MaterialFunction - > ParentFunction )
{
Package = MaterialFunction - > ParentFunction - > GetOutermost ( ) ;
}
if ( Package )
{
TArray < UPackage * > PackagesToSave ;
PackagesToSave . Add ( Package ) ;
FEditorFileUtils : : PromptForCheckoutAndSave ( PackagesToSave , false , false ) ;
}
}
bool FMaterialEditor : : OnRequestClose ( )
{
DestroyColorPicker ( ) ;
// @todo DB: Store off the viewport camera position/orientation to the material.
//AnimTree->PreviewCamPos = PreviewVC->ViewLocation;
//AnimTree->PreviewCamRot = PreviewVC->ViewRotation;
if ( bMaterialDirty )
{
// find out the user wants to do with this dirty material
EAppReturnType : : Type YesNoCancelReply = FMessageDialog : : Open ( EAppMsgType : : YesNoCancel ,
FText : : Format (
NSLOCTEXT ( " UnrealEd " , " Prompt_MaterialEditorClose " , " Would you like to apply changes to this material to the original material? \n {0} \n (No will lose all changes!) " ) ,
FText : : FromString ( OriginalMaterialObject - > GetPathName ( ) ) ) ) ;
// act on it
switch ( YesNoCancelReply )
{
case EAppReturnType : : Yes :
// update material and exit
UpdateOriginalMaterial ( ) ;
break ;
case EAppReturnType : : No :
// exit
break ;
case EAppReturnType : : Cancel :
// don't exit
return false ;
}
}
return true ;
}
void FMaterialEditor : : DrawMaterialInfoStrings (
FCanvas * Canvas ,
const UMaterial * Material ,
const FMaterialResource * MaterialResource ,
const TArray < FString > & CompileErrors ,
int32 & DrawPositionY ,
bool bDrawInstructions )
{
check ( Material & & MaterialResource ) ;
ERHIFeatureLevel : : Type FeatureLevel = MaterialResource - > GetFeatureLevel ( ) ;
FString FeatureLevelName ;
GetFeatureLevelName ( FeatureLevel , FeatureLevelName ) ;
// The font to use when displaying info strings
UFont * FontToUse = GEngine - > GetTinyFont ( ) ;
const int32 SpacingBetweenLines = 13 ;
if ( bDrawInstructions )
{
// Display any errors and messages in the upper left corner of the viewport.
TArray < FString > Descriptions ;
TArray < int32 > InstructionCounts ;
MaterialResource - > GetRepresentativeInstructionCounts ( Descriptions , InstructionCounts ) ;
for ( int32 InstructionIndex = 0 ; InstructionIndex < Descriptions . Num ( ) ; InstructionIndex + + )
{
FString InstructionCountString = FString : : Printf ( TEXT ( " %s: %u instructions " ) , * Descriptions [ InstructionIndex ] , InstructionCounts [ InstructionIndex ] ) ;
2014-04-02 18:09:23 -04:00
Canvas - > DrawShadowedString ( 5 , DrawPositionY , * InstructionCountString , FontToUse , FLinearColor ( 1 , 1 , 0 ) ) ;
2014-03-14 14:13:41 -04:00
DrawPositionY + = SpacingBetweenLines ;
}
// Display the number of samplers used by the material.
const int32 SamplersUsed = MaterialResource - > GetSamplerUsage ( ) ;
if ( SamplersUsed > = 0 )
{
int32 MaxSamplers = GetFeatureLevelMaxTextureSamplers ( MaterialResource - > GetFeatureLevel ( ) ) ;
2014-04-02 18:09:23 -04:00
Canvas - > DrawShadowedString (
2014-03-14 14:13:41 -04:00
5 ,
DrawPositionY ,
2015-04-16 13:02:21 -04:00
* FString : : Printf ( TEXT ( " %s samplers: %u/%u " ) , FeatureLevel < = ERHIFeatureLevel : : ES3_1 ? TEXT ( " Mobile texture " ) : TEXT ( " Texture " ) , SamplersUsed , MaxSamplers ) ,
2014-03-14 14:13:41 -04:00
FontToUse ,
SamplersUsed > MaxSamplers ? FLinearColor ( 1 , 0 , 0 ) : FLinearColor ( 1 , 1 , 0 )
) ;
DrawPositionY + = SpacingBetweenLines ;
}
}
for ( int32 ErrorIndex = 0 ; ErrorIndex < CompileErrors . Num ( ) ; ErrorIndex + + )
{
2014-04-02 18:09:23 -04:00
Canvas - > DrawShadowedString ( 5 , DrawPositionY , * FString : : Printf ( TEXT ( " [%s] %s " ) , * FeatureLevelName , * CompileErrors [ ErrorIndex ] ) , FontToUse , FLinearColor ( 1 , 0 , 0 ) ) ;
2014-03-14 14:13:41 -04:00
DrawPositionY + = SpacingBetweenLines ;
}
}
void FMaterialEditor : : DrawMessages ( FViewport * InViewport , FCanvas * Canvas )
{
2014-04-23 18:21:07 -04:00
if ( PreviewExpression ! = NULL )
{
Canvas - > PushAbsoluteTransform ( FMatrix : : Identity ) ;
// The message to display in the viewport.
FString Name = FString : : Printf ( TEXT ( " Previewing: %s " ) , * PreviewExpression - > GetName ( ) ) ;
// Size of the tile we are about to draw. Should extend the length of the view in X.
const FIntPoint TileSize ( InViewport - > GetSizeXY ( ) . X , 25 ) ;
const FColor PreviewColor ( 70 , 100 , 200 ) ;
const FColor FontColor ( 255 , 255 , 128 ) ;
UFont * FontToUse = GEditor - > EditorFont ;
Canvas - > DrawTile ( 0.0f , 0.0f , TileSize . X , TileSize . Y , 0.0f , 0.0f , 0.0f , 0.0f , PreviewColor ) ;
int32 XL , YL ;
StringSize ( FontToUse , XL , YL , * Name ) ;
if ( XL > TileSize . X )
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:21:07 -04:00
// There isn't enough room to show the preview expression name
Name = TEXT ( " Previewing " ) ;
2014-03-14 14:13:41 -04:00
StringSize ( FontToUse , XL , YL , * Name ) ;
}
2014-04-23 18:21:07 -04:00
// Center the string in the middle of the tile.
const FIntPoint StringPos ( ( TileSize . X - XL ) / 2 , ( ( TileSize . Y - YL ) / 2 ) + 1 ) ;
// Draw the preview message
Canvas - > DrawShadowedString ( StringPos . X , StringPos . Y , * Name , FontToUse , FontColor ) ;
Canvas - > PopTransform ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:21:07 -04:00
}
2014-03-14 14:13:41 -04:00
void FMaterialEditor : : RecenterEditor ( )
{
UEdGraphNode * FocusNode = NULL ;
if ( MaterialFunction )
{
bool bSetPreviewExpression = false ;
UMaterialExpressionFunctionOutput * FirstOutput = NULL ;
for ( int32 ExpressionIndex = Material - > Expressions . Num ( ) - 1 ; ExpressionIndex > = 0 ; ExpressionIndex - - )
{
UMaterialExpression * Expression = Material - > Expressions [ ExpressionIndex ] ;
UMaterialExpressionFunctionOutput * FunctionOutput = Cast < UMaterialExpressionFunctionOutput > ( Expression ) ;
if ( FunctionOutput )
{
FirstOutput = FunctionOutput ;
if ( FunctionOutput - > bLastPreviewed )
{
bSetPreviewExpression = true ;
FocusNode = FunctionOutput - > GraphNode ;
}
}
}
if ( ! bSetPreviewExpression & & FirstOutput )
{
FocusNode = FirstOutput - > GraphNode ;
}
}
else
{
FocusNode = Material - > MaterialGraph - > RootNode ;
}
if ( FocusNode )
{
2014-04-23 18:21:07 -04:00
JumpToNode ( FocusNode ) ;
2014-03-14 14:13:41 -04:00
}
else
{
// Get current view location so that we don't change the zoom amount
FVector2D CurrLocation ;
float CurrZoomLevel ;
GraphEditor - > GetViewLocation ( CurrLocation , CurrZoomLevel ) ;
GraphEditor - > SetViewLocation ( FVector2D : : ZeroVector , CurrZoomLevel ) ;
}
}
2015-02-19 00:33:19 -05:00
bool FMaterialEditor : : SetPreviewAsset ( UObject * InAsset )
2014-03-14 14:13:41 -04:00
{
if ( Viewport . IsValid ( ) )
{
2015-02-19 00:33:19 -05:00
return Viewport - > SetPreviewAsset ( InAsset ) ;
2014-03-14 14:13:41 -04:00
}
return false ;
}
2015-02-19 00:33:19 -05:00
bool FMaterialEditor : : SetPreviewAssetByName ( const TCHAR * InAssetName )
2014-03-14 14:13:41 -04:00
{
if ( Viewport . IsValid ( ) )
{
2015-02-19 00:33:19 -05:00
return Viewport - > SetPreviewAssetByName ( InAssetName ) ;
2014-03-14 14:13:41 -04:00
}
return false ;
}
void FMaterialEditor : : SetPreviewMaterial ( UMaterialInterface * InMaterialInterface )
{
if ( Viewport . IsValid ( ) )
{
Viewport - > SetPreviewMaterial ( InMaterialInterface ) ;
}
}
void FMaterialEditor : : RefreshPreviewViewport ( )
{
if ( Viewport . IsValid ( ) )
{
Viewport - > RefreshViewport ( ) ;
}
}
void FMaterialEditor : : LoadEditorSettings ( )
{
2015-02-03 05:40:57 -05:00
EditorOptions = NewObject < UMaterialEditorOptions > ( ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
if ( EditorOptions - > bHideUnusedConnectors ) { OnShowConnectors ( ) ; }
2014-07-11 08:44:19 -04:00
if ( bLivePreview ! = EditorOptions - > bLivePreviewUpdate )
2014-07-08 10:58:56 -04:00
{
ToggleLivePreview ( ) ;
}
2014-04-23 18:21:07 -04:00
if ( EditorOptions - > bAlwaysRefreshAllPreviews ) { OnAlwaysRefreshAllPreviews ( ) ; }
if ( EditorOptions - > bRealtimeExpressionViewport ) { ToggleRealTimeExpressions ( ) ; }
2014-04-02 18:09:23 -04:00
2014-03-14 14:13:41 -04:00
if ( Viewport . IsValid ( ) )
{
if ( EditorOptions - > bShowGrid ) { Viewport - > TogglePreviewGrid ( ) ; }
if ( EditorOptions - > bShowBackground ) { Viewport - > TogglePreviewBackground ( ) ; }
2015-03-09 10:00:46 -04:00
if ( EditorOptions - > bRealtimeMaterialViewport ) { Viewport - > OnToggleRealtime ( ) ; }
2014-03-14 14:13:41 -04:00
// Load the preview scene
Viewport - > PreviewScene . LoadSettings ( TEXT ( " MaterialEditor " ) ) ;
}
if ( EditorOptions - > bShowMobileStats )
{
ToggleMobileStats ( ) ;
}
2014-04-23 20:20:58 -04:00
2014-03-14 14:13:41 -04:00
// Primitive type
int32 PrimType ;
2015-04-20 10:12:55 -04:00
if ( GConfig - > GetInt ( TEXT ( " MaterialEditor " ) , TEXT ( " PrimType " ) , PrimType , GEditorPerProjectIni ) )
2014-03-14 14:13:41 -04:00
{
Viewport - > OnSetPreviewPrimitive ( ( EThumbnailPrimType ) PrimType ) ;
}
}
void FMaterialEditor : : SaveEditorSettings ( )
{
// Save the preview scene
2014-04-02 18:09:23 -04:00
check ( Viewport . IsValid ( ) ) ;
2014-03-14 14:13:41 -04:00
Viewport - > PreviewScene . SaveSettings ( TEXT ( " MaterialEditor " ) ) ;
if ( EditorOptions )
{
EditorOptions - > bShowGrid = Viewport - > IsTogglePreviewGridChecked ( ) ;
EditorOptions - > bShowBackground = Viewport - > IsTogglePreviewBackgroundChecked ( ) ;
EditorOptions - > bRealtimeMaterialViewport = Viewport - > IsRealtime ( ) ;
EditorOptions - > bShowMobileStats = bShowMobileStats ;
2014-04-23 18:21:07 -04:00
EditorOptions - > bHideUnusedConnectors = ! IsOnShowConnectorsChecked ( ) ;
EditorOptions - > bAlwaysRefreshAllPreviews = IsOnAlwaysRefreshAllPreviews ( ) ;
EditorOptions - > bRealtimeExpressionViewport = IsToggleRealTimeExpressionsChecked ( ) ;
2014-07-11 08:44:19 -04:00
EditorOptions - > bLivePreviewUpdate = IsToggleLivePreviewChecked ( ) ;
2014-03-14 14:13:41 -04:00
EditorOptions - > SaveConfig ( ) ;
}
2015-04-20 10:12:55 -04:00
GConfig - > SetInt ( TEXT ( " MaterialEditor " ) , TEXT ( " PrimType " ) , Viewport - > PreviewPrimType , GEditorPerProjectIni ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-07 09:52:40 -05:00
FText FMaterialEditor : : GetCodeViewText ( ) const
2014-03-14 14:13:41 -04:00
{
2015-01-07 09:52:40 -05:00
return FText : : FromString ( HLSLCode ) ;
2014-03-14 14:13:41 -04:00
}
FReply FMaterialEditor : : CopyCodeViewTextToClipboard ( )
{
2015-01-07 09:52:40 -05:00
FPlatformMisc : : ClipboardCopy ( * HLSLCode ) ;
2014-03-14 14:13:41 -04:00
return FReply : : Handled ( ) ;
}
2014-07-08 10:58:56 -04:00
void FMaterialEditor : : RegenerateCodeView ( bool bForce )
2014-03-14 14:13:41 -04:00
{
# define MARKTAG TEXT(" / *MARK_")
# define MARKTAGLEN 7
HLSLCode = TEXT ( " " ) ;
2014-07-08 10:58:56 -04:00
2014-10-23 21:38:06 -04:00
if ( ! CodeTab . IsValid ( ) | | ( ! bLivePreview & & ! bForce ) )
2014-07-08 10:58:56 -04:00
{
//When bLivePreview is false then the source can be out of date.
return ;
}
2014-03-14 14:13:41 -04:00
FString MarkupSource ;
2015-01-20 11:04:04 -05:00
if ( Material - > GetMaterialResource ( GMaxRHIFeatureLevel ) - > GetMaterialExpressionSource ( MarkupSource ) )
2014-03-14 14:13:41 -04:00
{
// Remove line-feeds and leave just CRs so the character counts match the selection ranges.
MarkupSource . ReplaceInline ( TEXT ( " \r " ) , TEXT ( " " ) ) ;
// Improve formatting: Convert tab to 4 spaces since STextBlock (currently) doesn't show tab characters
MarkupSource . ReplaceInline ( TEXT ( " \t " ) , TEXT ( " " ) ) ;
// Extract highlight ranges from markup tags
// Make a copy so we can insert null terminators.
TCHAR * MarkupSourceCopy = new TCHAR [ MarkupSource . Len ( ) + 1 ] ;
FCString : : Strcpy ( MarkupSourceCopy , MarkupSource . Len ( ) + 1 , * MarkupSource ) ;
TCHAR * Ptr = MarkupSourceCopy ;
while ( Ptr & & * Ptr ! = ' \0 ' )
{
TCHAR * NextTag = FCString : : Strstr ( Ptr , MARKTAG ) ;
if ( ! NextTag )
{
// No more tags, so we're done!
HLSLCode + = Ptr ;
break ;
}
// Copy the text up to the tag.
* NextTag = ' \0 ' ;
HLSLCode + = Ptr ;
// Advance past the markup tag to see what type it is (beginning or end)
NextTag + = MARKTAGLEN ;
int32 TagNumber = FCString : : Atoi ( NextTag + 1 ) ;
Ptr = FCString : : Strstr ( NextTag , TEXT ( " */ " ) ) + 2 ;
}
delete [ ] MarkupSourceCopy ;
}
}
2014-07-03 09:13:33 -04:00
void FMaterialEditor : : UpdatePreviewMaterial ( bool bForce )
2014-03-14 14:13:41 -04:00
{
2014-07-03 09:13:33 -04:00
if ( ! bLivePreview & & ! bForce )
{
//Don't update the preview material
return ;
}
2014-03-14 14:13:41 -04:00
bStatsFromPreviewMaterial = true ;
2014-04-23 18:21:07 -04:00
if ( PreviewExpression & & ExpressionPreviewMaterial )
{
PreviewExpression - > ConnectToPreviewMaterial ( ExpressionPreviewMaterial , 0 ) ;
}
2014-03-14 14:13:41 -04:00
2014-04-02 18:09:23 -04:00
if ( PreviewExpression )
2014-03-14 14:13:41 -04:00
{
// The preview material's expressions array must stay up to date before recompiling
// So that RebuildMaterialFunctionInfo will see all the nested material functions that may need to be updated
ExpressionPreviewMaterial - > Expressions = Material - > Expressions ;
2015-01-28 17:30:08 -05:00
FMaterialUpdateContext UpdateContext ( FMaterialUpdateContext : : EOptions : : SyncWithRenderingThread ) ;
2015-01-15 11:51:31 -05:00
UpdateContext . AddMaterial ( ExpressionPreviewMaterial ) ;
2014-03-14 14:13:41 -04:00
// If we are previewing an expression, update the expression preview material
ExpressionPreviewMaterial - > PreEditChange ( NULL ) ;
ExpressionPreviewMaterial - > PostEditChange ( ) ;
}
else
{
2015-01-28 17:30:08 -05:00
FMaterialUpdateContext UpdateContext ( FMaterialUpdateContext : : EOptions : : SyncWithRenderingThread ) ;
2015-01-15 11:51:31 -05:00
UpdateContext . AddMaterial ( Material ) ;
2014-03-14 14:13:41 -04:00
// Update the regular preview material when not previewing an expression.
Material - > PreEditChange ( NULL ) ;
Material - > PostEditChange ( ) ;
2014-04-23 20:20:58 -04:00
UpdateStatsMaterials ( ) ;
2014-03-14 14:13:41 -04:00
// Null out the expression preview material so they can be GC'ed
ExpressionPreviewMaterial = NULL ;
}
2014-04-02 18:09:23 -04:00
2014-03-14 14:13:41 -04:00
// Reregister all components that use the preview material, since UMaterial::PEC does not reregister components using a bIsPreviewMaterial=true material
RefreshPreviewViewport ( ) ;
}
void FMaterialEditor : : RebuildMaterialInstanceEditors ( UMaterialInstance * MatInst )
{
FAssetEditorManager & AssetEditorManager = FAssetEditorManager : : Get ( ) ;
TArray < UObject * > EditedAssets = AssetEditorManager . GetAllEditedAssets ( ) ;
for ( int32 AssetIdx = 0 ; AssetIdx < EditedAssets . Num ( ) ; AssetIdx + + )
{
UObject * EditedAsset = EditedAssets [ AssetIdx ] ;
UMaterialInstance * SourceInstance = Cast < UMaterialInstance > ( EditedAsset ) ;
if ( ! SourceInstance )
{
// Check to see if the EditedAssets are from material instance editor
UMaterialEditorInstanceConstant * EditorInstance = Cast < UMaterialEditorInstanceConstant > ( EditedAsset ) ;
if ( EditorInstance & & EditorInstance - > SourceInstance )
{
SourceInstance = Cast < UMaterialInstance > ( EditorInstance - > SourceInstance ) ;
}
}
// Ensure the material instance is valid and not a UMaterialInstanceDynamic, as that doesn't use FMaterialInstanceEditor as its editor
if ( SourceInstance ! = NULL & & ! SourceInstance - > IsA ( UMaterialInstanceDynamic : : StaticClass ( ) ) )
{
UMaterial * MICOriginalMaterial = SourceInstance - > GetMaterial ( ) ;
if ( MICOriginalMaterial = = OriginalMaterial )
{
IAssetEditorInstance * EditorInstance = AssetEditorManager . FindEditorForAsset ( EditedAsset , false ) ;
if ( EditorInstance ! = NULL )
{
FMaterialInstanceEditor * OtherEditor = static_cast < FMaterialInstanceEditor * > ( EditorInstance ) ;
OtherEditor - > RebuildMaterialInstanceEditor ( ) ;
}
}
}
}
}
void FMaterialEditor : : UpdateOriginalMaterial ( )
{
// If the Material has compilation errors, warn the user
for ( int32 i = ERHIFeatureLevel : : SM5 ; i > = 0 ; - - i )
{
ERHIFeatureLevel : : Type FeatureLevel = ( ERHIFeatureLevel : : Type ) i ;
if ( Material - > GetMaterialResource ( FeatureLevel ) - > GetCompileErrors ( ) . Num ( ) > 0 )
{
FString FeatureLevelName ;
GetFeatureLevelName ( FeatureLevel , FeatureLevelName ) ;
FSuppressableWarningDialog : : FSetupInfo Info (
FText : : Format ( NSLOCTEXT ( " UnrealEd " , " Warning_CompileErrorsInMaterial " , " The current material has compilation errors, so it will not render correctly in feature level {0}. \n Are you sure you wish to continue? " ) , FText : : FromString ( * FeatureLevelName ) ) ,
NSLOCTEXT ( " UnrealEd " , " Warning_CompileErrorsInMaterial_Title " , " Warning: Compilation errors in this Material " ) , " Warning_CompileErrorsInMaterial " ) ;
Info . ConfirmText = NSLOCTEXT ( " ModalDialogs " , " CompileErrorsInMaterialConfirm " , " Continue " ) ;
Info . CancelText = NSLOCTEXT ( " ModalDialogs " , " CompileErrorsInMaterialCancel " , " Abort " ) ;
FSuppressableWarningDialog CompileErrorsWarning ( Info ) ;
if ( CompileErrorsWarning . ShowModal ( ) = = FSuppressableWarningDialog : : Cancel )
{
return ;
}
}
}
// Make sure any graph position changes that might not have been copied are taken into account
2014-04-23 18:21:07 -04:00
Material - > MaterialGraph - > LinkMaterialExpressionsFromGraph ( ) ;
2014-03-14 14:13:41 -04:00
//remove any memory copies of shader files, so they will be reloaded from disk
//this way the material editor can be used for quick shader iteration
FlushShaderFileCache ( ) ;
//recompile and refresh the preview material so it will be updated if there was a shader change
2014-07-03 09:13:33 -04:00
//Force it even if bLivePreview is false.
UpdatePreviewMaterial ( true ) ;
2014-07-08 10:58:56 -04:00
RegenerateCodeView ( true ) ;
2014-03-14 14:13:41 -04:00
const FScopedBusyCursor BusyCursor ;
const FText LocalizedMaterialEditorApply = NSLOCTEXT ( " UnrealEd " , " ToolTip_MaterialEditorApply " , " Apply changes to original material and its use in the world. " ) ;
GWarn - > BeginSlowTask ( LocalizedMaterialEditorApply , true ) ;
GWarn - > StatusUpdate ( 1 , 1 , LocalizedMaterialEditorApply ) ;
// Handle propagation of the material function being edited
if ( MaterialFunction )
{
// Copy the expressions back from the preview material
MaterialFunction - > FunctionExpressions = Material - > Expressions ;
MaterialFunction - > FunctionEditorComments = Material - > EditorComments ;
// Preserve the thumbnail info
UThumbnailInfo * OriginalThumbnailInfo = MaterialFunction - > ParentFunction - > ThumbnailInfo ;
UThumbnailInfo * ThumbnailInfo = MaterialFunction - > ThumbnailInfo ;
MaterialFunction - > ParentFunction - > ThumbnailInfo = NULL ;
MaterialFunction - > ThumbnailInfo = NULL ;
// overwrite the original material function in place by constructing a new one with the same name
MaterialFunction - > ParentFunction = ( UMaterialFunction * ) StaticDuplicateObject (
MaterialFunction ,
MaterialFunction - > ParentFunction - > GetOuter ( ) ,
* MaterialFunction - > ParentFunction - > GetName ( ) ,
RF_AllFlags ,
MaterialFunction - > ParentFunction - > GetClass ( ) ) ;
// Restore the thumbnail info
MaterialFunction - > ParentFunction - > ThumbnailInfo = OriginalThumbnailInfo ;
MaterialFunction - > ThumbnailInfo = ThumbnailInfo ;
// Restore RF_Standalone on the original material function, as it had been removed from the preview material so that it could be GC'd.
MaterialFunction - > ParentFunction - > SetFlags ( RF_Standalone ) ;
for ( int32 ExpressionIndex = 0 ; ExpressionIndex < MaterialFunction - > ParentFunction - > FunctionExpressions . Num ( ) ; ExpressionIndex + + )
{
UMaterialExpression * CurrentExpression = MaterialFunction - > ParentFunction - > FunctionExpressions [ ExpressionIndex ] ;
// Link the expressions back to their function
CurrentExpression - > Material = NULL ;
CurrentExpression - > Function = MaterialFunction - > ParentFunction ;
}
for ( int32 ExpressionIndex = 0 ; ExpressionIndex < MaterialFunction - > ParentFunction - > FunctionEditorComments . Num ( ) ; ExpressionIndex + + )
{
UMaterialExpressionComment * CurrentExpression = MaterialFunction - > ParentFunction - > FunctionEditorComments [ ExpressionIndex ] ;
// Link the expressions back to their function
CurrentExpression - > Material = NULL ;
CurrentExpression - > Function = MaterialFunction - > ParentFunction ;
}
// mark the parent function as changed
MaterialFunction - > ParentFunction - > PreEditChange ( NULL ) ;
MaterialFunction - > ParentFunction - > PostEditChange ( ) ;
MaterialFunction - > ParentFunction - > MarkPackageDirty ( ) ;
// clear the dirty flag
bMaterialDirty = false ;
bStatsFromPreviewMaterial = false ;
// Create a material update context so we can safely update materials using this function.
{
FMaterialUpdateContext UpdateContext ;
// Go through all materials in memory and recompile them if they use this material function
for ( TObjectIterator < UMaterial > It ; It ; + + It )
{
UMaterial * CurrentMaterial = * It ;
if ( CurrentMaterial ! = Material )
{
bool bRecompile = false ;
// Preview materials often use expressions for rendering that are not in their Expressions array,
// And therefore their MaterialFunctionInfos are not up to date.
// However we don't want to trigger this if the Material is a preview material itself. This can now be the case with thumbnail preview materials for material functions.
if ( CurrentMaterial - > bIsPreviewMaterial & & ! Material - > bIsPreviewMaterial )
{
bRecompile = true ;
}
else
{
for ( int32 FunctionIndex = 0 ; FunctionIndex < CurrentMaterial - > MaterialFunctionInfos . Num ( ) ; FunctionIndex + + )
{
if ( CurrentMaterial - > MaterialFunctionInfos [ FunctionIndex ] . Function = = MaterialFunction - > ParentFunction )
{
bRecompile = true ;
break ;
}
}
}
if ( bRecompile )
{
UpdateContext . AddMaterial ( CurrentMaterial ) ;
// Propagate the function change to this material
CurrentMaterial - > PreEditChange ( NULL ) ;
CurrentMaterial - > PostEditChange ( ) ;
CurrentMaterial - > MarkPackageDirty ( ) ;
if ( CurrentMaterial - > MaterialGraph )
{
CurrentMaterial - > MaterialGraph - > RebuildGraph ( ) ;
}
}
}
}
}
// update the world's viewports
FEditorDelegates : : RefreshEditor . Broadcast ( ) ;
FEditorSupportDelegates : : RedrawAllViewports . Broadcast ( ) ;
}
// Handle propagation of the material being edited
else
{
2014-08-22 06:53:27 -04:00
FNavigationLockContext NavUpdateLock ( ENavigationLockReason : : MaterialUpdate ) ;
2014-03-14 14:13:41 -04:00
// Create a material update context so we can safely update materials.
{
FMaterialUpdateContext UpdateContext ;
UpdateContext . AddMaterial ( OriginalMaterial ) ;
// ensure the original copy of the material is removed from the editor's selection set
// or it will end up containing a stale, invalid entry
if ( OriginalMaterial - > IsSelected ( ) )
{
GEditor - > GetSelectedObjects ( ) - > Deselect ( OriginalMaterial ) ;
}
// Preserve the thumbnail info
UThumbnailInfo * OriginalThumbnailInfo = OriginalMaterial - > ThumbnailInfo ;
UThumbnailInfo * ThumbnailInfo = Material - > ThumbnailInfo ;
OriginalMaterial - > ThumbnailInfo = NULL ;
Material - > ThumbnailInfo = NULL ;
// A bit hacky, but disable material compilation in post load when we duplicate the material.
UMaterial : : ForceNoCompilationInPostLoad ( true ) ;
// overwrite the original material in place by constructing a new one with the same name
OriginalMaterial = ( UMaterial * ) StaticDuplicateObject ( Material , OriginalMaterial - > GetOuter ( ) , * OriginalMaterial - > GetName ( ) ,
RF_AllFlags ,
OriginalMaterial - > GetClass ( ) ) ;
// Post load has been called, allow materials to be compiled in PostLoad.
UMaterial : : ForceNoCompilationInPostLoad ( false ) ;
// Restore the thumbnail info
OriginalMaterial - > ThumbnailInfo = OriginalThumbnailInfo ;
Material - > ThumbnailInfo = ThumbnailInfo ;
// Change the original material object to the new original material
OriginalMaterialObject = OriginalMaterial ;
// Restore RF_Standalone on the original material, as it had been removed from the preview material so that it could be GC'd.
OriginalMaterial - > SetFlags ( RF_Standalone ) ;
// Manually copy bUsedAsSpecialEngineMaterial as it is duplicate transient to prevent accidental creation of new special engine materials
OriginalMaterial - > bUsedAsSpecialEngineMaterial = Material - > bUsedAsSpecialEngineMaterial ;
// If we are showing stats for mobile materials, compile the full material for ES2 here. That way we can see if permutations
// not used for preview materials fail to compile.
if ( bShowMobileStats )
{
OriginalMaterial - > SetFeatureLevelToCompile ( ERHIFeatureLevel : : ES2 , true ) ;
}
// let the material update itself if necessary
OriginalMaterial - > PreEditChange ( NULL ) ;
OriginalMaterial - > PostEditChange ( ) ;
OriginalMaterial - > MarkPackageDirty ( ) ;
// clear the dirty flag
bMaterialDirty = false ;
bStatsFromPreviewMaterial = false ;
// update the world's viewports
FEditorDelegates : : RefreshEditor . Broadcast ( ) ;
FEditorSupportDelegates : : RedrawAllViewports . Broadcast ( ) ;
// Force particle components to update their view relevance.
for ( TObjectIterator < UParticleSystemComponent > It ; It ; + + It )
{
It - > bIsViewRelevanceDirty = true ;
}
// Leaving this scope will update all dependent material instances.
}
RebuildMaterialInstanceEditors ( NULL ) ;
}
GWarn - > EndSlowTask ( ) ;
}
void FMaterialEditor : : UpdateMaterialInfoList ( bool bForceDisplay )
{
TArray < TSharedRef < class FTokenizedMessage > > Messages ;
TArray < TSharedPtr < FMaterialInfo > > TempMaterialInfoList ;
ERHIFeatureLevel : : Type FeatureLevelsToDisplay [ 2 ] ;
int32 NumFeatureLevels = 0 ;
// Always show basic features so that errors aren't hidden
2014-10-01 09:08:51 -04:00
FeatureLevelsToDisplay [ NumFeatureLevels + + ] = GMaxRHIFeatureLevel ;
2014-03-14 14:13:41 -04:00
if ( bShowMobileStats )
{
FeatureLevelsToDisplay [ NumFeatureLevels + + ] = ERHIFeatureLevel : : ES2 ;
}
if ( NumFeatureLevels > 0 )
{
UMaterial * MaterialForStats = bStatsFromPreviewMaterial ? Material : OriginalMaterial ;
for ( int32 i = 0 ; i < NumFeatureLevels ; + + i )
{
TArray < FString > CompileErrors ;
ERHIFeatureLevel : : Type FeatureLevel = FeatureLevelsToDisplay [ i ] ;
const FMaterialResource * MaterialResource = MaterialForStats - > GetMaterialResource ( FeatureLevel ) ;
if ( MaterialFunction & & ExpressionPreviewMaterial )
{
// Add a compile error message for functions missing an output
CompileErrors = ExpressionPreviewMaterial - > GetMaterialResource ( FeatureLevel ) - > GetCompileErrors ( ) ;
bool bFoundFunctionOutput = false ;
for ( int32 ExpressionIndex = 0 ; ExpressionIndex < Material - > Expressions . Num ( ) ; ExpressionIndex + + )
{
if ( Material - > Expressions [ ExpressionIndex ] - > IsA ( UMaterialExpressionFunctionOutput : : StaticClass ( ) ) )
{
bFoundFunctionOutput = true ;
break ;
}
}
if ( ! bFoundFunctionOutput )
{
CompileErrors . Add ( TEXT ( " Missing a function output " ) ) ;
}
}
else
{
CompileErrors = MaterialResource - > GetCompileErrors ( ) ;
}
// Only show general info if stats enabled
if ( ! MaterialFunction & & bShowStats )
{
// Display any errors and messages in the upper left corner of the viewport.
TArray < FString > Descriptions ;
TArray < int32 > InstructionCounts ;
2014-04-23 20:20:58 -04:00
TArray < FString > EmptyDescriptions ;
TArray < int32 > EmptyInstructionCounts ;
2014-03-14 14:13:41 -04:00
MaterialResource - > GetRepresentativeInstructionCounts ( Descriptions , InstructionCounts ) ;
2014-08-26 14:02:18 -04:00
//Built in stats is no longer exposed to the UI but may still be useful so they're still in the code.
2014-04-23 20:20:58 -04:00
bool bBuiltinStats = false ;
const FMaterialResource * EmptyMaterialResource = EmptyMaterial ? EmptyMaterial - > GetMaterialResource ( FeatureLevel ) : NULL ;
if ( bShowBuiltinStats & & bStatsFromPreviewMaterial & & EmptyMaterialResource & & InstructionCounts . Num ( ) > 0 )
{
EmptyMaterialResource - > GetRepresentativeInstructionCounts ( EmptyDescriptions , EmptyInstructionCounts ) ;
if ( EmptyInstructionCounts . Num ( ) > 0 )
{
//The instruction counts should match. If not, the preview material has been changed without the EmptyMaterial being updated to match.
if ( ensure ( InstructionCounts . Num ( ) = = EmptyInstructionCounts . Num ( ) ) )
{
bBuiltinStats = true ;
}
}
}
2014-04-02 18:09:23 -04:00
2014-03-14 14:13:41 -04:00
for ( int32 InstructionIndex = 0 ; InstructionIndex < Descriptions . Num ( ) ; InstructionIndex + + )
{
2014-04-23 20:20:58 -04:00
FString InstructionCountString = FString : : Printf ( TEXT ( " %s: %u instructions " ) , * Descriptions [ InstructionIndex ] , InstructionCounts [ InstructionIndex ] ) ;
if ( bBuiltinStats )
2014-04-02 18:09:23 -04:00
{
2014-04-23 20:20:58 -04:00
InstructionCountString + = FString : : Printf ( TEXT ( " - Built-in instructions: %u " ) , EmptyInstructionCounts [ InstructionIndex ] ) ;
2014-04-02 18:09:23 -04:00
}
2014-03-14 14:13:41 -04:00
TempMaterialInfoList . Add ( MakeShareable ( new FMaterialInfo ( InstructionCountString , FLinearColor : : Yellow ) ) ) ;
2014-04-23 20:20:58 -04:00
TSharedRef < FTokenizedMessage > Line = FTokenizedMessage : : Create ( EMessageSeverity : : Info ) ;
Line - > AddToken ( FTextToken : : Create ( FText : : FromString ( InstructionCountString ) ) ) ;
2014-03-14 14:13:41 -04:00
Messages . Add ( Line ) ;
}
// Display the number of samplers used by the material.
const int32 SamplersUsed = MaterialResource - > GetSamplerUsage ( ) ;
if ( SamplersUsed > = 0 )
{
int32 MaxSamplers = GetFeatureLevelMaxTextureSamplers ( MaterialResource - > GetFeatureLevel ( ) ) ;
2015-04-16 13:02:21 -04:00
FString SamplersString = FString : : Printf ( TEXT ( " %s samplers: %u/%u " ) , FeatureLevel < = ERHIFeatureLevel : : ES3_1 ? TEXT ( " Mobile texture " ) : TEXT ( " Texture " ) , SamplersUsed , MaxSamplers ) ;
2014-03-14 14:13:41 -04:00
TempMaterialInfoList . Add ( MakeShareable ( new FMaterialInfo ( SamplersString , FLinearColor : : Yellow ) ) ) ;
TSharedRef < FTokenizedMessage > Line = FTokenizedMessage : : Create ( EMessageSeverity : : Info ) ;
Line - > AddToken ( FTextToken : : Create ( FText : : FromString ( SamplersString ) ) ) ;
Messages . Add ( Line ) ;
}
}
FString FeatureLevelName ;
GetFeatureLevelName ( FeatureLevel , FeatureLevelName ) ;
for ( int32 ErrorIndex = 0 ; ErrorIndex < CompileErrors . Num ( ) ; ErrorIndex + + )
{
FString ErrorString = FString : : Printf ( TEXT ( " [%s] %s " ) , * FeatureLevelName , * CompileErrors [ ErrorIndex ] ) ;
TempMaterialInfoList . Add ( MakeShareable ( new FMaterialInfo ( ErrorString , FLinearColor : : Red ) ) ) ;
TSharedRef < FTokenizedMessage > Line = FTokenizedMessage : : Create ( EMessageSeverity : : Error ) ;
Line - > AddToken ( FTextToken : : Create ( FText : : FromString ( ErrorString ) ) ) ;
Messages . Add ( Line ) ;
bForceDisplay = true ;
}
}
}
bool bNeedsRefresh = false ;
if ( TempMaterialInfoList . Num ( ) ! = MaterialInfoList . Num ( ) )
{
bNeedsRefresh = true ;
}
for ( int32 Index = 0 ; ! bNeedsRefresh & & Index < TempMaterialInfoList . Num ( ) ; + + Index )
{
if ( TempMaterialInfoList [ Index ] - > Color ! = MaterialInfoList [ Index ] - > Color )
{
bNeedsRefresh = true ;
break ;
}
if ( TempMaterialInfoList [ Index ] - > Text ! = MaterialInfoList [ Index ] - > Text )
{
bNeedsRefresh = true ;
break ;
}
}
if ( bNeedsRefresh )
{
MaterialInfoList = TempMaterialInfoList ;
/*TSharedPtr<SWidget> TitleBar = GraphEditor->GetTitleBar();
if ( TitleBar . IsValid ( ) )
{
StaticCastSharedPtr < SMaterialEditorTitleBar > ( TitleBar ) - > RequestRefresh ( ) ;
} */
StatsListing - > ClearMessages ( ) ;
StatsListing - > AddMessages ( Messages ) ;
if ( bForceDisplay )
{
TabManager - > InvokeTab ( StatsTabId ) ;
}
}
}
void FMaterialEditor : : UpdateGraphNodeStates ( )
{
2014-10-01 09:08:51 -04:00
const FMaterialResource * ErrorMaterialResource = PreviewExpression ? ExpressionPreviewMaterial - > GetMaterialResource ( GMaxRHIFeatureLevel ) : Material - > GetMaterialResource ( GMaxRHIFeatureLevel ) ;
2014-03-14 14:13:41 -04:00
const FMaterialResource * ErrorMaterialResourceES2 = NULL ;
if ( bShowMobileStats )
{
ErrorMaterialResourceES2 = PreviewExpression ? ExpressionPreviewMaterial - > GetMaterialResource ( ERHIFeatureLevel : : ES2 ) : Material - > GetMaterialResource ( ERHIFeatureLevel : : ES2 ) ;
}
bool bUpdatedErrorState = false ;
// Have to loop through everything here as there's no way to be notified when the material resource updates
for ( int32 Index = 0 ; Index < Material - > MaterialGraph - > Nodes . Num ( ) ; + + Index )
{
UMaterialGraphNode * MaterialNode = Cast < UMaterialGraphNode > ( Material - > MaterialGraph - > Nodes [ Index ] ) ;
if ( MaterialNode )
{
MaterialNode - > bIsPreviewExpression = ( PreviewExpression = = MaterialNode - > MaterialExpression ) ;
MaterialNode - > bIsErrorExpression = ( ErrorMaterialResource - > GetErrorExpressions ( ) . Find ( MaterialNode - > MaterialExpression ) ! = INDEX_NONE )
| | ( ErrorMaterialResourceES2 & & ErrorMaterialResourceES2 - > GetErrorExpressions ( ) . Find ( MaterialNode - > MaterialExpression ) ! = INDEX_NONE ) ;
if ( MaterialNode - > bIsErrorExpression & & ! MaterialNode - > bHasCompilerMessage )
{
bUpdatedErrorState = true ;
MaterialNode - > bHasCompilerMessage = true ;
MaterialNode - > ErrorMsg = MaterialNode - > MaterialExpression - > LastErrorText ;
MaterialNode - > ErrorType = EMessageSeverity : : Error ;
}
else if ( ! MaterialNode - > bIsErrorExpression & & MaterialNode - > bHasCompilerMessage )
{
bUpdatedErrorState = true ;
MaterialNode - > bHasCompilerMessage = false ;
}
}
}
if ( bUpdatedErrorState )
{
// Rebuild the SGraphNodes to display/hide error block
GraphEditor - > NotifyGraphChanged ( ) ;
}
}
void FMaterialEditor : : AddReferencedObjects ( FReferenceCollector & Collector )
{
Collector . AddReferencedObject ( EditorOptions ) ;
Collector . AddReferencedObject ( Material ) ;
Collector . AddReferencedObject ( OriginalMaterial ) ;
Collector . AddReferencedObject ( MaterialFunction ) ;
Collector . AddReferencedObject ( ExpressionPreviewMaterial ) ;
2014-04-23 20:20:58 -04:00
Collector . AddReferencedObject ( EmptyMaterial ) ;
2014-03-14 14:13:41 -04:00
}
void FMaterialEditor : : BindCommands ( )
{
const FMaterialEditorCommands & Commands = FMaterialEditorCommands : : Get ( ) ;
ToolkitCommands - > MapAction (
Commands . Apply ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnApply ) ,
FCanExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnApplyEnabled ) ) ;
ToolkitCommands - > MapAction (
FEditorViewportCommands : : Get ( ) . ToggleRealTime ,
2015-03-09 10:00:46 -04:00
FExecuteAction : : CreateSP ( Viewport . ToSharedRef ( ) , & SMaterialEditorViewport : : OnToggleRealtime ) ,
2014-03-14 14:13:41 -04:00
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( Viewport . ToSharedRef ( ) , & SMaterialEditorViewport : : IsRealtime ) ) ;
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
FGenericCommands : : Get ( ) . Undo ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : UndoGraphAction ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
FGenericCommands : : Get ( ) . Redo ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : RedoGraphAction ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . CameraHome ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnCameraHome ) ,
FCanExecuteAction ( ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . CleanUnusedExpressions ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : CleanUnusedExpressions ) ,
FCanExecuteAction ( ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . ShowHideConnectors ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnShowConnectors ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FMaterialEditor : : IsOnShowConnectorsChecked ) ) ;
2014-03-14 14:13:41 -04:00
2014-07-03 09:13:33 -04:00
ToolkitCommands - > MapAction (
Commands . ToggleLivePreview ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : ToggleLivePreview ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FMaterialEditor : : IsToggleLivePreviewChecked ) ) ;
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . ToggleRealtimeExpressions ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : ToggleRealTimeExpressions ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FMaterialEditor : : IsToggleRealTimeExpressionsChecked ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . AlwaysRefreshAllPreviews ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnAlwaysRefreshAllPreviews ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FMaterialEditor : : IsOnAlwaysRefreshAllPreviews ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . ToggleMaterialStats ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : ToggleStats ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FMaterialEditor : : IsToggleStatsChecked ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . ToggleMobileStats ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : ToggleMobileStats ) ,
FCanExecuteAction ( ) ,
FIsActionChecked : : CreateSP ( this , & FMaterialEditor : : IsToggleMobileStatsChecked ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . UseCurrentTexture ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnUseCurrentTexture ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . ConvertObjects ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnConvertObjects ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . ConvertToTextureObjects ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnConvertTextures ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . ConvertToTextureSamples ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnConvertTextures ) ) ;
2014-03-14 14:13:41 -04:00
2014-10-23 21:38:06 -04:00
ToolkitCommands - > MapAction (
Commands . ConvertToConstant ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnConvertObjects ) ) ;
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . StopPreviewNode ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnPreviewNode ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . StartPreviewNode ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnPreviewNode ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . EnableRealtimePreviewNode ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnToggleRealtimePreview ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . DisableRealtimePreviewNode ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnToggleRealtimePreview ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . SelectDownstreamNodes ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnSelectDownsteamNodes ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . SelectUpstreamNodes ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnSelectUpsteamNodes ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . RemoveFromFavorites ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : RemoveSelectedExpressionFromFavorites ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . AddToFavorites ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : AddSelectedExpressionToFavorites ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
ToolkitCommands - > MapAction (
Commands . ForceRefreshPreviews ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnForceRefreshPreviews ) ) ;
ToolkitCommands - > MapAction (
Commands . FindInMaterial ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnFindInMaterial ) ) ;
}
2014-03-14 14:13:41 -04:00
void FMaterialEditor : : OnApply ( )
{
UE_LOG ( LogMaterialEditor , Log , TEXT ( " Applying material %s " ) , * GetEditingObjects ( ) [ 0 ] - > GetName ( ) ) ;
UpdateOriginalMaterial ( ) ;
}
bool FMaterialEditor : : OnApplyEnabled ( ) const
{
return bMaterialDirty = = true ;
}
void FMaterialEditor : : OnCameraHome ( )
{
RecenterEditor ( ) ;
}
void FMaterialEditor : : OnShowConnectors ( )
{
bHideUnusedConnectors = ! bHideUnusedConnectors ;
GraphEditor - > SetPinVisibility ( bHideUnusedConnectors ? SGraphEditor : : Pin_HideNoConnection : SGraphEditor : : Pin_Show ) ;
}
bool FMaterialEditor : : IsOnShowConnectorsChecked ( ) const
{
return bHideUnusedConnectors = = false ;
}
2014-07-03 09:13:33 -04:00
void FMaterialEditor : : ToggleLivePreview ( )
{
bLivePreview = ! bLivePreview ;
if ( bLivePreview )
{
UpdatePreviewMaterial ( ) ;
2014-07-08 10:58:56 -04:00
RegenerateCodeView ( ) ;
2014-07-03 09:13:33 -04:00
}
}
bool FMaterialEditor : : IsToggleLivePreviewChecked ( ) const
{
return bLivePreview ;
}
2014-03-14 14:13:41 -04:00
void FMaterialEditor : : ToggleRealTimeExpressions ( )
{
bIsRealtime = ! bIsRealtime ;
}
bool FMaterialEditor : : IsToggleRealTimeExpressionsChecked ( ) const
{
return bIsRealtime = = true ;
}
void FMaterialEditor : : OnAlwaysRefreshAllPreviews ( )
{
bAlwaysRefreshAllPreviews = ! bAlwaysRefreshAllPreviews ;
if ( bAlwaysRefreshAllPreviews )
{
RefreshExpressionPreviews ( ) ;
}
}
bool FMaterialEditor : : IsOnAlwaysRefreshAllPreviews ( ) const
{
return bAlwaysRefreshAllPreviews = = true ;
}
void FMaterialEditor : : ToggleStats ( )
{
// Toggle the showing of material stats each time the user presses the show stats button
bShowStats = ! bShowStats ;
UpdateMaterialInfoList ( bShowStats ) ;
}
bool FMaterialEditor : : IsToggleStatsChecked ( ) const
{
return bShowStats = = true ;
}
void FMaterialEditor : : ToggleMobileStats ( )
{
// Toggle the showing of material stats each time the user presses the show stats button
bShowMobileStats = ! bShowMobileStats ;
UPreviewMaterial * PreviewMaterial = Cast < UPreviewMaterial > ( Material ) ;
if ( PreviewMaterial )
{
{
// Sync with the rendering thread but don't reregister components. We will manually do so.
FMaterialUpdateContext UpdateContext ( FMaterialUpdateContext : : EOptions : : SyncWithRenderingThread ) ;
UpdateContext . AddMaterial ( PreviewMaterial ) ;
PreviewMaterial - > SetFeatureLevelToCompile ( ERHIFeatureLevel : : ES2 , bShowMobileStats ) ;
PreviewMaterial - > ForceRecompileForRendering ( ) ;
if ( ! bStatsFromPreviewMaterial )
{
OriginalMaterial - > SetFeatureLevelToCompile ( ERHIFeatureLevel : : ES2 , bShowMobileStats ) ;
OriginalMaterial - > ForceRecompileForRendering ( ) ;
}
}
2014-04-23 20:20:58 -04:00
UpdateStatsMaterials ( ) ;
2014-03-14 14:13:41 -04:00
RefreshPreviewViewport ( ) ;
}
UpdateMaterialInfoList ( bShowMobileStats ) ;
}
bool FMaterialEditor : : IsToggleMobileStatsChecked ( ) const
{
return bShowMobileStats = = true ;
}
void FMaterialEditor : : OnUseCurrentTexture ( )
{
// Set the currently selected texture in the generic browser
// as the texture to use in all selected texture sample expressions.
FEditorDelegates : : LoadSelectedAssetsIfNeeded . Broadcast ( ) ;
UTexture * SelectedTexture = GEditor - > GetSelectedObjects ( ) - > GetTop < UTexture > ( ) ;
if ( SelectedTexture )
{
const FScopedTransaction Transaction ( NSLOCTEXT ( " UnrealEd " , " UseCurrentTexture " , " Use Current Texture " ) ) ;
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( * NodeIt ) ;
if ( GraphNode & & GraphNode - > MaterialExpression - > IsA ( UMaterialExpressionTextureBase : : StaticClass ( ) ) )
{
UMaterialExpressionTextureBase * TextureBase = static_cast < UMaterialExpressionTextureBase * > ( GraphNode - > MaterialExpression ) ;
TextureBase - > Modify ( ) ;
TextureBase - > Texture = SelectedTexture ;
TextureBase - > AutoSetSampleType ( ) ;
}
}
// Update the current preview material.
UpdatePreviewMaterial ( ) ;
Material - > MarkPackageDirty ( ) ;
RegenerateCodeView ( ) ;
RefreshExpressionPreviews ( ) ;
SetMaterialDirty ( ) ;
}
}
void FMaterialEditor : : OnConvertObjects ( )
{
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
if ( SelectedNodes . Num ( ) > 0 )
{
2014-10-23 21:38:06 -04:00
const FScopedTransaction Transaction ( LOCTEXT ( " MaterialEditorConvert " , " Material Editor: Convert " ) ) ;
2014-03-14 14:13:41 -04:00
Material - > Modify ( ) ;
Material - > MaterialGraph - > Modify ( ) ;
TArray < class UEdGraphNode * > NodesToDelete ;
TArray < class UEdGraphNode * > NodesToSelect ;
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( * NodeIt ) ;
if ( GraphNode )
{
// Look for the supported classes to convert from
UMaterialExpression * CurrentSelectedExpression = GraphNode - > MaterialExpression ;
UMaterialExpressionConstant * Constant1Expression = Cast < UMaterialExpressionConstant > ( CurrentSelectedExpression ) ;
UMaterialExpressionConstant2Vector * Constant2Expression = Cast < UMaterialExpressionConstant2Vector > ( CurrentSelectedExpression ) ;
UMaterialExpressionConstant3Vector * Constant3Expression = Cast < UMaterialExpressionConstant3Vector > ( CurrentSelectedExpression ) ;
UMaterialExpressionConstant4Vector * Constant4Expression = Cast < UMaterialExpressionConstant4Vector > ( CurrentSelectedExpression ) ;
UMaterialExpressionTextureSample * TextureSampleExpression = Cast < UMaterialExpressionTextureSample > ( CurrentSelectedExpression ) ;
UMaterialExpressionComponentMask * ComponentMaskExpression = Cast < UMaterialExpressionComponentMask > ( CurrentSelectedExpression ) ;
UMaterialExpressionParticleSubUV * ParticleSubUVExpression = Cast < UMaterialExpressionParticleSubUV > ( CurrentSelectedExpression ) ;
2014-10-23 21:38:06 -04:00
UMaterialExpressionScalarParameter * ScalarParameterExpression = Cast < UMaterialExpressionScalarParameter > ( CurrentSelectedExpression ) ;
UMaterialExpressionVectorParameter * VectorParameterExpression = Cast < UMaterialExpressionVectorParameter > ( CurrentSelectedExpression ) ;
2014-03-14 14:13:41 -04:00
// Setup the class to convert to
UClass * ClassToCreate = NULL ;
if ( Constant1Expression )
{
ClassToCreate = UMaterialExpressionScalarParameter : : StaticClass ( ) ;
}
else if ( Constant2Expression | | Constant3Expression | | Constant4Expression )
{
ClassToCreate = UMaterialExpressionVectorParameter : : StaticClass ( ) ;
}
else if ( ParticleSubUVExpression ) // Has to come before the TextureSample comparison...
{
ClassToCreate = UMaterialExpressionTextureSampleParameterSubUV : : StaticClass ( ) ;
}
else if ( TextureSampleExpression & & TextureSampleExpression - > Texture & & TextureSampleExpression - > Texture - > IsA ( UTextureCube : : StaticClass ( ) ) )
{
ClassToCreate = UMaterialExpressionTextureSampleParameterCube : : StaticClass ( ) ;
}
else if ( TextureSampleExpression )
{
ClassToCreate = UMaterialExpressionTextureSampleParameter2D : : StaticClass ( ) ;
}
else if ( ComponentMaskExpression )
{
ClassToCreate = UMaterialExpressionStaticComponentMaskParameter : : StaticClass ( ) ;
}
2014-10-23 21:38:06 -04:00
else if ( ScalarParameterExpression )
{
ClassToCreate = UMaterialExpressionConstant : : StaticClass ( ) ;
}
else if ( VectorParameterExpression )
{
2014-10-27 20:13:48 -04:00
// Technically should be a constant 4 but UMaterialExpressionVectorParameter has an rgb pin, so using Constant3 to avoid a compile error
ClassToCreate = UMaterialExpressionConstant3Vector : : StaticClass ( ) ;
2014-10-23 21:38:06 -04:00
}
2014-03-14 14:13:41 -04:00
if ( ClassToCreate )
{
UMaterialExpression * NewExpression = CreateNewMaterialExpression ( ClassToCreate , FVector2D ( GraphNode - > NodePosX , GraphNode - > NodePosY ) , false , true ) ;
if ( NewExpression )
{
UMaterialGraphNode * NewGraphNode = CastChecked < UMaterialGraphNode > ( NewExpression - > GraphNode ) ;
NewGraphNode - > ReplaceNode ( GraphNode ) ;
bool bNeedsRefresh = false ;
// Copy over expression-specific values
if ( Constant1Expression )
{
bNeedsRefresh = true ;
CastChecked < UMaterialExpressionScalarParameter > ( NewExpression ) - > DefaultValue = Constant1Expression - > R ;
}
else if ( Constant2Expression )
{
bNeedsRefresh = true ;
CastChecked < UMaterialExpressionVectorParameter > ( NewExpression ) - > DefaultValue = FLinearColor ( Constant2Expression - > R , Constant2Expression - > G , 0 ) ;
}
else if ( Constant3Expression )
{
bNeedsRefresh = true ;
CastChecked < UMaterialExpressionVectorParameter > ( NewExpression ) - > DefaultValue = Constant3Expression - > Constant ;
CastChecked < UMaterialExpressionVectorParameter > ( NewExpression ) - > DefaultValue . A = 1.0f ;
}
else if ( Constant4Expression )
{
bNeedsRefresh = true ;
CastChecked < UMaterialExpressionVectorParameter > ( NewExpression ) - > DefaultValue = Constant4Expression - > Constant ;
}
else if ( TextureSampleExpression )
{
bNeedsRefresh = true ;
UMaterialExpressionTextureSampleParameter * NewTextureExpr = CastChecked < UMaterialExpressionTextureSampleParameter > ( NewExpression ) ;
NewTextureExpr - > Texture = TextureSampleExpression - > Texture ;
NewTextureExpr - > Coordinates = TextureSampleExpression - > Coordinates ;
NewTextureExpr - > AutoSetSampleType ( ) ;
NewTextureExpr - > IsDefaultMeshpaintTexture = TextureSampleExpression - > IsDefaultMeshpaintTexture ;
NewTextureExpr - > TextureObject = TextureSampleExpression - > TextureObject ;
NewTextureExpr - > MipValue = TextureSampleExpression - > MipValue ;
NewTextureExpr - > MipValueMode = TextureSampleExpression - > MipValueMode ;
}
else if ( ComponentMaskExpression )
{
bNeedsRefresh = true ;
UMaterialExpressionStaticComponentMaskParameter * ComponentMask = CastChecked < UMaterialExpressionStaticComponentMaskParameter > ( NewExpression ) ;
ComponentMask - > DefaultR = ComponentMaskExpression - > R ;
ComponentMask - > DefaultG = ComponentMaskExpression - > G ;
ComponentMask - > DefaultB = ComponentMaskExpression - > B ;
ComponentMask - > DefaultA = ComponentMaskExpression - > A ;
}
else if ( ParticleSubUVExpression )
{
bNeedsRefresh = true ;
CastChecked < UMaterialExpressionTextureSampleParameterSubUV > ( NewExpression ) - > Texture = ParticleSubUVExpression - > Texture ;
}
2014-10-23 21:38:06 -04:00
else if ( ScalarParameterExpression )
{
bNeedsRefresh = true ;
CastChecked < UMaterialExpressionConstant > ( NewExpression ) - > R = ScalarParameterExpression - > DefaultValue ;
}
else if ( VectorParameterExpression )
{
bNeedsRefresh = true ;
2014-10-28 12:23:01 -04:00
CastChecked < UMaterialExpressionConstant3Vector > ( NewExpression ) - > Constant = VectorParameterExpression - > DefaultValue ;
2014-10-23 21:38:06 -04:00
}
2014-03-14 14:13:41 -04:00
if ( bNeedsRefresh )
{
// Refresh the expression preview if we changed its properties after it was created
NewExpression - > bNeedToUpdatePreview = true ;
RefreshExpressionPreview ( NewExpression , true ) ;
}
NodesToDelete . AddUnique ( GraphNode ) ;
NodesToSelect . Add ( NewGraphNode ) ;
}
}
}
}
// Delete the replaced nodes
DeleteNodes ( NodesToDelete ) ;
// Select each of the newly converted expressions
for ( TArray < UEdGraphNode * > : : TConstIterator NodeIter ( NodesToSelect ) ; NodeIter ; + + NodeIter )
{
GraphEditor - > SetNodeSelection ( * NodeIter , true ) ;
}
}
}
void FMaterialEditor : : OnConvertTextures ( )
{
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
if ( SelectedNodes . Num ( ) > 0 )
{
const FScopedTransaction Transaction ( LOCTEXT ( " MaterialEditorConvertTexture " , " Material Editor: Convert to Texture " ) ) ;
Material - > Modify ( ) ;
Material - > MaterialGraph - > Modify ( ) ;
TArray < class UEdGraphNode * > NodesToDelete ;
TArray < class UEdGraphNode * > NodesToSelect ;
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( * NodeIt ) ;
if ( GraphNode )
{
// Look for the supported classes to convert from
UMaterialExpression * CurrentSelectedExpression = GraphNode - > MaterialExpression ;
UMaterialExpressionTextureSample * TextureSampleExpression = Cast < UMaterialExpressionTextureSample > ( CurrentSelectedExpression ) ;
UMaterialExpressionTextureObject * TextureObjectExpression = Cast < UMaterialExpressionTextureObject > ( CurrentSelectedExpression ) ;
// Setup the class to convert to
UClass * ClassToCreate = NULL ;
if ( TextureSampleExpression )
{
ClassToCreate = UMaterialExpressionTextureObject : : StaticClass ( ) ;
}
else if ( TextureObjectExpression )
{
ClassToCreate = UMaterialExpressionTextureSample : : StaticClass ( ) ;
}
if ( ClassToCreate )
{
UMaterialExpression * NewExpression = CreateNewMaterialExpression ( ClassToCreate , FVector2D ( GraphNode - > NodePosX , GraphNode - > NodePosY ) , false , true ) ;
if ( NewExpression )
{
UMaterialGraphNode * NewGraphNode = CastChecked < UMaterialGraphNode > ( NewExpression - > GraphNode ) ;
NewGraphNode - > ReplaceNode ( GraphNode ) ;
bool bNeedsRefresh = false ;
// Copy over expression-specific values
if ( TextureSampleExpression )
{
bNeedsRefresh = true ;
UMaterialExpressionTextureObject * NewTextureExpr = CastChecked < UMaterialExpressionTextureObject > ( NewExpression ) ;
NewTextureExpr - > Texture = TextureSampleExpression - > Texture ;
NewTextureExpr - > AutoSetSampleType ( ) ;
NewTextureExpr - > IsDefaultMeshpaintTexture = TextureSampleExpression - > IsDefaultMeshpaintTexture ;
}
else if ( TextureObjectExpression )
{
bNeedsRefresh = true ;
UMaterialExpressionTextureSample * NewTextureExpr = CastChecked < UMaterialExpressionTextureSample > ( NewExpression ) ;
NewTextureExpr - > Texture = TextureObjectExpression - > Texture ;
NewTextureExpr - > AutoSetSampleType ( ) ;
NewTextureExpr - > IsDefaultMeshpaintTexture = TextureObjectExpression - > IsDefaultMeshpaintTexture ;
NewTextureExpr - > MipValueMode = TMVM_None ;
}
if ( bNeedsRefresh )
{
// Refresh the expression preview if we changed its properties after it was created
NewExpression - > bNeedToUpdatePreview = true ;
RefreshExpressionPreview ( NewExpression , true ) ;
}
NodesToDelete . AddUnique ( GraphNode ) ;
NodesToSelect . Add ( NewGraphNode ) ;
}
}
}
}
// Delete the replaced nodes
DeleteNodes ( NodesToDelete ) ;
// Select each of the newly converted expressions
for ( TArray < UEdGraphNode * > : : TConstIterator NodeIter ( NodesToSelect ) ; NodeIter ; + + NodeIter )
{
GraphEditor - > SetNodeSelection ( * NodeIter , true ) ;
}
}
}
void FMaterialEditor : : OnPreviewNode ( )
{
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
if ( SelectedNodes . Num ( ) = = 1 )
{
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( * NodeIt ) ;
if ( GraphNode )
{
SetPreviewExpression ( GraphNode - > MaterialExpression ) ;
}
}
}
}
void FMaterialEditor : : OnToggleRealtimePreview ( )
{
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
if ( SelectedNodes . Num ( ) = = 1 )
{
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( * NodeIt ) ;
if ( GraphNode )
{
UMaterialExpression * SelectedExpression = GraphNode - > MaterialExpression ;
SelectedExpression - > bRealtimePreview = ! SelectedExpression - > bRealtimePreview ;
if ( SelectedExpression - > bRealtimePreview )
{
SelectedExpression - > bCollapsed = false ;
}
RefreshExpressionPreviews ( ) ;
SetMaterialDirty ( ) ;
}
}
}
}
void FMaterialEditor : : OnSelectDownsteamNodes ( )
{
TArray < UMaterialGraphNode * > NodesToCheck ;
TArray < UMaterialGraphNode * > CheckedNodes ;
TArray < UMaterialGraphNode * > NodesToSelect ;
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( * NodeIt ) ;
if ( GraphNode )
{
NodesToCheck . Add ( GraphNode ) ;
}
}
while ( NodesToCheck . Num ( ) > 0 )
{
UMaterialGraphNode * CurrentNode = NodesToCheck . Last ( ) ;
TArray < UEdGraphPin * > OutputPins ;
CurrentNode - > GetOutputPins ( OutputPins ) ;
for ( int32 Index = 0 ; Index < OutputPins . Num ( ) ; + + Index )
{
for ( int32 LinkIndex = 0 ; LinkIndex < OutputPins [ Index ] - > LinkedTo . Num ( ) ; + + LinkIndex )
{
UMaterialGraphNode * LinkedNode = Cast < UMaterialGraphNode > ( OutputPins [ Index ] - > LinkedTo [ LinkIndex ] - > GetOwningNode ( ) ) ;
if ( LinkedNode )
{
int32 FoundIndex = - 1 ;
CheckedNodes . Find ( LinkedNode , FoundIndex ) ;
if ( FoundIndex < 0 )
{
NodesToSelect . Add ( LinkedNode ) ;
NodesToCheck . Add ( LinkedNode ) ;
}
}
}
}
// This graph node has now been examined
CheckedNodes . Add ( CurrentNode ) ;
NodesToCheck . Remove ( CurrentNode ) ;
}
for ( int32 Index = 0 ; Index < NodesToSelect . Num ( ) ; + + Index )
{
GraphEditor - > SetNodeSelection ( NodesToSelect [ Index ] , true ) ;
}
}
void FMaterialEditor : : OnSelectUpsteamNodes ( )
{
TArray < UMaterialGraphNode * > NodesToCheck ;
TArray < UMaterialGraphNode * > CheckedNodes ;
TArray < UMaterialGraphNode * > NodesToSelect ;
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( * NodeIt ) ;
if ( GraphNode )
{
NodesToCheck . Add ( GraphNode ) ;
}
}
while ( NodesToCheck . Num ( ) > 0 )
{
UMaterialGraphNode * CurrentNode = NodesToCheck . Last ( ) ;
TArray < UEdGraphPin * > InputPins ;
CurrentNode - > GetInputPins ( InputPins ) ;
for ( int32 Index = 0 ; Index < InputPins . Num ( ) ; + + Index )
{
for ( int32 LinkIndex = 0 ; LinkIndex < InputPins [ Index ] - > LinkedTo . Num ( ) ; + + LinkIndex )
{
UMaterialGraphNode * LinkedNode = Cast < UMaterialGraphNode > ( InputPins [ Index ] - > LinkedTo [ LinkIndex ] - > GetOwningNode ( ) ) ;
if ( LinkedNode )
{
int32 FoundIndex = - 1 ;
CheckedNodes . Find ( LinkedNode , FoundIndex ) ;
if ( FoundIndex < 0 )
{
NodesToSelect . Add ( LinkedNode ) ;
NodesToCheck . Add ( LinkedNode ) ;
}
}
}
}
// This graph node has now been examined
CheckedNodes . Add ( CurrentNode ) ;
NodesToCheck . Remove ( CurrentNode ) ;
}
for ( int32 Index = 0 ; Index < NodesToSelect . Num ( ) ; + + Index )
{
GraphEditor - > SetNodeSelection ( NodesToSelect [ Index ] , true ) ;
}
}
void FMaterialEditor : : OnForceRefreshPreviews ( )
{
ForceRefreshExpressionPreviews ( ) ;
RefreshPreviewViewport ( ) ;
}
void FMaterialEditor : : OnCreateComment ( )
{
CreateNewMaterialExpressionComment ( GraphEditor - > GetPasteLocation ( ) ) ;
}
2014-05-08 05:29:54 -04:00
void FMaterialEditor : : OnCreateComponentMaskNode ( )
{
CreateNewMaterialExpression ( UMaterialExpressionComponentMask : : StaticClass ( ) , GraphEditor - > GetPasteLocation ( ) , true , false ) ;
}
2014-04-23 18:21:07 -04:00
void FMaterialEditor : : OnFindInMaterial ( )
{
TabManager - > InvokeTab ( FindTabId ) ;
FindResults - > FocusForUse ( ) ;
}
2014-09-05 08:25:23 -04:00
FString FMaterialEditor : : GetDocLinkForSelectedNode ( )
{
FString DocumentationLink ;
TArray < UObject * > SelectedNodes = GraphEditor - > GetSelectedNodes ( ) . Array ( ) ;
if ( SelectedNodes . Num ( ) = = 1 )
{
UMaterialGraphNode * SelectedGraphNode = Cast < UMaterialGraphNode > ( SelectedNodes [ 0 ] ) ;
if ( SelectedGraphNode ! = NULL )
{
FString DocLink = SelectedGraphNode - > GetDocumentationLink ( ) ;
FString DocExcerpt = SelectedGraphNode - > GetDocumentationExcerptName ( ) ;
DocumentationLink = FEditorClassUtils : : GetDocumentationLinkFromExcerpt ( DocLink , DocExcerpt ) ;
}
}
return DocumentationLink ;
}
void FMaterialEditor : : OnGoToDocumentation ( )
{
FString DocumentationLink = GetDocLinkForSelectedNode ( ) ;
if ( ! DocumentationLink . IsEmpty ( ) )
{
2015-01-14 13:15:22 -05:00
IDocumentation : : Get ( ) - > Open ( DocumentationLink , FDocumentationSourceInfo ( TEXT ( " rightclick_matnode " ) ) ) ;
2014-09-05 08:25:23 -04:00
}
}
bool FMaterialEditor : : CanGoToDocumentation ( )
{
FString DocumentationLink = GetDocLinkForSelectedNode ( ) ;
return ! DocumentationLink . IsEmpty ( ) ;
}
2014-03-14 14:13:41 -04:00
void FMaterialEditor : : RenameAssetFromRegistry ( const FAssetData & InAddedAssetData , const FString & InNewName )
{
// Grab the asset class, it will be checked for being a material function.
UClass * Asset = FindObject < UClass > ( ANY_PACKAGE , * InAddedAssetData . AssetClass . ToString ( ) ) ;
if ( Asset - > IsChildOf ( UMaterialFunction : : StaticClass ( ) ) )
{
2014-04-23 18:21:07 -04:00
ForceRefreshExpressionPreviews ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-23 18:21:07 -04:00
}
2014-03-14 14:13:41 -04:00
2015-03-08 15:25:46 -04:00
void FMaterialEditor : : OnAssetPostImport ( UFactory * InFactory , UObject * InObject )
{
UTexture * Texture = Cast < UTexture > ( InObject ) ;
if ( InFactory - > IsA ( UTextureFactory : : StaticClass ( ) ) & & Texture ! = nullptr )
{
// When a texture which is referenced in the material is imported, update the preview material
for ( UMaterialExpression * Expression : Material - > Expressions )
{
if ( UMaterialExpressionTextureBase * ExpressionTexture = Cast < UMaterialExpressionTextureBase > ( Expression ) )
{
if ( ExpressionTexture - > Texture = = Texture )
{
2015-04-06 05:12:48 -04:00
UpdateOriginalMaterial ( ) ;
2015-03-08 15:25:46 -04:00
break ;
}
}
else if ( UMaterialExpressionMaterialFunctionCall * ExpressionFunctionCall = Cast < UMaterialExpressionMaterialFunctionCall > ( Expression ) )
{
struct Local
{
2015-04-09 15:23:52 -04:00
static bool ReferencesImportedObject ( UMaterialFunction * Function , UTexture * InTexture )
2015-03-08 15:25:46 -04:00
{
2015-04-09 15:23:52 -04:00
for ( UMaterialExpression * MaterialExpression : Function - > FunctionExpressions )
2015-03-08 15:25:46 -04:00
{
2015-04-09 15:23:52 -04:00
if ( UMaterialExpressionTextureBase * MaterialExpressionTexture = Cast < UMaterialExpressionTextureBase > ( MaterialExpression ) )
2015-03-08 15:25:46 -04:00
{
2015-04-09 15:23:52 -04:00
if ( MaterialExpressionTexture - > Texture = = InTexture )
2015-03-08 15:25:46 -04:00
{
return true ;
}
}
2015-04-09 15:23:52 -04:00
else if ( UMaterialExpressionMaterialFunctionCall * MaterialExpressionFunctionCall = Cast < UMaterialExpressionMaterialFunctionCall > ( MaterialExpression ) )
2015-03-08 15:25:46 -04:00
{
2015-04-09 15:23:52 -04:00
if ( MaterialExpressionFunctionCall - > MaterialFunction ! = nullptr & &
ReferencesImportedObject ( MaterialExpressionFunctionCall - > MaterialFunction , InTexture ) )
2015-03-08 15:25:46 -04:00
{
return true ;
}
}
}
return false ;
}
} ;
if ( ExpressionFunctionCall - > MaterialFunction ! = nullptr & &
Local : : ReferencesImportedObject ( ExpressionFunctionCall - > MaterialFunction , Texture ) )
{
2015-04-06 05:12:48 -04:00
UpdateOriginalMaterial ( ) ;
2015-03-08 15:25:46 -04:00
break ;
}
}
}
}
}
2014-03-14 14:13:41 -04:00
void FMaterialEditor : : OnMaterialUsageFlagsChanged ( UMaterial * MaterialThatChanged , int32 FlagThatChanged )
{
EMaterialUsage Flag = static_cast < EMaterialUsage > ( FlagThatChanged ) ;
if ( MaterialThatChanged = = OriginalMaterial )
{
bool bNeedsRecompile = false ;
Material - > SetMaterialUsage ( bNeedsRecompile , Flag , MaterialThatChanged - > GetUsageByFlag ( Flag ) ) ;
2014-04-23 20:20:58 -04:00
UpdateStatsMaterials ( ) ;
2014-03-14 14:13:41 -04:00
}
}
2014-10-23 21:38:06 -04:00
void FMaterialEditor : : SetVectorParameterDefaultOnDependentMaterials ( FName ParameterName , const FLinearColor & Value , bool bOverride )
{
TArray < UMaterial * > MaterialsToOverride ;
if ( MaterialFunction )
{
// Find all materials that reference this function
for ( TObjectIterator < UMaterial > It ; It ; + + It )
{
UMaterial * CurrentMaterial = * It ;
if ( CurrentMaterial ! = Material )
{
bool bUpdate = false ;
for ( int32 FunctionIndex = 0 ; FunctionIndex < CurrentMaterial - > MaterialFunctionInfos . Num ( ) ; FunctionIndex + + )
{
if ( CurrentMaterial - > MaterialFunctionInfos [ FunctionIndex ] . Function = = MaterialFunction - > ParentFunction )
{
bUpdate = true ;
break ;
}
}
if ( bUpdate )
{
MaterialsToOverride . Add ( CurrentMaterial ) ;
}
}
}
}
else
{
MaterialsToOverride . Add ( OriginalMaterial ) ;
}
const ERHIFeatureLevel : : Type FeatureLevel = GEditor - > GetEditorWorldContext ( ) . World ( ) - > FeatureLevel ;
for ( int32 MaterialIndex = 0 ; MaterialIndex < MaterialsToOverride . Num ( ) ; MaterialIndex + + )
{
UMaterial * CurrentMaterial = MaterialsToOverride [ MaterialIndex ] ;
CurrentMaterial - > OverrideVectorParameterDefault ( ParameterName , Value , bOverride , FeatureLevel ) ;
}
// Update MI's that reference any of the materials affected
for ( TObjectIterator < UMaterialInstance > It ; It ; + + It )
{
UMaterialInstance * CurrentMaterialInstance = * It ;
// Only care about MI's with static parameters, because we are overriding parameter defaults,
// And only MI's with static parameters contain uniform expressions, which contain parameter defaults
if ( CurrentMaterialInstance - > bHasStaticPermutationResource )
{
UMaterial * BaseMaterial = CurrentMaterialInstance - > GetMaterial ( ) ;
if ( MaterialsToOverride . Contains ( BaseMaterial ) )
{
CurrentMaterialInstance - > OverrideVectorParameterDefault ( ParameterName , Value , bOverride , FeatureLevel ) ;
}
}
}
}
void FMaterialEditor : : OnVectorParameterDefaultChanged ( class UMaterialExpression * Expression , FName ParameterName , const FLinearColor & Value )
{
check ( Expression ) ;
if ( Expression - > Material = = Material & & OriginalMaterial )
{
SetVectorParameterDefaultOnDependentMaterials ( ParameterName , Value , true ) ;
OverriddenVectorParametersToRevert . AddUnique ( ParameterName ) ;
}
}
void FMaterialEditor : : SetScalarParameterDefaultOnDependentMaterials ( FName ParameterName , float Value , bool bOverride )
{
TArray < UMaterial * > MaterialsToOverride ;
if ( MaterialFunction )
{
// Find all materials that reference this function
for ( TObjectIterator < UMaterial > It ; It ; + + It )
{
UMaterial * CurrentMaterial = * It ;
if ( CurrentMaterial ! = Material )
{
bool bUpdate = false ;
for ( int32 FunctionIndex = 0 ; FunctionIndex < CurrentMaterial - > MaterialFunctionInfos . Num ( ) ; FunctionIndex + + )
{
if ( CurrentMaterial - > MaterialFunctionInfos [ FunctionIndex ] . Function = = MaterialFunction - > ParentFunction )
{
bUpdate = true ;
break ;
}
}
if ( bUpdate )
{
MaterialsToOverride . Add ( CurrentMaterial ) ;
}
}
}
}
else
{
MaterialsToOverride . Add ( OriginalMaterial ) ;
}
const ERHIFeatureLevel : : Type FeatureLevel = GEditor - > GetEditorWorldContext ( ) . World ( ) - > FeatureLevel ;
for ( int32 MaterialIndex = 0 ; MaterialIndex < MaterialsToOverride . Num ( ) ; MaterialIndex + + )
{
UMaterial * CurrentMaterial = MaterialsToOverride [ MaterialIndex ] ;
CurrentMaterial - > OverrideScalarParameterDefault ( ParameterName , Value , bOverride , FeatureLevel ) ;
}
// Update MI's that reference any of the materials affected
for ( TObjectIterator < UMaterialInstance > It ; It ; + + It )
{
UMaterialInstance * CurrentMaterialInstance = * It ;
// Only care about MI's with static parameters, because we are overriding parameter defaults,
// And only MI's with static parameters contain uniform expressions, which contain parameter defaults
if ( CurrentMaterialInstance - > bHasStaticPermutationResource )
{
UMaterial * BaseMaterial = CurrentMaterialInstance - > GetMaterial ( ) ;
if ( MaterialsToOverride . Contains ( BaseMaterial ) )
{
CurrentMaterialInstance - > OverrideScalarParameterDefault ( ParameterName , Value , bOverride , FeatureLevel ) ;
}
}
}
}
void FMaterialEditor : : OnScalarParameterDefaultChanged ( class UMaterialExpression * Expression , FName ParameterName , float Value )
{
check ( Expression ) ;
if ( Expression - > Material = = Material & & OriginalMaterial )
{
SetScalarParameterDefaultOnDependentMaterials ( ParameterName , Value , true ) ;
OverriddenScalarParametersToRevert . AddUnique ( ParameterName ) ;
}
}
2014-03-14 14:13:41 -04:00
TSharedRef < SDockTab > FMaterialEditor : : SpawnTab_Preview ( const FSpawnTabArgs & Args )
{
TSharedRef < SDockTab > SpawnedTab =
SNew ( SDockTab )
. Label ( LOCTEXT ( " ViewportTabTitle " , " Viewport " ) )
[
Viewport . ToSharedRef ( )
] ;
Viewport - > OnAddedToTab ( SpawnedTab ) ;
return SpawnedTab ;
}
TSharedRef < SDockTab > FMaterialEditor : : SpawnTab_GraphCanvas ( const FSpawnTabArgs & Args )
{
TSharedRef < SDockTab > SpawnedTab = SNew ( SDockTab )
. Label ( LOCTEXT ( " GraphCanvasTitle " , " Graph " ) ) ;
2014-04-02 18:09:23 -04:00
if ( GraphEditor . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
SpawnedTab - > SetContent ( GraphEditor . ToSharedRef ( ) ) ;
}
return SpawnedTab ;
}
TSharedRef < SDockTab > FMaterialEditor : : SpawnTab_MaterialProperties ( const FSpawnTabArgs & Args )
{
TSharedRef < SDockTab > SpawnedTab = SNew ( SDockTab )
. Icon ( FEditorStyle : : GetBrush ( " LevelEditor.Tabs.Details " ) )
. Label ( LOCTEXT ( " MaterialDetailsTitle " , " Details " ) )
[
MaterialDetailsView . ToSharedRef ( )
] ;
2014-04-02 18:09:23 -04:00
if ( GraphEditor . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
// Since we're initialising, make sure nothing is selected
GraphEditor - > ClearSelectionSet ( ) ;
}
return SpawnedTab ;
}
TSharedRef < SDockTab > FMaterialEditor : : SpawnTab_HLSLCode ( const FSpawnTabArgs & Args )
{
TSharedRef < SDockTab > SpawnedTab = SNew ( SDockTab )
. Label ( LOCTEXT ( " HLSLCodeTitle " , " HLSL Code " ) )
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
CodeViewUtility . ToSharedRef ( )
]
+ SVerticalBox : : Slot ( )
. FillHeight ( 1 )
[
CodeView . ToSharedRef ( )
]
] ;
2014-10-23 21:38:06 -04:00
CodeTab = SpawnedTab ;
2014-03-14 14:13:41 -04:00
RegenerateCodeView ( ) ;
return SpawnedTab ;
}
TSharedRef < SDockTab > FMaterialEditor : : SpawnTab_Palette ( const FSpawnTabArgs & Args )
{
check ( Args . GetTabId ( ) = = PaletteTabId ) ;
TSharedRef < SDockTab > SpawnedTab = SNew ( SDockTab )
. Icon ( FEditorStyle : : GetBrush ( " Kismet.Tabs.Palette " ) )
. Label ( LOCTEXT ( " MaterialPaletteTitle " , " Palette " ) )
[
2014-08-05 09:04:35 -04:00
SNew ( SBox )
2014-09-05 07:39:52 -04:00
. AddMetaData < FTagMetaData > ( FTagMetaData ( TEXT ( " MaterialPalette " ) ) )
2014-03-14 14:13:41 -04:00
[
Palette . ToSharedRef ( )
]
] ;
return SpawnedTab ;
}
TSharedRef < SDockTab > FMaterialEditor : : SpawnTab_Stats ( const FSpawnTabArgs & Args )
{
check ( Args . GetTabId ( ) = = StatsTabId ) ;
TSharedRef < SDockTab > SpawnedTab = SNew ( SDockTab )
. Icon ( FEditorStyle : : GetBrush ( " Kismet.Tabs.CompilerResults " ) )
. Label ( LOCTEXT ( " MaterialStatsTitle " , " Stats " ) )
[
2014-08-05 09:04:35 -04:00
SNew ( SBox )
2014-09-05 07:39:52 -04:00
. AddMetaData < FTagMetaData > ( FTagMetaData ( TEXT ( " MaterialStats " ) ) )
2014-03-14 14:13:41 -04:00
[
Stats . ToSharedRef ( )
]
] ;
return SpawnedTab ;
}
2014-04-23 18:21:07 -04:00
TSharedRef < SDockTab > FMaterialEditor : : SpawnTab_Find ( const FSpawnTabArgs & Args )
2014-03-14 14:13:41 -04:00
{
2014-04-23 18:21:07 -04:00
check ( Args . GetTabId ( ) = = FindTabId ) ;
TSharedRef < SDockTab > SpawnedTab = SNew ( SDockTab )
. Icon ( FEditorStyle : : GetBrush ( " Kismet.Tabs.FindResults " ) )
. Label ( LOCTEXT ( " MaterialFindTitle " , " Find Results " ) )
[
2014-08-05 09:04:35 -04:00
SNew ( SBox )
2014-09-05 07:39:52 -04:00
. AddMetaData < FTagMetaData > ( FTagMetaData ( TEXT ( " MaterialFind " ) ) )
2014-04-23 18:21:07 -04:00
[
FindResults . ToSharedRef ( )
]
] ;
return SpawnedTab ;
2014-03-14 14:13:41 -04:00
}
void FMaterialEditor : : SetPreviewExpression ( UMaterialExpression * NewPreviewExpression )
{
UMaterialExpressionFunctionOutput * FunctionOutput = Cast < UMaterialExpressionFunctionOutput > ( NewPreviewExpression ) ;
2014-06-30 10:45:18 -04:00
if ( ! NewPreviewExpression | | PreviewExpression = = NewPreviewExpression )
2014-03-14 14:13:41 -04:00
{
if ( FunctionOutput )
{
FunctionOutput - > bLastPreviewed = false ;
}
// If we are already previewing the selected expression toggle previewing off
PreviewExpression = NULL ;
ExpressionPreviewMaterial - > Expressions . Empty ( ) ;
SetPreviewMaterial ( Material ) ;
// Recompile the preview material to get changes that might have been made during previewing
UpdatePreviewMaterial ( ) ;
}
else if ( NewPreviewExpression )
{
if ( ExpressionPreviewMaterial = = NULL )
{
// Create the expression preview material if it hasnt already been created
2015-02-09 05:43:45 -05:00
ExpressionPreviewMaterial = NewObject < UMaterial > ( GetTransientPackage ( ) , NAME_None , RF_Public ) ;
2014-03-14 14:13:41 -04:00
ExpressionPreviewMaterial - > bIsPreviewMaterial = true ;
}
if ( FunctionOutput )
{
FunctionOutput - > bLastPreviewed = true ;
}
else
{
//Hooking up the output of the break expression doesn't make much sense, preview the expression feeding it instead.
UMaterialExpressionBreakMaterialAttributes * BreakExpr = Cast < UMaterialExpressionBreakMaterialAttributes > ( NewPreviewExpression ) ;
if ( BreakExpr & & BreakExpr - > GetInput ( 0 ) & & BreakExpr - > GetInput ( 0 ) - > Expression )
{
NewPreviewExpression = BreakExpr - > GetInput ( 0 ) - > Expression ;
}
}
// The expression preview material's expressions array must stay up to date before recompiling
// So that RebuildMaterialFunctionInfo will see all the nested material functions that may need to be updated
ExpressionPreviewMaterial - > Expressions = Material - > Expressions ;
// The preview window should now show the expression preview material
SetPreviewMaterial ( ExpressionPreviewMaterial ) ;
// Set the preview expression
PreviewExpression = NewPreviewExpression ;
// Recompile the preview material
UpdatePreviewMaterial ( ) ;
}
}
2014-04-23 18:21:07 -04:00
void FMaterialEditor : : JumpToNode ( const UEdGraphNode * Node )
{
GraphEditor - > JumpToNode ( Node , false ) ;
}
2014-03-14 14:13:41 -04:00
UMaterialExpression * FMaterialEditor : : CreateNewMaterialExpression ( UClass * NewExpressionClass , const FVector2D & NodePos , bool bAutoSelect , bool bAutoAssignResource )
{
check ( NewExpressionClass - > IsChildOf ( UMaterialExpression : : StaticClass ( ) ) ) ;
if ( ! IsAllowedExpressionType ( NewExpressionClass , MaterialFunction ! = NULL ) )
{
// Disallowed types should not be visible to the ui to be placed, so we don't need a warning here
return NULL ;
}
// Clear the selection
if ( bAutoSelect )
{
GraphEditor - > ClearSelectionSet ( ) ;
}
// Create the new expression.
UMaterialExpression * NewExpression = NULL ;
{
const FScopedTransaction Transaction ( NSLOCTEXT ( " UnrealEd " , " MaterialEditorNewExpression " , " Material Editor: New Expression " ) ) ;
Material - > Modify ( ) ;
UObject * ExpressionOuter = Material ;
if ( MaterialFunction )
{
ExpressionOuter = MaterialFunction ;
}
2015-02-03 05:40:57 -05:00
NewExpression = NewObject < UMaterialExpression > ( ExpressionOuter , NewExpressionClass , NAME_None , RF_Transactional ) ;
2014-03-14 14:13:41 -04:00
Material - > Expressions . Add ( NewExpression ) ;
NewExpression - > Material = Material ;
// Set the expression location.
2014-06-05 12:14:10 -04:00
NewExpression - > MaterialExpressionEditorX = NodePos . X ;
NewExpression - > MaterialExpressionEditorY = NodePos . Y ;
2014-03-14 14:13:41 -04:00
2014-09-11 08:13:08 -04:00
// Create a GUID for the node
NewExpression - > UpdateMaterialExpressionGuid ( true , true ) ;
2014-03-14 14:13:41 -04:00
if ( bAutoAssignResource )
{
// If the user is adding a texture, automatically assign the currently selected texture to it.
UMaterialExpressionTextureBase * METextureBase = Cast < UMaterialExpressionTextureBase > ( NewExpression ) ;
if ( METextureBase )
{
FEditorDelegates : : LoadSelectedAssetsIfNeeded . Broadcast ( ) ;
2014-07-02 07:30:47 -04:00
if ( UTexture * SelectedTexture = GEditor - > GetSelectedObjects ( ) - > GetTop < UTexture > ( ) )
{
METextureBase - > Texture = SelectedTexture ;
}
2014-03-14 14:13:41 -04:00
METextureBase - > AutoSetSampleType ( ) ;
}
UMaterialExpressionMaterialFunctionCall * MEMaterialFunction = Cast < UMaterialExpressionMaterialFunctionCall > ( NewExpression ) ;
if ( MEMaterialFunction )
{
FEditorDelegates : : LoadSelectedAssetsIfNeeded . Broadcast ( ) ;
MEMaterialFunction - > SetMaterialFunction ( MaterialFunction , NULL , GEditor - > GetSelectedObjects ( ) - > GetTop < UMaterialFunction > ( ) ) ;
}
UMaterialExpressionCollectionParameter * MECollectionParameter = Cast < UMaterialExpressionCollectionParameter > ( NewExpression ) ;
if ( MECollectionParameter )
{
FEditorDelegates : : LoadSelectedAssetsIfNeeded . Broadcast ( ) ;
MECollectionParameter - > Collection = GEditor - > GetSelectedObjects ( ) - > GetTop < UMaterialParameterCollection > ( ) ;
}
}
UMaterialExpressionFunctionInput * FunctionInput = Cast < UMaterialExpressionFunctionInput > ( NewExpression ) ;
if ( FunctionInput )
{
FunctionInput - > ConditionallyGenerateId ( true ) ;
FunctionInput - > ValidateName ( ) ;
}
UMaterialExpressionFunctionOutput * FunctionOutput = Cast < UMaterialExpressionFunctionOutput > ( NewExpression ) ;
if ( FunctionOutput )
{
FunctionOutput - > ConditionallyGenerateId ( true ) ;
FunctionOutput - > ValidateName ( ) ;
}
NewExpression - > UpdateParameterGuid ( true , true ) ;
UMaterialExpressionTextureSampleParameter * TextureParameterExpression = Cast < UMaterialExpressionTextureSampleParameter > ( NewExpression ) ;
2014-07-02 07:30:47 -04:00
if ( ( TextureParameterExpression ! = nullptr ) & & TextureParameterExpression - > CanRenameNode ( ) )
2014-03-14 14:13:41 -04:00
{
// Change the parameter's name on creation to mirror the object's name; this avoids issues of having colliding parameter
// names and having the name left as "None"
TextureParameterExpression - > ParameterName = TextureParameterExpression - > GetFName ( ) ;
}
UMaterialExpressionComponentMask * ComponentMaskExpression = Cast < UMaterialExpressionComponentMask > ( NewExpression ) ;
// Setup defaults for the most likely use case
// Can't change default properties as that will affect existing content
if ( ComponentMaskExpression )
{
ComponentMaskExpression - > R = true ;
ComponentMaskExpression - > G = true ;
}
UMaterialExpressionStaticComponentMaskParameter * StaticComponentMaskExpression = Cast < UMaterialExpressionStaticComponentMaskParameter > ( NewExpression ) ;
// Setup defaults for the most likely use case
// Can't change default properties as that will affect existing content
if ( StaticComponentMaskExpression )
{
StaticComponentMaskExpression - > DefaultR = true ;
}
UMaterialExpressionRotateAboutAxis * RotateAboutAxisExpression = Cast < UMaterialExpressionRotateAboutAxis > ( NewExpression ) ;
if ( RotateAboutAxisExpression )
{
// Create a default expression for the Position input
2015-02-03 05:40:57 -05:00
UMaterialExpressionWorldPosition * WorldPositionExpression = NewObject < UMaterialExpressionWorldPosition > ( ExpressionOuter , NAME_None , RF_Transactional ) ;
2014-03-14 14:13:41 -04:00
Material - > Expressions . Add ( WorldPositionExpression ) ;
WorldPositionExpression - > Material = Material ;
RotateAboutAxisExpression - > Position . Expression = WorldPositionExpression ;
2014-06-05 12:14:10 -04:00
WorldPositionExpression - > MaterialExpressionEditorX = RotateAboutAxisExpression - > MaterialExpressionEditorX - 250 ;
2014-03-14 14:13:41 -04:00
WorldPositionExpression - > MaterialExpressionEditorY = RotateAboutAxisExpression - > MaterialExpressionEditorY + 73 ;
Material - > MaterialGraph - > AddExpression ( WorldPositionExpression ) ;
if ( bAutoSelect )
{
GraphEditor - > SetNodeSelection ( WorldPositionExpression - > GraphNode , true ) ;
}
}
// Setup defaults for the most likely use case
// Can't change default properties as that will affect existing content
UMaterialExpressionTransformPosition * PositionTransform = Cast < UMaterialExpressionTransformPosition > ( NewExpression ) ;
if ( PositionTransform )
{
PositionTransform - > TransformSourceType = TRANSFORMPOSSOURCE_Local ;
PositionTransform - > TransformType = TRANSFORMPOSSOURCE_World ;
}
2014-07-21 04:33:11 -04:00
// Make sure the dynamic parameters are named based on existing ones
UMaterialExpressionDynamicParameter * DynamicExpression = Cast < UMaterialExpressionDynamicParameter > ( NewExpression ) ;
if ( DynamicExpression )
{
DynamicExpression - > UpdateDynamicParameterNames ( ) ;
}
2014-10-23 21:38:06 -04:00
Material - > AddExpressionParameter ( NewExpression , Material - > EditorParameters ) ;
2014-03-14 14:13:41 -04:00
if ( NewExpression )
{
Material - > MaterialGraph - > AddExpression ( NewExpression ) ;
// Select the new node.
if ( bAutoSelect )
{
GraphEditor - > SetNodeSelection ( NewExpression - > GraphNode , true ) ;
}
}
}
RegenerateCodeView ( ) ;
// Update the current preview material.
UpdatePreviewMaterial ( ) ;
Material - > MarkPackageDirty ( ) ;
RefreshExpressionPreviews ( ) ;
GraphEditor - > NotifyGraphChanged ( ) ;
SetMaterialDirty ( ) ;
return NewExpression ;
}
UMaterialExpressionComment * FMaterialEditor : : CreateNewMaterialExpressionComment ( const FVector2D & NodePos )
{
UMaterialExpressionComment * NewComment = NULL ;
{
Material - > Modify ( ) ;
UObject * ExpressionOuter = Material ;
if ( MaterialFunction )
{
ExpressionOuter = MaterialFunction ;
}
2015-02-03 05:40:57 -05:00
NewComment = NewObject < UMaterialExpressionComment > ( ExpressionOuter , NAME_None , RF_Transactional ) ;
2014-03-14 14:13:41 -04:00
// Add to the list of comments associated with this material.
Material - > EditorComments . Add ( NewComment ) ;
FSlateRect Bounds ;
if ( GraphEditor - > GetBoundsForSelectedNodes ( Bounds , 50.0f ) )
{
NewComment - > MaterialExpressionEditorX = Bounds . Left ;
NewComment - > MaterialExpressionEditorY = Bounds . Top ;
FVector2D Size = Bounds . GetSize ( ) ;
NewComment - > SizeX = Size . X ;
NewComment - > SizeY = Size . Y ;
}
else
{
NewComment - > MaterialExpressionEditorX = NodePos . X ;
NewComment - > MaterialExpressionEditorY = NodePos . Y ;
NewComment - > SizeX = 400 ;
NewComment - > SizeY = 100 ;
}
NewComment - > Text = NSLOCTEXT ( " K2Node " , " CommentBlock_NewEmptyComment " , " Comment " ) . ToString ( ) ;
}
if ( NewComment )
{
Material - > MaterialGraph - > AddComment ( NewComment ) ;
// Select the new comment.
GraphEditor - > ClearSelectionSet ( ) ;
GraphEditor - > SetNodeSelection ( NewComment - > GraphNode , true ) ;
}
Material - > MarkPackageDirty ( ) ;
GraphEditor - > NotifyGraphChanged ( ) ;
SetMaterialDirty ( ) ;
return NewComment ;
}
void FMaterialEditor : : ForceRefreshExpressionPreviews ( )
{
// Initialize expression previews.
const bool bOldAlwaysRefreshAllPreviews = bAlwaysRefreshAllPreviews ;
bAlwaysRefreshAllPreviews = true ;
RefreshExpressionPreviews ( ) ;
bAlwaysRefreshAllPreviews = bOldAlwaysRefreshAllPreviews ;
}
void FMaterialEditor : : AddToSelection ( UMaterialExpression * Expression )
{
GraphEditor - > SetNodeSelection ( Expression - > GraphNode , true ) ;
}
void FMaterialEditor : : SelectAllNodes ( )
{
GraphEditor - > SelectAllNodes ( ) ;
}
bool FMaterialEditor : : CanSelectAllNodes ( ) const
{
return GraphEditor . IsValid ( ) ;
}
void FMaterialEditor : : DeleteSelectedNodes ( )
{
TArray < UEdGraphNode * > NodesToDelete ;
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
NodesToDelete . Add ( CastChecked < UEdGraphNode > ( * NodeIt ) ) ;
}
DeleteNodes ( NodesToDelete ) ;
}
void FMaterialEditor : : DeleteNodes ( const TArray < UEdGraphNode * > & NodesToDelete )
{
if ( NodesToDelete . Num ( ) > 0 )
{
if ( ! CheckExpressionRemovalWarnings ( NodesToDelete ) )
{
return ;
}
// If we are previewing an expression and the expression being previewed was deleted
bool bHaveExpressionsToDelete = false ;
bool bPreviewExpressionDeleted = false ;
{
const FScopedTransaction Transaction ( NSLOCTEXT ( " UnrealEd " , " MaterialEditorDelete " , " Material Editor: Delete " ) ) ;
Material - > Modify ( ) ;
for ( int32 Index = 0 ; Index < NodesToDelete . Num ( ) ; + + Index )
{
if ( NodesToDelete [ Index ] - > CanUserDeleteNode ( ) )
{
// Break all node links first so that we don't update the material before deleting
NodesToDelete [ Index ] - > BreakAllNodeLinks ( ) ;
FBlueprintEditorUtils : : RemoveNode ( NULL , NodesToDelete [ Index ] , true ) ;
if ( UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( NodesToDelete [ Index ] ) )
{
UMaterialExpression * MaterialExpression = GraphNode - > MaterialExpression ;
bHaveExpressionsToDelete = true ;
DestroyColorPicker ( ) ;
if ( PreviewExpression = = MaterialExpression )
{
// The expression being previewed is also being deleted
bPreviewExpressionDeleted = true ;
}
MaterialExpression - > Modify ( ) ;
Material - > Expressions . Remove ( MaterialExpression ) ;
Material - > RemoveExpressionParameter ( MaterialExpression ) ;
// Make sure the deleted expression is caught by gc
MaterialExpression - > MarkPendingKill ( ) ;
}
else if ( UMaterialGraphNode_Comment * CommentNode = Cast < UMaterialGraphNode_Comment > ( NodesToDelete [ Index ] ) )
{
CommentNode - > MaterialExpressionComment - > Modify ( ) ;
Material - > EditorComments . Remove ( CommentNode - > MaterialExpressionComment ) ;
}
}
}
Material - > MaterialGraph - > LinkMaterialExpressionsFromGraph ( ) ;
} // ScopedTransaction
// Deselect all expressions and comments.
GraphEditor - > ClearSelectionSet ( ) ;
GraphEditor - > NotifyGraphChanged ( ) ;
if ( bHaveExpressionsToDelete )
{
if ( bPreviewExpressionDeleted )
{
// The preview expression was deleted. Null out our reference to it and reset to the normal preview material
PreviewExpression = NULL ;
SetPreviewMaterial ( Material ) ;
}
RegenerateCodeView ( ) ;
}
UpdatePreviewMaterial ( ) ;
Material - > MarkPackageDirty ( ) ;
SetMaterialDirty ( ) ;
if ( bHaveExpressionsToDelete )
{
RefreshExpressionPreviews ( ) ;
}
}
}
bool FMaterialEditor : : CanDeleteNodes ( ) const
{
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
if ( SelectedNodes . Num ( ) = = 1 )
{
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
if ( Cast < UMaterialGraphNode_Root > ( * NodeIt ) )
{
// Return false if only root node is selected, as it can't be deleted
return false ;
}
}
}
return SelectedNodes . Num ( ) > 0 ;
}
void FMaterialEditor : : DeleteSelectedDuplicatableNodes ( )
{
// Cache off the old selection
const FGraphPanelSelectionSet OldSelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
// Clear the selection and only select the nodes that can be duplicated
FGraphPanelSelectionSet RemainingNodes ;
GraphEditor - > ClearSelectionSet ( ) ;
for ( FGraphPanelSelectionSet : : TConstIterator SelectedIter ( OldSelectedNodes ) ; SelectedIter ; + + SelectedIter )
{
UEdGraphNode * Node = Cast < UEdGraphNode > ( * SelectedIter ) ;
if ( ( Node ! = NULL ) & & Node - > CanDuplicateNode ( ) )
{
GraphEditor - > SetNodeSelection ( Node , true ) ;
}
else
{
RemainingNodes . Add ( Node ) ;
}
}
// Delete the duplicatable nodes
DeleteSelectedNodes ( ) ;
// Reselect whatever's left from the original selection after the deletion
GraphEditor - > ClearSelectionSet ( ) ;
for ( FGraphPanelSelectionSet : : TConstIterator SelectedIter ( RemainingNodes ) ; SelectedIter ; + + SelectedIter )
{
if ( UEdGraphNode * Node = Cast < UEdGraphNode > ( * SelectedIter ) )
{
GraphEditor - > SetNodeSelection ( Node , true ) ;
}
}
}
void FMaterialEditor : : CopySelectedNodes ( )
{
// Export the selected nodes and place the text on the clipboard
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
FString ExportedText ;
for ( FGraphPanelSelectionSet : : TConstIterator SelectedIter ( SelectedNodes ) ; SelectedIter ; + + SelectedIter )
{
if ( UEdGraphNode * Node = Cast < UEdGraphNode > ( * SelectedIter ) )
{
Node - > PrepareForCopying ( ) ;
}
}
FEdGraphUtilities : : ExportNodesToText ( SelectedNodes , /*out*/ ExportedText ) ;
FPlatformMisc : : ClipboardCopy ( * ExportedText ) ;
// Make sure Material remains the owner of the copied nodes
for ( FGraphPanelSelectionSet : : TConstIterator SelectedIter ( SelectedNodes ) ; SelectedIter ; + + SelectedIter )
{
if ( UMaterialGraphNode * Node = Cast < UMaterialGraphNode > ( * SelectedIter ) )
{
Node - > PostCopyNode ( ) ;
}
else if ( UMaterialGraphNode_Comment * Comment = Cast < UMaterialGraphNode_Comment > ( * SelectedIter ) )
{
Comment - > PostCopyNode ( ) ;
}
}
}
bool FMaterialEditor : : CanCopyNodes ( ) const
{
// If any of the nodes can be duplicated then we should allow copying
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
for ( FGraphPanelSelectionSet : : TConstIterator SelectedIter ( SelectedNodes ) ; SelectedIter ; + + SelectedIter )
{
UEdGraphNode * Node = Cast < UEdGraphNode > ( * SelectedIter ) ;
if ( ( Node ! = NULL ) & & Node - > CanDuplicateNode ( ) )
{
return true ;
}
}
return false ;
}
void FMaterialEditor : : PasteNodes ( )
{
PasteNodesHere ( GraphEditor - > GetPasteLocation ( ) ) ;
}
void FMaterialEditor : : PasteNodesHere ( const FVector2D & Location )
{
// Undo/Redo support
const FScopedTransaction Transaction ( NSLOCTEXT ( " UnrealEd " , " MaterialEditorPaste " , " Material Editor: Paste " ) ) ;
Material - > MaterialGraph - > Modify ( ) ;
Material - > Modify ( ) ;
// Clear the selection set (newly pasted stuff will be selected)
GraphEditor - > ClearSelectionSet ( ) ;
// Grab the text to paste from the clipboard.
FString TextToImport ;
FPlatformMisc : : ClipboardPaste ( TextToImport ) ;
// Import the nodes
TSet < UEdGraphNode * > PastedNodes ;
FEdGraphUtilities : : ImportNodesFromText ( Material - > MaterialGraph , TextToImport , /*out*/ PastedNodes ) ;
//Average position of nodes so we can move them while still maintaining relative distances to each other
FVector2D AvgNodePosition ( 0.0f , 0.0f ) ;
for ( TSet < UEdGraphNode * > : : TIterator It ( PastedNodes ) ; It ; + + It )
{
UEdGraphNode * Node = * It ;
AvgNodePosition . X + = Node - > NodePosX ;
AvgNodePosition . Y + = Node - > NodePosY ;
}
if ( PastedNodes . Num ( ) > 0 )
{
float InvNumNodes = 1.0f / float ( PastedNodes . Num ( ) ) ;
AvgNodePosition . X * = InvNumNodes ;
AvgNodePosition . Y * = InvNumNodes ;
}
for ( TSet < UEdGraphNode * > : : TIterator It ( PastedNodes ) ; It ; + + It )
{
UEdGraphNode * Node = * It ;
if ( UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( Node ) )
{
// These are not copied and we must account for expressions pasted between different materials anyway
GraphNode - > RealtimeDelegate = Material - > MaterialGraph - > RealtimeDelegate ;
GraphNode - > MaterialDirtyDelegate = Material - > MaterialGraph - > MaterialDirtyDelegate ;
GraphNode - > bPreviewNeedsUpdate = false ;
UMaterialExpression * NewExpression = GraphNode - > MaterialExpression ;
NewExpression - > Material = Material ;
NewExpression - > Function = NULL ;
Material - > Expressions . Add ( NewExpression ) ;
// There can be only one default mesh paint texture.
UMaterialExpressionTextureBase * TextureSample = Cast < UMaterialExpressionTextureBase > ( NewExpression ) ;
if ( TextureSample )
{
TextureSample - > IsDefaultMeshpaintTexture = false ;
}
NewExpression - > UpdateParameterGuid ( true , true ) ;
UMaterialExpressionFunctionInput * FunctionInput = Cast < UMaterialExpressionFunctionInput > ( NewExpression ) ;
if ( FunctionInput )
{
FunctionInput - > ConditionallyGenerateId ( true ) ;
FunctionInput - > ValidateName ( ) ;
}
UMaterialExpressionFunctionOutput * FunctionOutput = Cast < UMaterialExpressionFunctionOutput > ( NewExpression ) ;
if ( FunctionOutput )
{
FunctionOutput - > ConditionallyGenerateId ( true ) ;
FunctionOutput - > ValidateName ( ) ;
}
}
else if ( UMaterialGraphNode_Comment * CommentNode = Cast < UMaterialGraphNode_Comment > ( Node ) )
{
CommentNode - > MaterialDirtyDelegate = Material - > MaterialGraph - > MaterialDirtyDelegate ;
CommentNode - > MaterialExpressionComment - > Material = Material ;
Material - > EditorComments . Add ( CommentNode - > MaterialExpressionComment ) ;
}
// Select the newly pasted stuff
GraphEditor - > SetNodeSelection ( Node , true ) ;
Node - > NodePosX = ( Node - > NodePosX - AvgNodePosition . X ) + Location . X ;
Node - > NodePosY = ( Node - > NodePosY - AvgNodePosition . Y ) + Location . Y ;
Node - > SnapToGrid ( SNodePanel : : GetSnapGridSize ( ) ) ;
// Give new node a different Guid from the old one
Node - > CreateNewGuid ( ) ;
}
2015-01-15 11:51:31 -05:00
UpdateMaterialAfterGraphChange ( ) ;
2014-03-14 14:13:41 -04:00
// Update UI
GraphEditor - > NotifyGraphChanged ( ) ;
}
bool FMaterialEditor : : CanPasteNodes ( ) const
{
FString ClipboardContent ;
FPlatformMisc : : ClipboardPaste ( ClipboardContent ) ;
return FEdGraphUtilities : : CanImportNodesFromText ( Material - > MaterialGraph , ClipboardContent ) ;
}
void FMaterialEditor : : CutSelectedNodes ( )
{
CopySelectedNodes ( ) ;
// Cut should only delete nodes that can be duplicated
DeleteSelectedDuplicatableNodes ( ) ;
}
bool FMaterialEditor : : CanCutNodes ( ) const
{
return CanCopyNodes ( ) & & CanDeleteNodes ( ) ;
}
void FMaterialEditor : : DuplicateNodes ( )
{
// Copy and paste current selection
CopySelectedNodes ( ) ;
PasteNodes ( ) ;
}
bool FMaterialEditor : : CanDuplicateNodes ( ) const
{
return CanCopyNodes ( ) ;
}
2014-11-25 17:51:09 -05:00
FText FMaterialEditor : : GetOriginalObjectName ( ) const
2014-03-14 14:13:41 -04:00
{
2014-11-25 17:51:09 -05:00
return FText : : FromString ( GetEditingObjects ( ) [ 0 ] - > GetName ( ) ) ;
2014-03-14 14:13:41 -04:00
}
void FMaterialEditor : : UpdateMaterialAfterGraphChange ( )
{
Material - > MaterialGraph - > LinkMaterialExpressionsFromGraph ( ) ;
// Update the current preview material.
UpdatePreviewMaterial ( ) ;
Material - > MarkPackageDirty ( ) ;
RegenerateCodeView ( ) ;
RefreshExpressionPreviews ( ) ;
SetMaterialDirty ( ) ;
}
int32 FMaterialEditor : : GetNumberOfSelectedNodes ( ) const
{
return GraphEditor - > GetSelectedNodes ( ) . Num ( ) ;
}
FMaterialRenderProxy * FMaterialEditor : : GetExpressionPreview ( UMaterialExpression * InExpression )
{
bool bNewlyCreated ;
return GetExpressionPreview ( InExpression , bNewlyCreated ) ;
}
void FMaterialEditor : : UndoGraphAction ( )
{
2014-04-23 18:21:07 -04:00
int32 NumExpressions = Material - > Expressions . Num ( ) ;
GEditor - > UndoTransaction ( ) ;
2014-04-02 18:09:23 -04:00
2014-04-23 18:21:07 -04:00
if ( NumExpressions ! = Material - > Expressions . Num ( ) )
{
Material - > BuildEditorParameterList ( ) ;
2014-04-02 18:09:23 -04:00
}
2014-04-23 18:21:07 -04:00
}
2014-04-23 18:06:41 -04:00
void FMaterialEditor : : RedoGraphAction ( )
{
2014-04-23 18:21:07 -04:00
// Clear selection, to avoid holding refs to nodes that go away
GraphEditor - > ClearSelectionSet ( ) ;
2014-04-02 18:09:23 -04:00
2014-04-23 18:21:07 -04:00
int32 NumExpressions = Material - > Expressions . Num ( ) ;
GEditor - > RedoTransaction ( ) ;
2014-04-23 18:06:41 -04:00
2014-04-23 18:21:07 -04:00
if ( NumExpressions ! = Material - > Expressions . Num ( ) )
{
Material - > BuildEditorParameterList ( ) ;
2014-04-23 18:06:41 -04:00
}
2014-04-23 18:21:07 -04:00
}
2014-04-23 18:06:41 -04:00
void FMaterialEditor : : PostUndo ( bool bSuccess )
{
2014-06-26 09:16:15 -04:00
if ( bSuccess )
{
GraphEditor - > ClearSelectionSet ( ) ;
Material - > BuildEditorParameterList ( ) ;
2014-04-23 18:06:41 -04:00
2014-06-26 09:16:15 -04:00
// Update the current preview material.
UpdatePreviewMaterial ( ) ;
2014-04-23 18:06:41 -04:00
2014-06-26 09:16:15 -04:00
RefreshExpressionPreviews ( ) ;
GraphEditor - > NotifyGraphChanged ( ) ;
SetMaterialDirty ( ) ;
}
2014-04-23 18:21:07 -04:00
}
2014-04-23 18:06:41 -04:00
void FMaterialEditor : : NotifyPreChange ( UProperty * PropertyAboutToChange )
{
2014-04-23 18:21:07 -04:00
check ( ! ScopedTransaction ) ;
ScopedTransaction = new FScopedTransaction ( NSLOCTEXT ( " UnrealEd " , " MaterialEditorEditProperties " , " Material Editor: Edit Properties " ) ) ;
FlushRenderingCommands ( ) ;
}
2014-04-23 18:06:41 -04:00
void FMaterialEditor : : NotifyPostChange ( const FPropertyChangedEvent & PropertyChangedEvent , UProperty * PropertyThatChanged )
{
2014-04-23 18:21:07 -04:00
check ( ScopedTransaction ) ;
2014-04-23 18:06:41 -04:00
2014-04-23 18:21:07 -04:00
if ( PropertyThatChanged )
{
const FName NameOfPropertyThatChanged ( * PropertyThatChanged - > GetName ( ) ) ;
2015-02-19 00:33:19 -05:00
if ( ( NameOfPropertyThatChanged = = GET_MEMBER_NAME_CHECKED ( UMaterialInterface , PreviewMesh ) ) | |
( NameOfPropertyThatChanged = = GET_MEMBER_NAME_CHECKED ( UMaterial , bUsedWithSkeletalMesh ) ) )
2014-04-23 18:06:41 -04:00
{
2014-04-23 18:21:07 -04:00
// SetPreviewMesh will return false if the material has bUsedWithSkeletalMesh and
// a skeleton was requested, in which case revert to a sphere static mesh.
2015-02-19 00:33:19 -05:00
if ( ! SetPreviewAssetByName ( * Material - > PreviewMesh . ToString ( ) ) )
2014-04-23 18:06:41 -04:00
{
2015-02-19 00:33:19 -05:00
SetPreviewAsset ( GUnrealEd - > GetThumbnailManager ( ) - > EditorSphere ) ;
2014-04-23 18:06:41 -04:00
}
}
2014-04-23 18:21:07 -04:00
FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
2014-04-23 18:06:41 -04:00
{
2014-04-23 18:21:07 -04:00
UMaterialGraphNode * SelectedNode = Cast < UMaterialGraphNode > ( * NodeIt ) ;
if ( SelectedNode & & SelectedNode - > MaterialExpression )
2014-04-23 18:06:41 -04:00
{
2014-04-23 18:21:07 -04:00
if ( NameOfPropertyThatChanged = = FName ( TEXT ( " ParameterName " ) ) )
{
Material - > UpdateExpressionParameterName ( SelectedNode - > MaterialExpression ) ;
}
else if ( NameOfPropertyThatChanged = = FName ( TEXT ( " ParamNames " ) ) )
{
Material - > UpdateExpressionDynamicParameterNames ( SelectedNode - > MaterialExpression ) ;
}
else
{
Material - > PropagateExpressionParameterChanges ( SelectedNode - > MaterialExpression ) ;
}
2014-04-23 18:06:41 -04:00
}
}
}
2014-03-14 14:13:41 -04:00
2014-04-23 18:21:07 -04:00
// Prevent constant recompilation of materials while properties are being interacted with
if ( PropertyChangedEvent . ChangeType ! = EPropertyChangeType : : Interactive )
{
// Also prevent recompilation when properties have no effect on material output
const FName PropertyName = PropertyChangedEvent . MemberProperty ? PropertyChangedEvent . MemberProperty - > GetFName ( ) : NAME_None ;
if ( PropertyName ! = GET_MEMBER_NAME_CHECKED ( UMaterialExpressionComment , Text )
& & PropertyName ! = GET_MEMBER_NAME_CHECKED ( UMaterialExpressionComment , CommentColor )
& & PropertyName ! = GET_MEMBER_NAME_CHECKED ( UMaterialExpression , Desc ) )
{
// Update the current preview material.
UpdatePreviewMaterial ( ) ;
RefreshExpressionPreviews ( ) ;
RegenerateCodeView ( ) ;
}
}
delete ScopedTransaction ;
ScopedTransaction = NULL ;
Material - > MarkPackageDirty ( ) ;
SetMaterialDirty ( ) ;
2015-04-10 14:37:56 -04:00
GetDefault < UMaterialGraphSchema > ( ) - > ForceVisualizationCacheClear ( ) ;
2014-04-23 18:21:07 -04:00
}
2014-03-14 14:13:41 -04:00
void FMaterialEditor : : ToggleCollapsed ( UMaterialExpression * MaterialExpression )
{
check ( MaterialExpression ) ;
{
const FScopedTransaction Transaction ( NSLOCTEXT ( " UnrealEd " , " MaterialEditorToggleCollapsed " , " Material Editor: Toggle Collapsed " ) ) ;
MaterialExpression - > Modify ( ) ;
MaterialExpression - > bCollapsed = ! MaterialExpression - > bCollapsed ;
}
MaterialExpression - > PreEditChange ( NULL ) ;
MaterialExpression - > PostEditChange ( ) ;
MaterialExpression - > MarkPackageDirty ( ) ;
SetMaterialDirty ( ) ;
// Update the preview.
RefreshExpressionPreview ( MaterialExpression , true ) ;
RefreshPreviewViewport ( ) ;
}
void FMaterialEditor : : RefreshExpressionPreviews ( )
{
const FScopedBusyCursor BusyCursor ;
if ( bAlwaysRefreshAllPreviews )
{
// we need to make sure the rendering thread isn't drawing these tiles
SCOPED_SUSPEND_RENDERING_THREAD ( true ) ;
// Refresh all expression previews.
ExpressionPreviews . Empty ( ) ;
}
else
{
// Only refresh expressions that are marked for realtime update.
for ( int32 ExpressionIndex = 0 ; ExpressionIndex < Material - > Expressions . Num ( ) ; + + ExpressionIndex )
{
UMaterialExpression * MaterialExpression = Material - > Expressions [ ExpressionIndex ] ;
RefreshExpressionPreview ( MaterialExpression , false ) ;
}
}
TArray < FMatExpressionPreview * > ExpressionPreviewsBeingCompiled ;
ExpressionPreviewsBeingCompiled . Empty ( 50 ) ;
// Go through all expression previews and create new ones as needed, and maintain a list of previews that are being compiled
for ( int32 ExpressionIndex = 0 ; ExpressionIndex < Material - > Expressions . Num ( ) ; + + ExpressionIndex )
{
UMaterialExpression * MaterialExpression = Material - > Expressions [ ExpressionIndex ] ;
if ( MaterialExpression & & ! MaterialExpression - > IsA ( UMaterialExpressionComment : : StaticClass ( ) ) )
{
bool bNewlyCreated ;
FMatExpressionPreview * Preview = GetExpressionPreview ( MaterialExpression , bNewlyCreated ) ;
if ( bNewlyCreated & & Preview )
{
ExpressionPreviewsBeingCompiled . Add ( Preview ) ;
}
}
}
}
void FMaterialEditor : : RefreshExpressionPreview ( UMaterialExpression * MaterialExpression , bool bRecompile )
{
if ( ( MaterialExpression - > bRealtimePreview | | MaterialExpression - > bNeedToUpdatePreview ) & & ! MaterialExpression - > bCollapsed )
{
for ( int32 PreviewIndex = 0 ; PreviewIndex < ExpressionPreviews . Num ( ) ; + + PreviewIndex )
{
FMatExpressionPreview & ExpressionPreview = ExpressionPreviews [ PreviewIndex ] ;
if ( ExpressionPreview . GetExpression ( ) = = MaterialExpression )
{
// we need to make sure the rendering thread isn't drawing this tile
SCOPED_SUSPEND_RENDERING_THREAD ( true ) ;
ExpressionPreviews . RemoveAt ( PreviewIndex ) ;
MaterialExpression - > bNeedToUpdatePreview = false ;
if ( bRecompile )
{
bool bNewlyCreated ;
GetExpressionPreview ( MaterialExpression , bNewlyCreated ) ;
}
break ;
}
}
}
}
FMatExpressionPreview * FMaterialEditor : : GetExpressionPreview ( UMaterialExpression * MaterialExpression , bool & bNewlyCreated )
{
bNewlyCreated = false ;
if ( ! MaterialExpression - > bHidePreviewWindow & & ! MaterialExpression - > bCollapsed )
{
FMatExpressionPreview * Preview = NULL ;
for ( int32 PreviewIndex = 0 ; PreviewIndex < ExpressionPreviews . Num ( ) ; + + PreviewIndex )
{
FMatExpressionPreview & ExpressionPreview = ExpressionPreviews [ PreviewIndex ] ;
if ( ExpressionPreview . GetExpression ( ) = = MaterialExpression )
{
Preview = & ExpressionPreviews [ PreviewIndex ] ;
break ;
}
}
if ( ! Preview )
{
bNewlyCreated = true ;
Preview = new ( ExpressionPreviews ) FMatExpressionPreview ( MaterialExpression ) ;
2014-10-01 09:08:51 -04:00
Preview - > CacheShaders ( GMaxRHIShaderPlatform , true ) ;
2014-03-14 14:13:41 -04:00
}
return Preview ;
}
return NULL ;
}
void FMaterialEditor : : PreColorPickerCommit ( FLinearColor LinearColor )
{
// Begin a property edit transaction.
if ( GEditor )
{
GEditor - > BeginTransaction ( LOCTEXT ( " ModifyColorPicker " , " Modify Color Picker Value " ) ) ;
}
NotifyPreChange ( NULL ) ;
UObject * Object = ColorPickerObject . Get ( false ) ;
if ( Object )
{
Object - > PreEditChange ( NULL ) ;
}
}
void FMaterialEditor : : OnColorPickerCommitted ( FLinearColor LinearColor )
{
UObject * Object = ColorPickerObject . Get ( false ) ;
if ( Object )
{
Object - > MarkPackageDirty ( ) ;
2014-10-23 21:38:06 -04:00
FPropertyChangedEvent Event ( ColorPickerProperty . Get ( false ) ) ;
Object - > PostEditChangeProperty ( Event ) ;
2014-03-14 14:13:41 -04:00
}
NotifyPostChange ( NULL , NULL ) ;
if ( GEditor )
{
GEditor - > EndTransaction ( ) ;
}
RefreshExpressionPreviews ( ) ;
}
TSharedRef < SGraphEditor > FMaterialEditor : : CreateGraphEditorWidget ( )
{
GraphEditorCommands = MakeShareable ( new FUICommandList ) ;
{
// Editing commands
GraphEditorCommands - > MapAction ( FGenericCommands : : Get ( ) . SelectAll ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : SelectAllNodes ) ,
FCanExecuteAction : : CreateSP ( this , & FMaterialEditor : : CanSelectAllNodes )
) ;
GraphEditorCommands - > MapAction ( FGenericCommands : : Get ( ) . Delete ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : DeleteSelectedNodes ) ,
FCanExecuteAction : : CreateSP ( this , & FMaterialEditor : : CanDeleteNodes )
) ;
GraphEditorCommands - > MapAction ( FGenericCommands : : Get ( ) . Copy ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : CopySelectedNodes ) ,
FCanExecuteAction : : CreateSP ( this , & FMaterialEditor : : CanCopyNodes )
) ;
GraphEditorCommands - > MapAction ( FGenericCommands : : Get ( ) . Paste ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : PasteNodes ) ,
FCanExecuteAction : : CreateSP ( this , & FMaterialEditor : : CanPasteNodes )
) ;
GraphEditorCommands - > MapAction ( FGenericCommands : : Get ( ) . Cut ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : CutSelectedNodes ) ,
FCanExecuteAction : : CreateSP ( this , & FMaterialEditor : : CanCutNodes )
) ;
GraphEditorCommands - > MapAction ( FGenericCommands : : Get ( ) . Duplicate ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : DuplicateNodes ) ,
FCanExecuteAction : : CreateSP ( this , & FMaterialEditor : : CanDuplicateNodes )
) ;
// Graph Editor Commands
GraphEditorCommands - > MapAction ( FGraphEditorCommands : : Get ( ) . CreateComment ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnCreateComment )
) ;
// Material specific commands
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . UseCurrentTexture ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnUseCurrentTexture )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . ConvertObjects ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnConvertObjects )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . ConvertToTextureObjects ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnConvertTextures )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . ConvertToTextureSamples ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnConvertTextures )
) ;
2014-10-23 21:38:06 -04:00
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . ConvertToConstant ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnConvertObjects )
) ;
2014-03-14 14:13:41 -04:00
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . StopPreviewNode ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnPreviewNode )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . StartPreviewNode ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnPreviewNode )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . EnableRealtimePreviewNode ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnToggleRealtimePreview )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . DisableRealtimePreviewNode ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnToggleRealtimePreview )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . SelectDownstreamNodes ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnSelectDownsteamNodes )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . SelectUpstreamNodes ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnSelectUpsteamNodes )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . RemoveFromFavorites ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : RemoveSelectedExpressionFromFavorites )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . AddToFavorites ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : AddSelectedExpressionToFavorites )
) ;
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . ForceRefreshPreviews ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnForceRefreshPreviews )
) ;
2014-05-08 05:29:54 -04:00
GraphEditorCommands - > MapAction ( FMaterialEditorCommands : : Get ( ) . CreateComponentMaskNode ,
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnCreateComponentMaskNode )
) ;
2014-09-05 08:25:23 -04:00
2015-04-09 11:34:39 -04:00
GraphEditorCommands - > MapAction ( FGraphEditorCommands : : Get ( ) . GoToDocumentation ,
2014-09-05 08:25:23 -04:00
FExecuteAction : : CreateSP ( this , & FMaterialEditor : : OnGoToDocumentation ) ,
FCanExecuteAction : : CreateSP ( this , & FMaterialEditor : : CanGoToDocumentation )
) ;
2014-03-14 14:13:41 -04:00
}
FGraphAppearanceInfo AppearanceInfo ;
if ( MaterialFunction )
{
2015-01-07 09:52:40 -05:00
AppearanceInfo . CornerText = LOCTEXT ( " AppearanceCornerText_MaterialFunction " , " MATERIAL FUNCTION " ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-01-07 09:52:40 -05:00
AppearanceInfo . CornerText = LOCTEXT ( " AppearanceCornerText_Material " , " MATERIAL " ) ;
2014-03-14 14:13:41 -04:00
}
SGraphEditor : : FGraphEditorEvents InEvents ;
InEvents . OnSelectionChanged = SGraphEditor : : FOnSelectionChanged : : CreateSP ( this , & FMaterialEditor : : OnSelectedNodesChanged ) ;
InEvents . OnNodeDoubleClicked = FSingleNodeEvent : : CreateSP ( this , & FMaterialEditor : : OnNodeDoubleClicked ) ;
InEvents . OnTextCommitted = FOnNodeTextCommitted : : CreateSP ( this , & FMaterialEditor : : OnNodeTitleCommitted ) ;
InEvents . OnSpawnNodeByShortcut = SGraphEditor : : FOnSpawnNodeByShortcut : : CreateSP ( this , & FMaterialEditor : : OnSpawnGraphNodeByShortcut , CastChecked < UEdGraph > ( Material - > MaterialGraph ) ) ;
// Create the title bar widget
TSharedPtr < SWidget > TitleBarWidget = SNew ( SMaterialEditorTitleBar )
. TitleText ( this , & FMaterialEditor : : GetOriginalObjectName ) ;
//.MaterialInfoList(&MaterialInfoList);
return SNew ( SGraphEditor )
. AdditionalCommands ( GraphEditorCommands )
. IsEditable ( true )
. TitleBar ( TitleBarWidget )
. Appearance ( AppearanceInfo )
. GraphToEdit ( Material - > MaterialGraph )
. GraphEvents ( InEvents )
2014-06-09 11:12:17 -04:00
. ShowGraphStateOverlay ( false ) ;
2014-03-14 14:13:41 -04:00
}
void FMaterialEditor : : CleanUnusedExpressions ( )
{
TArray < UEdGraphNode * > UnusedNodes ;
Material - > MaterialGraph - > GetUnusedExpressions ( UnusedNodes ) ;
if ( UnusedNodes . Num ( ) > 0 & & CheckExpressionRemovalWarnings ( UnusedNodes ) )
{
{
// Kill off expressions referenced by the material that aren't reachable.
const FScopedTransaction Transaction ( NSLOCTEXT ( " UnrealEd " , " MaterialEditorCleanUnusedExpressions " , " Material Editor: Clean Unused Expressions " ) ) ;
Material - > Modify ( ) ;
Material - > MaterialGraph - > Modify ( ) ;
for ( int32 Index = 0 ; Index < UnusedNodes . Num ( ) ; + + Index )
{
UMaterialGraphNode * GraphNode = CastChecked < UMaterialGraphNode > ( UnusedNodes [ Index ] ) ;
UMaterialExpression * MaterialExpression = GraphNode - > MaterialExpression ;
FBlueprintEditorUtils : : RemoveNode ( NULL , GraphNode , true ) ;
2014-06-27 07:35:59 -04:00
if ( PreviewExpression = = MaterialExpression )
{
SetPreviewExpression ( NULL ) ;
}
2014-03-14 14:13:41 -04:00
MaterialExpression - > Modify ( ) ;
Material - > Expressions . Remove ( MaterialExpression ) ;
Material - > RemoveExpressionParameter ( MaterialExpression ) ;
// Make sure the deleted expression is caught by gc
MaterialExpression - > MarkPendingKill ( ) ;
}
Material - > MaterialGraph - > LinkMaterialExpressionsFromGraph ( ) ;
} // ScopedTransaction
GraphEditor - > ClearSelectionSet ( ) ;
GraphEditor - > NotifyGraphChanged ( ) ;
SetMaterialDirty ( ) ;
}
}
bool FMaterialEditor : : CheckExpressionRemovalWarnings ( const TArray < UEdGraphNode * > & NodesToRemove )
{
FString FunctionWarningString ;
bool bFirstExpression = true ;
for ( int32 Index = 0 ; Index < NodesToRemove . Num ( ) ; + + Index )
{
if ( UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( NodesToRemove [ Index ] ) )
{
UMaterialExpressionFunctionInput * FunctionInput = Cast < UMaterialExpressionFunctionInput > ( GraphNode - > MaterialExpression ) ;
UMaterialExpressionFunctionOutput * FunctionOutput = Cast < UMaterialExpressionFunctionOutput > ( GraphNode - > MaterialExpression ) ;
if ( FunctionInput )
{
if ( ! bFirstExpression )
{
FunctionWarningString + = TEXT ( " , " ) ;
}
bFirstExpression = false ;
FunctionWarningString + = FunctionInput - > InputName ;
}
if ( FunctionOutput )
{
if ( ! bFirstExpression )
{
FunctionWarningString + = TEXT ( " , " ) ;
}
bFirstExpression = false ;
FunctionWarningString + = FunctionOutput - > OutputName ;
}
}
}
if ( FunctionWarningString . Len ( ) > 0 )
{
if ( EAppReturnType : : Yes ! = FMessageDialog : : Open ( EAppMsgType : : YesNo ,
FText : : Format (
NSLOCTEXT ( " UnrealEd " , " Prompt_MaterialEditorDeleteFunctionInputs " , " Delete function inputs or outputs \" {0} \" ? \n Any materials which use this function will lose their connections to these function inputs or outputs once deleted. " ) ,
FText : : FromString ( FunctionWarningString ) ) ) )
{
// User said don't delete
return false ;
}
}
return true ;
}
void FMaterialEditor : : RemoveSelectedExpressionFromFavorites ( )
{
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
if ( SelectedNodes . Num ( ) = = 1 )
{
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
if ( UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( * NodeIt ) )
{
MaterialExpressionClasses : : Get ( ) - > RemoveMaterialExpressionFromFavorites ( GraphNode - > MaterialExpression - > GetClass ( ) ) ;
EditorOptions - > FavoriteExpressions . Remove ( GraphNode - > MaterialExpression - > GetClass ( ) - > GetName ( ) ) ;
EditorOptions - > SaveConfig ( ) ;
}
}
}
}
void FMaterialEditor : : AddSelectedExpressionToFavorites ( )
{
const FGraphPanelSelectionSet SelectedNodes = GraphEditor - > GetSelectedNodes ( ) ;
if ( SelectedNodes . Num ( ) = = 1 )
{
for ( FGraphPanelSelectionSet : : TConstIterator NodeIt ( SelectedNodes ) ; NodeIt ; + + NodeIt )
{
if ( UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( * NodeIt ) )
{
MaterialExpressionClasses : : Get ( ) - > AddMaterialExpressionToFavorites ( GraphNode - > MaterialExpression - > GetClass ( ) ) ;
EditorOptions - > FavoriteExpressions . AddUnique ( GraphNode - > MaterialExpression - > GetClass ( ) - > GetName ( ) ) ;
EditorOptions - > SaveConfig ( ) ;
}
}
}
}
void FMaterialEditor : : OnSelectedNodesChanged ( const TSet < class UObject * > & NewSelection )
{
TArray < UObject * > SelectedObjects ;
UObject * EditObject = Material ;
if ( MaterialFunction )
{
EditObject = MaterialFunction ;
}
if ( NewSelection . Num ( ) = = 0 )
{
SelectedObjects . Add ( EditObject ) ;
}
else
{
for ( TSet < class UObject * > : : TConstIterator SetIt ( NewSelection ) ; SetIt ; + + SetIt )
{
if ( UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( * SetIt ) )
{
SelectedObjects . Add ( GraphNode - > MaterialExpression ) ;
}
else if ( UMaterialGraphNode_Comment * CommentNode = Cast < UMaterialGraphNode_Comment > ( * SetIt ) )
{
SelectedObjects . Add ( CommentNode - > MaterialExpressionComment ) ;
}
else
{
SelectedObjects . Add ( EditObject ) ;
}
}
}
GetDetailView ( ) - > SetObjects ( SelectedObjects , true ) ;
}
void FMaterialEditor : : OnNodeDoubleClicked ( class UEdGraphNode * Node )
{
UMaterialGraphNode * GraphNode = Cast < UMaterialGraphNode > ( Node ) ;
if ( GraphNode )
{
UMaterialExpressionConstant3Vector * Constant3Expression = Cast < UMaterialExpressionConstant3Vector > ( GraphNode - > MaterialExpression ) ;
UMaterialExpressionConstant4Vector * Constant4Expression = Cast < UMaterialExpressionConstant4Vector > ( GraphNode - > MaterialExpression ) ;
UMaterialExpressionFunctionInput * InputExpression = Cast < UMaterialExpressionFunctionInput > ( GraphNode - > MaterialExpression ) ;
UMaterialExpressionVectorParameter * VectorExpression = Cast < UMaterialExpressionVectorParameter > ( GraphNode - > MaterialExpression ) ;
FColorChannels ChannelEditStruct ;
2014-10-23 21:38:06 -04:00
// Reset to default
ColorPickerProperty = NULL ;
2014-03-14 14:13:41 -04:00
if ( Constant3Expression )
{
ChannelEditStruct . Red = & Constant3Expression - > Constant . R ;
ChannelEditStruct . Green = & Constant3Expression - > Constant . G ;
ChannelEditStruct . Blue = & Constant3Expression - > Constant . B ;
}
else if ( Constant4Expression )
{
ChannelEditStruct . Red = & Constant4Expression - > Constant . R ;
ChannelEditStruct . Green = & Constant4Expression - > Constant . G ;
ChannelEditStruct . Blue = & Constant4Expression - > Constant . B ;
ChannelEditStruct . Alpha = & Constant4Expression - > Constant . A ;
}
else if ( InputExpression )
{
ChannelEditStruct . Red = & InputExpression - > PreviewValue . X ;
ChannelEditStruct . Green = & InputExpression - > PreviewValue . Y ;
ChannelEditStruct . Blue = & InputExpression - > PreviewValue . Z ;
ChannelEditStruct . Alpha = & InputExpression - > PreviewValue . W ;
}
else if ( VectorExpression )
{
ChannelEditStruct . Red = & VectorExpression - > DefaultValue . R ;
ChannelEditStruct . Green = & VectorExpression - > DefaultValue . G ;
ChannelEditStruct . Blue = & VectorExpression - > DefaultValue . B ;
ChannelEditStruct . Alpha = & VectorExpression - > DefaultValue . A ;
2014-10-23 21:38:06 -04:00
static FName DefaultValueName = FName ( TEXT ( " DefaultValue " ) ) ;
// Store off the property the color picker will be manipulating, so we can construct a useful PostEditChangeProperty later
ColorPickerProperty = VectorExpression - > GetClass ( ) - > FindPropertyByName ( DefaultValueName ) ;
2014-03-14 14:13:41 -04:00
}
if ( ChannelEditStruct . Red | | ChannelEditStruct . Green | | ChannelEditStruct . Blue | | ChannelEditStruct . Alpha )
{
TArray < FColorChannels > Channels ;
Channels . Add ( ChannelEditStruct ) ;
ColorPickerObject = GraphNode - > MaterialExpression ;
// Open a color picker that only sends updates when Ok is clicked,
// Since it is too slow to recompile preview expressions as the user is picking different colors
FColorPickerArgs PickerArgs ;
PickerArgs . ParentWidget = GraphEditor ; //AsShared();
PickerArgs . bUseAlpha = Constant4Expression ! = NULL | | VectorExpression ! = NULL ;
PickerArgs . bOnlyRefreshOnOk = true ;
2014-09-25 17:33:36 -04:00
PickerArgs . bExpandAdvancedSection = true ;
2014-03-14 14:13:41 -04:00
PickerArgs . DisplayGamma = TAttribute < float > : : Create ( TAttribute < float > : : FGetter : : CreateUObject ( GEngine , & UEngine : : GetDisplayGamma ) ) ;
PickerArgs . ColorChannelsArray = & Channels ;
PickerArgs . OnColorCommitted = FOnLinearColorValueChanged : : CreateSP ( this , & FMaterialEditor : : OnColorPickerCommitted ) ;
PickerArgs . PreColorCommitted = FOnLinearColorValueChanged : : CreateSP ( this , & FMaterialEditor : : PreColorPickerCommit ) ;
OpenColorPicker ( PickerArgs ) ;
}
UMaterialExpressionTextureSample * TextureExpression = Cast < UMaterialExpressionTextureSample > ( GraphNode - > MaterialExpression ) ;
UMaterialExpressionTextureSampleParameter * TextureParameterExpression = Cast < UMaterialExpressionTextureSampleParameter > ( GraphNode - > MaterialExpression ) ;
UMaterialExpressionMaterialFunctionCall * FunctionExpression = Cast < UMaterialExpressionMaterialFunctionCall > ( GraphNode - > MaterialExpression ) ;
UMaterialExpressionCollectionParameter * CollectionParameter = Cast < UMaterialExpressionCollectionParameter > ( GraphNode - > MaterialExpression ) ;
TArray < UObject * > ObjectsToView ;
UObject * ObjectToEdit = NULL ;
if ( TextureExpression & & TextureExpression - > Texture )
{
ObjectsToView . Add ( TextureExpression - > Texture ) ;
}
else if ( TextureParameterExpression & & TextureParameterExpression - > Texture )
{
ObjectsToView . Add ( TextureParameterExpression - > Texture ) ;
}
else if ( FunctionExpression & & FunctionExpression - > MaterialFunction )
{
ObjectToEdit = FunctionExpression - > MaterialFunction ;
}
else if ( CollectionParameter & & CollectionParameter - > Collection )
{
ObjectToEdit = CollectionParameter - > Collection ;
}
if ( ObjectsToView . Num ( ) > 0 )
{
GEditor - > SyncBrowserToObjects ( ObjectsToView ) ;
}
if ( ObjectToEdit )
{
FAssetEditorManager : : Get ( ) . OpenEditorForAsset ( ObjectToEdit ) ;
}
}
}
void FMaterialEditor : : OnNodeTitleCommitted ( const FText & NewText , ETextCommit : : Type CommitInfo , UEdGraphNode * NodeBeingChanged )
{
if ( NodeBeingChanged )
{
const FScopedTransaction Transaction ( LOCTEXT ( " RenameNode " , " Rename Node " ) ) ;
NodeBeingChanged - > Modify ( ) ;
NodeBeingChanged - > OnRenameNode ( NewText . ToString ( ) ) ;
}
}
2015-03-17 11:36:28 -04:00
FReply FMaterialEditor : : OnSpawnGraphNodeByShortcut ( FInputChord InChord , const FVector2D & InPosition , UEdGraph * InGraph )
2014-03-14 14:13:41 -04:00
{
UEdGraph * Graph = InGraph ;
2015-03-17 11:36:28 -04:00
TSharedPtr < FEdGraphSchemaAction > Action = FMaterialEditorSpawnNodeCommands : : Get ( ) . GetGraphActionByChord ( InChord , InGraph ) ;
2014-03-14 14:13:41 -04:00
if ( Action . IsValid ( ) )
{
TArray < UEdGraphPin * > DummyPins ;
Action - > PerformAction ( Graph , DummyPins , InPosition ) ;
return FReply : : Handled ( ) ;
}
return FReply : : Unhandled ( ) ;
}
2014-04-23 20:20:58 -04:00
void FMaterialEditor : : UpdateStatsMaterials ( )
2014-03-14 14:13:41 -04:00
{
2014-04-23 20:20:58 -04:00
if ( bShowBuiltinStats & & bStatsFromPreviewMaterial )
{
UMaterial * StatsMaterial = Material ;
FString EmptyMaterialName = FString ( TEXT ( " MEStatsMaterial_Empty_ " ) ) + Material - > GetName ( ) ;
EmptyMaterial = ( UMaterial * ) StaticDuplicateObject ( Material , GetTransientPackage ( ) , * EmptyMaterialName , ~ RF_Standalone , UPreviewMaterial : : StaticClass ( ) ) ;
2014-03-14 14:13:41 -04:00
2014-04-23 20:20:58 -04:00
EmptyMaterial - > SetFeatureLevelToCompile ( ERHIFeatureLevel : : ES2 , bShowMobileStats ) ;
EmptyMaterial - > Expressions . Empty ( ) ;
//Disconnect all properties from the expressions
for ( int32 PropIdx = 0 ; PropIdx < MP_MAX ; + + PropIdx )
{
FExpressionInput * ExpInput = EmptyMaterial - > GetExpressionInputForProperty ( ( EMaterialProperty ) PropIdx ) ;
2014-10-08 15:27:19 -04:00
if ( ExpInput )
{
ExpInput - > Expression = NULL ;
}
2014-04-23 20:20:58 -04:00
}
EmptyMaterial - > bAllowDevelopmentShaderCompile = Material - > bAllowDevelopmentShaderCompile ;
EmptyMaterial - > PreEditChange ( NULL ) ;
EmptyMaterial - > PostEditChange ( ) ;
2014-04-23 17:43:00 -04:00
}
2014-03-14 14:13:41 -04:00
}
# undef LOCTEXT_NAMESPACE