A game about forced loneliness, made by TACStudios
1using System;
2using System.Linq;
3using System.Collections.Generic;
4using UnityEngine;
5using UnityEditor.ShaderGraph.Internal;
6using UnityEngine.Serialization;
7
8namespace UnityEditor.ShaderGraph
9{
10 [Serializable]
11 class ShaderKeyword : ShaderInput
12 {
13 public const string kVariantLimitWarning = "Graph is generating too many variants. Either delete Keywords, reduce Keyword variants or increase the Shader Variant Limit in Preferences > Shader Graph.";
14
15 public ShaderKeyword()
16 {
17 }
18
19 public ShaderKeyword(KeywordType keywordType)
20 {
21 this.displayName = keywordType.ToString();
22 this.keywordType = keywordType;
23
24 // Add sensible default entries for Enum type
25 if (keywordType == KeywordType.Enum)
26 {
27 m_Entries = new List<KeywordEntry>();
28 m_Entries.Add(new KeywordEntry(1, "A", "A"));
29 m_Entries.Add(new KeywordEntry(2, "B", "B"));
30 m_Entries.Add(new KeywordEntry(3, "C", "C"));
31 }
32 }
33
34 public static ShaderKeyword CreateBuiltInKeyword(KeywordDescriptor descriptor)
35 {
36 if (descriptor.entries != null)
37 {
38 for (int i = 0; i < descriptor.entries.Length; i++)
39 {
40 if (descriptor.entries[i].id == -1)
41 descriptor.entries[i].id = i + 1;
42 }
43 }
44
45 return new ShaderKeyword()
46 {
47 isBuiltIn = true,
48 displayName = descriptor.displayName,
49 overrideReferenceName = descriptor.referenceName,
50 keywordType = descriptor.type,
51 keywordDefinition = descriptor.definition,
52 keywordScope = descriptor.scope,
53 value = descriptor.value,
54 entries = descriptor.entries.ToList(),
55 };
56 }
57
58 [SerializeField]
59 private KeywordType m_KeywordType = KeywordType.Boolean;
60
61 public KeywordType keywordType
62 {
63 get => m_KeywordType;
64 set => m_KeywordType = value;
65 }
66
67 [SerializeField]
68 private KeywordDefinition m_KeywordDefinition = KeywordDefinition.ShaderFeature;
69
70 public KeywordDefinition keywordDefinition
71 {
72 get => m_KeywordDefinition;
73 set => m_KeywordDefinition = value;
74 }
75
76 [SerializeField]
77 private KeywordScope m_KeywordScope = KeywordScope.Local;
78
79 public KeywordScope keywordScope
80 {
81 get => m_KeywordScope;
82 set => m_KeywordScope = value;
83 }
84
85 [SerializeField]
86 private KeywordShaderStage m_KeywordStages = KeywordShaderStage.All;
87
88 public KeywordShaderStage keywordStages
89 {
90 get => m_KeywordStages;
91 set => m_KeywordStages = value;
92 }
93
94 [SerializeField]
95 private List<KeywordEntry> m_Entries;
96
97 public List<KeywordEntry> entries
98 {
99 get => m_Entries;
100 set => m_Entries = value;
101 }
102
103 [SerializeField]
104 private int m_Value;
105
106 public int value
107 {
108 get => m_Value;
109 set => m_Value = value;
110 }
111
112 [SerializeField]
113 private bool m_IsEditable = true; // this serializes !isBuiltIn
114
115 public bool isBuiltIn
116 {
117 get => !m_IsEditable;
118 set => m_IsEditable = !value;
119 }
120
121 internal override bool isCustomSlotAllowed => false;
122
123 internal override bool isExposable => !isBuiltIn && (keywordDefinition != KeywordDefinition.Predefined);
124
125 internal override bool isRenamable => !isBuiltIn;
126
127 internal override ConcreteSlotValueType concreteShaderValueType => keywordType.ToConcreteSlotValueType();
128
129 public override string GetOldDefaultReferenceName()
130 {
131 // _ON suffix is required for exposing Boolean type to Material
132 var suffix = string.Empty;
133 if (keywordType == KeywordType.Boolean)
134 {
135 suffix = "_ON";
136 }
137
138 return $"{keywordType.ToString()}_{objectId}{suffix}".ToUpper();
139 }
140
141 public void AppendPropertyBlockStrings(ShaderStringBuilder builder)
142 {
143 if (isExposed)
144 {
145 switch (keywordType)
146 {
147 case KeywordType.Enum:
148 string enumTagString = $"[KeywordEnum({string.Join(", ", entries.Select(x => x.displayName))})]";
149 builder.AppendLine($"{enumTagString}{referenceName}(\"{displayName}\", Float) = {value}");
150 break;
151 case KeywordType.Boolean:
152 if (referenceName.EndsWith("_ON"))
153 builder.AppendLine($"[Toggle]{referenceName.Remove(referenceName.Length - 3, 3)}(\"{displayName}\", Float) = {value}");
154 else
155 builder.AppendLine($"[Toggle({referenceName})]{referenceName}(\"{displayName}\", Float) = {value}");
156 break;
157 default:
158 break;
159 }
160 }
161 }
162
163 public void AppendKeywordDeclarationStrings(ShaderStringBuilder builder)
164 {
165 if (keywordDefinition != KeywordDefinition.Predefined)
166 {
167 if (keywordType == KeywordType.Boolean)
168 KeywordUtil.GenerateBooleanKeywordPragmaStrings(referenceName, keywordDefinition, keywordScope, keywordStages, str => builder.AppendLine(str));
169 else
170 KeywordUtil.GenerateEnumKeywordPragmaStrings(referenceName, keywordDefinition, keywordScope, keywordStages, entries, str => builder.AppendLine(str));
171 }
172 }
173
174 public string GetKeywordPreviewDeclarationString()
175 {
176 switch (keywordType)
177 {
178 case KeywordType.Boolean:
179 return value == 1 ? $"#define {referenceName}" : string.Empty;
180 case KeywordType.Enum:
181 return $"#define {referenceName}_{entries[value].referenceName}";
182 default:
183 throw new ArgumentOutOfRangeException();
184 }
185 }
186
187 internal override ShaderInput Copy()
188 {
189 // Keywords copy reference name
190 // This is because keywords are copied between graphs
191 // When copying dependent nodes
192 return new ShaderKeyword()
193 {
194 displayName = displayName,
195 value = value,
196 isBuiltIn = isBuiltIn,
197 keywordType = keywordType,
198 keywordDefinition = keywordDefinition,
199 keywordScope = keywordScope,
200 entries = entries,
201 keywordStages = keywordStages,
202 overrideReferenceName = overrideReferenceName
203 };
204 }
205
206 public override int latestVersion => 1;
207 public override void OnAfterDeserialize(string json)
208 {
209 if (sgVersion == 0)
210 {
211 // we now allow keywords to control whether they are exposed (for Material control) or not.
212 // old exposable keywords set their exposed state to maintain previous behavior
213 // (where bool keywords only showed up in the material when ending in "_ON")
214 if (isExposable)
215 {
216 if (m_KeywordType == KeywordType.Boolean)
217 generatePropertyBlock = referenceName.EndsWith("_ON");
218 else // KeywordType.Enum
219 generatePropertyBlock = true;
220 }
221 ChangeVersion(1);
222 }
223 }
224 }
225}