浏览代码

Undo/redo prototype

/main
Peter Bay Bastian 7 年前
当前提交
a3385c0f
共有 15 个文件被更改,包括 293 次插入26 次删除
  1. 26
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Implementation/Edge.cs
  2. 94
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Implementation/SerializableGraph.cs
  3. 2
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Implementation/SerializableNode.cs
  4. 26
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Implementation/SerializableSlot.cs
  5. 4
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Interfaces/IEdge.cs
  6. 1
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Interfaces/IGraph.cs
  7. 2
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Interfaces/INode.cs
  8. 4
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Interfaces/ISlot.cs
  9. 25
      MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Interfaces/SlotReference.cs
  10. 4
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/AbstractMaterialGraphEditWindow.cs
  11. 55
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialGraphPresenter.cs
  12. 7
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialNodePresenter.cs
  13. 2
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/PreviewSystem.cs
  14. 1
      MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Views/MaterialNodeView.cs
  15. 66
      MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Graphs/AbstractMaterialGraph.cs

26
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Implementation/Edge.cs


{
get { return m_InputSlot; }
}
protected bool Equals(Edge other)
{
return Equals(m_OutputSlot, other.m_OutputSlot) && Equals(m_InputSlot, other.m_InputSlot);
}
public bool Equals(IEdge other)
{
return Equals(other as object);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Edge)obj);
}
public override int GetHashCode()
{
unchecked
{
return ((m_OutputSlot != null ? m_OutputSlot.GetHashCode() : 0) * 397) ^ (m_InputSlot != null ? m_InputSlot.GetHashCode() : 0);
}
}
}
}

94
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Implementation/SerializableGraph.cs


using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using NUnit.Framework;
namespace UnityEngine.Graphing
{

public virtual void AddNode(INode node)
{
AddNodeNoValidate(node);
ValidateGraph();
}
void AddNodeNoValidate(INode node)
{
ValidateGraph();
}
public virtual void RemoveNode(INode node)

void RemoveEdgeNoValidate(IEdge e)
{
e = m_Edges.FirstOrDefault(x => x.Equals(e));
Assert.NotNull(e);
m_Edges.Remove(e);
List<IEdge> inputNodeEdges;

List<IEdge> outputNodeEdges;
if (m_NodeEdges.TryGetValue(e.outputSlot.nodeGuid, out outputNodeEdges))
outputNodeEdges.Remove(e);
NotifyChange(new EdgeRemovedGraphChange(e));
}

if (s == null)
return Enumerable.Empty<IEdge>();
var node = GetNodeFromGuid(s.nodeGuid);
if (node == null)
{
Debug.LogWarning("Node does not exist");
return Enumerable.Empty<IEdge>();
}
ISlot slot = slot = node.FindSlot<ISlot>(s.slotId);
return candidateEdges.Where(x =>
(x.outputSlot.nodeGuid == s.nodeGuid && x.outputSlot.slotId == s.slotId)
|| x.inputSlot.nodeGuid == s.nodeGuid && x.inputSlot.slotId == s.slotId);
return candidateEdges.Where(candidateEdge =>
{
var cs = slot.isInputSlot ? candidateEdge.inputSlot : candidateEdge.outputSlot;
return cs.nodeGuid == s.nodeGuid && cs.slotId == s.slotId;
});
}
public virtual void OnBeforeSerialize()

foreach (var node in GetNodes<INode>())
node.ValidateNode();
}
public virtual void ReplaceWith(IGraph other)
{
using (var pooledList = ListPool<IEdge>.GetDisposable())
{
var removedNodeEdges = pooledList.value;
foreach (var edge in m_Edges)
{
// Remove the edge if it doesn't exist in the other graph.
if (!other.ContainsNodeGuid(edge.inputSlot.nodeGuid) || !other.GetEdges(edge.inputSlot).Any(otherEdge => otherEdge.outputSlot.Equals(edge.outputSlot)))
removedNodeEdges.Add(edge);
}
foreach (var edge in removedNodeEdges)
RemoveEdge(edge);
}
using (var removedNodesPooledObject = ListPool<Guid>.GetDisposable())
using (var replacedNodesPooledObject = ListPool<INode>.GetDisposable())
{
var removedNodeGuids = removedNodesPooledObject.value;
var replacedNodes = replacedNodesPooledObject.value;
foreach (var node in m_Nodes.Values)
{
if (!other.ContainsNodeGuid(node.guid))
// Remove the node if it doesn't exist in the other graph.
removedNodeGuids.Add(node.guid);
else
// Replace the node with the one from the other graph otherwise.
replacedNodes.Add(node);
}
foreach (var nodeGuid in removedNodeGuids)
RemoveNode(m_Nodes[nodeGuid]);
foreach (var node in replacedNodes)
{
var currentNode = other.GetNodeFromGuid(node.guid);
currentNode.owner = this;
m_Nodes[node.guid] = currentNode;
currentNode.onModified = node.onModified;
currentNode.onReplaced = node.onReplaced;
// Notify listeners that the reference has changed.
if (node.onReplaced != null)
node.onReplaced(node, currentNode);
if (currentNode.onModified != null)
currentNode.onModified(node, ModificationScope.Node);
node.onModified = null;
node.onReplaced = null;
}
}
// Add nodes from other graph which don't exist in this one.
foreach (var node in other.GetNodes<INode>())
{
if (!ContainsNodeGuid(node.guid))
AddNode(node);
}
// Add edges from other graph which don't exist in this one.
foreach (var edge in other.edges)
{
if (!GetEdges(edge.inputSlot).Any(otherEdge => otherEdge.outputSlot.Equals(edge.outputSlot)))
Connect(edge.outputSlot, edge.inputSlot);
}
}
public void OnEnable()

2
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Implementation/SerializableNode.cs


public OnNodeModified onModified { get; set; }
public OnNodeReplaced onReplaced { get; set; }
public IEnumerable<T> GetInputSlots<T>() where T : ISlot
{
return GetSlots<T>().Where(x => x.isInputSlot);

26
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Implementation/SerializableSlot.cs


m_SlotType = slotType;
m_Hidden = hidden;
}
protected bool Equals(SerializableSlot other)
{
return m_Id == other.m_Id && owner.guid.Equals(other.owner.guid);
}
public bool Equals(ISlot other)
{
return Equals(other as object);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((SerializableSlot)obj);
}
public override int GetHashCode()
{
unchecked
{
return (m_Id * 397) ^ (owner != null ? owner.GetHashCode() : 0);
}
}
}
}

4
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Interfaces/IEdge.cs


using System;
public interface IEdge
public interface IEdge : IEquatable<IEdge>
{
SlotReference outputSlot { get; }
SlotReference inputSlot { get; }

1
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Interfaces/IGraph.cs


T GetNodeFromGuid<T>(Guid guid) where T : INode;
IEnumerable<IEdge> GetEdges(SlotReference s);
void ValidateGraph();
void ReplaceWith(IGraph other);
OnGraphChange onChange { get; set; }
}
}

2
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Interfaces/INode.cs


}
public delegate void OnNodeModified(INode node, ModificationScope scope);
public delegate void OnNodeReplaced(INode previous, INode current);
OnNodeReplaced onReplaced { get; set; }
IGraph owner { get; set; }
Guid guid { get; }
Guid RewriteGuid();

4
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Interfaces/ISlot.cs


using System;
public interface ISlot
public interface ISlot : IEquatable<ISlot>
{
int id { get; }
string displayName { get; set; }

25
MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Runtime/Interfaces/SlotReference.cs


namespace UnityEngine.Graphing
{
[Serializable]
public class SlotReference : ISerializationCallbackReceiver
public class SlotReference : ISerializationCallbackReceiver, IEquatable<SlotReference>
{
[SerializeField]
private int m_SlotId;

public void OnAfterDeserialize()
{
m_NodeGUID = new Guid(m_NodeGUIDSerialized);
}
public bool Equals(SlotReference other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return m_SlotId == other.m_SlotId && m_NodeGUID.Equals(other.m_NodeGUID);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((SlotReference)obj);
}
public override int GetHashCode()
{
unchecked
{
return (m_SlotId * 397) ^ m_NodeGUID.GetHashCode();
}
}
}
}

4
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/AbstractMaterialGraphEditWindow.cs


public abstract class AbstractMaterialGraphEditWindow<TGraphType> : HelperMaterialGraphEditWindow where TGraphType : AbstractMaterialGraph
{
public static bool allowAlwaysRepaint = true;
[SerializeField]
Object m_Selected;

return;
var subGraphNode = new SubGraphNode();
graphPresenter.AddNode(subGraphNode);
graphPresenter.graph.AddNode(subGraphNode);
subGraphNode.subGraphAsset = subGraph;
/* foreach (var edgeMap in inputsNeedingConnection)

55
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialGraphPresenter.cs


using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.Graphing;
using Debug = System.Diagnostics.Debug;
public class MaterialGraphObject : ScriptableObject
{
[SerializeField]
public string serializedGraph;
[SerializeField]
public int version;
}
[Serializable]
public class MaterialGraphPresenter : GraphViewPresenter
{

[SerializeField]
IMaterialGraphEditWindow m_Container;
[SerializeField]
MaterialGraphObject m_GraphObject;
[SerializeField]
int m_GraphVersion;
protected MaterialGraphPresenter()
{

EdgeAdded(new EdgeAddedGraphChange(edge));
this.graph.onChange += OnChange;
m_GraphObject = CreateInstance<MaterialGraphObject>();
Undo.undoRedoPerformed += UndoRedoPerformed;
RecordState();
}
void UndoRedoPerformed()
{
if (m_GraphObject.version != m_GraphVersion)
{
var targetGraph = JsonUtility.FromJson(m_GraphObject.serializedGraph, graph.GetType()) as IGraph;
graph.ReplaceWith(targetGraph);
m_GraphVersion = m_GraphObject.version;
}
}
void RecordState()
{
m_GraphObject.serializedGraph = JsonUtility.ToJson(graph, false);
m_GraphObject.version++;
m_GraphVersion = m_GraphObject.version;
}
void OnChange(GraphChange change)

var sourceNode = graph.GetNodeFromGuid(edge.outputSlot.nodeGuid);
var sourceSlot = sourceNode.FindOutputSlot<ISlot>(edge.outputSlot.slotId);
var sourceNodePresenter = m_Elements.OfType<MaterialNodePresenter>().FirstOrDefault(x => x.node == sourceNode);
var sourceAnchorPresenter = sourceNodePresenter.outputAnchors.OfType<GraphAnchorPresenter>().FirstOrDefault(x => x.slot == sourceSlot);
var sourceAnchorPresenter = sourceNodePresenter.outputAnchors.OfType<GraphAnchorPresenter>().FirstOrDefault(x => x.slot.Equals(sourceSlot));
var targetAnchor = targetNodePresenter.inputAnchors.OfType<GraphAnchorPresenter>().FirstOrDefault(x => x.slot == targetSlot);
var targetAnchor = targetNodePresenter.inputAnchors.OfType<GraphAnchorPresenter>().FirstOrDefault(x => x.slot.Equals(targetSlot));
var edgePresenter = CreateInstance<GraphEdgePresenter>();
edgePresenter.Initialize(edge);

public void AddNode(INode node)
{
Undo.RecordObject(m_GraphObject, "Add " + node.name);
RecordState();
}
public void RemoveElements(IEnumerable<MaterialNodePresenter> nodes, IEnumerable<GraphEdgePresenter> edges)

{
if (left != null && right != null)
{
Undo.RecordObject(m_GraphObject, "Connect Edge");
RecordState();
}
}

public void Cut()
{
Copy();
Undo.RecordObject(m_GraphObject, "Cut");
RecordState();
}
public bool canPaste

public void Paste()
{
var pastedGraph = DeserializeCopyBuffer(EditorGUIUtility.systemCopyBuffer);
Undo.RecordObject(m_GraphObject, "Paste");
RecordState();
}
public bool canDuplicate

public void Duplicate()
{
var graph = DeserializeCopyBuffer(JsonUtility.ToJson(CreateCopyPasteGraph(elements.Where(e => e.selected)), true));
Undo.RecordObject(m_GraphObject, "Duplicate");
RecordState();
}
public bool canDelete

public void Delete()
{
RecordState();
Undo.RecordObject(m_GraphObject, "Delete");
RecordState();
}
public override void AddElement(EdgePresenter edge)

7
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialNodePresenter.cs


m_Preview = previewSystem.GetPreview(inNode);
m_Preview.onPreviewChanged += OnPreviewChanged;
node.onReplaced += OnReplaced;
}
void OnReplaced(INode previous, INode current)
{
node = current as AbstractMaterialNode;
}
void OnPreviewChanged()

2
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/PreviewSystem.cs


void UpdateShader(Guid nodeGuid)
{
var node = m_Graph.GetNodeFromGuid<AbstractMaterialNode>(nodeGuid);
if (node == null)
return;
PreviewData previewData;
if (!m_Previews.TryGetValue(nodeGuid, out previewData))
return;

1
MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Views/MaterialNodeView.cs


public override void OnDataChanged()
{
base.OnDataChanged();
var nodePresenter = GetPresenter<MaterialNodePresenter>();
if (nodePresenter == null)

66
MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Graphs/AbstractMaterialGraph.cs


[Serializable]
public abstract class AbstractMaterialGraph : SerializableGraph, IGenerateProperties
{
[NonSerialized] private List<IShaderProperty> m_Properties = new List<IShaderProperty>();
[NonSerialized]
List<IShaderProperty> m_Properties = new List<IShaderProperty>();
[SerializeField] private List<SerializationHelper.JSONSerializedElement> m_SerializedProperties = new List<SerializationHelper.JSONSerializedElement>();
[SerializeField]
List<SerializationHelper.JSONSerializedElement> m_SerializedProperties = new List<SerializationHelper.JSONSerializedElement>();
public IEnumerable<IShaderProperty> properties
{

};
result[worldPosNode] = SerializationHelper.GetTypeSerializableAsString(typeof(WorldSpacePositionNode));
return result;
}
return result;
class IndexedProperty
{
public int index;
public IShaderProperty property;
}
public override void ReplaceWith(IGraph other)
{
var otherMG = other as AbstractMaterialGraph;
if (otherMG != null)
{
using (var removedPropertiesPooledObject = ListPool<Guid>.GetDisposable())
using (var replacedPropertiesPooledObject = ListPool<IndexedProperty>.GetDisposable())
{
var removedPropertyGuids = removedPropertiesPooledObject.value;
var replacedProperties = replacedPropertiesPooledObject.value;
var index = 0;
foreach (var property in m_Properties)
{
var otherProperty = otherMG.properties.FirstOrDefault(op => op.guid == property.guid);
if (otherProperty == null)
removedPropertyGuids.Add(property.guid);
else
replacedProperties.Add(new IndexedProperty { index = index, property = otherProperty });
index++;
}
foreach (var propertyGuid in removedPropertyGuids)
RemoveShaderProperty(propertyGuid);
foreach (var indexedProperty in replacedProperties)
{
m_Properties[indexedProperty.index] = indexedProperty.property;
// TODO: Notify of change
}
foreach (var otherProperty in otherMG.properties)
{
if (!properties.Any(p => p.guid == otherProperty.guid))
AddShaderProperty(otherProperty);
}
}
}
base.ReplaceWith(other);
}
public override void OnBeforeSerialize()

base.OnAfterDeserialize();
}
private static ShaderGraphRequirements GetRequierments(AbstractMaterialNode nodeForRequirements)
static ShaderGraphRequirements GetRequierments(AbstractMaterialNode nodeForRequirements)
{
var activeNodeList = ListPool<INode>.Get();
NodeUtils.DepthFirstCollectNodesFromNode(activeNodeList, nodeForRequirements);

// if anything needs tangentspace we have make
// sure to have our othonormal basis!
var compoundSpaces = requiresBitangent | requiresNormal | requiresPosition
| requiresTangent | requiresViewDir | requiresPosition
| requiresNormal;
| requiresTangent | requiresViewDir | requiresPosition
| requiresNormal;
var needsTangentSpace = (compoundSpaces & NeededCoordinateSpace.Tangent) > 0;
if (needsTangentSpace)

return reqs;
}
private static void GenerateSpaceTranslationSurfaceInputs(
static void GenerateSpaceTranslationSurfaceInputs(
NeededCoordinateSpace neededSpaces,
ShaderGenerator surfaceInputs,
string objectSpaceName,

{
foreach (var slot in node.GetInputSlots<MaterialSlot>())
surfaceDescriptionStruct.AddShaderChunk(AbstractMaterialNode.ConvertConcreteSlotValueTypeToString(AbstractMaterialNode.OutputPrecision.@float, slot.concreteValueType) + " " + slot.shaderOutputName + ";", false);
}
surfaceDescriptionStruct.Deindent();
surfaceDescriptionStruct.AddShaderChunk("};", false);

{
var foundEdges = GetEdges(input.slotReference).ToArray();
if (foundEdges.Any())
{
{
var outputRef = foundEdges[0].outputSlot;
var fromNode = GetNodeFromGuid<AbstractMaterialNode>(outputRef.nodeGuid);
surfaceDescriptionFunction.AddShaderChunk(string.Format("surface.{0} = {1};", input.shaderOutputName, fromNode.GetVariableNameForSlot(outputRef.slotId)), true);

正在加载...
取消
保存