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.
 
 
 

516 lines
15 KiB

// Amplify Shader Editor - Visual Shader Editing Tool
// Copyright (c) Amplify Creations, Lda <info@amplify.pt>
using UnityEngine;
using UnityEditor;
using System;
using System.Collections.Generic;
namespace AmplifyShaderEditor
{
[Serializable]
public class DynamicTypeNode : ParentNode
{
protected string m_inputA = string.Empty;
protected string m_inputB = string.Empty;
protected List<string> m_extensibleInputResults;
protected bool m_dynamicOutputType = true;
protected bool m_extensibleInputPorts = false;
protected bool m_allowMatrixCheck = false;
protected bool m_vectorMatrixOps = false;
//[SerializeField]
private int m_inputCount = 2;
//[SerializeField]
private int m_lastInputCount = 2;
private bool m_previouslyDragging = false;
private int m_beforePreviewCount = 0;
[UnityEngine.SerializeField]
protected WirePortDataType m_mainDataType = WirePortDataType.FLOAT;
protected WirePortDataType[] m_dynamicRestrictions =
{
WirePortDataType.OBJECT,
WirePortDataType.FLOAT,
WirePortDataType.FLOAT2,
WirePortDataType.FLOAT3,
WirePortDataType.FLOAT4,
WirePortDataType.COLOR,
WirePortDataType.INT
};
protected override void CommonInit( int uniqueId )
{
base.CommonInit( uniqueId );
m_useInternalPortData = true;
m_textLabelWidth = 35;
AddPorts();
}
protected virtual void AddPorts()
{
AddInputPort( WirePortDataType.FLOAT, false, "A" );
AddInputPort( WirePortDataType.FLOAT, false, "B" );
AddOutputPort( WirePortDataType.FLOAT, Constants.EmptyPortValue );
m_inputPorts[ 0 ].CreatePortRestrictions( m_dynamicRestrictions );
m_inputPorts[ 1 ].CreatePortRestrictions( m_dynamicRestrictions );
}
public override void OnConnectedOutputNodeChanges( int inputPortId, int otherNodeId, int otherPortId, string name, WirePortDataType type )
{
UpdateConnection( inputPortId );
}
public override void OnInputPortConnected( int portId, int otherNodeId, int otherPortId, bool activateNode = true )
{
base.OnInputPortConnected( portId, otherNodeId, otherPortId, activateNode );
UpdateConnection( portId );
}
public override void OnInputPortDisconnected( int portId )
{
base.OnInputPortDisconnected( portId );
UpdateDisconnectedConnection( portId );
UpdateConnection( portId );
UpdateEmptyInputPorts( true );
}
void UpdateDisconnectedConnection( int portId )
{
if( m_extensibleInputPorts || m_allowMatrixCheck )
{
int higher = 0;
int groupOneType = 0;
int groupTwoType = 0;
for( int i = 0; i < m_inputPorts.Count; i++ )
{
if( m_inputPorts[ i ].IsConnected )
{
int currentPriority = UIUtils.GetPriority( m_inputPorts[ i ].DataType );
if( !m_vectorMatrixOps && currentPriority < 3 )
currentPriority += 7;
if( currentPriority > higher && currentPriority > 2 )
{
higher = currentPriority;
m_mainDataType = m_inputPorts[ i ].DataType;
}
switch( m_inputPorts[ i ].DataType )
{
case WirePortDataType.FLOAT2:
case WirePortDataType.FLOAT3:
case WirePortDataType.FLOAT4:
case WirePortDataType.COLOR:
{
groupOneType++;
groupTwoType++;
}
break;
case WirePortDataType.FLOAT3x3:
{
groupOneType++;
}
break;
case WirePortDataType.FLOAT4x4:
{
groupTwoType++;
}
break;
}
}
}
for( int i = 0; i < m_inputPorts.Count; i++ )
{
if( !m_inputPorts[ i ].IsConnected )
{
m_inputPorts[ i ].ChangeType( m_mainDataType, false );
}
}
if( groupOneType > 0 && m_mainDataType == WirePortDataType.FLOAT4x4 )
{
m_errorMessageTooltip = "Doing this operation with FLOAT4x4 value only works against other FLOAT4x4 or FLOAT values";
m_showErrorMessage = true;
}
else if( groupTwoType > 0 && m_mainDataType == WirePortDataType.FLOAT3x3 )
{
m_errorMessageTooltip = "Doing this operation with FLOAT3x3 value only works against other FLOAT3x3 or FLOAT values";
m_showErrorMessage = true;
}
else
{
m_showErrorMessage = false;
}
if( m_dynamicOutputType )
m_outputPorts[ 0 ].ChangeType( m_mainDataType, false );
}
else
if( m_inputPorts[ 0 ].DataType != m_inputPorts[ 1 ].DataType )
{
int otherPortId = ( portId + 1 ) % 2;
if( m_inputPorts[ otherPortId ].IsConnected )
{
m_mainDataType = m_inputPorts[ otherPortId ].DataType;
m_inputPorts[ portId ].ChangeType( m_mainDataType, false );
if( m_dynamicOutputType )
m_outputPorts[ 0 ].ChangeType( m_mainDataType, false );
}
else
{
if( UIUtils.GetPriority( m_inputPorts[ 0 ].DataType ) > UIUtils.GetPriority( m_inputPorts[ 1 ].DataType ) )
{
m_mainDataType = m_inputPorts[ 0 ].DataType;
m_inputPorts[ 1 ].ChangeType( m_mainDataType, false );
}
else
{
m_mainDataType = m_inputPorts[ 1 ].DataType;
m_inputPorts[ 0 ].ChangeType( m_mainDataType, false );
}
if( m_dynamicOutputType )
{
if( m_mainDataType != m_outputPorts[ 0 ].DataType )
{
m_outputPorts[ 0 ].ChangeType( m_mainDataType, false );
}
}
}
}
}
void UpdateConnection( int portId )
{
if( m_extensibleInputPorts || m_allowMatrixCheck )
{
m_inputPorts[ portId ].MatchPortToConnection();
int higher = 0;
int groupOneType = 0;
int groupTwoType = 0;
for( int i = 0; i < m_inputPorts.Count; i++ )
{
if( m_inputPorts[ i ].IsConnected )
{
int currentPriority = UIUtils.GetPriority( m_inputPorts[ i ].DataType );
if( !m_vectorMatrixOps && currentPriority < 3 )
currentPriority += 7;
if( currentPriority > higher )
{
higher = currentPriority;
m_mainDataType = m_inputPorts[ i ].DataType;
}
switch( m_inputPorts[ i ].DataType )
{
case WirePortDataType.FLOAT2:
case WirePortDataType.FLOAT3:
case WirePortDataType.FLOAT4:
case WirePortDataType.COLOR:
{
groupOneType++;
groupTwoType++;
}
break;
case WirePortDataType.FLOAT3x3:
{
groupOneType++;
}
break;
case WirePortDataType.FLOAT4x4:
{
groupTwoType++;
}
break;
}
}
}
for( int i = 0; i < m_inputPorts.Count; i++ )
{
if( !m_inputPorts[ i ].IsConnected )
{
m_inputPorts[ i ].ChangeType( m_mainDataType, false );
}
}
if( groupOneType > 0 && m_mainDataType == WirePortDataType.FLOAT4x4 )
{
m_errorMessageTooltip = "Doing this operation with FLOAT4x4 value only works against other FLOAT4x4 or FLOAT values";
m_showErrorMessage = true;
}
else if( groupTwoType > 0 && m_mainDataType == WirePortDataType.FLOAT3x3 )
{
m_errorMessageTooltip = "Doing this operation with FLOAT3x3 value only works against other FLOAT3x3 or FLOAT values";
m_showErrorMessage = true;
}
else
{
m_showErrorMessage = false;
}
if( m_dynamicOutputType )
m_outputPorts[ 0 ].ChangeType( m_mainDataType, false );
}
else
{
m_inputPorts[ portId ].MatchPortToConnection();
int otherPortId = ( portId + 1 ) % 2;
if( !m_inputPorts[ otherPortId ].IsConnected )
{
m_inputPorts[ otherPortId ].ChangeType( m_inputPorts[ portId ].DataType, false );
}
if( m_inputPorts[ 0 ].DataType == m_inputPorts[ 1 ].DataType )
{
m_mainDataType = m_inputPorts[ 0 ].DataType;
if( m_dynamicOutputType )
m_outputPorts[ 0 ].ChangeType( InputPorts[ 0 ].DataType, false );
}
else
{
if( UIUtils.GetPriority( m_inputPorts[ 0 ].DataType ) > UIUtils.GetPriority( m_inputPorts[ 1 ].DataType ) )
{
m_mainDataType = m_inputPorts[ 0 ].DataType;
}
else
{
m_mainDataType = m_inputPorts[ 1 ].DataType;
}
if( m_dynamicOutputType )
{
if( m_mainDataType != m_outputPorts[ 0 ].DataType )
{
m_outputPorts[ 0 ].ChangeType( m_mainDataType, false );
}
}
}
}
}
public override void OnNodeLayout( DrawInfo drawInfo )
{
base.OnNodeLayout( drawInfo );
if( !m_extensibleInputPorts )
return;
if( m_previouslyDragging != m_containerGraph.ParentWindow.WireReferenceUtils.OutputPortReference.IsValid && m_containerGraph.ParentWindow.WireReferenceUtils.OutputPortReference.NodeId != UniqueId )
{
if( m_containerGraph.ParentWindow.WireReferenceUtils.OutputPortReference.IsValid )
{
m_beforePreviewCount = 2;
for( int i = 2; i < m_inputPorts.Count; i++ )
{
if( m_inputPorts[ i ].IsConnected )
{
m_beforePreviewCount++;
}
}
m_inputCount = m_beforePreviewCount + 1;
if( m_inputCount <= 10 )
{
if( m_inputCount > m_lastInputCount )
{
Undo.RegisterCompleteObjectUndo( m_containerGraph.ParentWindow, Constants.UndoCreateDynamicPortId );
RecordObject( Constants.UndoCreateDynamicPortId );
AddInputPort( m_mainDataType, false, ( ( char ) ( 'A' + m_inputCount - 1 ) ).ToString() );
m_inputPorts[ m_inputCount - 1 ].CreatePortRestrictions( m_dynamicRestrictions );
if( Selected && ContainerGraph.ParentWindow.ParametersWindow.IsMaximized )
Event.current.type = EventType.Used;
}
m_lastInputCount = m_inputCount;
m_sizeIsDirty = true;
m_isDirty = true;
SetSaveIsDirty();
}
}
else
{
bool hasEmpty = CheckValidConnections();
if( hasEmpty )
UpdateEmptyInputPorts( false );
}
m_previouslyDragging = m_containerGraph.ParentWindow.WireReferenceUtils.OutputPortReference.IsValid;
}
UpdateEmptyInputPorts( false );
}
private bool CheckValidConnections()
{
if( !m_extensibleInputPorts )
return false;
bool hasEmptyConnections = false;
bool hasMatrix = m_inputPorts[ 0 ].DataType == WirePortDataType.FLOAT3x3 || m_inputPorts[ 0 ].DataType == WirePortDataType.FLOAT4x4 || m_inputPorts[ 1 ].DataType == WirePortDataType.FLOAT3x3 || m_inputPorts[ 1 ].DataType == WirePortDataType.FLOAT4x4;
if( m_inputPorts.Count != m_beforePreviewCount )
{
if( hasMatrix )
{
bool showError = false;
for( int i = m_inputPorts.Count - 1; i >= 2; i-- )
{
if( m_inputPorts[ i ].IsConnected )
{
showError = true;
m_inputPorts[ i ].FullDeleteConnections();
}
hasEmptyConnections = true;
}
if( showError )
m_containerGraph.ParentWindow.ShowMessage( "Matrix operations are only valid for the first two inputs to prevent errors" );
}
else
{
for( int i = m_inputPorts.Count - 1; i >= 2; i-- )
{
if( m_inputPorts[ i ].DataType == WirePortDataType.FLOAT3x3 || m_inputPorts[ i ].DataType == WirePortDataType.FLOAT4x4 )
{
m_containerGraph.ParentWindow.ShowMessage( "Matrix operations are only valid for the first two inputs to prevent errors" );
m_inputPorts[ i ].FullDeleteConnections();
hasEmptyConnections = true;
}
else if( !m_inputPorts[ i ].IsConnected )
{
hasEmptyConnections = true;
}
}
}
}
return hasEmptyConnections;
}
private void UpdateEmptyInputPorts( bool recordUndo )
{
if( !m_extensibleInputPorts )
return;
if( !m_containerGraph.ParentWindow.WireReferenceUtils.OutputPortReference.IsValid )
{
if( recordUndo )
{
Undo.RegisterCompleteObjectUndo( m_containerGraph.ParentWindow, Constants.UndoDeleteDynamicPortId );
RecordObject( Constants.UndoDeleteDynamicPortId );
}
bool hasDeleted = false;
m_inputCount = 2;
for( int i = m_inputPorts.Count - 1; i >= 2; i-- )
{
if( !m_inputPorts[ i ].IsConnected )
{
hasDeleted = true;
DeleteInputPortByArrayIdx( i );
}
else
{
m_inputCount++;
}
}
if( hasDeleted || m_inputCount != m_lastInputCount )
{
for( int i = 2; i < m_inputPorts.Count; i++ )
{
m_inputPorts[ i ].Name = ( ( char ) ( 'A' + i ) ).ToString();
}
m_beforePreviewCount = m_inputPorts.Count;
m_inputCount = m_beforePreviewCount;
m_lastInputCount = m_inputCount;
m_sizeIsDirty = true;
m_isDirty = true;
SetSaveIsDirty();
}
}
m_inputCount = Mathf.Clamp( m_inputCount, 2, 10 );
}
public virtual string BuildResults( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
{
if( !m_extensibleInputPorts )
SetInputData( outputId, ref dataCollector, ignoreLocalvar );
else
SetExtensibleInputData( outputId, ref dataCollector, ignoreLocalvar );
return string.Empty;
}
public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
{
string result = BuildResults( outputId, ref dataCollector, ignoreLocalvar );
return CreateOutputLocalVariable( 0, result, ref dataCollector );
}
protected void SetInputData( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
{
m_inputA = m_inputPorts[ 0 ].GeneratePortInstructions( ref dataCollector );
if( m_inputPorts[ 0 ].DataType != m_mainDataType )
{
m_inputA = UIUtils.CastPortType( ref dataCollector, m_currentPrecisionType, new NodeCastInfo( UniqueId, outputId ), m_inputA, m_inputPorts[ 0 ].DataType, m_mainDataType, m_inputA );
}
m_inputB = m_inputPorts[ 1 ].GeneratePortInstructions( ref dataCollector );
if( m_inputPorts[ 1 ].DataType != m_mainDataType )
{
m_inputB = UIUtils.CastPortType( ref dataCollector, m_currentPrecisionType, new NodeCastInfo( UniqueId, outputId ), m_inputB, m_inputPorts[ 1 ].DataType, m_mainDataType, m_inputB );
}
}
protected void SetExtensibleInputData( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
{
m_extensibleInputResults = new List<string>();
for( int i = 0; i < m_inputPorts.Count; i++ )
{
m_extensibleInputResults.Add( m_inputPorts[ i ].GeneratePortInstructions( ref dataCollector ) );
if( m_inputPorts[ i ].DataType != m_mainDataType && m_inputPorts[ i ].DataType != WirePortDataType.FLOAT && m_inputPorts[ i ].DataType != WirePortDataType.INT )
{
m_extensibleInputResults[ i ] = UIUtils.CastPortType( ref dataCollector, m_currentPrecisionType, new NodeCastInfo( UniqueId, outputId ), m_extensibleInputResults[ i ], m_inputPorts[ i ].DataType, m_mainDataType, m_extensibleInputResults[ i ] );
}
}
}
void UpdatePorts()
{
m_lastInputCount = Mathf.Clamp( m_inputCount, 2, 10 );
for( int i = 2; i < m_inputCount; i++ )
{
AddInputPort( m_mainDataType, false, ( ( char ) ( 'A' + i ) ).ToString() );
m_inputPorts[ i ].CreatePortRestrictions( m_dynamicRestrictions );
}
m_sizeIsDirty = true;
SetSaveIsDirty();
}
public override void ReadFromString( ref string[] nodeParams )
{
base.ReadFromString( ref nodeParams );
if( m_extensibleInputPorts && UIUtils.CurrentShaderVersion() > 10005 )
{
m_inputCount = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
UpdatePorts();
}
}
public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
{
base.WriteToString( ref nodeInfo, ref connectionsInfo );
if( m_extensibleInputPorts )
IOUtils.AddFieldValueToString( ref nodeInfo, m_inputCount );
}
}
}