using System; using System.Collections.Generic; using System.Linq; using UnityEditor.ShaderGraph.Drawing; using UnityEditor.ShaderGraph.Internal; using UnityEditor.ShaderGraph.Serialization; using UnityEngine; namespace UnityEditor.ShaderGraph { class ConvertToPropertyAction : IGraphDataAction { void ConvertToProperty(GraphData graphData) { AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ConvertToPropertyAction"); AssertHelpers.IsNotNull(inlinePropertiesToConvert, "InlinePropertiesToConvert is null while carrying out ConvertToPropertyAction"); graphData.owner.RegisterCompleteObjectUndo("Convert to Property"); var defaultCategory = graphData.categories.FirstOrDefault(); AssertHelpers.IsNotNull(defaultCategory, "Default Category is null while carrying out ConvertToPropertyAction"); foreach (var converter in inlinePropertiesToConvert) { var convertedProperty = converter.AsShaderProperty(); var node = converter as AbstractMaterialNode; graphData.AddGraphInput(convertedProperty); // Also insert this input into the default category if (defaultCategory != null) { var addItemToCategoryAction = new AddItemToCategoryAction(); addItemToCategoryAction.categoryGuid = defaultCategory.categoryGuid; addItemToCategoryAction.itemToAdd = convertedProperty; graphData.owner.graphDataStore.Dispatch(addItemToCategoryAction); } // Add reference to converted property for use in responding to this action later convertedPropertyReferences.Add(convertedProperty); var propNode = new PropertyNode(); propNode.drawState = node.drawState; propNode.group = node.group; graphData.AddNode(propNode); propNode.property = convertedProperty; var oldSlot = node.FindSlot(converter.outputSlotId); var newSlot = propNode.FindSlot(PropertyNode.OutputSlotId); foreach (var edge in graphData.GetEdges(oldSlot.slotReference)) graphData.Connect(newSlot.slotReference, edge.inputSlot); graphData.RemoveNode(node); } } public Action modifyGraphDataAction => ConvertToProperty; public IList inlinePropertiesToConvert { get; set; } = new List(); public IList convertedPropertyReferences { get; set; } = new List(); public Vector2 nodePsition { get; set; } } class ConvertToInlineAction : IGraphDataAction { void ConvertToInline(GraphData graphData) { AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ConvertToInlineAction"); AssertHelpers.IsNotNull(propertyNodesToConvert, "PropertyNodesToConvert is null while carrying out ConvertToInlineAction"); graphData.owner.RegisterCompleteObjectUndo("Convert to Inline Node"); foreach (var propertyNode in propertyNodesToConvert) graphData.ReplacePropertyNodeWithConcreteNode(propertyNode); } public Action modifyGraphDataAction => ConvertToInline; public IEnumerable propertyNodesToConvert { get; set; } = new List(); } class DragGraphInputAction : IGraphDataAction { void DragGraphInput(GraphData graphData) { AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out DragGraphInputAction"); AssertHelpers.IsNotNull(graphInputBeingDraggedIn, "GraphInputBeingDraggedIn is null while carrying out DragGraphInputAction"); graphData.owner.RegisterCompleteObjectUndo("Drag Graph Input"); switch (graphInputBeingDraggedIn) { case AbstractShaderProperty property: { if (property is MultiJsonInternal.UnknownShaderPropertyType) break; // This could be from another graph, in which case we add a copy of the ShaderInput to this graph. if (graphData.properties.FirstOrDefault(p => p == property) == null) { var copyShaderInputAction = new CopyShaderInputAction(); copyShaderInputAction.shaderInputToCopy = property; graphData.owner.graphDataStore.Dispatch(copyShaderInputAction); property = (AbstractShaderProperty)copyShaderInputAction.copiedShaderInput; } var node = new PropertyNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; node.property = property; // this did come after, but it's not clear why. graphData.AddNode(node); break; } case ShaderKeyword keyword: { // This could be from another graph, in which case we add a copy of the ShaderInput to this graph. if (graphData.keywords.FirstOrDefault(k => k == keyword) == null) { var copyShaderInputAction = new CopyShaderInputAction(); copyShaderInputAction.shaderInputToCopy = keyword; graphData.owner.graphDataStore.Dispatch(copyShaderInputAction); keyword = (ShaderKeyword)copyShaderInputAction.copiedShaderInput; } var node = new KeywordNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; node.keyword = keyword; graphData.AddNode(node); break; } case ShaderDropdown dropdown: { if (graphData.IsInputAllowedInGraph(dropdown)) { // This could be from another graph, in which case we add a copy of the ShaderInput to this graph. if (graphData.dropdowns.FirstOrDefault(d => d == dropdown) == null) { var copyShaderInputAction = new CopyShaderInputAction(); copyShaderInputAction.shaderInputToCopy = dropdown; graphData.owner.graphDataStore.Dispatch(copyShaderInputAction); dropdown = (ShaderDropdown)copyShaderInputAction.copiedShaderInput; } var node = new DropdownNode(); var drawState = node.drawState; drawState.position = new Rect(nodePosition, drawState.position.size); node.drawState = drawState; node.dropdown = dropdown; graphData.AddNode(node); } break; } default: throw new ArgumentOutOfRangeException(); } } public Action modifyGraphDataAction => DragGraphInput; public ShaderInput graphInputBeingDraggedIn { get; set; } public Vector2 nodePosition { get; set; } } }