A game about forced loneliness, made by TACStudios
1using System;
2using System.Linq;
3using System.Collections.Generic;
4using UnityEngine;
5using UnityEngine.Rendering;
6using UnityEngine.UIElements;
7using UnityEditor;
8using UnityEditor.ShaderGraph;
9using UnityEditor.UIElements;
10using UnityEditor.ShaderGraph.Serialization;
11using SubTargetListPool = UnityEngine.Rendering.ListPool<UnityEditor.ShaderGraph.SubTarget>;
12using System.Reflection;
13
14namespace UnityEditor.Rendering.CustomRenderTexture.ShaderGraph
15{
16 [GenerateBlocks]
17 internal struct FullScreenBlocks
18 {
19 // TODO: use base color and alpha blocks
20 public static BlockFieldDescriptor colorBlock = new BlockFieldDescriptor(String.Empty, "Color", "Color",
21 new ColorRGBAControl(UnityEngine.Color.white), ShaderStage.Fragment);
22 }
23
24 sealed class CustomRenderTextureTarget : Target
25 {
26 // Constants
27 const string kAssetGuid = "a0bae34258e39cd4899b63278c24c086"; // FullscreenPassTarget.cs
28
29 // SubTarget
30 List<SubTarget> m_SubTargets;
31 List<string> m_SubTargetNames;
32 int activeSubTargetIndex => m_SubTargets.IndexOf(m_ActiveSubTarget);
33
34 // View
35 PopupField<string> m_SubTargetField;
36 TextField m_CustomGUIField;
37
38 [SerializeField]
39 JsonData<SubTarget> m_ActiveSubTarget;
40
41 [SerializeField]
42 string m_CustomEditorGUI;
43
44 public CustomRenderTextureTarget()
45 {
46 displayName = "Custom Render Texture";
47 isHidden = false;
48 m_SubTargets = GetSubTargets(this);
49 m_SubTargetNames = m_SubTargets.Select(x => x.displayName).ToList();
50 ProcessSubTargetList(ref m_ActiveSubTarget, ref m_SubTargets);
51 }
52
53 public static void ProcessSubTargetList(ref JsonData<SubTarget> activeSubTarget, ref List<SubTarget> subTargets)
54 {
55 if (subTargets == null || subTargets.Count == 0)
56 return;
57
58 // assign the initial sub-target, if none is assigned yet
59 if (activeSubTarget.value == null)
60 activeSubTarget = subTargets[0];
61
62 // Update SubTarget list with active SubTarget
63 var activeSubTargetType = activeSubTarget.value.GetType();
64 var activeSubTargetCurrent = subTargets.FirstOrDefault(x => x.GetType() == activeSubTargetType);
65 var index = subTargets.IndexOf(activeSubTargetCurrent);
66 subTargets[index] = activeSubTarget;
67 }
68
69 public static List<SubTarget> GetSubTargets<T>(T target) where T : Target
70 {
71 // Get Variants
72 var subTargets = SubTargetListPool.Get();
73 var typeCollection = TypeCache.GetTypesDerivedFrom<SubTarget>();
74 foreach (var type in typeCollection)
75 {
76 if (type.IsAbstract || !type.IsClass)
77 continue;
78
79 var subTarget = (SubTarget)Activator.CreateInstance(type);
80 if (!subTarget.isHidden && subTarget.targetType.Equals(typeof(T)))
81 {
82 subTarget.target = target;
83 subTargets.Add(subTarget);
84 }
85 }
86
87 return subTargets;
88 }
89
90 public SubTarget activeSubTarget
91 {
92 get => m_ActiveSubTarget;
93 set => m_ActiveSubTarget = value;
94 }
95
96 public string customEditorGUI
97 {
98 get => m_CustomEditorGUI;
99 set => m_CustomEditorGUI = value;
100 }
101
102 public override bool IsActive() => activeSubTarget.IsActive();
103
104 public override void Setup(ref TargetSetupContext context)
105 {
106 // Setup the Target
107 context.AddAssetDependency(new GUID(kAssetGuid), AssetCollection.Flags.SourceDependency);
108
109 // Setup the active SubTarget
110 ProcessSubTargetList(ref m_ActiveSubTarget, ref m_SubTargets);
111 m_ActiveSubTarget.value.target = this;
112 m_ActiveSubTarget.value.Setup(ref context);
113
114 // Override EditorGUI
115 if (!string.IsNullOrEmpty(m_CustomEditorGUI))
116 {
117 context.SetDefaultShaderGUI(m_CustomEditorGUI);
118 }
119 }
120
121 public override void GetFields(ref TargetFieldContext context)
122 {
123 var descs = context.blocks.Select(x => x.descriptor);
124 // Core fields
125 context.AddField(Fields.GraphVertex, descs.Contains(BlockFields.VertexDescription.Position) ||
126 descs.Contains(BlockFields.VertexDescription.Normal) ||
127 descs.Contains(BlockFields.VertexDescription.Tangent));
128 context.AddField(Fields.GraphPixel);
129
130 // SubTarget fields
131 m_ActiveSubTarget.value.GetFields(ref context);
132 }
133
134 public override void GetActiveBlocks(ref TargetActiveBlockContext context)
135 {
136 // SubTarget blocks
137 m_ActiveSubTarget.value.GetActiveBlocks(ref context);
138 }
139
140 public override void GetPropertiesGUI(ref TargetPropertyGUIContext context, Action onChange, Action<String> registerUndo)
141 {
142 // Core properties
143 m_SubTargetField = new PopupField<string>(m_SubTargetNames, activeSubTargetIndex);
144 context.AddProperty("Material", m_SubTargetField, (evt) =>
145 {
146 if (Equals(activeSubTargetIndex, m_SubTargetField.index))
147 return;
148
149 registerUndo("Change Material");
150 m_ActiveSubTarget = m_SubTargets[m_SubTargetField.index];
151 onChange();
152 });
153
154 // SubTarget properties
155 m_ActiveSubTarget.value.GetPropertiesGUI(ref context, onChange, registerUndo);
156
157 // Custom Editor GUI
158 // Requires FocusOutEvent
159 m_CustomGUIField = new TextField("") { value = customEditorGUI };
160 m_CustomGUIField.RegisterCallback<FocusOutEvent>(s =>
161 {
162 if (Equals(customEditorGUI, m_CustomGUIField.value))
163 return;
164
165 registerUndo("Change Custom Editor GUI");
166 customEditorGUI = m_CustomGUIField.value;
167 onChange();
168 });
169 context.AddProperty("Custom Editor GUI", m_CustomGUIField, (evt) => { });
170 }
171
172 public bool TrySetActiveSubTarget(Type subTargetType)
173 {
174 if (!subTargetType.IsSubclassOf(typeof(SubTarget)))
175 return false;
176
177 foreach (var subTarget in m_SubTargets)
178 {
179 if (subTarget.GetType().Equals(subTargetType))
180 {
181 m_ActiveSubTarget = subTarget;
182 return true;
183 }
184 }
185
186 return false;
187 }
188
189 public override bool WorksWithSRP(RenderPipelineAsset scriptableRenderPipeline) => true;
190
191 public override bool IsNodeAllowedByTarget(System.Type nodeType)
192 {
193 SRPFilterAttribute srpFilter = NodeClassCache.GetAttributeOnNodeType<SRPFilterAttribute>(nodeType);
194 bool allowed = true;
195
196 if (srpFilter != null)
197 allowed = false;
198
199 return allowed && nodeType != typeof(MainLightDirectionNode);
200 }
201 }
202
203 static class FullscreePasses
204 {
205 public static PassDescriptor CustomRenderTexture = new PassDescriptor
206 {
207 // Definition
208 referenceName = "SHADERPASS_CUSTOM_RENDER_TEXTURE",
209 useInPreview = true,
210
211 // Template
212 passTemplatePath = AssetDatabase.GUIDToAssetPath("afa536a0de48246de92194c9e987b0b8"), // CustomTextureSubShader.template
213
214 // Port Mask
215 validVertexBlocks = new BlockFieldDescriptor[]
216 {
217 BlockFields.VertexDescription.Position,
218 BlockFields.VertexDescription.Normal,
219 BlockFields.VertexDescription.Tangent,
220 },
221 validPixelBlocks = new BlockFieldDescriptor[]
222 {
223 BlockFields.SurfaceDescription.BaseColor,
224 BlockFields.SurfaceDescription.Alpha,
225 },
226
227 // Fields
228 structs = new StructCollection
229 {
230 { Structs.Attributes },
231 { Structs.SurfaceDescriptionInputs },
232 { Structs.VertexDescriptionInputs },
233 },
234 requiredFields = new FieldCollection()
235 {
236 StructFields.Attributes.color,
237 StructFields.Attributes.uv0,
238 StructFields.Varyings.color,
239 StructFields.Varyings.texCoord0,
240 },
241 fieldDependencies = new DependencyCollection()
242 {
243 { FieldDependencies.Default },
244 },
245 };
246 }
247}