예제 #1
0
        protected void UpdateSlot(InventorySlot slot, int slotIndex, Item item, bool isSubSlot)
        {
            bool mouseOn = slot.InteractRect.Contains(PlayerInput.MousePosition) && !Locked;

            slot.State = GUIComponent.ComponentState.None;

            if (mouseOn &&
                (draggingItem != null || selectedSlot == null || selectedSlot.Slot == slot) &&
                (highlightedSubInventory == null || highlightedSubInventory == this || highlightedSubInventorySlot?.Slot == slot || highlightedSubInventory.Owner == item))
            {
                slot.State = GUIComponent.ComponentState.Hover;

                if (selectedSlot == null || (!selectedSlot.IsSubSlot && isSubSlot))
                {
                    selectedSlot = new SlotReference(this, slot, slotIndex, isSubSlot);
                }

                if (draggingItem == null)
                {
                    if (PlayerInput.LeftButtonHeld())
                    {
                        draggingItem = Items[slotIndex];
                        draggingSlot = slot;
                    }
                }
                else if (PlayerInput.LeftButtonReleased())
                {
                    if (PlayerInput.DoubleClicked())
                    {
                        doubleClickedItem = item;
                    }
                }
            }
        }
예제 #2
0
        public IEdge Connect(SlotReference fromSlotRef, SlotReference toSlotRef)
        {
            var newEdge = ConnectNoValidate(fromSlotRef, toSlotRef);

            ValidateGraph();
            return(newEdge);
        }
예제 #3
0
        protected virtual void CreateSlots()
        {
            slots = new InventorySlot[capacity];

            int rectWidth = 40, rectHeight = 40;
            int spacing = 10;

            int rows = (int)Math.Ceiling((double)capacity / slotsPerRow);

            int startX = (int)centerPos.X - (rectWidth * slotsPerRow + spacing * (slotsPerRow - 1)) / 2;
            int startY = (int)centerPos.Y - rows * (spacing + rectHeight);

            Rectangle slotRect = new Rectangle(startX, startY, rectWidth, rectHeight);

            for (int i = 0; i < capacity; i++)
            {
                slotRect.X = startX + (rectWidth + spacing) * (i % slotsPerRow) + (int)DrawOffset.X;
                slotRect.Y = startY + (rectHeight + spacing) * ((int)Math.Floor((double)i / slotsPerRow)) + (int)DrawOffset.Y;

                slots[i] = new InventorySlot(slotRect);
            }

            if (selectedSlot != null && selectedSlot.Inventory == this)
            {
                selectedSlot = new SlotReference(this, slots[selectedSlot.SlotIndex], selectedSlot.SlotIndex, selectedSlot.IsSubSlot);
            }
        }
예제 #4
0
        public IEnumerable <IEdge> GetEdges(SlotReference s)
        {
            var edges = new List <IEdge>();

            GetEdges(s, edges);
            return(edges);
        }
예제 #5
0
        public void GetEdges(SlotReference s, List <IEdge> foundEdges)
        {
            var node = GetNodeFromGuid(s.nodeGuid);

            if (node == null)
            {
                return;
            }
            ISlot slot = node.FindSlot <ISlot>(s.slotId);

            List <IEdge> candidateEdges;

            if (!m_NodeEdges.TryGetValue(s.nodeGuid, out candidateEdges))
            {
                return;
            }

            foreach (var edge in candidateEdges)
            {
                var cs = slot.isInputSlot ? edge.inputSlot : edge.outputSlot;
                if (cs.nodeGuid == s.nodeGuid && cs.slotId == s.slotId)
                {
                    foundEdges.Add(edge);
                }
            }
        }
예제 #6
0
        protected static Rectangle GetSubInventoryHoverArea(SlotReference subSlot)
        {
            Rectangle hoverArea = subSlot.Slot.Rect;

            hoverArea.Location += subSlot.Slot.DrawOffset.ToPoint();
            hoverArea           = Rectangle.Union(hoverArea, subSlot.Slot.EquipButtonRect);
            if (subSlot.Inventory?.slots != null)
            {
                foreach (InventorySlot slot in subSlot.Inventory.slots)
                {
                    Rectangle subSlotRect = slot.InteractRect;
                    subSlotRect.Location += slot.DrawOffset.ToPoint();
                    hoverArea             = Rectangle.Union(hoverArea, subSlotRect);
                }
                if (subSlot.Slot.SubInventoryDir < 0)
                {
                    hoverArea.Height -= hoverArea.Bottom - subSlot.Slot.Rect.Bottom;
                }
                else
                {
                    int over = subSlot.Slot.Rect.Y - hoverArea.Y;
                    hoverArea.Y      += over;
                    hoverArea.Height -= over;
                }
            }
            hoverArea.Inflate(10, 10);
            return(hoverArea);
        }
예제 #7
0
        public override void CreateSlots()
        {
            if (slots == null)
            {
                slots = new InventorySlot[capacity];
            }

            for (int i = 0; i < capacity; i++)
            {
                InventorySlot prevSlot = slots[i];

                Sprite    slotSprite = slotSpriteSmall;
                Rectangle slotRect   = new Rectangle(
                    (int)(SlotPositions[i].X),
                    (int)(SlotPositions[i].Y),
                    (int)(slotSprite.size.X * UIScale), (int)(slotSprite.size.Y * UIScale));

                if (Items[i] != null)
                {
                    ItemContainer itemContainer = Items[i].GetComponent <ItemContainer>();
                    if (itemContainer != null)
                    {
                        if (itemContainer.InventoryTopSprite != null)
                        {
                            slotRect.Width = Math.Max(slotRect.Width, (int)(itemContainer.InventoryTopSprite.size.X * UIScale));
                        }
                        if (itemContainer.InventoryBottomSprite != null)
                        {
                            slotRect.Width = Math.Max(slotRect.Width, (int)(itemContainer.InventoryBottomSprite.size.X * UIScale));
                        }
                    }
                }

                slots[i] = new InventorySlot(slotRect)
                {
                    SubInventoryDir = Math.Sign(HUDLayoutSettings.InventoryAreaUpper.Bottom - slotRect.Center.Y),
                    Disabled        = false,
                    SlotSprite      = slotSprite,
                    Color           = SlotTypes[i] == InvSlotType.Any ? Color.White * 0.2f : Color.White * 0.4f
                };
                if (prevSlot != null)
                {
                    slots[i].DrawOffset = prevSlot.DrawOffset;
                    slots[i].Color      = prevSlot.Color;
                }

                if (selectedSlot?.ParentInventory == this && selectedSlot.SlotIndex == i)
                {
                    selectedSlot = new SlotReference(this, slots[i], i, selectedSlot.IsSubSlot, selectedSlot.Inventory);
                }
            }

            AssignQuickUseNumKeys();

            highlightedSubInventorySlots.Clear();

            screenResolution = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
            CalculateBackgroundFrame();
        }
예제 #8
0
        public bool FindPort(SlotReference slotRef, out ShaderPort port)
        {
            port = inputContainer.Query <ShaderPort>().ToList()
                   .Concat(outputContainer.Query <ShaderPort>().ToList())
                   .First(p => p.slot.slotReference.Equals(slotRef));

            return(port != null);
        }
예제 #9
0
        public virtual void CreateSlots()
        {
            slots = new InventorySlot[capacity];

            int rows    = (int)Math.Ceiling((double)capacity / slotsPerRow);
            int columns = Math.Min(slotsPerRow, capacity);

            Vector2 spacing  = new Vector2(10 * UIScale, (10 + EquipIndicator.size.Y) * UIScale);
            Vector2 rectSize = new Vector2(60.0f * UIScale);

            //y is larger to give more space for the header
            padding = new Vector4(spacing.X, 40 * UIScale, spacing.X, spacing.X);

            Vector2 slotAreaSize = new Vector2(
                columns * rectSize.X + (columns - 1) * spacing.X,
                rows * rectSize.Y + (rows - 1) * spacing.Y);

            slotAreaSize.X += padding.X + padding.Z;
            slotAreaSize.Y += padding.Y + padding.W;

            Vector2 topLeft = new Vector2(
                GameMain.GraphicsWidth / 2 - slotAreaSize.X / 2,
                GameMain.GraphicsHeight / 2 - slotAreaSize.Y / 2);

            if (RectTransform != null)
            {
                Vector2 scale = new Vector2(
                    RectTransform.Rect.Width / slotAreaSize.X,
                    RectTransform.Rect.Height / slotAreaSize.Y);

                spacing   *= scale;
                rectSize  *= scale;
                padding.X *= scale.X; padding.Z *= scale.X;
                padding.Y *= scale.Y; padding.W *= scale.Y;

                topLeft  = RectTransform.TopLeft.ToVector2() + new Vector2(padding.X, padding.Y);
                prevRect = RectTransform.Rect;
            }

            Rectangle slotRect = new Rectangle((int)topLeft.X, (int)topLeft.Y, (int)rectSize.X, (int)rectSize.Y);

            for (int i = 0; i < capacity; i++)
            {
                slotRect.X            = (int)(topLeft.X + (rectSize.X + spacing.X) * (i % slotsPerRow));
                slotRect.Y            = (int)(topLeft.Y + (rectSize.Y + spacing.Y) * ((int)Math.Floor((double)i / slotsPerRow)));
                slots[i]              = new InventorySlot(slotRect);
                slots[i].InteractRect = new Rectangle(
                    (int)(slots[i].Rect.X - spacing.X / 2 - 1), (int)(slots[i].Rect.Y - spacing.Y / 2 - 1),
                    (int)(slots[i].Rect.Width + spacing.X + 2), (int)(slots[i].Rect.Height + spacing.Y + 2));
            }

            if (selectedSlot != null && selectedSlot.ParentInventory == this)
            {
                selectedSlot = new SlotReference(this, slots[selectedSlot.SlotIndex], selectedSlot.SlotIndex, selectedSlot.IsSubSlot, selectedSlot.Inventory);
            }
            CalculateBackgroundFrame();
        }
예제 #10
0
        private static void GetParents(IGraph graph, SlotReference slot, Queue <INode> nodes)
        {
            var m_edges = graph.GetEdges(slot);

            foreach (var edge in m_edges)
            {
                var otherSlot = edge.inputSlot.Equals(slot) ? edge.outputSlot : edge.inputSlot;
                nodes.Enqueue(graph.GetNodeFromGuid(otherSlot.nodeGuid));
            }
        }
예제 #11
0
        private static void GetChildren(IGraph graph, SlotReference slot, IList <INode> nodes)
        {
            var m_edges = graph.GetEdges(slot);

            foreach (var edge in m_edges)
            {
                var otherSlot = edge.inputSlot.Equals(slot) ? edge.outputSlot : edge.inputSlot;
                nodes.Add(graph.GetNodeFromGuid(otherSlot.nodeGuid));
            }
        }
예제 #12
0
        public void GetOutputAndInputSlots(out SlotReference outputSlotRef, out List<SlotReference> inputSlotRefs)
        {
            var inputSlot = FindSlot<MaterialSlot>(kInputSlotID);
            var inEdges = owner.GetEdges(inputSlot.slotReference).ToList();
            outputSlotRef = inEdges.Any() ? inEdges.First().outputSlot : new SlotReference();

            var outputSlot = FindSlot<MaterialSlot>(kOutputSlotID);
            // Get the slot where this edge ends.
            var outEdges = owner.GetEdges(outputSlot.slotReference);
            inputSlotRefs = new List<SlotReference>(outEdges.Select(edge => edge.inputSlot));
        }
예제 #13
0
        IEdge ConnectNoValidate(SlotReference fromSlotRef, SlotReference toSlotRef)
        {
            var fromNode = GetNodeFromGuid(fromSlotRef.nodeGuid);
            var toNode   = GetNodeFromGuid(toSlotRef.nodeGuid);

            if (fromNode == null || toNode == null)
            {
                return(null);
            }

            // if fromNode is already connected to toNode
            // do now allow a connection as toNode will then
            // have an edge to fromNode creating a cycle.
            // if this is parsed it will lead to an infinite loop.
            var dependentNodes = new List <AbstractMaterialNode>();

            NodeUtils.CollectNodesNodeFeedsInto(dependentNodes, toNode);
            if (dependentNodes.Contains(fromNode))
            {
                return(null);
            }

            var fromSlot = fromNode.FindSlot <ISlot>(fromSlotRef.slotId);
            var toSlot   = toNode.FindSlot <ISlot>(toSlotRef.slotId);

            if (fromSlot.isOutputSlot == toSlot.isOutputSlot)
            {
                return(null);
            }

            var outputSlot = fromSlot.isOutputSlot ? fromSlotRef : toSlotRef;
            var inputSlot  = fromSlot.isInputSlot ? fromSlotRef : toSlotRef;

            s_TempEdges.Clear();
            GetEdges(inputSlot, s_TempEdges);

            // remove any inputs that exits before adding
            foreach (var edge in s_TempEdges)
            {
                RemoveEdgeNoValidate(edge);
            }

            var newEdge = new Edge(outputSlot, inputSlot);

            m_Edges.Add(newEdge);
            m_AddedEdges.Add(newEdge);
            AddEdgeToNodeEdges(newEdge);

            //Debug.LogFormat("Connected edge: {0} -> {1} ({2} -> {3})\n{4}", newEdge.outputSlot.nodeGuid, newEdge.inputSlot.nodeGuid, fromNode.name, toNode.name, Environment.StackTrace);
            return(newEdge);
        }
예제 #14
0
        protected override string GetOutputForSlot(SlotReference fromSocketRef, ConcreteSlotValueType valueType, GenerationMode generationMode)
        {
            var slotRef = NodeUtils.DepthFirstCollectRedirectNodeFromNode(this);
            var fromLeftNode = owner.GetNodeFromGuid<AbstractMaterialNode>(slotRef.nodeGuid);
            if (fromLeftNode is RedirectNodeData)
            {
                return GetSlotValue(kInputSlotID, generationMode);
            }

            if (fromLeftNode != null)
            {
                return GenerationUtils.AdaptNodeOutput(fromLeftNode, slotRef.slotId, valueType);
            }
            return base.GetOutputForSlot(fromSocketRef, valueType, generationMode);
        }
예제 #15
0
        protected internal override string GetOutputForSlot(SlotReference fromSocketRef, ConcreteSlotValueType valueType, GenerationMode generationMode)
        {
            var slotRef      = NodeUtils.DepthFirstCollectRedirectNodeFromNode(this);
            var fromLeftNode = slotRef.node;

            if (fromLeftNode is RedirectNodeData)
            {
                return(GetSlotValue(kInputSlotID, generationMode));
            }

            if (fromLeftNode != null)
            {
                return(GenerationUtils.AdaptNodeOutput(fromLeftNode, slotRef.slotId, valueType));
            }
            return(base.GetOutputForSlot(fromSocketRef, valueType, generationMode));
        }
예제 #16
0
        internal void PasteGraph(CopyPasteGraph graphToPaste, List <INode> remappedNodes, List <IEdge> remappedEdges)
        {
            var nodeGuidMap = new Dictionary <Guid, Guid>();

            foreach (var node in graphToPaste.GetNodes <INode>())
            {
                var oldGuid = node.guid;
                var newGuid = node.RewriteGuid();
                nodeGuidMap[oldGuid] = newGuid;

                var drawState = node.drawState;
                var position  = drawState.position;
                position.x        += 30;
                position.y        += 30;
                drawState.position = position;
                node.drawState     = drawState;
                remappedNodes.Add(node);
                AddNode(node);

                // add the node to the pasted node list
                m_PastedNodes.Add(node);
            }

            // only connect edges within pasted elements, discard
            // external edges.
            foreach (var edge in graphToPaste.edges)
            {
                var outputSlot = edge.outputSlot;
                var inputSlot  = edge.inputSlot;

                Guid remappedOutputNodeGuid;
                Guid remappedInputNodeGuid;
                if (nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid) &&
                    nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid))
                {
                    var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId);
                    var inputSlotRef  = new SlotReference(remappedInputNodeGuid, inputSlot.slotId);
                    remappedEdges.Add(Connect(outputSlotRef, inputSlotRef));
                }
            }

            ValidateGraph();
        }
예제 #17
0
        private void ShowSubInventory(SlotReference slotRef, float deltaTime, Camera cam, List <SlotReference> hideSubInventories, bool isEquippedSubInventory)
        {
            Rectangle hoverArea = GetSubInventoryHoverArea(slotRef);

            if (isEquippedSubInventory)
            {
                foreach (SlotReference highlightedSubInventorySlot in highlightedSubInventorySlots)
                {
                    if (highlightedSubInventorySlot == slotRef)
                    {
                        continue;
                    }
                    if (hoverArea.Intersects(GetSubInventoryHoverArea(highlightedSubInventorySlot)))
                    {
                        return; // If an equipped one intersects with a currently active hover one, do not open
                    }
                }
            }

            if (isEquippedSubInventory)
            {
                slotRef.Inventory.OpenState = 1.0f; // Reset animation when initially equipped
            }

            highlightedSubInventorySlots.Add(slotRef);
            slotRef.Inventory.HideTimer = 1f;
            UpdateSubInventory(deltaTime, slotRef.SlotIndex, cam);

            //hide previously opened subinventories if this one overlaps with them
            foreach (SlotReference highlightedSubInventorySlot in highlightedSubInventorySlots)
            {
                if (highlightedSubInventorySlot == slotRef)
                {
                    continue;
                }
                if (hoverArea.Intersects(GetSubInventoryHoverArea(highlightedSubInventorySlot)))
                {
                    hideSubInventories.Add(highlightedSubInventorySlot);
                    highlightedSubInventorySlot.Inventory.HideTimer = 0.0f;
                }
            }
        }
예제 #18
0
        public static void UpdateDragging()
        {
            if (draggingItem != null && PlayerInput.LeftButtonReleased())
            {
                if (selectedSlot == null)
                {
                    draggingItem.ParentInventory?.CreateNetworkEvent();
                    draggingItem.Drop();
                    GUI.PlayUISound(GUISoundType.DropItem);
                }
                else if (selectedSlot.Inventory.Items[selectedSlot.SlotIndex] != draggingItem)
                {
                    Inventory selectedInventory = selectedSlot.Inventory;
                    int       slotIndex         = selectedSlot.SlotIndex;
                    if (selectedInventory.TryPutItem(draggingItem, slotIndex, true, true, Character.Controlled))
                    {
                        if (selectedInventory.slots != null)
                        {
                            selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f);
                        }
                        GUI.PlayUISound(GUISoundType.PickItem);
                    }
                    else
                    {
                        if (selectedInventory.slots != null)
                        {
                            selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.Red, 0.1f, 0.9f);
                        }
                        GUI.PlayUISound(GUISoundType.PickItemFail);
                    }
                    draggingItem = null;
                    draggingSlot = null;
                }

                draggingItem = null;
            }

            if (selectedSlot != null && !selectedSlot.Slot.InteractRect.Contains(PlayerInput.MousePosition))
            {
                selectedSlot = null;
            }
        }
예제 #19
0
        public void InsertInGraph(IGraph graph, List <INode> remappedNodes, List <IEdge> remappedEdges)
        {
            var nodeGuidMap = new Dictionary <Guid, Guid>();

            foreach (var node in GetNodes <INode>())
            {
                var oldGuid = node.guid;
                var newGuid = node.RewriteGuid();
                nodeGuidMap[oldGuid] = newGuid;

                var drawState = node.drawState;
                var position  = drawState.position;
                position.x        += 30;
                position.y        += 30;
                drawState.position = position;
                node.drawState     = drawState;
                remappedNodes.Add(node);
                graph.AddNode(node);
            }

            // only connect edges within pasted elements, discard
            // external edges.
            foreach (var edge in edges)
            {
                var outputSlot = edge.outputSlot;
                var inputSlot  = edge.inputSlot;

                Guid remappedOutputNodeGuid;
                Guid remappedInputNodeGuid;
                if (nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid) &&
                    nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid))
                {
                    var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId);
                    var inputSlotRef  = new SlotReference(remappedInputNodeGuid, inputSlot.slotId);
                    remappedEdges.Add(graph.Connect(outputSlotRef, inputSlotRef));
                }
            }

            m_Nodes.Clear();
            m_Edges.Clear();
            graph.ValidateGraph();
        }
예제 #20
0
        // Static version for testability
        public static RedirectNodeData Create(GraphData graph, SlotValueType edgeType, Vector2 absolutePosition, SlotReference inputRef, SlotReference outputRef, GroupData group)
        {
            var nodeData = new RedirectNodeData();

            nodeData.AddSlots(edgeType);
            nodeData.SetPosition(absolutePosition);
            nodeData.group = group;

            // Hard-coded for single input-output. Changes would be needed for multi-input redirects
            var nodeInSlotRef  = nodeData.GetSlotReference(RedirectNodeData.kInputSlotID);
            var nodeOutSlotRef = nodeData.GetSlotReference(RedirectNodeData.kOutputSlotID);

            graph.owner.RegisterCompleteObjectUndo("Add Redirect Node");
            graph.AddNode(nodeData);

            graph.Connect(outputRef, nodeInSlotRef);
            graph.Connect(nodeOutSlotRef, inputRef);

            return(nodeData);
        }
예제 #21
0
        internal void PasteGraph(CopyPasteGraph graphToPaste, List <AbstractMaterialNode> remappedNodes, List <IEdge> remappedEdges)
        {
            var groupGuidMap = new Dictionary <Guid, Guid>();

            foreach (var group in graphToPaste.groups)
            {
                var position = group.position;
                position.x += 30;
                position.y += 30;

                GroupData newGroup = new GroupData(group.title, position);

                var oldGuid = group.guid;
                var newGuid = newGroup.guid;
                groupGuidMap[oldGuid] = newGuid;

                AddGroup(newGroup);
                m_PastedGroups.Add(newGroup);
            }

            var nodeGuidMap = new Dictionary <Guid, Guid>();

            foreach (var node in graphToPaste.GetNodes <AbstractMaterialNode>())
            {
                AbstractMaterialNode pastedNode = node;

                var oldGuid = node.guid;
                var newGuid = node.RewriteGuid();
                nodeGuidMap[oldGuid] = newGuid;

                // Check if the property nodes need to be made into a concrete node.
                if (node is PropertyNode)
                {
                    PropertyNode propertyNode = (PropertyNode)node;

                    // If the property is not in the current graph, do check if the
                    // property can be made into a concrete node.
                    if (!m_Properties.Select(x => x.guid).Contains(propertyNode.propertyGuid))
                    {
                        // If the property is in the serialized paste graph, make the property node into a property node.
                        var pastedGraphMetaProperties = graphToPaste.metaProperties.Where(x => x.guid == propertyNode.propertyGuid);
                        if (pastedGraphMetaProperties.Any())
                        {
                            pastedNode           = pastedGraphMetaProperties.FirstOrDefault().ToConcreteNode();
                            pastedNode.drawState = node.drawState;
                            nodeGuidMap[oldGuid] = pastedNode.guid;
                        }
                    }
                }

                AbstractMaterialNode abstractMaterialNode = (AbstractMaterialNode)node;
                // Check if the node is inside a group
                if (groupGuidMap.ContainsKey(abstractMaterialNode.groupGuid))
                {
                    var absNode = pastedNode as AbstractMaterialNode;
                    absNode.groupGuid = groupGuidMap[abstractMaterialNode.groupGuid];
                    pastedNode        = absNode;
                }

                var drawState = node.drawState;
                var position  = drawState.position;
                position.x        += 30;
                position.y        += 30;
                drawState.position = position;
                node.drawState     = drawState;
                remappedNodes.Add(pastedNode);
                AddNode(pastedNode);

                // add the node to the pasted node list
                m_PastedNodes.Add(pastedNode);
            }

            // only connect edges within pasted elements, discard
            // external edges.
            foreach (var edge in graphToPaste.edges)
            {
                var outputSlot = edge.outputSlot;
                var inputSlot  = edge.inputSlot;

                Guid remappedOutputNodeGuid;
                Guid remappedInputNodeGuid;
                if (nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid) &&
                    nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid))
                {
                    var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId);
                    var inputSlotRef  = new SlotReference(remappedInputNodeGuid, inputSlot.slotId);
                    remappedEdges.Add(Connect(outputSlotRef, inputSlotRef));
                }
            }

            ValidateGraph();
        }
        public void ToSubGraph()
        {
            var graphView = graphEditorView.graphView;

            var path = EditorUtility.SaveFilePanelInProject("Save Sub Graph", "New Shader Sub Graph", ShaderSubGraphImporter.Extension, "");

            path = path.Replace(Application.dataPath, "Assets");
            if (path.Length == 0)
            {
                return;
            }

            graphObject.RegisterCompleteObjectUndo("Convert To Subgraph");

            var nodes  = graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode || x.node is SubGraphOutputNode)).Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray();
            var bounds = Rect.MinMaxRect(float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity);

            foreach (var node in nodes)
            {
                var center = node.drawState.position.center;
                bounds = Rect.MinMaxRect(
                    Mathf.Min(bounds.xMin, center.x),
                    Mathf.Min(bounds.yMin, center.y),
                    Mathf.Max(bounds.xMax, center.x),
                    Mathf.Max(bounds.yMax, center.y));
            }
            var middle = bounds.center;

            bounds.center = Vector2.zero;

            // Collect graph inputs
            var graphInputs = graphView.selection.OfType <BlackboardField>().Select(x => x.userData as ShaderInput);

            // Collect the property nodes and get the corresponding properties
            var propertyNodeGuids = graphView.selection.OfType <IShaderNodeView>().Where(x => (x.node is PropertyNode)).Select(x => ((PropertyNode)x.node).propertyGuid);
            var metaProperties    = graphView.graph.properties.Where(x => propertyNodeGuids.Contains(x.guid));

            // Collect the keyword nodes and get the corresponding keywords
            var keywordNodeGuids = graphView.selection.OfType <IShaderNodeView>().Where(x => (x.node is KeywordNode)).Select(x => ((KeywordNode)x.node).keywordGuid);
            var metaKeywords     = graphView.graph.keywords.Where(x => keywordNodeGuids.Contains(x.guid));

            var copyPasteGraph = new CopyPasteGraph(
                graphView.graph.assetGuid,
                graphView.selection.OfType <ShaderGroup>().Select(x => x.userData),
                graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode || x.node is SubGraphOutputNode)).Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(),
                graphView.selection.OfType <Edge>().Select(x => x.userData as IEdge),
                graphInputs,
                metaProperties,
                metaKeywords,
                graphView.selection.OfType <StickyNote>().Select(x => x.userData));

            var deserialized = CopyPasteGraph.FromJson(JsonUtility.ToJson(copyPasteGraph, false));

            if (deserialized == null)
            {
                return;
            }

            var subGraph = new GraphData {
                isSubGraph = true
            };

            subGraph.path = "Sub Graphs";
            var subGraphOutputNode = new SubGraphOutputNode();

            {
                var drawState = subGraphOutputNode.drawState;
                drawState.position           = new Rect(new Vector2(bounds.xMax + 200f, 0f), drawState.position.size);
                subGraphOutputNode.drawState = drawState;
            }
            subGraph.AddNode(subGraphOutputNode);

            // Always copy deserialized keyword inputs
            foreach (ShaderKeyword keyword in deserialized.metaKeywords)
            {
                ShaderInput copiedInput = keyword.Copy();
                subGraph.SanitizeGraphInputName(copiedInput);
                subGraph.SanitizeGraphInputReferenceName(copiedInput, keyword.overrideReferenceName);
                subGraph.AddGraphInput(copiedInput);

                // Update the keyword nodes that depends on the copied keyword
                var dependentKeywordNodes = deserialized.GetNodes <KeywordNode>().Where(x => x.keywordGuid == keyword.guid);
                foreach (var node in dependentKeywordNodes)
                {
                    node.owner       = graphView.graph;
                    node.keywordGuid = copiedInput.guid;
                }
            }

            var groupGuidMap = new Dictionary <Guid, Guid>();

            foreach (GroupData groupData in deserialized.groups)
            {
                var oldGuid = groupData.guid;
                var newGuid = groupData.RewriteGuid();
                groupGuidMap[oldGuid] = newGuid;
                subGraph.CreateGroup(groupData);
            }

            List <Guid> groupGuids  = new List <Guid>();
            var         nodeGuidMap = new Dictionary <Guid, Guid>();

            foreach (var node in deserialized.GetNodes <AbstractMaterialNode>())
            {
                var oldGuid = node.guid;
                var newGuid = node.RewriteGuid();
                nodeGuidMap[oldGuid] = newGuid;
                var drawState = node.drawState;
                drawState.position = new Rect(drawState.position.position - middle, drawState.position.size);
                node.drawState     = drawState;

                if (!groupGuids.Contains(node.groupGuid))
                {
                    groupGuids.Add(node.groupGuid);
                }

                // Checking if the group guid is also being copied.
                // If not then nullify that guid
                if (node.groupGuid != Guid.Empty)
                {
                    node.groupGuid = !groupGuidMap.ContainsKey(node.groupGuid) ? Guid.Empty : groupGuidMap[node.groupGuid];
                }

                subGraph.AddNode(node);
            }

            foreach (var note in deserialized.stickyNotes)
            {
                if (!groupGuids.Contains(note.groupGuid))
                {
                    groupGuids.Add(note.groupGuid);
                }

                if (note.groupGuid != Guid.Empty)
                {
                    note.groupGuid = !groupGuidMap.ContainsKey(note.groupGuid) ? Guid.Empty : groupGuidMap[note.groupGuid];
                }

                note.RewriteGuid();
                subGraph.AddStickyNote(note);
            }

            // figure out what needs remapping
            var externalOutputSlots = new List <IEdge>();
            var externalInputSlots  = new List <IEdge>();

            foreach (var edge in deserialized.edges)
            {
                var outputSlot = edge.outputSlot;
                var inputSlot  = edge.inputSlot;

                Guid remappedOutputNodeGuid;
                Guid remappedInputNodeGuid;
                var  outputSlotExistsInSubgraph = nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid);
                var  inputSlotExistsInSubgraph  = nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid);

                // pasting nice internal links!
                if (outputSlotExistsInSubgraph && inputSlotExistsInSubgraph)
                {
                    var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId);
                    var inputSlotRef  = new SlotReference(remappedInputNodeGuid, inputSlot.slotId);
                    subGraph.Connect(outputSlotRef, inputSlotRef);
                }
                // one edge needs to go to outside world
                else if (outputSlotExistsInSubgraph)
                {
                    externalInputSlots.Add(edge);
                }
                else if (inputSlotExistsInSubgraph)
                {
                    externalOutputSlots.Add(edge);
                }
            }

            // Find the unique edges coming INTO the graph
            var uniqueIncomingEdges = externalOutputSlots.GroupBy(
                edge => edge.outputSlot,
                edge => edge,
                (key, edges) => new { slotRef = key, edges = edges.ToList() });

            var externalInputNeedingConnection = new List <KeyValuePair <IEdge, AbstractShaderProperty> >();

            var       amountOfProps  = uniqueIncomingEdges.Count();
            const int height         = 40;
            const int subtractHeight = 20;
            var       propPos        = new Vector2(0, -((amountOfProps / 2) + height) - subtractHeight);

            foreach (var group in uniqueIncomingEdges)
            {
                var sr       = group.slotRef;
                var fromNode = graphObject.graph.GetNodeFromGuid(sr.nodeGuid);
                var fromSlot = fromNode.FindOutputSlot <MaterialSlot>(sr.slotId);

                AbstractShaderProperty prop;
                switch (fromSlot.concreteValueType)
                {
                case ConcreteSlotValueType.Texture2D:
                    prop = new Texture2DShaderProperty();
                    break;

                case ConcreteSlotValueType.Texture2DArray:
                    prop = new Texture2DArrayShaderProperty();
                    break;

                case ConcreteSlotValueType.Texture3D:
                    prop = new Texture3DShaderProperty();
                    break;

                case ConcreteSlotValueType.Cubemap:
                    prop = new CubemapShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector4:
                    prop = new Vector4ShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector3:
                    prop = new Vector3ShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector2:
                    prop = new Vector2ShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector1:
                    prop = new Vector1ShaderProperty();
                    break;

                case ConcreteSlotValueType.Boolean:
                    prop = new BooleanShaderProperty();
                    break;

                case ConcreteSlotValueType.Matrix2:
                    prop = new Matrix2ShaderProperty();
                    break;

                case ConcreteSlotValueType.Matrix3:
                    prop = new Matrix3ShaderProperty();
                    break;

                case ConcreteSlotValueType.Matrix4:
                    prop = new Matrix4ShaderProperty();
                    break;

                case ConcreteSlotValueType.SamplerState:
                    prop = new SamplerStateShaderProperty();
                    break;

                case ConcreteSlotValueType.Gradient:
                    prop = new GradientShaderProperty();
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                if (prop != null)
                {
                    var materialGraph    = (GraphData)graphObject.graph;
                    var fromPropertyNode = fromNode as PropertyNode;
                    var fromProperty     = fromPropertyNode != null?materialGraph.properties.FirstOrDefault(p => p.guid == fromPropertyNode.propertyGuid) : null;

                    prop.displayName = fromProperty != null ? fromProperty.displayName : fromSlot.concreteValueType.ToString();

                    subGraph.AddGraphInput(prop);
                    var propNode = new PropertyNode();
                    {
                        var drawState = propNode.drawState;
                        drawState.position = new Rect(new Vector2(bounds.xMin - 300f, 0f) + propPos, drawState.position.size);
                        propPos           += new Vector2(0, height);
                        propNode.drawState = drawState;
                    }
                    subGraph.AddNode(propNode);
                    propNode.propertyGuid = prop.guid;

                    foreach (var edge in group.edges)
                    {
                        subGraph.Connect(
                            new SlotReference(propNode.guid, PropertyNode.OutputSlotId),
                            new SlotReference(nodeGuidMap[edge.inputSlot.nodeGuid], edge.inputSlot.slotId));
                        externalInputNeedingConnection.Add(new KeyValuePair <IEdge, AbstractShaderProperty>(edge, prop));
                    }
                }
            }

            var uniqueOutgoingEdges = externalInputSlots.GroupBy(
                edge => edge.outputSlot,
                edge => edge,
                (key, edges) => new { slot = key, edges = edges.ToList() });

            var externalOutputsNeedingConnection = new List <KeyValuePair <IEdge, IEdge> >();

            foreach (var group in uniqueOutgoingEdges)
            {
                var outputNode = subGraph.outputNode as SubGraphOutputNode;

                AbstractMaterialNode node = graphView.graph.GetNodeFromGuid(group.edges[0].outputSlot.nodeGuid);
                MaterialSlot         slot = node.FindSlot <MaterialSlot>(group.edges[0].outputSlot.slotId);
                var slotId = outputNode.AddSlot(slot.concreteValueType);

                var inputSlotRef = new SlotReference(outputNode.guid, slotId);

                foreach (var edge in group.edges)
                {
                    var newEdge = subGraph.Connect(new SlotReference(nodeGuidMap[edge.outputSlot.nodeGuid], edge.outputSlot.slotId), inputSlotRef);
                    externalOutputsNeedingConnection.Add(new KeyValuePair <IEdge, IEdge>(edge, newEdge));
                }
            }

            if (FileUtilities.WriteShaderGraphToDisk(path, subGraph))
            {
                AssetDatabase.ImportAsset(path);
            }

            var loadedSubGraph = AssetDatabase.LoadAssetAtPath(path, typeof(SubGraphAsset)) as SubGraphAsset;

            if (loadedSubGraph == null)
            {
                return;
            }

            var subGraphNode = new SubGraphNode();
            var ds           = subGraphNode.drawState;

            ds.position            = new Rect(middle - new Vector2(100f, 150f), Vector2.zero);
            subGraphNode.drawState = ds;

            // Add the subgraph into the group if the nodes was all in the same group group
            if (groupGuids.Count == 1)
            {
                subGraphNode.groupGuid = groupGuids[0];
            }

            graphObject.graph.AddNode(subGraphNode);
            subGraphNode.asset = loadedSubGraph;

            foreach (var edgeMap in externalInputNeedingConnection)
            {
                graphObject.graph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode.guid, edgeMap.Value.guid.GetHashCode()));
            }

            foreach (var edgeMap in externalOutputsNeedingConnection)
            {
                graphObject.graph.Connect(new SlotReference(subGraphNode.guid, edgeMap.Value.inputSlot.slotId), edgeMap.Key.inputSlot);
            }

            graphObject.graph.RemoveElements(
                graphView.selection.OfType <IShaderNodeView>().Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(),
                new IEdge[] {},
                new GroupData[] {},
                graphView.selection.OfType <StickyNote>().Select(x => x.userData).ToArray());
            graphObject.graph.ValidateGraph();
        }
예제 #23
0
 public void Connect(SlotReference from, SlotReference to)
 {
     _graph.Connect(from, to);
 }
        public void ToSubGraph()
        {
            var path = EditorUtility.SaveFilePanelInProject("Save Sub Graph", "New Shader Sub Graph", ShaderSubGraphImporter.Extension, "");

            path = path.Replace(Application.dataPath, "Assets");
            if (path.Length == 0)
            {
                return;
            }

            graphObject.RegisterCompleteObjectUndo("Convert To Subgraph");
            var graphView = graphEditorView.graphView;

            var nodes  = graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode)).Select(x => x.node as AbstractMaterialNode).ToArray();
            var bounds = Rect.MinMaxRect(float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity);

            foreach (var node in nodes)
            {
                var center = node.drawState.position.center;
                bounds = Rect.MinMaxRect(
                    Mathf.Min(bounds.xMin, center.x),
                    Mathf.Min(bounds.yMin, center.y),
                    Mathf.Max(bounds.xMax, center.x),
                    Mathf.Max(bounds.yMax, center.y));
            }
            var middle = bounds.center;

            bounds.center = Vector2.zero;

            // Collect the property nodes and get the corresponding properties
            var propertyNodeGuids = graphView.selection.OfType <IShaderNodeView>().Where(x => (x.node is PropertyNode)).Select(x => ((PropertyNode)x.node).propertyGuid);
            var metaProperties    = graphView.graph.properties.Where(x => propertyNodeGuids.Contains(x.guid));

            var copyPasteGraph = new CopyPasteGraph(
                graphView.graph.guid,
                graphView.selection.OfType <ShaderGroup>().Select(x => x.userData),
                graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode)).Select(x => x.node as AbstractMaterialNode),
                graphView.selection.OfType <Edge>().Select(x => x.userData as IEdge),
                graphView.selection.OfType <BlackboardField>().Select(x => x.userData as AbstractShaderProperty),
                metaProperties);

            var deserialized = CopyPasteGraph.FromJson(JsonUtility.ToJson(copyPasteGraph, false));

            if (deserialized == null)
            {
                return;
            }

            var subGraph = new GraphData {
                isSubGraph = true
            };

            subGraph.path = "Sub Graphs";
            var subGraphOutputNode = new SubGraphOutputNode();

            {
                var drawState = subGraphOutputNode.drawState;
                drawState.position           = new Rect(new Vector2(bounds.xMax + 200f, 0f), drawState.position.size);
                subGraphOutputNode.drawState = drawState;
            }
            subGraph.AddNode(subGraphOutputNode);

            var nodeGuidMap = new Dictionary <Guid, Guid>();

            foreach (var node in deserialized.GetNodes <AbstractMaterialNode>())
            {
                var oldGuid = node.guid;
                var newGuid = node.RewriteGuid();
                nodeGuidMap[oldGuid] = newGuid;
                var drawState = node.drawState;
                drawState.position = new Rect(drawState.position.position - middle, drawState.position.size);
                node.drawState     = drawState;
                subGraph.AddNode(node);
            }

            // figure out what needs remapping
            var externalOutputSlots = new List <IEdge>();
            var externalInputSlots  = new List <IEdge>();

            foreach (var edge in deserialized.edges)
            {
                var outputSlot = edge.outputSlot;
                var inputSlot  = edge.inputSlot;

                Guid remappedOutputNodeGuid;
                Guid remappedInputNodeGuid;
                var  outputSlotExistsInSubgraph = nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid);
                var  inputSlotExistsInSubgraph  = nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid);

                // pasting nice internal links!
                if (outputSlotExistsInSubgraph && inputSlotExistsInSubgraph)
                {
                    var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId);
                    var inputSlotRef  = new SlotReference(remappedInputNodeGuid, inputSlot.slotId);
                    subGraph.Connect(outputSlotRef, inputSlotRef);
                }
                // one edge needs to go to outside world
                else if (outputSlotExistsInSubgraph)
                {
                    externalInputSlots.Add(edge);
                }
                else if (inputSlotExistsInSubgraph)
                {
                    externalOutputSlots.Add(edge);
                }
            }

            // Find the unique edges coming INTO the graph
            var uniqueIncomingEdges = externalOutputSlots.GroupBy(
                edge => edge.outputSlot,
                edge => edge,
                (key, edges) => new { slotRef = key, edges = edges.ToList() });

            var externalInputNeedingConnection = new List <KeyValuePair <IEdge, AbstractShaderProperty> >();

            foreach (var group in uniqueIncomingEdges)
            {
                var sr       = group.slotRef;
                var fromNode = graphObject.graph.GetNodeFromGuid(sr.nodeGuid);
                var fromSlot = fromNode.FindOutputSlot <MaterialSlot>(sr.slotId);

                AbstractShaderProperty prop;
                switch (fromSlot.concreteValueType)
                {
                case ConcreteSlotValueType.Texture2D:
                    prop = new TextureShaderProperty();
                    break;

                case ConcreteSlotValueType.Texture2DArray:
                    prop = new Texture2DArrayShaderProperty();
                    break;

                case ConcreteSlotValueType.Texture3D:
                    prop = new Texture3DShaderProperty();
                    break;

                case ConcreteSlotValueType.Cubemap:
                    prop = new CubemapShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector4:
                    prop = new Vector4ShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector3:
                    prop = new Vector3ShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector2:
                    prop = new Vector2ShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector1:
                    prop = new Vector1ShaderProperty();
                    break;

                case ConcreteSlotValueType.Boolean:
                    prop = new BooleanShaderProperty();
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                if (prop != null)
                {
                    var materialGraph    = (GraphData)graphObject.graph;
                    var fromPropertyNode = fromNode as PropertyNode;
                    var fromProperty     = fromPropertyNode != null?materialGraph.properties.FirstOrDefault(p => p.guid == fromPropertyNode.propertyGuid) : null;

                    prop.displayName = fromProperty != null ? fromProperty.displayName : fromSlot.concreteValueType.ToString();

                    subGraph.AddShaderProperty(prop);
                    var propNode = new PropertyNode();
                    {
                        var drawState = propNode.drawState;
                        drawState.position = new Rect(new Vector2(bounds.xMin - 300f, 0f), drawState.position.size);
                        propNode.drawState = drawState;
                    }
                    subGraph.AddNode(propNode);
                    propNode.propertyGuid = prop.guid;

                    foreach (var edge in group.edges)
                    {
                        subGraph.Connect(
                            new SlotReference(propNode.guid, PropertyNode.OutputSlotId),
                            new SlotReference(nodeGuidMap[edge.inputSlot.nodeGuid], edge.inputSlot.slotId));
                        externalInputNeedingConnection.Add(new KeyValuePair <IEdge, AbstractShaderProperty>(edge, prop));
                    }
                }
            }

            var uniqueOutgoingEdges = externalInputSlots.GroupBy(
                edge => edge.inputSlot,
                edge => edge,
                (key, edges) => new { slot = key, edges = edges.ToList() });

            var externalOutputsNeedingConnection = new List <KeyValuePair <IEdge, IEdge> >();

            foreach (var group in uniqueOutgoingEdges)
            {
                var outputNode = subGraph.outputNode as SubGraphOutputNode;

                AbstractMaterialNode node = graphView.graph.GetNodeFromGuid(group.edges[0].outputSlot.nodeGuid);
                MaterialSlot         slot = node.FindSlot <MaterialSlot>(group.edges[0].outputSlot.slotId);
                var slotId = outputNode.AddSlot(slot.concreteValueType);

                var inputSlotRef = new SlotReference(outputNode.guid, slotId);

                foreach (var edge in group.edges)
                {
                    var newEdge = subGraph.Connect(new SlotReference(nodeGuidMap[edge.outputSlot.nodeGuid], edge.outputSlot.slotId), inputSlotRef);
                    externalOutputsNeedingConnection.Add(new KeyValuePair <IEdge, IEdge>(edge, newEdge));
                }
            }

            File.WriteAllText(path, EditorJsonUtility.ToJson(subGraph));
            AssetDatabase.ImportAsset(path);

            var loadedSubGraph = AssetDatabase.LoadAssetAtPath(path, typeof(MaterialSubGraphAsset)) as MaterialSubGraphAsset;

            if (loadedSubGraph == null)
            {
                return;
            }

            var subGraphNode = new SubGraphNode();
            var ds           = subGraphNode.drawState;

            ds.position            = new Rect(middle - new Vector2(100f, 150f), Vector2.zero);
            subGraphNode.drawState = ds;
            graphObject.graph.AddNode(subGraphNode);
            subGraphNode.subGraphAsset = loadedSubGraph;

            foreach (var edgeMap in externalInputNeedingConnection)
            {
                graphObject.graph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode.guid, edgeMap.Value.guid.GetHashCode()));
            }

            foreach (var edgeMap in externalOutputsNeedingConnection)
            {
                graphObject.graph.Connect(new SlotReference(subGraphNode.guid, edgeMap.Value.inputSlot.slotId), edgeMap.Key.inputSlot);
            }

            graphObject.graph.RemoveElements(
                graphView.selection.OfType <IShaderNodeView>().Select(x => x.node as AbstractMaterialNode),
                Enumerable.Empty <IEdge>(),
                Enumerable.Empty <GroupData>());
            graphObject.graph.ValidateGraph();
        }
예제 #25
0
        public void ToSubGraph()
        {
            var graphView = graphEditorView.graphView;

            string path;
            string sessionStateResult = SessionState.GetString(k_PrevSubGraphPathKey, k_PrevSubGraphPathDefaultValue);
            string pathToOriginSG     = Path.GetDirectoryName(AssetDatabase.GUIDToAssetPath(selectedGuid));

            if (!sessionStateResult.Equals(k_PrevSubGraphPathDefaultValue))
            {
                path = sessionStateResult;
            }
            else
            {
                path = pathToOriginSG;
            }

            path = EditorUtility.SaveFilePanelInProject("Save Sub Graph", "New Shader Sub Graph", ShaderSubGraphImporter.Extension, "", path);
            path = path.Replace(Application.dataPath, "Assets");
            if (path.Length == 0)
            {
                return;
            }

            graphObject.RegisterCompleteObjectUndo("Convert To Subgraph");

            var nodes  = graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode || x.node is SubGraphOutputNode)).Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray();
            var bounds = Rect.MinMaxRect(float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity);

            foreach (var node in nodes)
            {
                var center = node.drawState.position.center;
                bounds = Rect.MinMaxRect(
                    Mathf.Min(bounds.xMin, center.x),
                    Mathf.Min(bounds.yMin, center.y),
                    Mathf.Max(bounds.xMax, center.x),
                    Mathf.Max(bounds.yMax, center.y));
            }
            var middle = bounds.center;

            bounds.center = Vector2.zero;

            // Collect graph inputs
            var graphInputs = graphView.selection.OfType <BlackboardField>().Select(x => x.userData as ShaderInput);

            // Collect the property nodes and get the corresponding properties
            var propertyNodes  = graphView.selection.OfType <IShaderNodeView>().Where(x => (x.node is PropertyNode)).Select(x => ((PropertyNode)x.node).property);
            var metaProperties = graphView.graph.properties.Where(x => propertyNodes.Contains(x));

            // Collect the keyword nodes and get the corresponding keywords
            var keywordNodes = graphView.selection.OfType <IShaderNodeView>().Where(x => (x.node is KeywordNode)).Select(x => ((KeywordNode)x.node).keyword);
            var metaKeywords = graphView.graph.keywords.Where(x => keywordNodes.Contains(x));

            var copyPasteGraph = new CopyPasteGraph(graphView.selection.OfType <ShaderGroup>().Select(x => x.userData),
                                                    graphView.selection.OfType <IShaderNodeView>().Where(x => !(x.node is PropertyNode || x.node is SubGraphOutputNode)).Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(),
                                                    graphView.selection.OfType <Edge>().Select(x => x.userData as Graphing.Edge),
                                                    graphInputs,
                                                    metaProperties,
                                                    metaKeywords,
                                                    graphView.selection.OfType <StickyNote>().Select(x => x.userData),
                                                    true);

            // why do we serialize and deserialize only to make copies of everything in the steps below?
            // is this just to clear out all non-serialized data?
            var deserialized = CopyPasteGraph.FromJson(MultiJson.Serialize(copyPasteGraph), graphView.graph);

            if (deserialized == null)
            {
                return;
            }

            var subGraph = new GraphData {
                isSubGraph = true, path = "Sub Graphs"
            };
            var subGraphOutputNode = new SubGraphOutputNode();

            {
                var drawState = subGraphOutputNode.drawState;
                drawState.position           = new Rect(new Vector2(bounds.xMax + 200f, 0f), drawState.position.size);
                subGraphOutputNode.drawState = drawState;
            }
            subGraph.AddNode(subGraphOutputNode);
            subGraph.outputNode = subGraphOutputNode;

            // Always copy deserialized keyword inputs
            foreach (ShaderKeyword keyword in deserialized.metaKeywords)
            {
                var copiedInput = (ShaderKeyword)keyword.Copy();
                subGraph.SanitizeGraphInputName(copiedInput);
                subGraph.SanitizeGraphInputReferenceName(copiedInput, keyword.overrideReferenceName);
                subGraph.AddGraphInput(copiedInput);

                // Update the keyword nodes that depends on the copied keyword
                var dependentKeywordNodes = deserialized.GetNodes <KeywordNode>().Where(x => x.keyword == keyword);
                foreach (var node in dependentKeywordNodes)
                {
                    node.owner   = graphView.graph;
                    node.keyword = copiedInput;
                }
            }

            foreach (GroupData groupData in deserialized.groups)
            {
                subGraph.CreateGroup(groupData);
            }

            foreach (var node in deserialized.GetNodes <AbstractMaterialNode>())
            {
                var drawState = node.drawState;
                drawState.position = new Rect(drawState.position.position - middle, drawState.position.size);
                node.drawState     = drawState;

                // Checking if the group guid is also being copied.
                // If not then nullify that guid
                if (node.group != null && !subGraph.groups.Contains(node.group))
                {
                    node.group = null;
                }

                subGraph.AddNode(node);
            }

            foreach (var note in deserialized.stickyNotes)
            {
                if (note.group != null && !subGraph.groups.Contains(note.group))
                {
                    note.group = null;
                }

                subGraph.AddStickyNote(note);
            }

            // figure out what needs remapping
            var externalOutputSlots = new List <Graphing.Edge>();
            var externalInputSlots  = new List <Graphing.Edge>();

            foreach (var edge in deserialized.edges)
            {
                var outputSlot = edge.outputSlot;
                var inputSlot  = edge.inputSlot;

                var outputSlotExistsInSubgraph = subGraph.ContainsNode(outputSlot.node);
                var inputSlotExistsInSubgraph  = subGraph.ContainsNode(inputSlot.node);

                // pasting nice internal links!
                if (outputSlotExistsInSubgraph && inputSlotExistsInSubgraph)
                {
                    subGraph.Connect(outputSlot, inputSlot);
                }
                // one edge needs to go to outside world
                else if (outputSlotExistsInSubgraph)
                {
                    externalInputSlots.Add(edge);
                }
                else if (inputSlotExistsInSubgraph)
                {
                    externalOutputSlots.Add(edge);
                }
            }

            // Find the unique edges coming INTO the graph
            var uniqueIncomingEdges = externalOutputSlots.GroupBy(
                edge => edge.outputSlot,
                edge => edge,
                (key, edges) => new { slotRef = key, edges = edges.ToList() });

            var externalInputNeedingConnection = new List <KeyValuePair <IEdge, AbstractShaderProperty> >();

            var       amountOfProps  = uniqueIncomingEdges.Count();
            const int height         = 40;
            const int subtractHeight = 20;
            var       propPos        = new Vector2(0, -((amountOfProps / 2) + height) - subtractHeight);

            foreach (var group in uniqueIncomingEdges)
            {
                var sr       = group.slotRef;
                var fromNode = sr.node;
                var fromSlot = sr.slot;

                var materialGraph = graphObject.graph;
                var fromProperty  = fromNode is PropertyNode fromPropertyNode
                    ? materialGraph.properties.FirstOrDefault(p => p == fromPropertyNode.property)
                    : null;

                AbstractShaderProperty prop;
                switch (fromSlot.concreteValueType)
                {
                case ConcreteSlotValueType.Texture2D:
                    prop = new Texture2DShaderProperty();
                    break;

                case ConcreteSlotValueType.Texture2DArray:
                    prop = new Texture2DArrayShaderProperty();
                    break;

                case ConcreteSlotValueType.Texture3D:
                    prop = new Texture3DShaderProperty();
                    break;

                case ConcreteSlotValueType.Cubemap:
                    prop = new CubemapShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector4:
                    prop = new Vector4ShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector3:
                    prop = new Vector3ShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector2:
                    prop = new Vector2ShaderProperty();
                    break;

                case ConcreteSlotValueType.Vector1:
                    prop = new Vector1ShaderProperty();
                    break;

                case ConcreteSlotValueType.Boolean:
                    prop = new BooleanShaderProperty();
                    break;

                case ConcreteSlotValueType.Matrix2:
                    prop = new Matrix2ShaderProperty();
                    break;

                case ConcreteSlotValueType.Matrix3:
                    prop = new Matrix3ShaderProperty();
                    break;

                case ConcreteSlotValueType.Matrix4:
                    prop = new Matrix4ShaderProperty();
                    break;

                case ConcreteSlotValueType.SamplerState:
                    prop = new SamplerStateShaderProperty();
                    break;

                case ConcreteSlotValueType.Gradient:
                    prop = new GradientShaderProperty();
                    break;

                case ConcreteSlotValueType.VirtualTexture:
                    prop = new VirtualTextureShaderProperty()
                    {
                        // also copy the VT settings over from the original property (if there is one)
                        value = (fromProperty as VirtualTextureShaderProperty)?.value ?? new SerializableVirtualTexture()
                    };
                    break;

                default:
                    throw new ArgumentOutOfRangeException();
                }

                prop.displayName = fromProperty != null
                    ? fromProperty.displayName
                    : fromSlot.concreteValueType.ToString();
                prop.displayName = GraphUtil.SanitizeName(subGraph.addedInputs.Select(p => p.displayName), "{0} ({1})",
                                                          prop.displayName);

                subGraph.AddGraphInput(prop);
                var propNode = new PropertyNode();
                {
                    var drawState = propNode.drawState;
                    drawState.position = new Rect(new Vector2(bounds.xMin - 300f, 0f) + propPos,
                                                  drawState.position.size);
                    propPos           += new Vector2(0, height);
                    propNode.drawState = drawState;
                }
                subGraph.AddNode(propNode);
                propNode.property = prop;

                foreach (var edge in group.edges)
                {
                    subGraph.Connect(
                        new SlotReference(propNode, PropertyNode.OutputSlotId),
                        edge.inputSlot);
                    externalInputNeedingConnection.Add(new KeyValuePair <IEdge, AbstractShaderProperty>(edge, prop));
                }
            }

            var uniqueOutgoingEdges = externalInputSlots.GroupBy(
                edge => edge.outputSlot,
                edge => edge,
                (key, edges) => new { slot = key, edges = edges.ToList() });

            var externalOutputsNeedingConnection = new List <KeyValuePair <IEdge, IEdge> >();

            foreach (var group in uniqueOutgoingEdges)
            {
                var outputNode = subGraph.outputNode as SubGraphOutputNode;

                AbstractMaterialNode node = group.edges[0].outputSlot.node;
                MaterialSlot         slot = node.FindSlot <MaterialSlot>(group.edges[0].outputSlot.slotId);
                var slotId = outputNode.AddSlot(slot.concreteValueType);

                var inputSlotRef = new SlotReference(outputNode, slotId);

                foreach (var edge in group.edges)
                {
                    var newEdge = subGraph.Connect(edge.outputSlot, inputSlotRef);
                    externalOutputsNeedingConnection.Add(new KeyValuePair <IEdge, IEdge>(edge, newEdge));
                }
            }

            if (FileUtilities.WriteShaderGraphToDisk(path, subGraph))
            {
                AssetDatabase.ImportAsset(path);
            }

            // Store path for next time
            if (!pathToOriginSG.Equals(Path.GetDirectoryName(path)))
            {
                SessionState.SetString(k_PrevSubGraphPathKey, Path.GetDirectoryName(path));
            }
            else
            {
                // Or continue to make it so that next time it will open up in the converted-from SG's directory
                SessionState.EraseString(k_PrevSubGraphPathKey);
            }

            var loadedSubGraph = AssetDatabase.LoadAssetAtPath(path, typeof(SubGraphAsset)) as SubGraphAsset;

            if (loadedSubGraph == null)
            {
                return;
            }

            var subGraphNode = new SubGraphNode();
            var ds           = subGraphNode.drawState;

            ds.position            = new Rect(middle - new Vector2(100f, 150f), Vector2.zero);
            subGraphNode.drawState = ds;

            // Add the subgraph into the group if the nodes was all in the same group group
            var firstNode = copyPasteGraph.GetNodes <AbstractMaterialNode>().FirstOrDefault();

            if (firstNode != null && copyPasteGraph.GetNodes <AbstractMaterialNode>().All(x => x.group == firstNode.group))
            {
                subGraphNode.group = firstNode.group;
            }

            subGraphNode.asset = loadedSubGraph;
            graphObject.graph.AddNode(subGraphNode);

            foreach (var edgeMap in externalInputNeedingConnection)
            {
                graphObject.graph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode, edgeMap.Value.guid.GetHashCode()));
            }

            foreach (var edgeMap in externalOutputsNeedingConnection)
            {
                graphObject.graph.Connect(new SlotReference(subGraphNode, edgeMap.Value.inputSlot.slotId), edgeMap.Key.inputSlot);
            }

            graphObject.graph.RemoveElements(
                graphView.selection.OfType <IShaderNodeView>().Select(x => x.node).Where(x => x.allowedInSubGraph).ToArray(),
                new IEdge[] {},
                new GroupData[] {},
                graphView.selection.OfType <StickyNote>().Select(x => x.userData).ToArray());
            graphObject.graph.ValidateGraph();
        }
예제 #26
0
        public static void UpdateDragging()
        {
            if (draggingItem != null && PlayerInput.LeftButtonReleased())
            {
                if (CharacterHealth.OpenHealthWindow != null &&
                    CharacterHealth.OpenHealthWindow.OnItemDropped(draggingItem, false))
                {
                    draggingItem = null;
                    return;
                }

                if (selectedSlot == null)
                {
                    draggingItem.ParentInventory?.CreateNetworkEvent();
                    draggingItem.Drop();
                    GUI.PlayUISound(GUISoundType.DropItem);
                }
                else if (selectedSlot.ParentInventory.Items[selectedSlot.SlotIndex] != draggingItem)
                {
                    Inventory selectedInventory = selectedSlot.ParentInventory;
                    int       slotIndex         = selectedSlot.SlotIndex;
                    if (selectedInventory.TryPutItem(draggingItem, slotIndex, true, true, Character.Controlled))
                    {
                        if (selectedInventory.slots != null)
                        {
                            selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.White, 0.1f, 0.4f);
                        }
                        GUI.PlayUISound(GUISoundType.PickItem);
                    }
                    else
                    {
                        if (selectedInventory.slots != null)
                        {
                            selectedInventory.slots[slotIndex].ShowBorderHighlight(Color.Red, 0.1f, 0.9f);
                        }
                        GUI.PlayUISound(GUISoundType.PickItemFail);
                    }
                    selectedInventory.HideTimer = 1.0f;
                    if (selectedSlot.ParentInventory?.Owner is Item parentItem && parentItem.ParentInventory != null)
                    {
                        for (int i = 0; i < parentItem.ParentInventory.capacity; i++)
                        {
                            if (parentItem.ParentInventory.HideSlot(i))
                            {
                                continue;
                            }
                            if (parentItem.ParentInventory.Items[i] != parentItem)
                            {
                                continue;
                            }

                            highlightedSubInventorySlots.Add(new SlotReference(
                                                                 parentItem.ParentInventory, parentItem.ParentInventory.slots[i],
                                                                 i, false, selectedSlot.ParentInventory));
                            break;
                        }
                    }
                    draggingItem = null;
                    draggingSlot = null;
                }

                draggingItem = null;
            }

            if (selectedSlot != null && !selectedSlot.Slot.MouseOn())
            {
                selectedSlot = null;
            }
        }
예제 #27
0
        protected void UpdateSlot(InventorySlot slot, int slotIndex, Item item, bool isSubSlot)
        {
            Rectangle interactRect = slot.InteractRect;

            interactRect.Location += slot.DrawOffset.ToPoint();

            bool mouseOnGUI = false;

            /*if (GUI.MouseOn != null)
             * {
             *  //block usage if the mouse is on a GUIComponent that's not related to this inventory
             *  if (RectTransform == null || (RectTransform != GUI.MouseOn.RectTransform && !GUI.MouseOn.IsParentOf(RectTransform.GUIComponent)))
             *  {
             *      mouseOnGUI = true;
             *  }
             * }*/

            bool mouseOn = interactRect.Contains(PlayerInput.MousePosition) && !Locked && !mouseOnGUI;

            if (PlayerInput.LeftButtonHeld() && PlayerInput.RightButtonHeld())
            {
                mouseOn = false;
            }

            if (selectedSlot != null && selectedSlot.Slot != slot)
            {
                //subinventory slot highlighted -> don't allow highlighting this one
                if (selectedSlot.IsSubSlot && !isSubSlot)
                {
                    mouseOn = false;
                }
                else if (!selectedSlot.IsSubSlot && isSubSlot && mouseOn)
                {
                    selectedSlot = null;
                }
            }


            slot.State = GUIComponent.ComponentState.None;

            if (mouseOn && (draggingItem != null || selectedSlot == null || selectedSlot.Slot == slot))
            // &&
            //(highlightedSubInventories.Count == 0 || highlightedSubInventories.Contains(this) || highlightedSubInventorySlot?.Slot == slot || highlightedSubInventory.Owner == item))
            {
                slot.State = GUIComponent.ComponentState.Hover;

                if (selectedSlot == null || (!selectedSlot.IsSubSlot && isSubSlot))
                {
                    selectedSlot = new SlotReference(this, slot, slotIndex, isSubSlot, Items[slotIndex]?.GetComponent <ItemContainer>()?.Inventory);
                }

                if (draggingItem == null)
                {
                    if (PlayerInput.LeftButtonDown())
                    {
                        draggingItem = Items[slotIndex];
                        draggingSlot = slot;
                    }
                }
                else if (PlayerInput.LeftButtonReleased())
                {
                    if (PlayerInput.DoubleClicked())
                    {
                        doubleClickedItem = item;
                    }
                }
            }
        }
예제 #28
0
 public bool FindPort(SlotReference slot, out ShaderPort port)
 {
     port = contentContainer.Q("top")?.Query <ShaderPort>().Where(p => p.slot.slotReference.Equals(slot)).First();
     return(port != null);
 }
예제 #29
0
 public bool FindPort(SlotReference slot, out ShaderPort port)
 {
     port = output as ShaderPort;
     return(port != null && port.slot.slotReference.Equals(slot));
 }