155 lines
5.7 KiB
C#
155 lines
5.7 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using UnityEditor.Experimental.GraphView;
|
|
using UnityEditor.ShaderGraph.Drawing;
|
|
using UnityEditor.ShaderGraph.Serialization;
|
|
|
|
namespace UnityEditor.ShaderGraph
|
|
{
|
|
sealed class ContextView : StackNode, IDisposable
|
|
{
|
|
ContextData m_ContextData;
|
|
|
|
// Currently we only need one Port per context
|
|
// As the Contexts are hardcoded we know their directions
|
|
Port m_Port;
|
|
|
|
//need this from graph view specifically for nodecreation
|
|
EditorWindow m_EditorWindow;
|
|
|
|
// When dealing with more Contexts, `name` should be serialized in the ContextData
|
|
// Right now we dont do this so we dont overcommit to serializing unknowns
|
|
public ContextView(string name, ContextData contextData, EditorWindow editorWindow)
|
|
{
|
|
// Set data
|
|
m_ContextData = contextData;
|
|
m_EditorWindow = editorWindow;
|
|
|
|
// Header
|
|
var headerLabel = new Label() { name = "headerLabel" };
|
|
headerLabel.text = name;
|
|
headerContainer.Add(headerLabel);
|
|
}
|
|
|
|
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
|
|
{
|
|
// Disable the context menu for block nodes. This prevents a duplicate "disconnect all"
|
|
// option from getting registered which grays out stack block node's option.
|
|
if (evt.target is MaterialNodeView) return;
|
|
|
|
// If the user didn't click on a block node (i.e. the stack frame), include the "Add Block Node" item.
|
|
InsertCreateNodeAction(evt, childCount, 0);
|
|
evt.menu.InsertSeparator(null, 1);
|
|
}
|
|
|
|
public ContextData contextData => m_ContextData;
|
|
public Port port => m_Port;
|
|
|
|
// We need to use graphViewChange.movedElements to check whether a BlockNode has moved onto the GraphView
|
|
// but Nodes return in movedElements when they are mid-drag because they are removed from the stack (placeholder)
|
|
// StackNode has `dragEntered` but its protected so we need `isDragging`
|
|
public bool isDragging => dragEntered;
|
|
|
|
public void AddPort(Direction direction)
|
|
{
|
|
var capacity = direction == Direction.Input ? Port.Capacity.Single : Port.Capacity.Multi;
|
|
var container = direction == Direction.Input ? inputContainer : outputContainer;
|
|
m_Port = Port.Create<Edge>(Orientation.Vertical, direction, capacity, null);
|
|
m_Port.portName = "";
|
|
|
|
// Vertical ports have no representation in Model
|
|
// Therefore we need to disable interaction
|
|
m_Port.pickingMode = PickingMode.Ignore;
|
|
|
|
container.Add(m_Port);
|
|
}
|
|
|
|
public void InsertBlock(MaterialNodeView nodeView)
|
|
{
|
|
if (!(nodeView.userData is BlockNode blockNode))
|
|
return;
|
|
|
|
// If index is -1 the node is being added to the end of the Stack
|
|
if (blockNode.index == -1)
|
|
{
|
|
AddElement(nodeView);
|
|
return;
|
|
}
|
|
|
|
// Add or Insert based on index
|
|
if (blockNode.index >= contentContainer.childCount)
|
|
{
|
|
AddElement(nodeView);
|
|
}
|
|
else
|
|
{
|
|
InsertElement(blockNode.index, nodeView);
|
|
}
|
|
}
|
|
|
|
public void InsertElements(int insertIndex, IEnumerable<GraphElement> elements)
|
|
{
|
|
var blockDatas = elements.Select(x => x.userData as BlockNode).ToArray();
|
|
for (int i = 0; i < blockDatas.Length; i++)
|
|
{
|
|
contextData.blocks.Remove(blockDatas[i]);
|
|
}
|
|
|
|
int count = elements.Count();
|
|
var refs = new JsonRef<BlockNode>[count];
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
refs[i] = blockDatas[i];
|
|
}
|
|
|
|
contextData.blocks.InsertRange(insertIndex, refs);
|
|
|
|
var window = m_EditorWindow as MaterialGraphEditWindow;
|
|
window?.graphEditorView?.graphView?.graph?.ValidateCustomBlockLimit();
|
|
}
|
|
|
|
protected override bool AcceptsElement(GraphElement element, ref int proposedIndex, int maxIndex)
|
|
{
|
|
return element.userData is BlockNode blockNode && blockNode.descriptor != null &&
|
|
blockNode.descriptor.shaderStage == contextData.shaderStage;
|
|
}
|
|
|
|
protected override void OnSeparatorContextualMenuEvent(ContextualMenuPopulateEvent evt, int separatorIndex)
|
|
{
|
|
base.OnSeparatorContextualMenuEvent(evt, separatorIndex);
|
|
InsertCreateNodeAction(evt, separatorIndex, 0);
|
|
}
|
|
|
|
void InsertCreateNodeAction(ContextualMenuPopulateEvent evt, int separatorIndex, int itemIndex)
|
|
{
|
|
//we need to arbitrarily add the editor position values because node creation context
|
|
//exptects a non local coordinate
|
|
var mousePosition = evt.mousePosition + m_EditorWindow.position.position;
|
|
var graphView = GetFirstAncestorOfType<MaterialGraphView>();
|
|
|
|
evt.menu.InsertAction(itemIndex, "Add Block Node", (e) =>
|
|
{
|
|
var context = new NodeCreationContext
|
|
{
|
|
screenMousePosition = mousePosition,
|
|
target = this,
|
|
index = separatorIndex,
|
|
};
|
|
graphView.nodeCreationRequest(context);
|
|
});
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
m_Port = null;
|
|
m_ContextData = null;
|
|
m_EditorWindow = null;
|
|
inputContainer.Clear();
|
|
outputContainer.Clear();
|
|
}
|
|
}
|
|
}
|