123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367 |
- using UnityEngine;
- using System;
- using System.Collections.Generic;
- using UnityEditor.Graphing;
- using UnityEditor.ShaderGraph.Drawing.Controls;
- using UnityEditor.ShaderGraph.Internal;
- using UnityEngine.Assertions;
- using UnityEngine.UIElements;
- using GraphDataStore = UnityEditor.ShaderGraph.DataStore<UnityEditor.ShaderGraph.GraphData>;
-
- namespace UnityEditor.ShaderGraph.Drawing
- {
- class ChangeExposedFlagAction : IGraphDataAction
- {
- internal ChangeExposedFlagAction(ShaderInput shaderInput, bool newIsExposed)
- {
- this.shaderInputReference = shaderInput;
- this.newIsExposedValue = newIsExposed;
- this.oldIsExposedValue = shaderInput.generatePropertyBlock;
- }
-
- void ChangeExposedFlag(GraphData graphData)
- {
- AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeExposedFlagAction");
- AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ChangeExposedFlagAction");
- // The Undos are currently handled in ShaderInputPropertyDrawer but we want to move that out from there and handle here
- //graphData.owner.RegisterCompleteObjectUndo("Change Exposed Toggle");
- shaderInputReference.generatePropertyBlock = newIsExposedValue;
- }
-
- public Action<GraphData> modifyGraphDataAction => ChangeExposedFlag;
-
- // Reference to the shader input being modified
- internal ShaderInput shaderInputReference { get; private set; }
-
- // New value of whether the shader input should be exposed to the material inspector
- internal bool newIsExposedValue { get; private set; }
- internal bool oldIsExposedValue { get; private set; }
- }
-
- class ChangePropertyValueAction : IGraphDataAction
- {
- void ChangePropertyValue(GraphData graphData)
- {
- AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangePropertyValueAction");
- AssertHelpers.IsNotNull(shaderInputReference, "ShaderPropertyReference is null while carrying out ChangePropertyValueAction");
- // The Undos are currently handled in ShaderInputPropertyDrawer but we want to move that out from there and handle here
- //graphData.owner.RegisterCompleteObjectUndo("Change Property Value");
- var material = graphData.owner.materialArtifact;
- switch (shaderInputReference)
- {
- case BooleanShaderProperty booleanProperty:
- booleanProperty.value = ((ToggleData)newShaderInputValue).isOn;
- if (material) material.SetFloat(shaderInputReference.referenceName, booleanProperty.value ? 1.0f : 0.0f);
- break;
- case Vector1ShaderProperty vector1Property:
- vector1Property.value = (float)newShaderInputValue;
- if (material) material.SetFloat(shaderInputReference.referenceName, vector1Property.value);
- break;
- case Vector2ShaderProperty vector2Property:
- vector2Property.value = (Vector2)newShaderInputValue;
- if (material) material.SetVector(shaderInputReference.referenceName, vector2Property.value);
- break;
- case Vector3ShaderProperty vector3Property:
- vector3Property.value = (Vector3)newShaderInputValue;
- if (material) material.SetVector(shaderInputReference.referenceName, vector3Property.value);
- break;
- case Vector4ShaderProperty vector4Property:
- vector4Property.value = (Vector4)newShaderInputValue;
- if (material) material.SetVector(shaderInputReference.referenceName, vector4Property.value);
- break;
- case ColorShaderProperty colorProperty:
- colorProperty.value = (Color)newShaderInputValue;
- if (material) material.SetColor(shaderInputReference.referenceName, colorProperty.value);
- break;
- case Texture2DShaderProperty texture2DProperty:
- texture2DProperty.value.texture = (Texture)newShaderInputValue;
- if (material) material.SetTexture(shaderInputReference.referenceName, texture2DProperty.value.texture);
- break;
- case Texture2DArrayShaderProperty texture2DArrayProperty:
- texture2DArrayProperty.value.textureArray = (Texture2DArray)newShaderInputValue;
- if (material) material.SetTexture(shaderInputReference.referenceName, texture2DArrayProperty.value.textureArray);
- break;
- case Texture3DShaderProperty texture3DProperty:
- texture3DProperty.value.texture = (Texture3D)newShaderInputValue;
- if (material) material.SetTexture(shaderInputReference.referenceName, texture3DProperty.value.texture);
- break;
- case CubemapShaderProperty cubemapProperty:
- cubemapProperty.value.cubemap = (Cubemap)newShaderInputValue;
- if (material) material.SetTexture(shaderInputReference.referenceName, cubemapProperty.value.cubemap);
- break;
- case Matrix2ShaderProperty matrix2Property:
- matrix2Property.value = (Matrix4x4)newShaderInputValue;
- break;
- case Matrix3ShaderProperty matrix3Property:
- matrix3Property.value = (Matrix4x4)newShaderInputValue;
- break;
- case Matrix4ShaderProperty matrix4Property:
- matrix4Property.value = (Matrix4x4)newShaderInputValue;
- break;
- case SamplerStateShaderProperty samplerStateProperty:
- samplerStateProperty.value = (TextureSamplerState)newShaderInputValue;
- break;
- case GradientShaderProperty gradientProperty:
- gradientProperty.value = (Gradient)newShaderInputValue;
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
-
- public Action<GraphData> modifyGraphDataAction => ChangePropertyValue;
-
- // Reference to the shader input being modified
- internal ShaderInput shaderInputReference { get; set; }
-
- // New value of the shader property
-
- internal object newShaderInputValue { get; set; }
- }
-
- class ChangeDisplayNameAction : IGraphDataAction
- {
- void ChangeDisplayName(GraphData graphData)
- {
- AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeDisplayNameAction");
- AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ChangeDisplayNameAction");
- graphData.owner.RegisterCompleteObjectUndo("Change Display Name");
- if (newDisplayNameValue != shaderInputReference.displayName)
- {
- shaderInputReference.SetDisplayNameAndSanitizeForGraph(graphData, newDisplayNameValue);
- }
- }
-
- public Action<GraphData> modifyGraphDataAction => ChangeDisplayName;
-
- // Reference to the shader input being modified
- internal ShaderInput shaderInputReference { get; set; }
-
- internal string newDisplayNameValue { get; set; }
- }
-
- class ChangeReferenceNameAction : IGraphDataAction
- {
- void ChangeReferenceName(GraphData graphData)
- {
- AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeReferenceNameAction");
- AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ChangeReferenceNameAction");
- // The Undos are currently handled in ShaderInputPropertyDrawer but we want to move that out from there and handle here
- //graphData.owner.RegisterCompleteObjectUndo("Change Reference Name");
- if (newReferenceNameValue != shaderInputReference.overrideReferenceName)
- {
- graphData.SanitizeGraphInputReferenceName(shaderInputReference, newReferenceNameValue);
- }
- }
-
- public Action<GraphData> modifyGraphDataAction => ChangeReferenceName;
-
- // Reference to the shader input being modified
- internal ShaderInput shaderInputReference { get; set; }
-
- internal string newReferenceNameValue { get; set; }
- }
-
- class ResetReferenceNameAction : IGraphDataAction
- {
- void ResetReferenceName(GraphData graphData)
- {
- AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ResetReferenceNameAction");
- AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out ResetReferenceNameAction");
- graphData.owner.RegisterCompleteObjectUndo("Reset Reference Name");
- shaderInputReference.overrideReferenceName = null;
- }
-
- public Action<GraphData> modifyGraphDataAction => ResetReferenceName;
-
- // Reference to the shader input being modified
- internal ShaderInput shaderInputReference { get; set; }
- }
-
- class DeleteShaderInputAction : IGraphDataAction
- {
- void DeleteShaderInput(GraphData graphData)
- {
- AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out DeleteShaderInputAction");
- AssertHelpers.IsNotNull(shaderInputsToDelete, "ShaderInputsToDelete is null while carrying out DeleteShaderInputAction");
- // This is called by MaterialGraphView currently, no need to repeat it here, though ideally it would live here
- //graphData.owner.RegisterCompleteObjectUndo("Delete Graph Input(s)");
-
- foreach (var shaderInput in shaderInputsToDelete)
- {
- graphData.RemoveGraphInput(shaderInput);
- }
- }
-
- public Action<GraphData> modifyGraphDataAction => DeleteShaderInput;
-
- // Reference to the shader input(s) being deleted
- internal IList<ShaderInput> shaderInputsToDelete { get; set; } = new List<ShaderInput>();
- }
-
- class ShaderInputViewController : SGViewController<ShaderInput, ShaderInputViewModel>
- {
- // Exposed for PropertyView
- internal GraphData graphData => DataStore.State;
-
- internal ShaderInputViewController(ShaderInput shaderInput, ShaderInputViewModel inViewModel, GraphDataStore graphDataStore)
- : base(shaderInput, inViewModel, graphDataStore)
- {
- InitializeViewModel();
-
- m_SgBlackboardField = new SGBlackboardField(ViewModel);
- m_SgBlackboardField.controller = this;
-
- m_BlackboardRowView = new SGBlackboardRow(m_SgBlackboardField, null);
- m_BlackboardRowView.expanded = SessionState.GetBool($"Unity.ShaderGraph.Input.{shaderInput.objectId}.isExpanded", false);
- }
-
- void InitializeViewModel()
- {
- if (Model == null)
- {
- AssertHelpers.Fail("Could not initialize shader input view model as shader input was null.");
- return;
- }
- ViewModel.model = Model;
- ViewModel.isSubGraph = DataStore.State.isSubGraph;
- ViewModel.isInputExposed = (DataStore.State.isSubGraph || Model.isExposed);
- ViewModel.inputName = Model.displayName;
- switch (Model)
- {
- case AbstractShaderProperty shaderProperty:
- ViewModel.inputTypeName = shaderProperty.GetPropertyTypeString();
- // Handles upgrade fix for deprecated old Color property
- shaderProperty.onBeforeVersionChange += (_) => graphData.owner.RegisterCompleteObjectUndo($"Change {shaderProperty.displayName} Version");
- break;
- case ShaderKeyword shaderKeyword:
- ViewModel.inputTypeName = shaderKeyword.keywordType + " Keyword";
- ViewModel.inputTypeName = shaderKeyword.isBuiltIn ? "Built-in " + ViewModel.inputTypeName : ViewModel.inputTypeName;
- break;
- case ShaderDropdown shaderDropdown:
- ViewModel.inputTypeName = "Dropdown";
- break;
- }
-
- ViewModel.requestModelChangeAction = this.RequestModelChange;
- }
-
- SGBlackboardRow m_BlackboardRowView;
- SGBlackboardField m_SgBlackboardField;
-
- internal SGBlackboardRow BlackboardItemView => m_BlackboardRowView;
-
- protected override void RequestModelChange(IGraphDataAction changeAction)
- {
- DataStore.Dispatch(changeAction);
- }
-
- // Called by GraphDataStore.Subscribe after the model has been changed
- protected override void ModelChanged(GraphData graphData, IGraphDataAction changeAction)
- {
- switch (changeAction)
- {
- case ChangeExposedFlagAction changeExposedFlagAction:
- // ModelChanged is called overzealously on everything
- // but we only care if the action pertains to our Model
- if (changeExposedFlagAction.shaderInputReference == Model)
- {
- ViewModel.isInputExposed = Model.generatePropertyBlock;
- if (changeExposedFlagAction.oldIsExposedValue != changeExposedFlagAction.newIsExposedValue)
- DirtyNodes(ModificationScope.Graph);
- m_SgBlackboardField.UpdateFromViewModel();
- }
- break;
-
- case ChangePropertyValueAction changePropertyValueAction:
- if (changePropertyValueAction.shaderInputReference == Model)
- {
- DirtyNodes(ModificationScope.Graph);
- m_SgBlackboardField.MarkDirtyRepaint();
- }
- break;
-
- case ResetReferenceNameAction resetReferenceNameAction:
- if (resetReferenceNameAction.shaderInputReference == Model)
- {
- DirtyNodes(ModificationScope.Graph);
- }
- break;
-
- case ChangeReferenceNameAction changeReferenceNameAction:
- if (changeReferenceNameAction.shaderInputReference == Model)
- {
- DirtyNodes(ModificationScope.Graph);
- }
- break;
-
- case ChangeDisplayNameAction changeDisplayNameAction:
- if (changeDisplayNameAction.shaderInputReference == Model)
- {
- ViewModel.inputName = Model.displayName;
- DirtyNodes(ModificationScope.Layout);
- m_SgBlackboardField.UpdateFromViewModel();
- }
- break;
- }
- }
-
- // TODO: This should communicate to node controllers instead of searching for the nodes themselves everytime, but that's going to take a while...
- internal void DirtyNodes(ModificationScope modificationScope = ModificationScope.Node)
- {
- foreach (var observer in Model.InputObservers)
- {
- observer.OnShaderInputUpdated(modificationScope);
- }
-
- switch (Model)
- {
- case AbstractShaderProperty property:
- var graphEditorView = m_BlackboardRowView.GetFirstAncestorOfType<GraphEditorView>();
- if (graphEditorView == null)
- return;
- var colorManager = graphEditorView.colorManager;
- var nodes = graphEditorView.graphView.Query<MaterialNodeView>().ToList();
-
- colorManager.SetNodesDirty(nodes);
- colorManager.UpdateNodeViews(nodes);
- break;
- case ShaderKeyword keyword:
- // Cant determine if Sub Graphs contain the keyword so just update them
- foreach (var node in DataStore.State.GetNodes<SubGraphNode>())
- {
- node.Dirty(modificationScope);
- }
-
- break;
- case ShaderDropdown dropdown:
- // Cant determine if Sub Graphs contain the dropdown so just update them
- foreach (var node in DataStore.State.GetNodes<SubGraphNode>())
- {
- node.Dirty(modificationScope);
- }
-
- break;
- default:
- throw new ArgumentOutOfRangeException();
- }
- }
-
- public override void Dispose()
- {
- if (m_SgBlackboardField == null)
- return;
-
- Model?.ClearObservers();
-
- base.Dispose();
- Cleanup();
-
- BlackboardItemView.Dispose();
- m_SgBlackboardField.Dispose();
-
- m_BlackboardRowView = null;
- m_SgBlackboardField = null;
- }
- }
- }
|