You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

650 lines
20 KiB

// Amplify Shader Editor - Visual Shader Editing Tool
// Copyright (c) Amplify Creations, Lda <info@amplify.pt>
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace AmplifyShaderEditor
{
public enum ShaderPropertyScope
{
Shader,
SubShader,
Pass
}
[Serializable]
[NodeAttributes( "Template Parameter", "Constants And Properties", "Select and use one of the pre-existing properties given by the template" )]
public sealed class TemplateShaderPropertyNode : TemplateNodeParent
{
private const string CurrentScopeStr = "Scope";
private const string WarningStr = "Preview doesn't work with global variables";
private const string PropertyLabelStr = "Parameter";
private const string TypeLabelStr = "Type: ";
private const string PropertyNameStr = "Property Name: ";
private int IntPropertyId;
private int FloatPropertyId;
private int VectorPropertyId;
private int Sampler2DPropertyId;
private int Sampler3DPropertyId;
private int SamplerCubePropertyId;
[SerializeField]
private int m_currentPropertyIdx = -1;
[SerializeField]
private string m_propertyName = string.Empty;
[SerializeField]
private int m_propertyNameId = 0;
[SerializeField]
private string m_typeName = string.Empty;
[SerializeField]
private string m_propertyNameLabel = string.Empty;
private bool m_fetchPropertyId = false;
private bool m_fetchScopeFromProperty = false;
private List<TemplateShaderPropertyData> m_shaderProperties = null;
private string[] m_propertyLabels = null;
private UpperLeftWidgetHelper m_upperLeftWidgetHelper = new UpperLeftWidgetHelper();
//Multi-Pass only properties
[SerializeField]
private ShaderPropertyScope m_currentScope = ShaderPropertyScope.Shader;
protected override void CommonInit( int uniqueId )
{
base.CommonInit( uniqueId );
m_previewShaderGUID = "4feb2016be0ece148b8bf234508f6aa4";
}
void FetchScope()
{
int shaderScopeCount = m_templateMPData.AvailableShaderProperties.Count;
for( int i = 0; i < shaderScopeCount; i++ )
{
if( m_templateMPData.AvailableShaderProperties[ i ].PropertyName.Equals( m_propertyName ) )
{
m_currentScope = ShaderPropertyScope.Shader;
}
}
int subShaderScopeCount = m_templateMPData.SubShaders[ SubShaderIdx ].AvailableShaderGlobals.Count;
for( int i = 0; i < subShaderScopeCount; i++ )
{
if( m_templateMPData.SubShaders[ SubShaderIdx ].AvailableShaderGlobals[ i ].PropertyName.Equals( m_propertyName ) )
{
m_currentScope = ShaderPropertyScope.SubShader;
}
}
int passScopeCount = m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].AvailableShaderGlobals.Count;
for( int i = 0; i < passScopeCount; i++ )
{
if( m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].AvailableShaderGlobals[ i ].PropertyName.Equals( m_propertyName ) )
{
m_currentScope = ShaderPropertyScope.Pass;
}
}
}
void FetchShaderProperties()
{
if( m_templateMPData == null )
m_templateMPData = ( m_containerGraph.CurrentMasterNode as TemplateMultiPassMasterNode ).CurrentTemplate;
if( m_templateMPData != null )
{
switch( m_currentScope )
{
case ShaderPropertyScope.Shader:
m_shaderProperties = m_templateMPData.AvailableShaderProperties;
break;
case ShaderPropertyScope.SubShader:
m_shaderProperties = m_templateMPData.SubShaders[ SubShaderIdx ].AvailableShaderGlobals;
break;
case ShaderPropertyScope.Pass:
m_shaderProperties = m_templateMPData.SubShaders[ SubShaderIdx ].Passes[ PassIdx ].AvailableShaderGlobals;
break;
}
}
}
public override void OnEnable()
{
base.OnEnable();
IntPropertyId = Shader.PropertyToID( "_IntData" );
FloatPropertyId = Shader.PropertyToID( "_FloatData" );
VectorPropertyId = Shader.PropertyToID( "_VectorData" );
Sampler2DPropertyId = Shader.PropertyToID( "_Sampler2DData" );
Sampler3DPropertyId = Shader.PropertyToID( "_Sampler3DData" );
SamplerCubePropertyId = Shader.PropertyToID( "_SamplerCubeData" );
}
public override void DrawProperties()
{
base.DrawProperties();
if( m_multiPassMode )
{
DrawMultipassProperties();
}
if( m_currentPropertyIdx > -1 )
{
bool hasProperties = ( m_shaderProperties != null && m_shaderProperties.Count > 0 );
if( hasProperties )
{
EditorGUI.BeginChangeCheck();
m_currentPropertyIdx = EditorGUILayoutPopup( PropertyLabelStr, m_currentPropertyIdx, m_propertyLabels );
if( EditorGUI.EndChangeCheck() )
{
UpdateFromId();
}
EditorGUILayout.LabelField( m_typeName );
if( m_shaderProperties[ m_currentPropertyIdx ].PropertyType != PropertyType.Global )
{
EditorGUILayout.LabelField( m_propertyNameLabel );
}
}
}
}
void DrawMultipassProperties()
{
EditorGUI.BeginChangeCheck();
m_currentScope = (ShaderPropertyScope)EditorGUILayoutEnumPopup( CurrentScopeStr, m_currentScope );
if( EditorGUI.EndChangeCheck() )
{
FetchShaderProperties();
FetchPropertyId();
}
bool showSubShader = false;
bool showPass = false;
switch( m_currentScope )
{
case ShaderPropertyScope.SubShader:
{
showSubShader = true;
}
break;
case ShaderPropertyScope.Pass:
{
showSubShader = true;
showPass = true;
}
break;
}
if( showSubShader )
{
DrawSubShaderUI();
}
if( showPass )
{
DrawPassUI();
}
}
protected override void OnSubShaderChange()
{
FetchShaderProperties();
FetchPropertyId();
}
protected override void OnPassChange()
{
FetchShaderProperties();
FetchPropertyId();
}
override protected void CheckWarningState()
{
if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader )
{
ShowTab( NodeMessageType.Error, ErrorMessageStr );
}
else
{
if( m_shaderProperties != null &&
m_shaderProperties.Count > 0 &&
m_shaderProperties.Count > m_currentPropertyIdx &&
m_shaderProperties[ m_currentPropertyIdx ].PropertyType == PropertyType.Global &&
m_showPreview )
{
ShowTab( NodeMessageType.Info, WarningStr );
}
else
{
m_showErrorMessage = false;
}
}
}
public override void SetPreviewInputs()
{
if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader )
return;
if( m_shaderProperties == null || m_currentPropertyIdx >= m_shaderProperties.Count )
return;
if( m_shaderProperties[ m_currentPropertyIdx ].PropertyType == PropertyType.Global )
{
m_additionalContent.text = string.Empty;
PreviewMaterial.SetInt( IntPropertyId, 0 );
return;
}
Material currMat = m_containerGraph.CurrentMaterial;
if( currMat != null && currMat.HasProperty( m_propertyNameId ) )
{
switch( m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType )
{
case WirePortDataType.INT:
{
int value = currMat.GetInt( m_propertyNameId );
SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, GenerateTitle( value ) ) );
PreviewMaterial.SetInt( IntPropertyId, value );
}
break;
case WirePortDataType.FLOAT:
{
float value = currMat.GetFloat( m_propertyNameId );
SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, GenerateTitle( value ) ) );
PreviewMaterial.SetFloat( FloatPropertyId, value );
}
break;
case WirePortDataType.FLOAT4:
{
Vector4 value = currMat.GetVector( m_propertyNameId );
SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, GenerateTitle( value.x, value.y, value.z, value.w ) ) );
PreviewMaterial.SetVector( VectorPropertyId, value );
}
break;
case WirePortDataType.COLOR:
{
Color value = currMat.GetColor( m_propertyNameId );
SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, GenerateTitle( value.r, value.g, value.b, value.a ) ) );
PreviewMaterial.SetColor( VectorPropertyId, value );
}
break;
case WirePortDataType.SAMPLER2D:
{
Texture value = currMat.GetTexture( m_propertyNameId );
if( value )
SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, value.name ) );
else
SetAdditonalTitleText( string.Empty );
PreviewMaterial.SetTexture( Sampler2DPropertyId, value );
}
break;
case WirePortDataType.SAMPLER3D:
{
Texture value = currMat.GetTexture( m_propertyNameId );
if( value )
SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, value.name ) );
else
SetAdditonalTitleText( string.Empty );
PreviewMaterial.SetTexture( Sampler3DPropertyId, value );
}
break;
case WirePortDataType.SAMPLERCUBE:
{
Texture value = currMat.GetTexture( m_propertyNameId );
if( value )
SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr, value.name ) );
else
SetAdditonalTitleText( string.Empty );
PreviewMaterial.SetTexture( SamplerCubePropertyId, value );
}
break;
}
}
else
{
SetAdditonalTitleText( string.Empty );
}
}
public override void Draw( DrawInfo drawInfo )
{
if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader )
{
if( !m_showErrorMessage || m_errorMessageTypeIsError == NodeMessageType.Info )
{
ShowTab( NodeMessageType.Error, ErrorMessageStr );
}
}
else if( m_showErrorMessage )
{
if( m_errorMessageTypeIsError == NodeMessageType.Error )
HideTab();
}
base.Draw( drawInfo );
if( m_containerGraph.CurrentCanvasMode != NodeAvailability.TemplateShader )
return;
if( m_shaderProperties == null )
{
MasterNode masterNode = m_containerGraph.CurrentMasterNode;
if( masterNode.CurrentMasterNodeCategory == AvailableShaderTypes.Template )
{
if( SetTemplate( masterNode ) )
{
m_fetchPropertyId = true;
}
}
}
if( m_fetchScopeFromProperty )
{
m_fetchScopeFromProperty = false;
FetchScope();
FetchShaderProperties();
}
if( m_fetchPropertyId )
{
m_fetchPropertyId = false;
FetchPropertyId();
}
if( m_currentPropertyIdx > -1 )
{
EditorGUI.BeginChangeCheck();
m_currentPropertyIdx = m_upperLeftWidgetHelper.DrawWidget( this, m_currentPropertyIdx, m_propertyLabels );
if( EditorGUI.EndChangeCheck() )
{
UpdateFromId();
}
}
}
void FetchPropertyId()
{
if( m_shaderProperties != null )
{
m_currentPropertyIdx = 0;
m_propertyLabels = new string[ m_shaderProperties.Count ];
for( int i = 0; i < m_shaderProperties.Count; i++ )
{
if( m_shaderProperties[ i ].PropertyName.Equals( m_propertyName ) )
{
m_currentPropertyIdx = i;
}
m_propertyLabels[ i ] = m_shaderProperties[ i ].PropertyInspectorName;
}
UpdateFromId();
}
else
{
m_currentPropertyIdx = -1;
}
}
void UpdateFromId()
{
if( m_shaderProperties != null )
{
if( m_shaderProperties.Count == 0 )
{
for( int i = 0; i < 4; i++ )
m_containerGraph.DeleteConnection( false, UniqueId, i, false, true );
m_headerColor = UIUtils.GetColorFromCategory( "Default" );
m_content.text = "None";
m_additionalContent.text = string.Empty;
m_previewMaterialPassId = 1;
PreviewMaterial.SetFloat( FloatPropertyId, 0 );
m_showPreview = false;
m_drawPreviewExpander = false;
m_outputPorts[ 0 ].ChangeProperties( "None", WirePortDataType.FLOAT, false );
ConfigurePorts();
return;
}
m_drawPreviewExpander = true;
bool areCompatible = TemplateHelperFunctions.CheckIfCompatibles( m_outputPorts[ 0 ].DataType, m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType );
switch( m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType )
{
case WirePortDataType.SAMPLER1D:
case WirePortDataType.SAMPLER2D:
case WirePortDataType.SAMPLER3D:
case WirePortDataType.SAMPLERCUBE:
m_outputPorts[ 0 ].ChangeProperties( "Tex", m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType, false );
m_headerColor = UIUtils.GetColorFromCategory( "Textures" );
break;
case WirePortDataType.INT:
case WirePortDataType.FLOAT:
m_outputPorts[ 0 ].ChangeProperties( Constants.EmptyPortValue, m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType, false );
m_headerColor = UIUtils.GetColorFromCategory( "Constants And Properties" );
break;
case WirePortDataType.FLOAT4:
m_outputPorts[ 0 ].ChangeProperties( "XYZW", m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType, false );
m_headerColor = UIUtils.GetColorFromCategory( "Constants And Properties" );
break;
case WirePortDataType.COLOR:
m_outputPorts[ 0 ].ChangeProperties( "RGBA", m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType, false );
m_headerColor = UIUtils.GetColorFromCategory( "Constants And Properties" );
break;
default:
case WirePortDataType.OBJECT:
case WirePortDataType.FLOAT3x3:
case WirePortDataType.FLOAT4x4:
m_outputPorts[ 0 ].ChangeProperties( "Out", m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType, false );
m_headerColor = UIUtils.GetColorFromCategory( "Constants And Properties" );
break;
}
if( !areCompatible )
{
for( int i = 0; i < 4; i++ )
m_containerGraph.DeleteConnection( false, UniqueId, i, false, true );
}
ConfigurePorts();
m_propertyName = m_shaderProperties[ m_currentPropertyIdx ].PropertyName;
m_content.text = m_shaderProperties[ m_currentPropertyIdx ].PropertyInspectorName;
m_propertyNameId = Shader.PropertyToID( m_propertyName );
m_typeName = TypeLabelStr + m_shaderProperties[ m_currentPropertyIdx ].PropertyType.ToString();
if( m_shaderProperties[ m_currentPropertyIdx ].PropertyType != PropertyType.Global )
{
m_propertyNameLabel = PropertyNameStr + m_shaderProperties[ m_currentPropertyIdx ].PropertyName;
}
m_sizeIsDirty = true;
Material currMat = m_containerGraph.CurrentMaterial;
if( currMat != null )
{
if( m_shaderProperties[ m_currentPropertyIdx ].PropertyType == PropertyType.Global )
{
m_previewMaterialPassId = 0;
if( !m_showErrorMessage && m_showPreview )
{
ShowTab( NodeMessageType.Info, WarningStr );
}
}
else
{
if( m_showErrorMessage && m_errorMessageTypeIsError != NodeMessageType.Error )
{
HideTab();
}
switch( m_shaderProperties[ m_currentPropertyIdx ].PropertyDataType )
{
case WirePortDataType.INT: m_previewMaterialPassId = 0; break;
case WirePortDataType.FLOAT: m_previewMaterialPassId = 1; break;
case WirePortDataType.FLOAT4:
case WirePortDataType.COLOR: m_previewMaterialPassId = 2; break;
case WirePortDataType.SAMPLER2D: m_previewMaterialPassId = 3; break;
case WirePortDataType.SAMPLER3D: m_previewMaterialPassId = 4; break;
case WirePortDataType.SAMPLERCUBE: m_previewMaterialPassId = 5; break;
default: PreviewMaterial.SetPass( 0 ); break;
}
}
}
CheckWarningState();
}
}
string GenerateTitle( params float[] values )
{
//string finalResult = "( ";
string finalResult = string.Empty;
if( values.Length == 1 )
{
finalResult += values[ 0 ].ToString( Mathf.Abs( values[ 0 ] ) > 1000 ? Constants.PropertyBigFloatFormatLabel : Constants.PropertyFloatFormatLabel );
}
else
{
for( int i = 0; i < values.Length; i++ )
{
finalResult += values[ i ].ToString( Mathf.Abs( values[ i ] ) > 1000 ? Constants.PropertyBigVectorFormatLabel : Constants.PropertyVectorFormatLabel );
if( i < ( values.Length - 1 ) )
finalResult += ",";
}
}
//finalResult += " )";
return finalResult;
}
public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
{
if( dataCollector.MasterNodeCategory != AvailableShaderTypes.Template )
{
UIUtils.ShowMessage( "Template Parameter node is only intended for templates use only" );
return m_outputPorts[ outputId ].ErrorValue;
}
if( m_shaderProperties == null || m_shaderProperties.Count ==0 )
{
UIUtils.ShowMessage( "Attempting to fetch inexistant parameter on " + m_nodeAttribs.Name +" node");
return m_outputPorts[ outputId ].ErrorValue;
}
if( m_multiPassMode )
{
switch( m_currentScope )
{
case ShaderPropertyScope.SubShader:
{
if( dataCollector.TemplateDataCollectorInstance.MultipassSubshaderIdx != SubShaderIdx )
{
UIUtils.ShowMessage( string.Format( "{0} is only intended for subshader {1}", m_propertyLabels[ m_currentPropertyIdx ], SubShaderIdx ) );
return m_outputPorts[ outputId ].ErrorValue;
}
}
break;
case ShaderPropertyScope.Pass:
{
if( dataCollector.TemplateDataCollectorInstance.MultipassSubshaderIdx != SubShaderIdx ||
dataCollector.TemplateDataCollectorInstance.MultipassPassIdx != PassIdx
)
{
UIUtils.ShowMessage( string.Format( "{0} is only intended for subshader {1} and pass {2}", m_propertyLabels[ m_currentPropertyIdx ], SubShaderIdx, PassIdx ) );
return m_outputPorts[ outputId ].ErrorValue;
}
}
break;
}
}
return GetOutputVectorItem( 0, outputId, m_propertyName );
}
public override void ReadFromString( ref string[] nodeParams )
{
base.ReadFromString( ref nodeParams );
m_propertyName = GetCurrentParam( ref nodeParams );
m_propertyNameId = Shader.PropertyToID( m_propertyName );
if( UIUtils.CurrentShaderVersion() > TemplatesManager.MPShaderVersion )
{
m_currentScope = (ShaderPropertyScope)Enum.Parse( typeof( ShaderPropertyScope ), GetCurrentParam( ref nodeParams ) );
}
else
{
m_fetchScopeFromProperty = true;
}
m_fetchPropertyId = true;
}
public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
{
base.WriteToString( ref nodeInfo, ref connectionsInfo );
IOUtils.AddFieldValueToString( ref nodeInfo, m_propertyName );
IOUtils.AddFieldValueToString( ref nodeInfo, m_currentScope );
}
public override void OnMasterNodeReplaced( MasterNode newMasterNode )
{
base.OnMasterNodeReplaced( newMasterNode );
if( newMasterNode.CurrentMasterNodeCategory == AvailableShaderTypes.Template )
{
SetTemplate( newMasterNode );
if( m_fetchScopeFromProperty )
{
m_fetchScopeFromProperty = false;
FetchScope();
}
FetchShaderProperties();
FetchPropertyId();
//m_containerGraph.DeleteConnection( false, UniqueId, 0, false, true );
}
}
bool SetTemplate( MasterNode newMasterNode )
{
if( m_containerGraph.MultiPassMasterNodes.NodesList.Count > 0 )
{
m_multiPassMode = true;
TemplateMultiPassMasterNode templateMasterNode = ( newMasterNode as TemplateMultiPassMasterNode );
if( templateMasterNode != null )
{
m_templateMPData = templateMasterNode.CurrentTemplate;
UpdateSubShaderAmount();
FetchShaderProperties();
return true;
}
}
else
{
m_multiPassMode = false;
TemplateMasterNode templateMasterNode = ( newMasterNode as TemplateMasterNode );
if( templateMasterNode != null )
{
m_shaderProperties = templateMasterNode.CurrentTemplate.AvailableShaderProperties;
return true;
}
}
return false;
}
public override void RefreshExternalReferences()
{
base.RefreshExternalReferences();
CheckWarningState();
}
public override void Destroy()
{
base.Destroy();
m_propertyLabels = null;
m_shaderProperties = null;
m_upperLeftWidgetHelper = null;
}
}
}