123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- using UnityEditor.Graphing;
- using UnityEditor.ShaderGraph.Drawing;
- using UnityEditor.ShaderGraph.Serialization;
-
- namespace UnityEditor.ShaderGraph
- {
- [Serializable]
- [Title("Utility", "Dropdown")]
- class DropdownNode : AbstractMaterialNode, IOnAssetEnabled, IGeneratesBodyCode, IShaderInputObserver
- {
- 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;
- 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;
- }
- }
-
- public void OnShaderInputUpdated(ModificationScope modificationScope)
- {
- UpdateNode();
- Dirty(modificationScope);
-
- if(modificationScope == ModificationScope.Layout)
- UpdateNodeDisplayName(dropdown.displayName);
- }
- }
- }
|