Beispiel #1
0
        void MoveNode(int id, Vector2 newOffset, bool snapToPixel = true)
        {
            if (m_playing)
            {
                return;
            }

            PowerAnimFrame frame = GetCurrentFrame();

            if (frame == null)
            {
                return;
            }

            Sprite sprite = GetSpriteAtTime(m_animTime);

            if (sprite != null && snapToPixel)
            {
                // Snap offset to sprite pixels
                newOffset = new Vector2(Utils.Snap(newOffset.x, 0.5f), Utils.Snap(newOffset.y, 0.5f));
            }

            SetNodeOffsetAtFrame(frame, id, newOffset);
            m_nodePositions[id] = newOffset;

            // NB: Don't wanna apply changes while dragging, just apply on lift. So no ApplyChanges() here.
        }
Beispiel #2
0
        // Gets node at frame, creating it if it doesn't exist
        Node FindOrCreateNodeAtFrame(PowerAnimFrame frame, int nodeId)
        {
            if (frame == null)
            {
                return(null);
            }

            Node node = null;

            if (frame.m_nodes == null)
            {
                frame.m_nodes = new List <Node>(1);
            }
            else
            {
                node = frame.m_nodes.Find(item => item.m_nodeId == nodeId);
            }

            if (node == null)
            {
                // Adding node first time, set it's id, and set offset/angle to whatever the cached one is (if it's set on a previous frame it'll use that).

                node = new Node()
                {
                    m_nodeId = nodeId
                };
                frame.m_nodes.Add(node);
                // Set defaults for frame (based on previous frames)
                InitNodeValues(node, frame);
            }
            return(node);
        }
Beispiel #3
0
 // Sets the angle of a node on a particular anim frame, adding it if it didn't exist.
 void SetNodeAngleAtFrame(PowerAnimFrame frame, int nodeId, float angle)
 {
     if (frame != null)
     {
         FindOrCreateNodeAtFrame(frame, nodeId).m_angle = Mathf.Repeat(angle, 360f);
     }
 }
Beispiel #4
0
        // Updates the current frame's node pos/rot, if node isn't overriden on current frame it's set to last set position
        void UpdateCurrentFrameNodePositions()
        {
            // NB:  Could cashe stuff to do this more efficiently than looping through every node every frame.
            int currFrame = GetCurrentFrameId();

            if (currFrame < 0)
            {
                return;
            }

            // Work backwards through nodes to find the latest node with a value
            for (int nodeId = 0; nodeId < PowerSpriteAnimNodes.NUM_NODES; ++nodeId)
            {
                m_nodePositions[nodeId] = Vector2.zero;
                m_nodeAngles[nodeId]    = 0;

                for (int frameId = currFrame; frameId >= 0; --frameId)
                {
                    Node           node  = null;
                    PowerAnimFrame frame = m_frames[frameId];
                    if (frame.m_nodes != null)
                    {
                        node = frame.m_nodes.Find(item => item.m_nodeId == nodeId);
                    }

                    if (node != null)
                    {
                        m_nodePositions[nodeId] = node.m_offset;
                        m_nodeAngles[nodeId]    = Mathf.Repeat(node.m_angle, 360f);
                        break;                 // brake from inner loop
                    }
                }
            }
        }
Beispiel #5
0
        void LayoutAnimationNodesPanel(Rect rect)
        {
            UpdateCurrentFrameNodePositions();

            Event e = Event.current;

            PowerAnimFrame currentFrame = GetCurrentFrame();

            //
            // Draw Nodes - back to front (selected at front)
            //
            for (int i = 0; i < PowerSpriteAnimNodes.NUM_NODES; ++i)
            {
                if (i != m_selectedNode && Utils.BitMask.IsSet(m_visibleNodes, i))
                {
                    LayoutNode(rect, i, currentFrame);
                }
            }
            if (m_selectedNode >= 0)
            {
                LayoutNode(rect, m_selectedNode, currentFrame);
            }

            //
            // Handle node events - front to back (selected last)
            //
            if (m_selectedNode >= 0)
            {
                HandleNodeEvents(rect, m_selectedNode, e);
            }
            for (int i = PowerSpriteAnimNodes.NUM_NODES - 1; i >= 0; --i)
            {
                if (i != m_selectedNode && Utils.BitMask.IsSet(m_visibleNodes, i))
                {
                    HandleNodeEvents(rect, i, e);
                }
            }

            //
            // Check for double click to add node
            //

            if (m_playing == false && e.button == 0 && e.type == EventType.MouseDown && rect.Contains(e.mousePosition) && m_dragState == eDragState.None)
            {
                if (m_selectedNode >= 0)
                {
                    ClearSelection();
                    GUI.FocusControl("none");
                    e.Use();
                }
                if (e.clickCount == 2 && GetUnusedNodeId() >= 0)
                {
                    // Double clicked, add new node at position, with the cached angle from the last set frame
                    AddNode((e.mousePosition - rect.center - m_previewOffset) / m_previewScale);
                    GUI.FocusControl("none");
                    e.Use();
                }
            }
        }
Beispiel #6
0
        void LayoutFrameListFrame(Rect rect, int index, bool isActive, bool isFocused)
        {
            if (m_frames == null || index < 0 || index >= m_frames.Count)
            {
                return;
            }
            PowerAnimFrame frame = m_frames[index];

            EditorGUI.BeginChangeCheck();
            rect = new Rect(rect)
            {
                height = rect.height - 4, y = rect.y + 2
            };


            // frame ID
            float xOffset = rect.x;
            float width   = Styles.INFOPANEL_LABEL_RIGHTALIGN.CalcSize(new GUIContent(index.ToString())).x;

            EditorGUI.LabelField(new Rect(rect)
            {
                x = xOffset, width = width
            }, index.ToString(), Styles.INFOPANEL_LABEL_RIGHTALIGN);

            // Frame Sprite
            xOffset += width + 5;
            width    = (rect.xMax - 5 - 28) - xOffset;

            // Sprite thingy
            Rect spriteFieldRect = new Rect(rect)
            {
                x = xOffset, width = width, height = 16
            };

            frame.m_sprite = EditorGUI.ObjectField(spriteFieldRect, frame.m_sprite, typeof(Sprite), false) as Sprite;

            // Frame length (in samples)
            xOffset += width + 5;
            width    = 28;
            GUI.SetNextControlName("FrameLen");
            int frameLen = frame.m_length;

            frameLen = EditorGUI.IntField(new Rect(rect)
            {
                x = xOffset, width = width
            }, frameLen);
            SetFrameLength(frame, frameLen);


            if (EditorGUI.EndChangeCheck())
            {
                // Apply events
                ApplyChanges();
            }
        }
Beispiel #7
0
        // Sets the y offset of a node on a particular anim frame, adding it if it didn't exist.
        void SetNodeYAtFrame(PowerAnimFrame frame, int nodeId, float value)
        {
            Node node = FindOrCreateNodeAtFrame(frame, nodeId);

            // if (value == 0 && onLoad == false ) - This function is only called on load
            //  value = 0.0001f; // Zero nodes are stripped, so when setting to zero, actually set to a real low value
            if (node != null)
            {
                node.m_offset = new Vector2(node.m_offset.x, value);
            }
        }
Beispiel #8
0
        // Sets the offset of a node on a particular anim frame, adding it if it didn't exist.
        void SetNodeOffsetAtFrame(PowerAnimFrame frame, int nodeId, Vector2 offset)
        {
            Node node = FindOrCreateNodeAtFrame(frame, nodeId);

            if (offset == Vector2.zero)
            {
                offset = new Vector2(0.0001f, 0.0001f);        // Zero nodes are stripped, so when setting to zero, actually set to a real low value
            }
            if (node != null)
            {
                node.m_offset = offset;
            }
        }
Beispiel #9
0
        void RotateNode(int id, float newAngle)
        {
            if (m_playing)
            {
                return;
            }

            PowerAnimFrame frame = GetCurrentFrame();

            if (frame == null)
            {
                return;
            }

            SetNodeAngleAtFrame(frame, id, newAngle);
            m_nodeAngles[id] = Mathf.Repeat(newAngle, 360);

            // NB: Don't wanna apply changes while dragging, just apply on lift. So no ApplyChanges() here.
        }
Beispiel #10
0
 // Sets node values based on what nodes have on previous frames
 void InitNodeValues(Node node, PowerAnimFrame frame)
 {
     // Work backwards to find last node
     for (int frameId = m_frames.FindIndex(item => item == frame) - 1; frameId >= 0; --frameId)
     {
         Node           prevFrameNode = null;
         PowerAnimFrame prevFrame     = m_frames[frameId];
         if (prevFrame.m_nodes != null)
         {
             prevFrameNode = prevFrame.m_nodes.Find(item => item.m_nodeId == node.m_nodeId);
         }
         if (prevFrameNode != null)
         {
             node.m_offset = prevFrameNode.m_offset;
             node.m_angle  = prevFrameNode.m_angle;
             break;
         }
     }
 }
Beispiel #11
0
        // Delete the node form the current frame, if there are no frames left, deletes the node
        void DeleteNode(int id)
        {
            if (m_playing)
            {
                return;
            }

            // check if on other frames
            bool           onOtherFrames = false;
            PowerAnimFrame currentFrame  = GetCurrentFrame();

            if (currentFrame == null)
            {
                return;
            }
            foreach (PowerAnimFrame frame in m_frames)
            {
                if (frame != currentFrame && frame.m_nodes != null && frame.m_nodes.Exists(item => item.m_nodeId == id && (item.m_offset != Vector2.zero || item.m_angle != 0)))
                {
                    onOtherFrames = true;
                    break;
                }
            }
            if (onOtherFrames == false)
            {
                m_nodePositions[id] = Vector2.zero;
                m_nodeAngles[id]    = 0;
                m_nodeMask          = Utils.BitMask.UnsetAt(m_nodeMask, id);
            }

            if (currentFrame.m_nodes != null)
            {
                currentFrame.m_nodes.RemoveAll(item => item.m_nodeId == id);
            }

            ApplyChanges();
        }
Beispiel #12
0
        // Node data editor
        void LayoutBottomBarNodeData(Rect rect)
        {
            PowerAnimFrame currentFrame = GetCurrentFrame();
            bool           frameHasNode = (currentFrame != null && currentFrame.m_nodes != null && currentFrame.m_nodes.Exists(item => item.m_nodeId == m_selectedNode));

            GUIContent labelContent = null;

            float xOffset = 10;
            float width   = 60;

            GUI.Label(new Rect(xOffset, 1, width, rect.height), "Node: " + m_selectedNode, EditorStyles.boldLabel);

            Vector2 pos   = m_nodePositions[m_selectedNode];
            float   angle = m_nodeAngles[m_selectedNode];

            // Position
            EditorGUI.BeginChangeCheck();

            xOffset     += width;
            width        = 10;
            labelContent = new GUIContent("X");
            width        = EditorStyles.miniLabel.CalcSize(labelContent).x;
            GUI.Label(new Rect(xOffset, 1, width, rect.height), labelContent, EditorStyles.miniLabel);

            xOffset += width;
            width    = 40;
            GUI.SetNextControlName("OffsetX");
            pos.x = EditorGUI.FloatField(new Rect(xOffset, 2, width, rect.height - 3), Mathf.Abs(pos.x) <= 0.00011f ? 0 : pos.x, EditorStyles.miniTextField);

            xOffset     += width;
            width        = 10;
            labelContent = new GUIContent("Y");
            width        = EditorStyles.miniLabel.CalcSize(labelContent).x;
            GUI.Label(new Rect(xOffset, 0, width, rect.height), labelContent, EditorStyles.miniLabel);

            xOffset += width;
            width    = 40;
            GUI.SetNextControlName("OffsetY");
            pos.y = EditorGUI.FloatField(new Rect(xOffset, 2, width, rect.height - 3), Mathf.Abs(pos.y) <= 0.00011f ? 0 : pos.y, EditorStyles.miniTextField);
            if (EditorGUI.EndChangeCheck())
            {
                MoveNode(m_selectedNode, pos);
                ApplyChanges();
            }

            // Angle
            EditorGUI.BeginChangeCheck();
            xOffset     += width + 1;
            labelContent = new GUIContent("Angle:");
            width        = EditorStyles.miniLabel.CalcSize(labelContent).x;
            GUI.Label(new Rect(xOffset, 1, width, rect.height), labelContent, EditorStyles.miniLabel);

            xOffset += width;
            GUI.SetNextControlName("Angle");
            width = Mathf.Max(25, EditorStyles.miniTextField.CalcSize(new GUIContent(angle.ToString())).x + 2);
            angle = EditorGUI.FloatField(new Rect(xOffset, 2, width, rect.height - 3), angle, EditorStyles.miniTextField);

            if (EditorGUI.EndChangeCheck())
            {
                RotateNode(m_selectedNode, angle);
                ApplyChanges();
            }

            // Display Name
            xOffset     += width + 15;
            labelContent = new GUIContent("Preview name:");
            width        = EditorStyles.miniLabel.CalcSize(labelContent).x;
            EditorGUI.LabelField(new Rect(xOffset, 1, width, rect.height - 3), labelContent, EditorStyles.miniLabel);
            xOffset += width;

            width = 60;
            GUI.SetNextControlName("NodeName");
            width = Mathf.Max(25, EditorStyles.miniTextField.CalcSize(new GUIContent(m_defaultNodeNames[m_selectedNode])).x + 2);
            m_defaultNodeNames[m_selectedNode] = EditorGUI.TextField(new Rect(xOffset, 2, width, rect.height - 3), m_defaultNodeNames[m_selectedNode], EditorStyles.miniTextField);
            xOffset += width;

            labelContent = new GUIContent("/ sprite");
            width        = EditorStyles.miniLabel.CalcSize(labelContent).x;
            EditorGUI.LabelField(new Rect(xOffset, 1, width, rect.height - 3), labelContent, EditorStyles.miniLabel);
            xOffset += width;

            width        = 70;
            labelContent = new GUIContent(m_defaultNodeSprites[m_selectedNode] == null ? "None" : m_defaultNodeSprites[m_selectedNode].name);
            width        = Mathf.Min(120, EditorStyles.miniTextField.CalcSize(labelContent).x + 38);
            //width =  Mathf.Max( 25, EditorStyles.miniTextField.CalcSize(new GUIContent(m_defaultNodeSprites[m_selectedNode])).x + 2 );
            m_defaultNodeSprites[m_selectedNode] = EditorGUI.ObjectField(new Rect(xOffset, 2, width, rect.height - 3), m_defaultNodeSprites[m_selectedNode], typeof(Sprite), false) as Sprite;
            xOffset += width;

            //width = 120;
            //GUI.Label( new Rect(xOffset,1, width,rect.height), "(editor only)", EditorStyles.miniLabel );

            // Align to right
            xOffset = rect.width;

            // Reset button
            width    = 50;
            xOffset -= width + 5;
            if (GUI.Button(new Rect(xOffset, 2, width, rect.height - 4), "Delete", EditorStyles.miniButton))
            {
                DeleteNodeAllFrames(m_selectedNode);
            }


                #if UNITY_2019_1_OR_NEWER
            width = 125;
                #else
            width = 105;
                #endif
            xOffset    -= width + 5;
            GUI.enabled = frameHasNode;
            if (GUI.Button(new Rect(xOffset, 2, width, rect.height - 4), "Clear Frame Offset", EditorStyles.miniButton))
            {
                DeleteNode(m_selectedNode);
            }
            GUI.enabled = true;
        }
Beispiel #13
0
        void LayoutNode(Rect rect, int nodeId, PowerAnimFrame currentFrame)
        {
            if (Utils.BitMask.IsSet(m_nodeMask, nodeId) == false)
            {
                return;
            }

            //
            // Translate node position to preview window
            //
            Vector2 nodePos = m_nodePositions[nodeId];

            nodePos = nodePos * m_previewScale;
            nodePos = nodePos + m_previewOffset;
            Rect nodeRect = new Rect(rect.center.x + nodePos.x - 8, rect.center.y + nodePos.y - 8, 16, 16);

            // Check rect is visible
            if (rect.Contains(nodeRect.center) == false)
            {
                return;
            }

            //
            // Draw
            //
            Color savedColor = Handles.color;

            Handles.color = Color.white;    // NODE_COLORS[i%NODE_COLORS.Length];

            bool hasSprite = m_defaultNodeSprites[nodeId] != null;

            if (hasSprite)
            {
                // Render node sprite if it has one
                LayoutFrameSprite(new Rect(rect)
                {
                    center = nodeRect.center
                }, m_defaultNodeSprites[nodeId], m_previewScale, Vector2.zero /*m_previewOffset*/, false, true, m_nodeAngles[nodeId]);
            }
            string nodeText = nodeId.ToString();

            if (string.IsNullOrEmpty(m_defaultNodeNames[nodeId]) == false && hasSprite == false)
            {
                nodeText = string.Concat(nodeText, ':', m_defaultNodeNames[nodeId]);
            }
            float textWidth     = Styles.PREVIEW_LABEL_BOLD.CalcSize(new GUIContent(nodeText)).x + 2;
            Rect  labelRectName = new Rect(nodeRect)
            {
                x = nodeRect.x + 12f, y = nodeRect.y - 1, width = textWidth
            };

            // Offset while dragging or if angle arrow would be overlapping text
            if (m_selectedNode == nodeId && (m_dragState == eDragState.MoveNode || (m_nodeAngles[nodeId] < 10 || m_nodeAngles[nodeId] > 340)))
            {
                labelRectName.y = labelRectName.y - 10f;
            }
            GUI.Label(new Rect(labelRectName)
            {
                x = labelRectName.x + 1f, y = labelRectName.y + 1f
            }, nodeText, new GUIStyle(Styles.PREVIEW_LABEL_BOLD_SHADOW)
            {
                fontSize = 10
            });
            GUI.Label(new Rect(labelRectName)
            {
                x = labelRectName.x + 1f, y = labelRectName.y
            }, nodeText, new GUIStyle(Styles.PREVIEW_LABEL_BOLD_SHADOW)
            {
                fontSize = 10
            });
            GUI.Label(new Rect(labelRectName)
            {
                x = labelRectName.x - 1f, y = labelRectName.y - 1f
            }, nodeText, new GUIStyle(Styles.PREVIEW_LABEL_BOLD_SHADOW)
            {
                fontSize = 10
            });
            GUI.Label(labelRectName, nodeText, new GUIStyle(Styles.PREVIEW_LABEL_BOLD)
            {
                fontSize = 10
            });

            // Alpha lower when the frame doesn't have the node overriden
            bool  frameHasNode = (currentFrame != null && currentFrame.m_nodes != null && currentFrame.m_nodes.Exists(item => item.m_nodeId == nodeId));
            float alpha        = frameHasNode ? 1.0f : 0.25f;
            float sizeInner    = frameHasNode ? 4 : 3;

            Color colorSelectedOutline   = Color.white.WithAlpha(alpha);
            Color colorUnselectedOutline = Color.black.WithAlpha(0.5f * alpha);

            Quaternion nodeRotation = Quaternion.Euler(0, 0, -m_nodeAngles[nodeId]);

            if (m_selectedNode == nodeId)
            {
                if (m_dragState == eDragState.MoveNode)
                {
                    // Draw crosshair
                    float crosshairLength = 256;

                    Handles.color = Color.white.WithAlpha(0.4f);
                    DrawLine(new Vector2(nodeRect.center.x + 1 - crosshairLength, nodeRect.center.y + 1), new Vector2(nodeRect.center.x + 1 + crosshairLength, nodeRect.center.y + 1), Handles.color, 0);
                    DrawLine(new Vector2(nodeRect.center.x + 1, nodeRect.center.y + 1 - crosshairLength), new Vector2(nodeRect.center.x + 1, nodeRect.center.y + 1 + crosshairLength), Handles.color, 0);
                    Handles.DrawWireDisc(nodeRect.center, Vector3.back, 128);
                    Handles.DrawWireDisc(nodeRect.center, Vector3.back, 96);
                    Handles.DrawWireDisc(nodeRect.center, Vector3.back, 64);
                    Handles.DrawWireDisc(nodeRect.center, Vector3.back, 32);

                    crosshairLength = 20;
                    DrawLine(new Vector2(nodeRect.center.x + 1 - crosshairLength, nodeRect.center.y + 1), new Vector2(nodeRect.center.x + 1 + crosshairLength, nodeRect.center.y + 1), Color.black, 0);
                    DrawLine(new Vector2(nodeRect.center.x + 1, nodeRect.center.y + 1 - crosshairLength), new Vector2(nodeRect.center.x + 1, nodeRect.center.y + 1 + crosshairLength), Color.black, 0);
                    DrawLine(new Vector2(nodeRect.center.x - crosshairLength, nodeRect.center.y), new Vector2(nodeRect.center.x + crosshairLength, nodeRect.center.y), NODE_COLORS[nodeId % NODE_COLORS.Length], 0);
                    DrawLine(new Vector2(nodeRect.center.x, nodeRect.center.y - crosshairLength), new Vector2(nodeRect.center.x, nodeRect.center.y + crosshairLength), NODE_COLORS[nodeId % NODE_COLORS.Length], 0);
                    // Draw position string
                    string  positionString = string.Format("{0:0.0}, {1:0.0}", m_nodePositions[nodeId].x, m_nodePositions[nodeId].y);
                    Vector2 labelSize      = Styles.PREVIEW_LABEL_BOLD.CalcSize(new GUIContent(positionString));
                    Rect    labelRect      = new Rect(nodeRect.x + 30, nodeRect.y + 5, labelSize.x, labelSize.y);
                    GUI.Label(new Rect(labelRect)
                    {
                        x = labelRect.x + 1f, y = labelRect.y + 1f
                    }, positionString, Styles.PREVIEW_LABEL_BOLD_SHADOW);
                    GUI.Label(new Rect(labelRect)
                    {
                        x = labelRect.x - 1f, y = labelRect.y - 1f
                    }, positionString, Styles.PREVIEW_LABEL_BOLD_SHADOW);
                    GUI.Label(labelRect, positionString, Styles.PREVIEW_LABEL_BOLD);
                }
                else
                {
                    Handles.color = NODE_COLORS[nodeId % NODE_COLORS.Length].WithAlpha(alpha);

                    Vector2 angleOffset = nodeRotation * Vector2.right * ROTATE_ARROW_LENGTH;

                    Vector2 lineOffset = nodeRotation * Vector2.up;
                    DrawLine(nodeRect.center + lineOffset, nodeRect.center + angleOffset + lineOffset, Handles.color);
                    lineOffset = nodeRotation * Vector2.down;
                    DrawLine(nodeRect.center + lineOffset, nodeRect.center + angleOffset + lineOffset, Handles.color);
                    Handles.DrawSolidArc((Vector3)nodeRect.center + (nodeRotation * Vector2.right * (ROTATE_ARROW_LENGTH + 3)), Vector3.back, Quaternion.Euler(0, 0, -m_nodeAngles[nodeId] + 20f) * Vector2.left, 40, 10);
                    DrawLine(nodeRect.center, nodeRect.center + angleOffset, Color.white);

                    Handles.DrawSolidDisc(nodeRect.center, Vector3.back, sizeInner + 3);

                    Handles.color = colorSelectedOutline;
                    Handles.DrawSolidDisc(nodeRect.center, Vector3.back, sizeInner + 2);

                    Handles.color = NODE_COLORS[nodeId % NODE_COLORS.Length].WithAlpha(alpha);
                    Handles.DrawSolidDisc(nodeRect.center, Vector3.back, sizeInner);

                    if (m_dragState == eDragState.RotateNode)
                    {
                        // Draw angle string
                        string  angleString = string.Format("{0:0}\u00B0", m_nodeAngles[nodeId]);
                        Vector2 labelSize   = Styles.PREVIEW_LABEL_BOLD.CalcSize(new GUIContent(angleString));
                        Rect    labelRect   = new Rect(nodeRect.x + 15, nodeRect.y + 15, labelSize.x, labelSize.y);
                        GUI.Label(new Rect(labelRect)
                        {
                            x = labelRect.x + 1f, y = labelRect.y + 1f
                        }, angleString, Styles.PREVIEW_LABEL_BOLD_SHADOW);
                        GUI.Label(new Rect(labelRect)
                        {
                            x = labelRect.x - 1f, y = labelRect.y - 1f
                        }, angleString, Styles.PREVIEW_LABEL_BOLD_SHADOW);
                        GUI.Label(labelRect, angleString, Styles.PREVIEW_LABEL_BOLD);
                    }
                }
            }
            else
            {
                Handles.color = colorUnselectedOutline;
                Handles.DrawSolidDisc(new Vector2(nodeRect.center.x, nodeRect.center.y), Vector3.back, sizeInner + 1);
                // Draw angle arrow
                float       arrowSize  = sizeInner * 3.0f;
                const float arrowAngle = 40;
                if (m_nodeAngles[nodeId] != 0)
                {
                    Handles.DrawSolidArc((Vector3)nodeRect.center + (nodeRotation * Vector2.right * (arrowSize + 3)), Vector3.back, Quaternion.Euler(0, 0, -m_nodeAngles[nodeId] + (arrowAngle * 0.5f)) * Vector2.left, arrowAngle, arrowSize);
                }
                Handles.color = NODE_COLORS[nodeId % NODE_COLORS.Length].WithAlpha(alpha);
                if (m_nodeAngles[nodeId] != 0)
                {
                    Handles.DrawSolidArc((Vector3)nodeRect.center + (nodeRotation * Vector2.right * arrowSize), Vector3.back, Quaternion.Euler(0, 0, -m_nodeAngles[nodeId] + (arrowAngle * 0.5f)) * Vector2.left, arrowAngle, arrowSize);
                }

                // Draw foreground dot
                Handles.DrawSolidDisc(new Vector2(nodeRect.center.x, nodeRect.center.y), Vector3.back, sizeInner);
            }
            Handles.color = savedColor;
        }