A game about forced loneliness, made by TACStudios
at master 17 kB view raw
1using UnityEngine; 2using System; 3using System.Collections.Generic; 4using UnityEditor.Graphing; 5using UnityEditor.ShaderGraph.Drawing.Controls; 6using UnityEditor.ShaderGraph.Internal; 7using UnityEngine.Assertions; 8using UnityEngine.UIElements; 9using GraphDataStore = UnityEditor.ShaderGraph.DataStore<UnityEditor.ShaderGraph.GraphData>; 10 11namespace UnityEditor.ShaderGraph.Drawing 12{ 13 class ChangeExposedFlagAction : IGraphDataAction 14 { 15 internal ChangeExposedFlagAction(ShaderInput shaderInput, bool newIsExposed) 16 { 17 this.shaderInputReference = shaderInput; 18 this.newIsExposedValue = newIsExposed; 19 this.oldIsExposedValue = shaderInput.generatePropertyBlock; 20 } 21 22 void ChangeExposedFlag(GraphData graphData) 23 { 24 AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeExposedFlagAction"); 25 AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ChangeExposedFlagAction"); 26 // The Undos are currently handled in ShaderInputPropertyDrawer but we want to move that out from there and handle here 27 //graphData.owner.RegisterCompleteObjectUndo("Change Exposed Toggle"); 28 shaderInputReference.generatePropertyBlock = newIsExposedValue; 29 } 30 31 public Action<GraphData> modifyGraphDataAction => ChangeExposedFlag; 32 33 // Reference to the shader input being modified 34 internal ShaderInput shaderInputReference { get; private set; } 35 36 // New value of whether the shader input should be exposed to the material inspector 37 internal bool newIsExposedValue { get; private set; } 38 internal bool oldIsExposedValue { get; private set; } 39 } 40 41 class ChangePropertyValueAction : IGraphDataAction 42 { 43 void ChangePropertyValue(GraphData graphData) 44 { 45 AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangePropertyValueAction"); 46 AssertHelpers.IsNotNull(shaderInputReference, "ShaderPropertyReference is null while carrying out ChangePropertyValueAction"); 47 // The Undos are currently handled in ShaderInputPropertyDrawer but we want to move that out from there and handle here 48 //graphData.owner.RegisterCompleteObjectUndo("Change Property Value"); 49 var material = graphData.owner.materialArtifact; 50 switch (shaderInputReference) 51 { 52 case BooleanShaderProperty booleanProperty: 53 booleanProperty.value = ((ToggleData)newShaderInputValue).isOn; 54 if (material) material.SetFloat(shaderInputReference.referenceName, booleanProperty.value ? 1.0f : 0.0f); 55 break; 56 case Vector1ShaderProperty vector1Property: 57 vector1Property.value = (float)newShaderInputValue; 58 if (material) material.SetFloat(shaderInputReference.referenceName, vector1Property.value); 59 break; 60 case Vector2ShaderProperty vector2Property: 61 vector2Property.value = (Vector2)newShaderInputValue; 62 if (material) material.SetVector(shaderInputReference.referenceName, vector2Property.value); 63 break; 64 case Vector3ShaderProperty vector3Property: 65 vector3Property.value = (Vector3)newShaderInputValue; 66 if (material) material.SetVector(shaderInputReference.referenceName, vector3Property.value); 67 break; 68 case Vector4ShaderProperty vector4Property: 69 vector4Property.value = (Vector4)newShaderInputValue; 70 if (material) material.SetVector(shaderInputReference.referenceName, vector4Property.value); 71 break; 72 case ColorShaderProperty colorProperty: 73 colorProperty.value = (Color)newShaderInputValue; 74 if (material) material.SetColor(shaderInputReference.referenceName, colorProperty.value); 75 break; 76 case Texture2DShaderProperty texture2DProperty: 77 texture2DProperty.value.texture = (Texture)newShaderInputValue; 78 if (material) material.SetTexture(shaderInputReference.referenceName, texture2DProperty.value.texture); 79 break; 80 case Texture2DArrayShaderProperty texture2DArrayProperty: 81 texture2DArrayProperty.value.textureArray = (Texture2DArray)newShaderInputValue; 82 if (material) material.SetTexture(shaderInputReference.referenceName, texture2DArrayProperty.value.textureArray); 83 break; 84 case Texture3DShaderProperty texture3DProperty: 85 texture3DProperty.value.texture = (Texture3D)newShaderInputValue; 86 if (material) material.SetTexture(shaderInputReference.referenceName, texture3DProperty.value.texture); 87 break; 88 case CubemapShaderProperty cubemapProperty: 89 cubemapProperty.value.cubemap = (Cubemap)newShaderInputValue; 90 if (material) material.SetTexture(shaderInputReference.referenceName, cubemapProperty.value.cubemap); 91 break; 92 case Matrix2ShaderProperty matrix2Property: 93 matrix2Property.value = (Matrix4x4)newShaderInputValue; 94 break; 95 case Matrix3ShaderProperty matrix3Property: 96 matrix3Property.value = (Matrix4x4)newShaderInputValue; 97 break; 98 case Matrix4ShaderProperty matrix4Property: 99 matrix4Property.value = (Matrix4x4)newShaderInputValue; 100 break; 101 case SamplerStateShaderProperty samplerStateProperty: 102 samplerStateProperty.value = (TextureSamplerState)newShaderInputValue; 103 break; 104 case GradientShaderProperty gradientProperty: 105 gradientProperty.value = (Gradient)newShaderInputValue; 106 break; 107 default: 108 throw new ArgumentOutOfRangeException(); 109 } 110 } 111 112 public Action<GraphData> modifyGraphDataAction => ChangePropertyValue; 113 114 // Reference to the shader input being modified 115 internal ShaderInput shaderInputReference { get; set; } 116 117 // New value of the shader property 118 119 internal object newShaderInputValue { get; set; } 120 } 121 122 class ChangeDisplayNameAction : IGraphDataAction 123 { 124 void ChangeDisplayName(GraphData graphData) 125 { 126 AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeDisplayNameAction"); 127 AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ChangeDisplayNameAction"); 128 graphData.owner.RegisterCompleteObjectUndo("Change Display Name"); 129 if (newDisplayNameValue != shaderInputReference.displayName) 130 { 131 shaderInputReference.SetDisplayNameAndSanitizeForGraph(graphData, newDisplayNameValue); 132 } 133 } 134 135 public Action<GraphData> modifyGraphDataAction => ChangeDisplayName; 136 137 // Reference to the shader input being modified 138 internal ShaderInput shaderInputReference { get; set; } 139 140 internal string newDisplayNameValue { get; set; } 141 } 142 143 class ChangeReferenceNameAction : IGraphDataAction 144 { 145 void ChangeReferenceName(GraphData graphData) 146 { 147 AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeReferenceNameAction"); 148 AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ChangeReferenceNameAction"); 149 // The Undos are currently handled in ShaderInputPropertyDrawer but we want to move that out from there and handle here 150 //graphData.owner.RegisterCompleteObjectUndo("Change Reference Name"); 151 if (newReferenceNameValue != shaderInputReference.overrideReferenceName) 152 { 153 graphData.SanitizeGraphInputReferenceName(shaderInputReference, newReferenceNameValue); 154 } 155 } 156 157 public Action<GraphData> modifyGraphDataAction => ChangeReferenceName; 158 159 // Reference to the shader input being modified 160 internal ShaderInput shaderInputReference { get; set; } 161 162 internal string newReferenceNameValue { get; set; } 163 } 164 165 class ResetReferenceNameAction : IGraphDataAction 166 { 167 void ResetReferenceName(GraphData graphData) 168 { 169 AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ResetReferenceNameAction"); 170 AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ResetReferenceNameAction"); 171 graphData.owner.RegisterCompleteObjectUndo("Reset Reference Name"); 172 shaderInputReference.overrideReferenceName = null; 173 } 174 175 public Action<GraphData> modifyGraphDataAction => ResetReferenceName; 176 177 // Reference to the shader input being modified 178 internal ShaderInput shaderInputReference { get; set; } 179 } 180 181 class DeleteShaderInputAction : IGraphDataAction 182 { 183 void DeleteShaderInput(GraphData graphData) 184 { 185 AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out DeleteShaderInputAction"); 186 AssertHelpers.IsNotNull(shaderInputsToDelete, "ShaderInputsToDelete is null while carrying out DeleteShaderInputAction"); 187 // This is called by MaterialGraphView currently, no need to repeat it here, though ideally it would live here 188 //graphData.owner.RegisterCompleteObjectUndo("Delete Graph Input(s)"); 189 190 foreach (var shaderInput in shaderInputsToDelete) 191 { 192 graphData.RemoveGraphInput(shaderInput); 193 } 194 } 195 196 public Action<GraphData> modifyGraphDataAction => DeleteShaderInput; 197 198 // Reference to the shader input(s) being deleted 199 internal IList<ShaderInput> shaderInputsToDelete { get; set; } = new List<ShaderInput>(); 200 } 201 202 class ShaderInputViewController : SGViewController<ShaderInput, ShaderInputViewModel> 203 { 204 // Exposed for PropertyView 205 internal GraphData graphData => DataStore.State; 206 207 internal ShaderInputViewController(ShaderInput shaderInput, ShaderInputViewModel inViewModel, GraphDataStore graphDataStore) 208 : base(shaderInput, inViewModel, graphDataStore) 209 { 210 InitializeViewModel(); 211 212 m_SgBlackboardField = new SGBlackboardField(ViewModel); 213 m_SgBlackboardField.controller = this; 214 215 m_BlackboardRowView = new SGBlackboardRow(m_SgBlackboardField, null); 216 m_BlackboardRowView.expanded = SessionState.GetBool($"Unity.ShaderGraph.Input.{shaderInput.objectId}.isExpanded", false); 217 } 218 219 void InitializeViewModel() 220 { 221 if (Model == null) 222 { 223 AssertHelpers.Fail("Could not initialize shader input view model as shader input was null."); 224 return; 225 } 226 ViewModel.model = Model; 227 ViewModel.isSubGraph = DataStore.State.isSubGraph; 228 ViewModel.isInputExposed = (DataStore.State.isSubGraph || Model.isExposed); 229 ViewModel.inputName = Model.displayName; 230 switch (Model) 231 { 232 case AbstractShaderProperty shaderProperty: 233 ViewModel.inputTypeName = shaderProperty.GetPropertyTypeString(); 234 // Handles upgrade fix for deprecated old Color property 235 shaderProperty.onBeforeVersionChange += (_) => graphData.owner.RegisterCompleteObjectUndo($"Change {shaderProperty.displayName} Version"); 236 break; 237 case ShaderKeyword shaderKeyword: 238 ViewModel.inputTypeName = shaderKeyword.keywordType + " Keyword"; 239 ViewModel.inputTypeName = shaderKeyword.isBuiltIn ? "Built-in " + ViewModel.inputTypeName : ViewModel.inputTypeName; 240 break; 241 case ShaderDropdown shaderDropdown: 242 ViewModel.inputTypeName = "Dropdown"; 243 break; 244 } 245 246 ViewModel.requestModelChangeAction = this.RequestModelChange; 247 } 248 249 SGBlackboardRow m_BlackboardRowView; 250 SGBlackboardField m_SgBlackboardField; 251 252 internal SGBlackboardRow BlackboardItemView => m_BlackboardRowView; 253 254 protected override void RequestModelChange(IGraphDataAction changeAction) 255 { 256 DataStore.Dispatch(changeAction); 257 } 258 259 // Called by GraphDataStore.Subscribe after the model has been changed 260 protected override void ModelChanged(GraphData graphData, IGraphDataAction changeAction) 261 { 262 switch (changeAction) 263 { 264 case ChangeExposedFlagAction changeExposedFlagAction: 265 // ModelChanged is called overzealously on everything 266 // but we only care if the action pertains to our Model 267 if (changeExposedFlagAction.shaderInputReference == Model) 268 { 269 ViewModel.isInputExposed = Model.generatePropertyBlock; 270 if (changeExposedFlagAction.oldIsExposedValue != changeExposedFlagAction.newIsExposedValue) 271 DirtyNodes(ModificationScope.Graph); 272 m_SgBlackboardField.UpdateFromViewModel(); 273 } 274 break; 275 276 case ChangePropertyValueAction changePropertyValueAction: 277 if (changePropertyValueAction.shaderInputReference == Model) 278 { 279 DirtyNodes(ModificationScope.Graph); 280 m_SgBlackboardField.MarkDirtyRepaint(); 281 } 282 break; 283 284 case ResetReferenceNameAction resetReferenceNameAction: 285 if (resetReferenceNameAction.shaderInputReference == Model) 286 { 287 DirtyNodes(ModificationScope.Graph); 288 } 289 break; 290 291 case ChangeReferenceNameAction changeReferenceNameAction: 292 if (changeReferenceNameAction.shaderInputReference == Model) 293 { 294 DirtyNodes(ModificationScope.Graph); 295 } 296 break; 297 298 case ChangeDisplayNameAction changeDisplayNameAction: 299 if (changeDisplayNameAction.shaderInputReference == Model) 300 { 301 ViewModel.inputName = Model.displayName; 302 DirtyNodes(ModificationScope.Layout); 303 m_SgBlackboardField.UpdateFromViewModel(); 304 } 305 break; 306 } 307 } 308 309 // TODO: This should communicate to node controllers instead of searching for the nodes themselves everytime, but that's going to take a while... 310 internal void DirtyNodes(ModificationScope modificationScope = ModificationScope.Node) 311 { 312 foreach (var observer in Model.InputObservers) 313 { 314 observer.OnShaderInputUpdated(modificationScope); 315 } 316 317 switch (Model) 318 { 319 case AbstractShaderProperty property: 320 var graphEditorView = m_BlackboardRowView.GetFirstAncestorOfType<GraphEditorView>(); 321 if (graphEditorView == null) 322 return; 323 var colorManager = graphEditorView.colorManager; 324 var nodes = graphEditorView.graphView.Query<MaterialNodeView>().ToList(); 325 326 colorManager.SetNodesDirty(nodes); 327 colorManager.UpdateNodeViews(nodes); 328 break; 329 case ShaderKeyword keyword: 330 // Cant determine if Sub Graphs contain the keyword so just update them 331 foreach (var node in DataStore.State.GetNodes<SubGraphNode>()) 332 { 333 node.Dirty(modificationScope); 334 } 335 336 break; 337 case ShaderDropdown dropdown: 338 // Cant determine if Sub Graphs contain the dropdown so just update them 339 foreach (var node in DataStore.State.GetNodes<SubGraphNode>()) 340 { 341 node.Dirty(modificationScope); 342 } 343 344 break; 345 default: 346 throw new ArgumentOutOfRangeException(); 347 } 348 } 349 350 public override void Dispose() 351 { 352 if (m_SgBlackboardField == null) 353 return; 354 355 Model?.ClearObservers(); 356 357 base.Dispose(); 358 Cleanup(); 359 360 BlackboardItemView.Dispose(); 361 m_SgBlackboardField.Dispose(); 362 363 m_BlackboardRowView = null; 364 m_SgBlackboardField = null; 365 } 366 } 367}