Beispiel #1
0
        public static void OnSceneGUIEasy(SerializedProperty aPath, Path2D.Plane aPlane = Path2D.Plane.XY, PathSnap aSnapMode = PathSnap.Unity, float aSmartSnapDist = 0, PathEditorVisuals aVisuals = null)
        {
            SerializedObject obj = aPath.serializedObject;
            Transform        t   = ((Component)obj.targetObject).transform;
            Path2D           raw = EditorTools.GetTargetObjectOfProperty(aPath) as Path2D;

            OnSceneGUI(t.localToWorldMatrix, t.worldToLocalMatrix, aPath, raw, true, null, null, aPlane, aSnapMode, aSmartSnapDist, KeyCode.C, aVisuals);
            DoDragSelect(t.localToWorldMatrix, raw, new Rect(0, 0, Screen.width, Screen.height), aVisuals);
            obj.ApplyModifiedProperties();
        }
Beispiel #2
0
 private static Vector2 Deplane(Vector3 aPt, Path2D.Plane aPlane)
 {
     return(aPlane == Path2D.Plane.XY ? aPt.xy() : aPt.xz());
 }
Beispiel #3
0
        public static List <Vector3> GetAllHandleLocations(Matrix4x4 aTransform, Path2D aPathRaw, bool aShowShiftAdd = true, Path2D.Plane aPlane = Path2D.Plane.XY)
        {
            List <Vector3>      result   = new List <Vector3>();
            List <Vector2>      points   = aPathRaw.GetPathRaw();
            List <PointControl> controls = aPathRaw.GetControls();
            bool showControls            = !Event.current.shift && !Event.current.alt;

            // add all points
            List <Vector3> worldPoints = PathUtil.To3D(points, aTransform, aPlane == Path2D.Plane.XY ? PathUtil.ConvertOptions.XY : PathUtil.ConvertOptions.XZ);

            result.AddRange(worldPoints);

            // add the control points
            if (showControls)
            {
                for (int i = 0; i < points.Count; i++)
                {
                    PointControl ctrl = controls[i];
                    PointType    t    = ctrl.type;
                    Vector3      at   = worldPoints[i];

                    if (t == PointType.CircleCorner)
                    {
                        Vector3 end1   = PathUtil.GetRoundedCornerEnd(i, points, controls, aPathRaw.Closed, ctrl.radius, true);
                        Vector3 end2   = PathUtil.GetRoundedCornerEnd(i, points, controls, aPathRaw.Closed, ctrl.radius, false);
                        Vector3 normal = Vector2.Lerp(end1.xy() - points[i], end2.xy() - points[i], 0.5f).normalized;

                        result.Add(at + aTransform.MultiplyVector(Plane(normal * (ctrl.radius + 0.2f), aPlane)));
                    }
                    else if (t == PointType.Free || t == PointType.Locked)
                    {
                        Vector3 v = aTransform.MultiplyVector(Plane(ctrl.controlPrev, aPlane)) + at;
                        result.Add(v);

                        if (t == PointType.Locked)
                        {
                            v = -aTransform.MultiplyVector(Plane(ctrl.controlPrev, aPlane)) + at;
                        }
                        else
                        {
                            v = aTransform.MultiplyVector(Plane(ctrl.controlNext, aPlane)) + at;
                        }
                        result.Add(v);
                    }
                }
            }

            // create the plane on which all edits occur
            Plane editPlane;

            if (aPlane == Path2D.Plane.XY)
            {
                editPlane = new Plane(aTransform.MultiplyPoint3x4(Vector3.zero), aTransform.MultiplyPoint3x4(Vector3.right), aTransform.MultiplyPoint3x4(Vector3.up));
            }
            else
            {
                editPlane = new Plane(aTransform.MultiplyPoint3x4(Vector3.zero), aTransform.MultiplyPoint3x4(Vector3.right), aTransform.MultiplyPoint3x4(Vector3.forward));
            }

            // add shift-add handle
            if (Event.current.shift && aShowShiftAdd)
            {
                Ray   r    = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
                float dist = 0;
                if (editPlane.Raycast(r, out dist))
                {
                    result.Add(r.GetPoint(dist));
                }
            }

            return(result);
        }
Beispiel #4
0
 private static Vector3 Plane(Vector2 aPt, Path2D.Plane aPlane)
 {
     return(aPlane == Path2D.Plane.XY ? aPt.xy0() : aPt.x0y());
 }
Beispiel #5
0
        private static void ShowPointDeleteMode(Path2D aPathRaw, int aIndex, Selection aSelection, Matrix4x4 aTransform, SerializedProperty aPath, Action <SerializedProperty, int> aOnRemovePoint, Path2D.Plane aPlane, PathEditorVisuals aVisuals)
        {
            Handles.color = aVisuals.colorHandleDelete * _activeHandleTint;
            Vector3 aAt = aTransform.MultiplyPoint3x4(Plane(aPathRaw[aIndex], aPlane));

            if (Handles.Button(aAt,
                               SceneView.lastActiveSceneView.camera.transform.rotation,
                               HandleUtility.GetHandleSize(aAt) * aVisuals.sizeVertexDelete,
                               HandleUtility.GetHandleSize(aAt) * aVisuals.sizeVertexDelete,
                               aVisuals.capVertexDelete))
            {
                SerializedProperty points   = aPath.FindPropertyRelative("_points");
                SerializedProperty controls = aPath.FindPropertyRelative("_pointControls");
                aSelection.Each(aIndex, i => {
                    points.DeleteArrayElementAtIndex(i);
                    controls.DeleteArrayElementAtIndex(i);
                    if (aOnRemovePoint != null)
                    {
                        aOnRemovePoint(aPath, i);
                    }
                });
                aSelection.ids.Clear();

                if (_recentInteract == aIndex)
                {
                    _recentInteract = -1;
                }
                GUI.changed = true;
            }
        }
Beispiel #6
0
        private static void ShowHandles(Path2D aPathRaw, int aIndex, Matrix4x4 aTransform, Matrix4x4 aInvTransform, SerializedProperty aPath, bool aShowMeta, bool aUnlock, Path2D.Plane aPlane, Plane aEditPlane, PathEditorVisuals aVisuals)
        {
            PointControl ctrl   = aPathRaw.GetControls(aIndex);
            bool         locked = ctrl.type == PointType.Locked;
            Vector3      at     = aTransform.MultiplyPoint3x4(Plane(aPathRaw[aIndex], aPlane));

            if (ctrl.type == PointType.Auto || ctrl.type == PointType.AutoSymmetrical || ctrl.type == PointType.Sharp)
            {
            }
            else if (ctrl.type == PointType.CircleCorner)
            {
                if (aPathRaw.Closed || (aIndex != 0 && aIndex != aPathRaw.Count - 1))
                {
                    float size         = HandleUtility.GetHandleSize(at);
                    float radiusOffset = .2f;

                    Vector3 end1   = PathUtil.GetRoundedCornerEnd(aIndex, aPathRaw.GetPathRaw(), aPathRaw.GetControls(), aPathRaw.Closed, ctrl.radius, true);
                    Vector3 end2   = PathUtil.GetRoundedCornerEnd(aIndex, aPathRaw.GetPathRaw(), aPathRaw.GetControls(), aPathRaw.Closed, ctrl.radius, false);
                    Vector3 normal = Vector2.Lerp(end1.xy() - aPathRaw[aIndex], end2.xy() - aPathRaw[aIndex], 0.5f).normalized;

                    Vector3 v  = aTransform.MultiplyVector(Plane(normal * (ctrl.radius + radiusOffset), aPlane)) + at;
                    Vector3 nV = Handles.FreeMoveHandle(v,
                                                        SceneView.lastActiveSceneView.camera.transform.rotation,
                                                        size * aVisuals.sizeControlHandle,
                                                        Vector3.zero,
                                                        aVisuals.capControlHandle);

                    if (nV != v)
                    {
                        SerializedProperty radius = aPath.FindPropertyRelative("_pointControls").GetArrayElementAtIndex(aIndex).FindPropertyRelative("radius");
                        nV  = EditorTools.ProjectPoint(nV, aEditPlane);
                        nV -= at;
                        nV  = aInvTransform.MultiplyVector(nV);
                        Vector2 newPos = Deplane(nV, aPlane);
                        radius.floatValue = SnapScale(radius.floatValue, Mathf.Max(0, newPos.magnitude - radiusOffset), PathSnap.World);
                        _recentInteract   = aIndex;
                        GUI.changed       = true;
                    }

                    if (aShowMeta)
                    {
                        string txt = Math.Round(ctrl.radius, 2).ToString();
                        Handles.Label(v, txt, ShadowStyle);
                        Handles.Label(v, txt, LabelStyle);
                    }
                }
            }
            else
            {
                Vector2 newPos;
                Vector3 v  = aTransform.MultiplyVector(Plane(ctrl.controlPrev, aPlane)) + at;
                Vector3 nV = Handles.FreeMoveHandle(v,
                                                    SceneView.lastActiveSceneView.camera.transform.rotation,
                                                    HandleUtility.GetHandleSize(v) * aVisuals.sizeControlHandle,
                                                    Vector3.zero,
                                                    aVisuals.capControlHandle);

                if (nV != v)
                {
                    SerializedProperty controlProp = aPath.FindPropertyRelative("_pointControls").GetArrayElementAtIndex(aIndex);
                    SerializedProperty type        = controlProp.FindPropertyRelative("type");
                    SerializedProperty prev        = controlProp.FindPropertyRelative("controlPrev");

                    nV                = EditorTools.ProjectPoint(nV, aEditPlane);
                    nV               -= at;
                    nV                = aInvTransform.MultiplyVector(nV);
                    newPos            = Deplane(nV, aPlane);
                    prev.vector2Value = SnapRadial(v, prev.vector2Value, newPos, aTransform, aInvTransform, PathSnap.World);
                    if (aUnlock)
                    {
                        ctrl.type           = PointType.Free;
                        type.enumValueIndex = (int)ctrl.type;
                    }
                    _recentInteract = aIndex;
                    GUI.changed     = true;
                }

                if (ctrl.type == PointType.Locked)
                {
                    v = -aTransform.MultiplyVector(Plane(ctrl.controlPrev, aPlane)) + at;
                }
                else
                {
                    v = aTransform.MultiplyVector(Plane(ctrl.controlNext, aPlane)) + at;
                }

                nV = Handles.FreeMoveHandle(v,
                                            SceneView.lastActiveSceneView.camera.transform.rotation,
                                            HandleUtility.GetHandleSize(v) * aVisuals.sizeControlHandle,
                                            Vector3.zero,
                                            aVisuals.capControlHandle);

                if (nV != v)
                {
                    SerializedProperty controlProp = aPath.FindPropertyRelative("_pointControls").GetArrayElementAtIndex(aIndex);
                    SerializedProperty type        = controlProp.FindPropertyRelative("type");
                    SerializedProperty prev        = controlProp.FindPropertyRelative("controlPrev");
                    SerializedProperty next        = controlProp.FindPropertyRelative("controlNext");

                    nV  = EditorTools.ProjectPoint(nV, aEditPlane);
                    nV -= at;
                    nV  = aInvTransform.MultiplyVector(nV);
                    if (aUnlock)
                    {
                        ctrl.type           = PointType.Free;
                        type.enumValueIndex = (int)ctrl.type;
                    }

                    if (ctrl.type == PointType.Locked)
                    {
                        newPos            = Deplane(-nV, aPlane);
                        prev.vector2Value = SnapRadial(v, prev.vector2Value, newPos, aTransform, aInvTransform, PathSnap.World);
                    }
                    else
                    {
                        newPos            = Deplane(nV, aPlane);
                        next.vector2Value = SnapRadial(v, next.vector2Value, newPos, aTransform, aInvTransform, PathSnap.World);
                    }
                    _recentInteract = aIndex;
                    GUI.changed     = true;
                }

                if (aShowMeta)
                {
                    bool xz = aPlane == Path2D.Plane.XZ;

                    Vector2 prop2   = (locked?ctrl.controlPrev:ctrl.controlNext);
                    Vector3 handle1 = aTransform.MultiplyVector(Plane(ctrl.controlPrev, aPlane)) + at;
                    Vector3 handle2 = (locked?-1:1) * aTransform.MultiplyVector(Plane((locked?ctrl.controlPrev:ctrl.controlNext), aPlane)) + at;
                    float   ang1    = PathUtil.ClockwiseAngle(ctrl.controlPrev, Vector2.right);                //Vector2.Angle(prev.vector2Value, Vector2.right);
                    float   ang2    = PathUtil.ClockwiseAngle((locked?-1:1) * prop2, Vector2.right);           //Vector2.Angle(prop2.vector2Value, Vector2.right);
                    float   mag1    = ctrl.controlPrev.magnitude;
                    float   mag2    = prop2.magnitude;

                    Vector3 pos = Vector3.Lerp(handle1, at, 0.5f);
                    string  txt = Math.Round(mag1, 2).ToString();
                    Handles.Label(pos, txt, ShadowStyle); Handles.Label(pos, txt, LabelStyle);
                    pos = Vector3.Lerp(handle2, at, 0.5f);
                    txt = Math.Round(mag2, 2).ToString();
                    Handles.Label(pos, txt, ShadowStyle); Handles.Label(pos, txt, LabelStyle);

                    pos = handle1;
                    txt = "\u00B0" + Mathf.Round(ang1);
                    Handles.Label(pos, txt, ShadowStyle); Handles.Label(pos, txt, LabelStyle);
                    pos = handle2;
                    txt = "\u00B0" + Mathf.Round(ang2);
                    Handles.Label(pos, txt, ShadowStyle); Handles.Label(pos, txt, LabelStyle);

                    if (ctrl.type == PointType.Free)
                    {
                        if (ang2 < ang1)
                        {
                            ang2 += 360;
                        }
                        float ang     = ang2 - ang1;
                        float halfAng = ang1 + ang / 2;

                        float   arcRadius = HandleUtility.GetHandleSize(at) * aVisuals.sizeVertex * 1.75f;
                        Vector3 centerArc = new Vector3(Mathf.Cos(halfAng * Mathf.Deg2Rad), Mathf.Sin(halfAng * Mathf.Deg2Rad), 0);
                        if (xz)
                        {
                            centerArc = new Vector3(centerArc.x, 0, centerArc.y);
                        }
                        centerArc = aTransform.MultiplyVector(centerArc);

                        var centeredStyle = new GUIStyle(GUI.skin.label);
                        centeredStyle.contentOffset    = new Vector2(-9, -9);
                        centeredStyle.normal.textColor = new Color(0, 0, 0, 0.5f);
                        Handles.Label(at + centerArc * arcRadius * 2f, "\u00B0" + Mathf.Round(ang), centeredStyle);
                        centeredStyle.contentOffset    = new Vector2(-10, -10);
                        centeredStyle.normal.textColor = Color.white;
                        Handles.Label(at + centerArc * arcRadius * 2f, "\u00B0" + Mathf.Round(ang), centeredStyle);

                        Handles.DrawWireArc(at, aPlane == Path2D.Plane.XY?Vector3.forward:Vector3.up, ((xz?handle2:handle1) - at).normalized, ang, arcRadius);
                    }
                }
            }
        }
Beispiel #7
0
        private static void ShowPointTypeMode(Path2D aPathRaw, int aIndex, Selection aSelection, Matrix4x4 aTransform, Matrix4x4 aInvTransform, SerializedProperty aPath, Path2D.Plane aPlane, PathEditorVisuals aVisuals)
        {
            Handles.color = aVisuals.colorHandle * _activeHandleTint;
            Handles.CapFunction cap = aVisuals.capVertex;
            if (aVisuals.capVertexTypes != null)
            {
                cap = aVisuals.capVertexTypes[(int)aPathRaw.GetControls(aIndex).type];
            }
            Vector3 v = aTransform.MultiplyPoint3x4(Plane(aPathRaw[aIndex], aPlane));

            EditorGUIUtility.AddCursorRect(new Rect(0, 0, Screen.width, Screen.height), MouseCursor.RotateArrow);
            if (Handles.Button(v,
                               SceneView.lastActiveSceneView.camera.transform.rotation,
                               HandleUtility.GetHandleSize(v) * aVisuals.sizeVertexMode,
                               HandleUtility.GetHandleSize(v) * aVisuals.sizeVertexMode,
                               cap))
            {
                PointType t = aPathRaw.GetControls(aIndex).type;
                if (t == PointType.Auto)
                {
                    t = PointType.Locked;
                }
                else if (t == PointType.Free)
                {
                    t = PointType.Locked;
                }
                else if (t == PointType.Locked)
                {
                    t = PointType.CircleCorner;
                }
                else if (t == PointType.CircleCorner)
                {
                    t = PointType.Sharp;
                }
                else if (t == PointType.Sharp)
                {
                    t = PointType.Auto;
                }

                SerializedProperty pointControls = aPath.FindPropertyRelative("_pointControls");
                aSelection.Each(aIndex, i => pointControls.GetArrayElementAtIndex(i).FindPropertyRelative("type").enumValueIndex = (int)t);

                _recentInteract = aIndex;
                GUI.changed     = true;
            }
        }
Beispiel #8
0
        private static void ShowPoint(Path2D aPathRaw, int aIndex, Selection aSelection, Matrix4x4 aTransform, Matrix4x4 aInvTransform, SerializedProperty aPath, Path2D.Plane aPlane, Plane aEditPlane, PathSnap aSnapMode, float aSmartSnapDist, PathEditorVisuals aVisuals)
        {
            Handles.color = aVisuals.colorHandle * _activeHandleTint;
            Handles.CapFunction cap = aVisuals.capVertex;
            if (aVisuals.capVertexTypes != null)
            {
                cap = aVisuals.capVertexTypes[(int)aPathRaw.GetControls(aIndex).type];
            }

            Vector3 v  = aTransform.MultiplyPoint3x4(Plane(aPathRaw[aIndex], aPlane));
            Vector3 nV = Handles.FreeMoveHandle(v,
                                                SceneView.lastActiveSceneView.camera.transform.rotation,
                                                HandleUtility.GetHandleSize(v) * aVisuals.sizeVertex,
                                                Vector3.zero,
                                                cap);

            if (nV != v)
            {
                nV = EditorTools.ProjectPoint(nV, aEditPlane);
                nV = aInvTransform.MultiplyPoint3x4(nV);
                Vector2 newPos = Deplane(nV, aPlane);
                newPos = Snap(aPathRaw[aIndex], newPos, aTransform, aInvTransform, aSnapMode);
                if (!Event.current.control && aSmartSnapDist != 0)
                {
                    newPos = SmartSnap(newPos, aPathRaw, aIndex, aSelection.ids, aSmartSnapDist);
                }

                Vector2 delta = newPos - aPathRaw[aIndex];
                aSelection.Each(aIndex, i => aPath.FindPropertyRelative("_points").GetArrayElementAtIndex(i).vector2Value += delta);

                GUI.changed     = true;
                _recentInteract = aIndex;
            }
        }
Beispiel #9
0
        public static void ShowPathLines(Path2D aPathRaw, Matrix4x4 aTransform, bool aShowControls, Path2D.Plane aPlane, PathEditorVisuals aVisuals)
        {
            if (aShowControls)
            {
                Handles.color = aVisuals.colorControlLine;
                for (int i = 0; i < aPathRaw.Count; i++)
                {
                    PointControl c  = aPathRaw.GetControls(i);
                    Vector3      pt = aTransform.MultiplyPoint3x4(Plane(aPathRaw[i], aPlane));

                    if (c.type == PointType.Auto || c.type == PointType.AutoSymmetrical)
                    {
                        Handles.DrawDottedLines(new Vector3[] { pt + aTransform.MultiplyVector(Plane(c.controlPrev, aPlane)), pt, pt, pt + aTransform.MultiplyVector(Plane(c.controlNext, aPlane)) }, 4);
                    }
                    else if (c.type == PointType.Free)
                    {
                        Handles.DrawPolyLine(pt + aTransform.MultiplyVector(Plane(c.controlPrev, aPlane)), pt, pt + aTransform.MultiplyVector(Plane(c.controlNext, aPlane)));
                    }
                    else if (c.type == PointType.Locked)
                    {
                        Handles.DrawPolyLine(pt + aTransform.MultiplyVector(Plane(c.controlPrev, aPlane)), pt + aTransform.MultiplyVector(Plane(-c.controlPrev, aPlane)));
                    }
                    else if (c.type == PointType.CircleCorner)
                    {
                        Vector3 end1 = PathUtil.GetRoundedCornerEnd(i, aPathRaw.GetPathRaw(), aPathRaw.GetControls(), aPathRaw.Closed, c.radius, true);
                        Handles.DrawDottedLine(pt, aTransform.MultiplyPoint(Plane(end1, aPlane)), 4);
                        Vector3 end2 = PathUtil.GetRoundedCornerEnd(i, aPathRaw.GetPathRaw(), aPathRaw.GetControls(), aPathRaw.Closed, c.radius, false);
                        Handles.DrawDottedLine(pt, aTransform.MultiplyPoint(Plane(end2, aPlane)), 4);

                        Vector3 center = Vector2.Lerp(end1.xy() - aPathRaw[i], end2.xy() - aPathRaw[i], 0.5f).normalized *(c.radius + 0.2f);
                        Handles.DrawLine(pt, pt + aTransform.MultiplyVector(Plane(center, aPlane)));
                    }
                }
            }

            Handles.color  = aVisuals.colorLine;
            Handles.matrix = aTransform;
            EditorTools.DrawPolyLine(aPathRaw.GetFinalPath(), aPathRaw.Closed);
            Handles.matrix = Matrix4x4.identity;
        }
Beispiel #10
0
        private static void ShowShiftAdd(Path2D aPathRaw, Matrix4x4 aTransform, Matrix4x4 aInvTransform, SerializedProperty aPath, Action <SerializedProperty, int> aOnAddPoint, Path2D.Plane aPlane, Plane aEditPlane, PathEditorVisuals aVisuals)
        {
            if (Event.current.type == EventType.MouseMove)
            {
                SceneView.RepaintAll();
            }

            Ray   r    = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
            float dist = 0;

            if (aEditPlane.Raycast(r, out dist))
            {
                Vector3        worldPt = r.GetPoint(dist);
                Vector3        localPt = aInvTransform.MultiplyPoint3x4(worldPt);
                List <Vector2> points  = aPathRaw.GetPathRaw();
                int            segment = PathUtil.GetClosestSegment(points, Deplane(localPt, aPlane), aPathRaw.Closed);

                Vector3 p1          = points.Count == 0 ? worldPt : aTransform.MultiplyPoint3x4(Plane(points[segment], aPlane));
                Vector3 p2          = points.Count == 0 ? worldPt : aTransform.MultiplyPoint3x4(Plane(points[PathUtil.WrapIndex(segment + 1, points.Count, aPathRaw.Closed)], aPlane));
                float   d1          = Vector3.Distance(p1, worldPt);
                float   d2          = Vector3.Distance(p2, worldPt);
                int     insertIndex = 0;

                EditorGUIUtility.AddCursorRect(new Rect(0, 0, Screen.width, Screen.height), MouseCursor.ArrowPlus);

                // draw dotted lines, and figure out what index we'll be adding to
                if (!aPathRaw.Closed && segment == 0 && d1 < d2)
                {
                    Handles.DrawDottedLine(p1, worldPt, 4);
                    insertIndex = 0;
                }
                else if (!aPathRaw.Closed && segment == points.Count - 2 && d2 < d1)
                {
                    Handles.DrawDottedLine(p2, worldPt, 4);
                    insertIndex = points.Count;
                }
                else
                {
                    Handles.DrawDottedLine(p1, worldPt, 4);
                    Handles.DrawDottedLine(p2, worldPt, 4);
                    insertIndex = segment + 1;
                }

                // do the add point button
                if (Handles.Button(worldPt,
                                   SceneView.lastActiveSceneView.camera.transform.rotation,
                                   HandleUtility.GetHandleSize(worldPt) * aVisuals.sizeVertexAdd,
                                   HandleUtility.GetHandleSize(worldPt) * aVisuals.sizeVertexAdd,
                                   aVisuals.capVertexAdd))
                {
                    AddPoint(aPath, Deplane(localPt, aPlane), insertIndex);
                    if (aOnAddPoint != null)
                    {
                        aOnAddPoint(aPath, insertIndex);
                    }

                    _recentInteract = insertIndex;
                    GUI.changed     = true;
                }
            }
        }
Beispiel #11
0
        public static void OnSceneGUI(Matrix4x4 aTransform, Matrix4x4 aInvTransform, SerializedProperty aPath, Path2D aPathRaw, bool aShowShiftAdd = true, Action <SerializedProperty, int> aOnAddPoint = null, Action <SerializedProperty, int> aOnRemovePoint = null, Path2D.Plane aPlane = Path2D.Plane.XY, PathSnap aSnapMode = PathSnap.Unity, float aSmartSnapDist = 0, KeyCode aVertModeKey = KeyCode.C, PathEditorVisuals aVisuals = null)
        {
            if (aVisuals == null)
            {
                aVisuals = _defaultVisuals;
            }

            // get the current selection list
            Selection selection = GetSelection(aPathRaw);

            bool showControls = !Event.current.shift && !Event.current.alt;

            // check for point type switching mode
            if (Event.current.type == EventType.KeyDown && Event.current.keyCode == aVertModeKey)
            {
                _vMode = true;
                Event.current.Use();
            }
            if (Event.current.type == EventType.KeyUp && Event.current.keyCode == aVertModeKey)
            {
                _vMode = false;
                Event.current.Use();
            }
            bool deleteMode = Event.current.alt;

            // draw all the curve and handle lines
            if (Event.current.type == EventType.Repaint)
            {
                ShowPathLines(aPathRaw, aTransform, showControls, aPlane, aVisuals);
            }

            // create the plane on which all edits occur
            Plane editPlane;

            if (aPlane == Path2D.Plane.XY)
            {
                editPlane = new Plane(aTransform.MultiplyPoint3x4(Vector3.zero), aTransform.MultiplyPoint3x4(Vector3.right), aTransform.MultiplyPoint3x4(Vector3.up));
            }
            else
            {
                editPlane = new Plane(aTransform.MultiplyPoint3x4(Vector3.zero), aTransform.MultiplyPoint3x4(Vector3.right), aTransform.MultiplyPoint3x4(Vector3.forward));
            }

            // check for shift-add point to path
            if (Event.current.shift && aShowShiftAdd && Event.current.button != 1 && !Event.current.control)
            {
                ShowShiftAdd(aPathRaw, aTransform, aInvTransform, aPath, aOnAddPoint, aPlane, editPlane, aVisuals);
            }

            // draw the handles for each point
            for (int i = 0; i < aPathRaw.Count; i++)
            {
                if (selection.Count > 0)
                {
                    _activeHandleTint = selection.IsSelected(i) ? aVisuals.colorSelectionTint : aVisuals.colorUnselectedTint;
                }
                else
                {
                    _activeHandleTint = aVisuals.colorNoSelectionTint;
                }

                if (deleteMode)
                {
                    ShowPointDeleteMode(aPathRaw, i, selection, aTransform, aPath, aOnRemovePoint, aPlane, aVisuals);
                }
                else if (_vMode)
                {
                    ShowPointTypeMode(aPathRaw, i, selection, aTransform, aInvTransform, aPath, aPlane, aVisuals);
                }
                else
                {
                    ShowPoint(aPathRaw, i, selection, aTransform, aInvTransform, aPath, aPlane, editPlane, aSnapMode, aSmartSnapDist, aVisuals);
                }
                if (showControls)
                {
                    ShowHandles(aPathRaw, i, aTransform, aInvTransform, aPath, i == _recentInteract, _vMode, aPlane, editPlane, aVisuals);
                }
            }

            if (GUI.changed)
            {
                SetDirty(aPath);
            }

            Handles.color = Color.white;
        }