A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Reflection;
5using UnityEditor.ShaderGraph.Drawing;
6using UnityEngine;
7using UnityEditor.Graphing;
8using UnityEditor.Rendering;
9using UnityEngine.Rendering.ShaderGraph;
10using UnityEngine.UIElements;
11
12namespace UnityEditor.ShaderGraph
13{
14 class SubGraphOutputNode : AbstractMaterialNode
15 {
16 static string s_MissingOutputSlot = "A Sub Graph must have at least one output slot";
17 static List<ConcreteSlotValueType> s_ValidSlotTypes = new List<ConcreteSlotValueType>()
18 {
19 ConcreteSlotValueType.Vector1,
20 ConcreteSlotValueType.Vector2,
21 ConcreteSlotValueType.Vector3,
22 ConcreteSlotValueType.Vector4,
23 ConcreteSlotValueType.Matrix2,
24 ConcreteSlotValueType.Matrix3,
25 ConcreteSlotValueType.Matrix4,
26 ConcreteSlotValueType.Boolean
27 };
28 public bool IsFirstSlotValid = true;
29
30 public SubGraphOutputNode()
31 {
32 name = "Output";
33 }
34
35 // Link to the Sub Graph overview page instead of the specific Node page, seems more useful
36 public override string documentationURL => Documentation.GetPageLink("Sub-graph");
37
38 void ValidateShaderStage()
39 {
40 List<MaterialSlot> slots = new List<MaterialSlot>();
41 GetInputSlots(slots);
42
43 // Reset all input slots back to All, otherwise they'll be incorrectly configured when traversing below
44 foreach (MaterialSlot slot in slots)
45 slot.stageCapability = ShaderStageCapability.All;
46
47 foreach (var slot in slots)
48 {
49 slot.stageCapability = NodeUtils.GetEffectiveShaderStageCapability(slot, true);
50 }
51 }
52
53 void ValidateSlotName()
54 {
55 List<MaterialSlot> slots = new List<MaterialSlot>();
56 GetInputSlots(slots);
57
58 foreach (var slot in slots)
59 {
60 var error = NodeUtils.ValidateSlotName(slot.RawDisplayName(), out string errorMessage);
61 if (error)
62 {
63 owner.AddValidationError(objectId, errorMessage);
64 break;
65 }
66 }
67 }
68
69 void ValidateSlotType()
70 {
71 List<MaterialSlot> slots = new List<MaterialSlot>();
72 GetInputSlots(slots);
73
74 if (!slots.Any())
75 {
76 owner.AddValidationError(objectId, s_MissingOutputSlot, ShaderCompilerMessageSeverity.Error);
77 }
78 else if (!s_ValidSlotTypes.Contains(slots.FirstOrDefault().concreteValueType))
79 {
80 IsFirstSlotValid = false;
81 owner.AddValidationError(objectId, "Preview can only compile if the first output slot is a Vector, Matrix, or Boolean type. Please adjust slot types.", ShaderCompilerMessageSeverity.Error);
82 }
83 }
84
85 public override void ValidateNode()
86 {
87 base.ValidateNode();
88 IsFirstSlotValid = true;
89 ValidateSlotType();
90 if (IsFirstSlotValid)
91 ValidateShaderStage();
92 }
93
94 protected override void OnSlotsChanged()
95 {
96 base.OnSlotsChanged();
97 ValidateNode();
98 }
99
100 public int AddSlot(ConcreteSlotValueType concreteValueType)
101 {
102 var index = this.GetInputSlots<MaterialSlot>().Count() + 1;
103 var name = NodeUtils.GetDuplicateSafeNameForSlot(this, index, "Out_" + concreteValueType.ToString());
104 AddSlot(MaterialSlot.CreateMaterialSlot(concreteValueType.ToSlotValueType(), index, name,
105 NodeUtils.GetHLSLSafeName(name), SlotType.Input, Vector4.zero));
106 return index;
107 }
108
109 public override bool canDeleteNode => false;
110
111 public override bool canCopyNode => false;
112 }
113}