186 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			186 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|   | using System; | ||
|  | using System.Collections.Generic; | ||
|  | using System.Linq; | ||
|  | using UnityEngine; | ||
|  | using UnityEditor.Graphing; | ||
|  | using UnityEditor.ShaderGraph.Serialization; | ||
|  | 
 | ||
|  | namespace UnityEditor.ShaderGraph | ||
|  | { | ||
|  |     [Serializable] | ||
|  |     [Title("Utility", "Dropdown")] | ||
|  |     class DropdownNode : AbstractMaterialNode, IOnAssetEnabled, IGeneratesBodyCode | ||
|  |     { | ||
|  |         internal const int k_MinEnumEntries = 2; | ||
|  | 
 | ||
|  |         public DropdownNode() | ||
|  |         { | ||
|  |             UpdateNodeAfterDeserialization(); | ||
|  |         } | ||
|  | 
 | ||
|  |         [SerializeField] | ||
|  |         JsonRef<ShaderDropdown> m_Dropdown; | ||
|  | 
 | ||
|  |         public ShaderDropdown dropdown | ||
|  |         { | ||
|  |             get { return m_Dropdown; } | ||
|  |             set | ||
|  |             { | ||
|  |                 if (m_Dropdown == value) | ||
|  |                     return; | ||
|  | 
 | ||
|  |                 m_Dropdown = value; | ||
|  |                 m_Dropdown.value.displayNameUpdateTrigger += UpdateNodeDisplayName; | ||
|  |                 UpdateNode(); | ||
|  |                 Dirty(ModificationScope.Topological); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public override bool canSetPrecision => false; | ||
|  |         public override bool hasPreview => true; | ||
|  |         public const int OutputSlotId = 0; | ||
|  | 
 | ||
|  |         public override bool allowedInMainGraph { get => false; } | ||
|  | 
 | ||
|  |         public void UpdateNodeDisplayName(string newDisplayName) | ||
|  |         { | ||
|  |             MaterialSlot foundSlot = FindSlot<MaterialSlot>(OutputSlotId); | ||
|  | 
 | ||
|  |             if (foundSlot != null) | ||
|  |                 foundSlot.displayName = newDisplayName; | ||
|  |         } | ||
|  | 
 | ||
|  |         public void OnEnable() | ||
|  |         { | ||
|  |             UpdateNode(); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void UpdateNode() | ||
|  |         { | ||
|  |             name = dropdown.displayName; | ||
|  |             UpdatePorts(); | ||
|  |         } | ||
|  | 
 | ||
|  |         void UpdatePorts() | ||
|  |         { | ||
|  |             // Get slots | ||
|  |             List<MaterialSlot> inputSlots = new List<MaterialSlot>(); | ||
|  |             GetInputSlots(inputSlots); | ||
|  | 
 | ||
|  |             // Store the edges | ||
|  |             Dictionary<MaterialSlot, List<IEdge>> edgeDict = new Dictionary<MaterialSlot, List<IEdge>>(); | ||
|  |             foreach (MaterialSlot slot in inputSlots) | ||
|  |                 edgeDict.Add(slot, (List<IEdge>)slot.owner.owner.GetEdges(slot.slotReference)); | ||
|  | 
 | ||
|  |             // Remove old slots | ||
|  |             for (int i = 0; i < inputSlots.Count; i++) | ||
|  |             { | ||
|  |                 RemoveSlot(inputSlots[i].id); | ||
|  |             } | ||
|  | 
 | ||
|  |             // Add output slot | ||
|  |             AddSlot(new DynamicVectorMaterialSlot(OutputSlotId, "Out", "Out", SlotType.Output, Vector4.zero)); | ||
|  | 
 | ||
|  |             // Add input slots | ||
|  |             int[] slotIds = new int[dropdown.entries.Count + 1]; | ||
|  |             slotIds[dropdown.entries.Count] = OutputSlotId; | ||
|  |             for (int i = 0; i < dropdown.entries.Count; i++) | ||
|  |             { | ||
|  |                 // Get slot based on entry id | ||
|  |                 MaterialSlot slot = inputSlots.Where(x => | ||
|  |                     x.id == dropdown.entries[i].id && | ||
|  |                     x.RawDisplayName() == dropdown.entries[i].displayName && | ||
|  |                     x.shaderOutputName == dropdown.entries[i].displayName).FirstOrDefault(); | ||
|  | 
 | ||
|  |                 if (slot == null) | ||
|  |                 { | ||
|  |                     slot = new DynamicVectorMaterialSlot(dropdown.entries[i].id, dropdown.entries[i].displayName, dropdown.entries[i].displayName, SlotType.Input, Vector4.zero); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 AddSlot(slot); | ||
|  |                 slotIds[i] = dropdown.entries[i].id; | ||
|  |             } | ||
|  |             RemoveSlotsNameNotMatching(slotIds); | ||
|  | 
 | ||
|  |             // Reconnect the edges | ||
|  |             foreach (KeyValuePair<MaterialSlot, List<IEdge>> entry in edgeDict) | ||
|  |             { | ||
|  |                 foreach (IEdge edge in entry.Value) | ||
|  |                 { | ||
|  |                     owner.Connect(edge.outputSlot, edge.inputSlot); | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             ValidateNode(); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void GenerateNodeCode(ShaderStringBuilder sb, GenerationMode generationMode) | ||
|  |         { | ||
|  |             var outputSlot = FindOutputSlot<MaterialSlot>(OutputSlotId); | ||
|  | 
 | ||
|  |             bool isGeneratingSubgraph = owner.isSubGraph && (generationMode != GenerationMode.Preview); | ||
|  |             if (generationMode == GenerationMode.Preview || !isGeneratingSubgraph) | ||
|  |             { | ||
|  |                 sb.AppendLine(string.Format($"{outputSlot.concreteValueType.ToShaderString()} {GetVariableNameForSlot(OutputSlotId)};")); | ||
|  |                 var value = GetSlotValue(GetSlotIdForActiveSelection(), generationMode); | ||
|  |                 sb.AppendLine(string.Format($"{GetVariableNameForSlot(OutputSlotId)} = {value};")); | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 // Iterate all entries in the dropdown | ||
|  |                 for (int i = 0; i < dropdown.entries.Count; i++) | ||
|  |                 { | ||
|  |                     if (i == 0) | ||
|  |                     { | ||
|  |                         sb.AppendLine(string.Format($"{outputSlot.concreteValueType.ToShaderString()} {GetVariableNameForSlot(OutputSlotId)};")); | ||
|  |                         sb.AppendLine($"if ({m_Dropdown.value.referenceName} == {i})"); | ||
|  |                     } | ||
|  |                     else | ||
|  |                     { | ||
|  |                         sb.AppendLine($"else if ({m_Dropdown.value.referenceName} == {i})"); | ||
|  |                     } | ||
|  | 
 | ||
|  |                     { | ||
|  |                         sb.AppendLine("{"); | ||
|  |                         sb.IncreaseIndent(); | ||
|  |                         var value = GetSlotValue(GetSlotIdForPermutation(new KeyValuePair<ShaderDropdown, int>(dropdown, i)), generationMode); | ||
|  |                         sb.AppendLine(string.Format($"{GetVariableNameForSlot(OutputSlotId)} = {value};")); | ||
|  |                         sb.DecreaseIndent(); | ||
|  |                         sb.AppendLine("}"); | ||
|  |                     } | ||
|  | 
 | ||
|  |                     if (i == dropdown.entries.Count - 1) | ||
|  |                     { | ||
|  |                         sb.AppendLine($"else"); | ||
|  |                         sb.AppendLine("{"); | ||
|  |                         sb.IncreaseIndent(); | ||
|  |                         var value = GetSlotValue(GetSlotIdForPermutation(new KeyValuePair<ShaderDropdown, int>(dropdown, 0)), generationMode); | ||
|  |                         sb.AppendLine(string.Format($"{GetVariableNameForSlot(OutputSlotId)} = {value};")); | ||
|  |                         sb.DecreaseIndent(); | ||
|  |                         sb.AppendLine("}"); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public int GetSlotIdForPermutation(KeyValuePair<ShaderDropdown, int> permutation) | ||
|  |         { | ||
|  |             return permutation.Key.entries[permutation.Value].id; | ||
|  |         } | ||
|  | 
 | ||
|  |         public int GetSlotIdForActiveSelection() | ||
|  |         { | ||
|  |             return dropdown.entries[dropdown.value].id; | ||
|  |         } | ||
|  | 
 | ||
|  |         protected override void CalculateNodeHasError() | ||
|  |         { | ||
|  |             if (dropdown == null || !owner.dropdowns.Any(x => x == dropdown)) | ||
|  |             { | ||
|  |                 owner.AddConcretizationError(objectId, "Dropdown Node has no associated dropdown."); | ||
|  |                 hasError = true; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |