Example #1
0
 public override void SetSelection(MeshSelection selection)
 {
     m_vertexSelection.Clear();
     m_selection.Clear();
     foreach (KeyValuePair <ProBuilderMesh, IList <int> > kvp in selection.SelectedIndices)
     {
         m_vertexSelection.Add(kvp.Key, kvp.Value);
     }
 }
        public override void SetSelection(MeshSelection selection)
        {
            m_edgeSelection.Clear();
            m_selection.Clear();

            foreach (KeyValuePair <ProBuilderMesh, IList <Edge> > kvp in selection.SelectedEdges)
            {
                m_edgeSelection.Add(kvp.Key, kvp.Value);
            }
        }
Example #3
0
        public static float PickVertex(Camera camera, Vector3 mousePosition, float maxDistance, GameObject pickedObject, IEnumerable <ProBuilderMesh> meshes, bool depthTest, ref SceneSelection selection)
        {
            //  selection.Clear();
            m_nearestVertices.Clear();

            maxDistance = maxDistance * maxDistance;

            if (pickedObject != null)
            {
                ProBuilderMesh mesh = pickedObject.GetComponent <ProBuilderMesh>();
                if (mesh != null)
                {
                    GetNearestVertices(camera, mesh, mousePosition, m_nearestVertices, maxDistance, 1.0f);
                }
            }

            foreach (ProBuilderMesh mesh in meshes)
            {
                if (!mesh.selectable)
                {
                    continue;
                }

                GetNearestVertices(camera, mesh, mousePosition, m_nearestVertices, maxDistance, 1.0f);
            }

            m_nearestVertices.Sort((x, y) => x.screenDistance.CompareTo(y.screenDistance));


            ProBuilderMesh selectedMesh   = selection.mesh;
            int            selectedVertex = selection.vertex;

            selection.Clear();

            int startIndex = 0;

            for (int i = 0; i < m_nearestVertices.Count; i++)
            {
                VertexPickerEntry pickerEntry = m_nearestVertices[i];
                if (pickerEntry.mesh == selectedMesh && pickerEntry.vertex == selectedVertex)
                {
                    startIndex  = i + 1;
                    startIndex %= m_nearestVertices.Count;
                }
            }

            for (int i = startIndex; i < m_nearestVertices.Count; i++)
            {
                if (!depthTest || !PointIsOccluded(camera, m_nearestVertices[i].mesh, m_nearestVertices[i].worldPosition))
                {
                    selection.gameObject = m_nearestVertices[i].mesh.gameObject;
                    selection.mesh       = m_nearestVertices[i].mesh;
                    selection.vertex     = m_nearestVertices[i].vertex;
                    return(Mathf.Sqrt(m_nearestVertices[i].screenDistance));
                }
            }

            return(Mathf.Infinity);
        }
        public override void SetSelection(MeshSelection selection)
        {
            m_vertexSelection.Clear();
            m_selection.Clear();

            if (selection != null)
            {
                selection = selection.ToVertices(false);
                foreach (KeyValuePair <GameObject, IList <int> > kvp in selection.SelectedIndices)
                {
                    PBMesh pbMesh = kvp.Key.GetComponent <PBMesh>();
                    if (pbMesh.IsMarkedAsDestroyed)
                    {
                        continue;
                    }

                    m_vertexSelection.Add(kvp.Key.GetComponent <ProBuilderMesh>(), kvp.Value);
                }
            }
        }
        static float VertexRaycast(Vector3 mousePosition, ScenePickerPreferences pickerOptions, bool allowUnselected, SceneSelection selection)
        {
            Camera cam = SceneView.lastActiveSceneView.camera;

            selection.Clear();
            s_NearestVertices.Clear();
            selection.gameObject = HandleUtility.PickGameObject(mousePosition, false);
            float          maxDistance = ScenePickerPreferences.maxPointerDistance * ScenePickerPreferences.maxPointerDistance;
            ProBuilderMesh hoveredMesh = selection.gameObject != null?selection.gameObject.GetComponent <ProBuilderMesh>() : null;

            if (allowUnselected && selection.gameObject != null)
            {
                if (hoveredMesh != null && hoveredMesh.selectable && !MeshSelection.Contains(hoveredMesh))
                {
                    GetNearestVertices(hoveredMesh, mousePosition, s_NearestVertices, maxDistance, 1);
                }
            }

            if (selection.mesh == null)
            {
                foreach (var mesh in MeshSelection.topInternal)
                {
                    if (!mesh.selectable)
                    {
                        continue;
                    }

                    GetNearestVertices(mesh, mousePosition, s_NearestVertices, maxDistance, hoveredMesh == mesh || hoveredMesh == null ? 1.0f : ScenePickerPreferences.offPointerMultiplier);
                }
            }

            s_NearestVertices.Sort((x, y) => x.screenDistance.CompareTo(y.screenDistance));

            for (int i = 0; i < s_NearestVertices.Count; i++)
            {
                if (!UnityEngine.ProBuilder.HandleUtility.PointIsOccluded(cam, s_NearestVertices[i].mesh, s_NearestVertices[i].worldPosition))
                {
                    selection.gameObject = s_NearestVertices[i].mesh.gameObject;
                    selection.mesh       = s_NearestVertices[i].mesh;
                    selection.SetSingleVertex(s_NearestVertices[i].vertex);

                    return(Mathf.Sqrt(s_NearestVertices[i].screenDistance));
                }
            }

            return(Mathf.Infinity);
        }
Example #6
0
        public override MeshSelection ClearSelection()
        {
            MeshSelection selection = new MeshSelection();

            foreach (ProBuilderMesh mesh in m_edgeSelection.Meshes)
            {
                selection.UnselectedEdges.Add(mesh, m_edgeSelection.GetEdges(mesh).ToArray());
            }

            m_edgeSelection.Clear();
            m_selection.Clear();

            if (selection.UnselectedEdges.Count > 0)
            {
                return(selection);
            }
            return(null);
        }
        public static float PickVertex(Camera camera, Vector3 mousePosition, float maxDistance, Transform transform, IList <Vector3> positions, ref SceneSelection selection)
        {
            selection.Clear();
            m_nearestVertices.Clear();

            maxDistance = maxDistance * maxDistance;

            GetNearestVertices(camera, transform, positions, mousePosition, m_nearestVertices, maxDistance, 1.0f);

            m_nearestVertices.Sort((x, y) => x.screenDistance.CompareTo(y.screenDistance));

            for (int i = 0; i < m_nearestVertices.Count;)
            {
                //selection.gameObject = m_nearestVertices[i].mesh.gameObject;
                //selection.mesh = m_nearestVertices[i].mesh;
                selection.vertex = m_nearestVertices[i].vertex;
                return(Mathf.Sqrt(m_nearestVertices[i].screenDistance));
            }

            return(Mathf.Infinity);
        }
        public static float PickEdge(Camera camera, Vector3 mousePosition, float maxDistance, GameObject pickedObject, IEnumerable <ProBuilderMesh> meshes, ref SceneSelection selection)
        {
            selection.Clear();
            selection.gameObject = pickedObject;
            ProBuilderMesh hoveredMesh = selection.gameObject != null?selection.gameObject.GetComponent <ProBuilderMesh>() : null;

            float bestDistance           = maxDistance;
            float unselectedBestDistance = maxDistance;

            //bool hoveredIsInSelection = meshes.Contains(hoveredMesh);
            //const bool allowUnselected = true;

            //if (hoveredMesh != null && (allowUnselected || hoveredIsInSelection))
            if (hoveredMesh != null)
            {
                EdgeAndDistance tup = GetNearestEdgeOnMesh(camera, hoveredMesh, mousePosition);

                if (tup.edge.IsValid() && tup.distance < maxDistance)
                {
                    selection.gameObject   = hoveredMesh.gameObject;
                    selection.mesh         = hoveredMesh;
                    selection.edge         = tup.edge;
                    unselectedBestDistance = tup.distance;

                    // if it's in the selection, it automatically wins as best. if not, treat this is a fallback.
                    //if (hoveredIsInSelection)
                    {
                        return(tup.distance);
                    }
                }
            }

            foreach (ProBuilderMesh mesh in meshes)
            {
                Transform       trs       = mesh.transform;
                IList <Vector3> positions = mesh.positions;
                m_edges.Clear();

                //When the pointer is over another object, apply a modifier to the distance to prefer picking the object hovered over the currently selected
                //var distMultiplier = (hoveredMesh == mesh || hoveredMesh == null) ? 1.0f : pickerPrefs.offPointerMultiplier;
                const float distMultiplier = 1.0f;

                foreach (Face face in mesh.faces)
                {
                    foreach (Edge edge in face.edges)
                    {
                        int x = edge.a;
                        int y = edge.b;


                        float d = DistanceToLine(camera, mousePosition,
                                                 trs.TransformPoint(positions[x]),
                                                 trs.TransformPoint(positions[y]));

                        d *= distMultiplier;

                        if (d == bestDistance)
                        {
                            m_edges.Add(new Edge(x, y));
                        }
                        else if (d < bestDistance)
                        {
                            m_edges.Clear();
                            m_edges.Add(new Edge(x, y));

                            selection.gameObject = mesh.gameObject;
                            selection.mesh       = mesh;
                            selection.edge       = new Edge(x, y);
                            bestDistance         = d;
                        }
                    }
                }

                //If more than 1 edge is closest, the closest is one of the vertex.
                //Get closest edge to the camera.
                if (m_edges.Count > 1)
                {
                    selection.edge = GetClosestEdgeToCamera(camera, mousePosition, positions, m_edges);
                }
            }

            if (selection.gameObject != null)
            {
                if (bestDistance < maxDistance)
                {
                    return(bestDistance);
                }

                return(Mathf.Infinity);// unselectedBestDistance;
            }

            return(Mathf.Infinity);
        }
        static float EdgeRaycast(Vector3 mousePosition, ScenePickerPreferences pickerPrefs, bool allowUnselected, SceneSelection selection)
        {
            selection.Clear();
            selection.gameObject = UHandleUtility.PickGameObject(mousePosition, false);
            var hoveredMesh = selection.gameObject != null?selection.gameObject.GetComponent <ProBuilderMesh>() : null;

            float bestDistance           = pickerPrefs.maxPointerDistance;
            float unselectedBestDistance = bestDistance;
            bool  hoveredIsInSelection   = MeshSelection.topInternal.Contains(hoveredMesh);

            if (hoveredMesh != null && (allowUnselected || hoveredIsInSelection))
            {
                var tup = GetNearestEdgeOnMesh(hoveredMesh, mousePosition);

                if (tup.edge.IsValid() && tup.distance < pickerPrefs.maxPointerDistance)
                {
                    selection.gameObject   = hoveredMesh.gameObject;
                    selection.mesh         = hoveredMesh;
                    selection.edge         = tup.edge;
                    unselectedBestDistance = tup.distance;

                    // if it's in the selection, it automatically wins as best. if not, treat this is a fallback.
                    if (hoveredIsInSelection)
                    {
                        return(tup.distance);
                    }
                }
            }

            foreach (var mesh in MeshSelection.topInternal)
            {
                var trs       = mesh.transform;
                var positions = mesh.positionsInternal;

                foreach (var face in mesh.facesInternal)
                {
                    foreach (var edge in face.edges)
                    {
                        int x = edge.a;
                        int y = edge.b;

                        float d = UHandleUtility.DistanceToLine(
                            trs.TransformPoint(positions[x]),
                            trs.TransformPoint(positions[y]));

                        if (d < bestDistance)
                        {
                            selection.gameObject = mesh.gameObject;
                            selection.mesh       = mesh;
                            selection.edge       = new Edge(x, y);
                            bestDistance         = d;
                        }
                    }
                }
            }

            if (selection.gameObject != null)
            {
                if (bestDistance < pickerPrefs.maxPointerDistance)
                {
                    return(bestDistance);
                }
                return(unselectedBestDistance);
            }

            return(Mathf.Infinity);
        }
        static float VertexRaycast(Vector3 mousePosition, ScenePickerPreferences pickerOptions, bool allowUnselected, SceneSelection selection)
        {
            Camera cam = SceneView.lastActiveSceneView.camera;

            selection.Clear();
            s_NearestVertices.Clear();
            selection.gameObject = HandleUtility.PickGameObject(mousePosition, false);
            float maxDistance = pickerOptions.maxPointerDistance * pickerOptions.maxPointerDistance;

            if (allowUnselected && selection.gameObject != null)
            {
                var mesh = selection.gameObject.GetComponent <ProBuilderMesh>();

                if (mesh != null && mesh.selectable && !MeshSelection.Contains(mesh))
                {
                    var matches = GetNearestVertices(mesh, mousePosition, s_NearestVertices, maxDistance);

                    for (int i = 0; i < matches; i++)
                    {
                        // Append `maxDistance` so that selected meshes are favored
                        s_NearestVertices[i] = new VertexPickerEntry()
                        {
                            mesh           = s_NearestVertices[i].mesh,
                            vertex         = s_NearestVertices[i].vertex,
                            screenDistance = s_NearestVertices[i].screenDistance + maxDistance,
                            worldPosition  = s_NearestVertices[i].worldPosition
                        };
                    }
                }
            }

            if (selection.mesh == null)
            {
                foreach (var mesh in MeshSelection.topInternal)
                {
                    if (!mesh.selectable)
                    {
                        continue;
                    }

                    GetNearestVertices(mesh, mousePosition, s_NearestVertices, maxDistance);
                }
            }

            s_NearestVertices.Sort((x, y) => x.screenDistance.CompareTo(y.screenDistance));

            for (int i = 0; i < s_NearestVertices.Count; i++)
            {
                if (!UnityEngine.ProBuilder.HandleUtility.PointIsOccluded(cam, s_NearestVertices[i].mesh, s_NearestVertices[i].worldPosition))
                {
                    selection.gameObject = s_NearestVertices[i].mesh.gameObject;
                    selection.mesh       = s_NearestVertices[i].mesh;
                    selection.vertex     = s_NearestVertices[i].vertex;

                    // If mesh was unselected, remove the distance modifier
                    if (s_NearestVertices[i].screenDistance > maxDistance)
                    {
                        return(Mathf.Sqrt(s_NearestVertices[i].screenDistance - maxDistance));
                    }

                    return(Mathf.Sqrt(s_NearestVertices[i].screenDistance));
                }
            }

            return(Mathf.Infinity);
        }
        static float FaceRaycast(Vector3 mousePosition,
                                 ScenePickerPreferences pickerOptions,
                                 bool allowUnselected,
                                 SceneSelection selection,
                                 int deepClickOffset = 0,
                                 bool isPreview      = true)
        {
            GameObject     pickedGo   = null;
            ProBuilderMesh pickedPb   = null;
            Face           pickedFace = null;

            int newHash = 0;

            // If any event modifiers are engaged don't cycle the deep click
            EventModifiers em = Event.current.modifiers;

            if (isPreview || em != EventModifiers.None)
            {
                EditorHandleUtility.GetHovered(mousePosition, s_OverlappingGameObjects);
            }
            else
            {
                EditorHandleUtility.GetAllOverlapping(mousePosition, s_OverlappingGameObjects);
            }

            selection.Clear();

            float distance = Mathf.Infinity;

            for (int i = 0, next = 0, pickedCount = s_OverlappingGameObjects.Count; i < pickedCount; i++)
            {
                var  go   = s_OverlappingGameObjects[i];
                var  mesh = go.GetComponent <ProBuilderMesh>();
                Face face = null;

                if (mesh != null && (allowUnselected || MeshSelection.topInternal.Contains(mesh)))
                {
                    Ray        ray = UHandleUtility.GUIPointToWorldRay(mousePosition);
                    RaycastHit hit;

                    if (UnityEngine.ProBuilder.HandleUtility.FaceRaycast(ray,
                                                                         mesh,
                                                                         out hit,
                                                                         Mathf.Infinity,
                                                                         pickerOptions.cullMode))
                    {
                        face     = mesh.facesInternal[hit.face];
                        distance = Vector2.SqrMagnitude(((Vector2)mousePosition) - HandleUtility.WorldToGUIPoint(mesh.transform.TransformPoint(hit.point)));
                    }
                }

                // pb_Face doesn't define GetHashCode, meaning it falls to object.GetHashCode (reference comparison)
                int hash = face == null?go.GetHashCode() : face.GetHashCode();

                if (s_DeepSelectionPrevious == hash)
                {
                    next = (i + (1 + deepClickOffset)) % pickedCount;
                }

                if (next == i)
                {
                    pickedGo   = go;
                    pickedPb   = mesh;
                    pickedFace = face;

                    newHash = hash;

                    // a prior hash was matched, this is the next. if
                    // it's just the first iteration don't break (but do
                    // set the default).
                    if (next != 0)
                    {
                        break;
                    }
                }
            }

            if (!isPreview)
            {
                s_DeepSelectionPrevious = newHash;
            }

            if (pickedGo != null)
            {
                Event.current.Use();

                if (pickedPb != null)
                {
                    if (pickedPb.selectable)
                    {
                        selection.gameObject = pickedGo;
                        selection.mesh       = pickedPb;
                        selection.face       = pickedFace;

                        return(Mathf.Sqrt(distance));
                    }
                }

                // If clicked off a pb_Object but onto another gameobject, set the selection
                // and dip out.
                selection.gameObject = pickedGo;
                return(Mathf.Sqrt(distance));
            }

            return(distance);
        }
        void OnSceneGUI(SceneView sceneView)
        {
#if !UNITY_2018_2_OR_NEWER
            if (s_ResetOnSceneGUIState != null)
            {
                s_ResetOnSceneGUIState.Invoke(sceneView, null);
            }
#endif

            SceneStyles.Init();

            m_CurrentEvent = Event.current;

            EditorMeshHandles.DrawSceneHandles(SceneDragAndDropListener.isDragging ? SelectMode.None : selectMode);

            DrawHandleGUI(sceneView);

#if SHORTCUT_MANAGER
            // Escape isn't assignable as a shortcut
            if (m_CurrentEvent.type == EventType.KeyDown)
            {
                if (m_CurrentEvent.keyCode == KeyCode.Escape && selectMode != SelectMode.Object)
                {
                    selectMode = SelectMode.Object;
                    m_CurrentEvent.Use();
                }
            }
#else
            if (m_CurrentEvent.type == EventType.MouseDown && m_CurrentEvent.button == 1)
            {
                m_IsRightMouseDown = true;
            }

            if (m_CurrentEvent.type == EventType.MouseUp && m_CurrentEvent.button == 1 || m_CurrentEvent.type == EventType.Ignore)
            {
                m_IsRightMouseDown = false;
            }

            if (!m_IsRightMouseDown && (m_CurrentEvent.type == EventType.KeyUp ? m_CurrentEvent.keyCode : KeyCode.None) != KeyCode.None)
            {
                if (ShortcutCheck(m_CurrentEvent))
                {
                    m_CurrentEvent.Use();
                    return;
                }
            }

            if (m_CurrentEvent.type == EventType.KeyDown)
            {
                if (s_Shortcuts.value.Any(x => x.Matches(m_CurrentEvent.keyCode, m_CurrentEvent.modifiers)))
                {
                    m_CurrentEvent.Use();
                }
            }
#endif

            if (selectMode == SelectMode.Object)
            {
                return;
            }

            // Check mouse position in scene and determine if we should highlight something
            if (s_ShowHoverHighlight &&
                m_CurrentEvent.type == EventType.MouseMove &&
                selectMode.IsMeshElementMode())
            {
                m_Hovering.CopyTo(m_HoveringPrevious);

                if (GUIUtility.hotControl != 0 ||
                    EditorSceneViewPicker.MouseRayHitTest(m_CurrentEvent.mousePosition, selectMode, m_ScenePickerPreferences, m_Hovering) > ScenePickerPreferences.maxPointerDistance)
                {
                    m_Hovering.Clear();
                }

                if (!m_Hovering.Equals(m_HoveringPrevious))
                {
                    SceneView.RepaintAll();
                }
            }

            if (Tools.current == Tool.View)
            {
                return;
            }

            // Overrides the toolbar transform tools
            if (Tools.current != Tool.None && Tools.current != m_CurrentTool)
            {
                SetTool_Internal(Tools.current);
            }

            Tools.current = Tool.None;

            if (selectMode.IsMeshElementMode() && MeshSelection.selectedVertexCount > 0)
            {
                var tool = GetToolForSelectMode(m_CurrentTool, s_SelectMode);

                if (tool != null)
                {
                    tool.OnSceneGUI(m_CurrentEvent);
                }
            }

            if (EditorHandleUtility.SceneViewInUse(m_CurrentEvent) || m_CurrentEvent.isKey)
            {
                m_IsDragging = false;

                if (GUIUtility.hotControl == m_DefaultControl)
                {
                    GUIUtility.hotControl = 0;
                }

                return;
            }

            // This prevents us from selecting other objects in the scene,
            // and allows for the selection of faces / vertices.
            m_DefaultControl = GUIUtility.GetControlID(FocusType.Passive);
            HandleUtility.AddDefaultControl(m_DefaultControl);

            if (m_CurrentEvent.type == EventType.MouseDown && HandleUtility.nearestControl == m_DefaultControl)
            {
                // double clicking object
                if (m_CurrentEvent.clickCount > 1)
                {
                    DoubleClick(m_CurrentEvent);
                }

                m_InitialMousePosition = m_CurrentEvent.mousePosition;
                // readyForMouseDrag prevents a bug wherein after ending a drag an errant
                // MouseDrag event is sent with no corresponding MouseDown/MouseUp event.
                m_IsReadyForMouseDrag = true;

                GUIUtility.hotControl = m_DefaultControl;
            }

            if (m_CurrentEvent.type == EventType.MouseDrag && m_IsReadyForMouseDrag && GUIUtility.hotControl == m_DefaultControl)
            {
                if (!m_IsDragging && Vector2.Distance(m_CurrentEvent.mousePosition, m_InitialMousePosition) > k_MouseDragThreshold)
                {
                    sceneView.Repaint();
                    m_IsDragging = true;
                }
            }

            if (m_CurrentEvent.type == EventType.Ignore)
            {
                if (m_IsDragging)
                {
                    m_IsReadyForMouseDrag = false;
                    m_IsDragging          = false;
                    EditorSceneViewPicker.DoMouseDrag(m_MouseDragRect, selectMode, m_ScenePickerPreferences);
                }

                if (m_WasDoubleClick)
                {
                    m_WasDoubleClick = false;
                }

                if (GUIUtility.hotControl == m_DefaultControl)
                {
                    GUIUtility.hotControl = 0;
                }
            }

            if (m_CurrentEvent.type == EventType.MouseUp && GUIUtility.hotControl == m_DefaultControl)
            {
                GUIUtility.hotControl = 0;

                if (m_WasDoubleClick)
                {
                    m_WasDoubleClick = false;
                }
                else
                {
                    if (!m_IsDragging)
                    {
                        if (UVEditor.instance)
                        {
                            UVEditor.instance.ResetUserPivot();
                        }

                        EditorSceneViewPicker.DoMouseClick(m_CurrentEvent, selectMode, m_ScenePickerPreferences);
                        UpdateSelection();
                        SceneView.RepaintAll();
                    }
                    else
                    {
                        m_IsDragging          = false;
                        m_IsReadyForMouseDrag = false;

                        if (UVEditor.instance)
                        {
                            UVEditor.instance.ResetUserPivot();
                        }

                        EditorSceneViewPicker.DoMouseDrag(m_MouseDragRect, selectMode, m_ScenePickerPreferences);

                        if (GUIUtility.hotControl == m_DefaultControl)
                        {
                            GUIUtility.hotControl = 0;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Get the nearest <see cref="Edge"/> to a screen position.
        /// </summary>
        /// <returns>
        /// Distance is returned as the screen distance to mesh, not edge.
        /// </returns>
        static float EdgeRaycast(Vector3 mousePosition, ScenePickerPreferences pickerPrefs, bool allowUnselected, SceneSelection selection)
        {
            selection.Clear();
            selection.gameObject = UHandleUtility.PickGameObject(mousePosition, false);
            var hoveredMesh = selection.gameObject != null?selection.gameObject.GetComponent <ProBuilderMesh>() : null;

            float bestDistance         = Mathf.Infinity;
            bool  hoveredIsInSelection = MeshSelection.topInternal.Contains(hoveredMesh);

            if (hoveredMesh != null && (allowUnselected || hoveredIsInSelection))
            {
                var tup = GetNearestEdgeOnMesh(hoveredMesh, mousePosition);

                if (tup.edge.IsValid())
                {
                    selection.gameObject = hoveredMesh.gameObject;
                    selection.mesh       = hoveredMesh;
                    selection.SetSingleEdge(tup.edge);
                    bestDistance = tup.distance;

                    // If the nearest edge was acquired by a raycast, then the distance to mesh is 0f.
                    if (hoveredIsInSelection)
                    {
                        return(tup.distance);
                    }
                }
            }

            foreach (var mesh in MeshSelection.topInternal)
            {
                var trs       = mesh.transform;
                var positions = mesh.positionsInternal;
                s_EdgeBuffer.Clear();

                // When the pointer is over another object, apply a modifier to the distance to prefer picking the
                // object hovered over the currently selected
                var distMultiplier = (hoveredMesh == mesh || hoveredMesh == null)
                    ? 1.0f
                    : ScenePickerPreferences.offPointerMultiplier;

                foreach (var face in mesh.facesInternal)
                {
                    foreach (var edge in face.edges)
                    {
                        int x = edge.a;
                        int y = edge.b;

                        float d = UHandleUtility.DistanceToLine(
                            trs.TransformPoint(positions[x]),
                            trs.TransformPoint(positions[y]));

                        d *= distMultiplier;

                        // best distance isn't set to maxPointerDistance because we want to preserve an unselected
                        // gameobject over a selected gameobject with an out of bounds edge.
                        if (d > ScenePickerPreferences.maxPointerDistance)
                        {
                            continue;
                        }

                        // account for stacked edges
                        if (Mathf.Approximately(d, bestDistance))
                        {
                            s_EdgeBuffer.Add(new Edge(x, y));
                        }
                        else if (d < bestDistance)
                        {
                            s_EdgeBuffer.Clear();
                            s_EdgeBuffer.Add(new Edge(x, y));

                            selection.gameObject = mesh.gameObject;
                            selection.mesh       = mesh;
                            selection.SetSingleEdge(new Edge(x, y));
                            bestDistance = d;
                        }
                    }
                }

                // If more than 1 edge is closest, the closest is one of the vertex.
                // Get closest edge to the camera.
                if (s_EdgeBuffer.Count > 1)
                {
                    selection.SetSingleEdge(GetClosestEdgeToCamera(positions, s_EdgeBuffer));
                }
            }

            return(selection.gameObject != null ? bestDistance : Mathf.Infinity);
        }
        void OnSceneGUI(SceneView sceneView)
        {
            SceneStyles.Init();

            m_CurrentEvent = Event.current;

            EditorHandleDrawing.DrawSceneHandles(SceneDragAndDropListener.isDragging ? SelectMode.None : selectMode);

            DrawHandleGUI(sceneView);

            if (m_CurrentEvent.type == EventType.KeyDown)
            {
                // Escape isn't assignable as a shortcut
                if (m_CurrentEvent.keyCode == KeyCode.Escape && selectMode != SelectMode.Object)
                {
                    selectMode = SelectMode.Object;

                    m_IsDragging          = false;
                    m_IsReadyForMouseDrag = false;

                    m_CurrentEvent.Use();
                }
            }

            if (selectMode == SelectMode.Object)
            {
                return;
            }

            bool pathSelectionModifier = EditorHandleUtility.IsSelectionPathModifier(m_CurrentEvent.modifiers);

            // Check mouse position in scene and determine if we should highlight something
            if (s_ShowHoverHighlight &&
                selectMode.IsMeshElementMode() &&
                (m_CurrentEvent.type == EventType.MouseMove ||
                 (m_wasSelectingPath != pathSelectionModifier && m_CurrentEvent.isKey)))
            {
                m_Hovering.CopyTo(m_HoveringPrevious);
                if (GUIUtility.hotControl != 0 ||
                    EditorSceneViewPicker.MouseRayHitTest(m_CurrentEvent.mousePosition, selectMode, m_ScenePickerPreferences, m_Hovering) > ScenePickerPreferences.maxPointerDistance)
                {
                    m_Hovering.Clear();
                }

                if (!m_Hovering.Equals(m_HoveringPrevious))
                {
                    if (pathSelectionModifier)
                    {
                        EditorSceneViewPicker.DoMouseHover(m_Hovering);
                    }

                    SceneView.RepaintAll();
                }
            }

            m_wasSelectingPath = pathSelectionModifier;

            if (Tools.current == Tool.View)
            {
                return;
            }

            switch (m_CurrentEvent.type)
            {
            case EventType.ValidateCommand:
            case EventType.ExecuteCommand:
                bool execute = m_CurrentEvent.type == EventType.ExecuteCommand;
                switch (m_CurrentEvent.commandName)
                {
                case "SelectAll":
                    if (execute)
                    {
                        SelectAll();
                    }
                    m_CurrentEvent.Use();
                    break;

                case "DeselectAll":
                    if (execute)
                    {
                        DeselectAll();
                    }
                    m_CurrentEvent.Use();
                    break;

                case "InvertSelection":
                    if (execute)
                    {
                        InvertSelection();
                    }
                    m_CurrentEvent.Use();
                    break;
                }
                break;
            }

            if (EditorHandleUtility.SceneViewInUse(m_CurrentEvent))
            {
                if (m_IsDragging)
                {
                    m_IsDragging = false;
                }

                if (GUIUtility.hotControl == m_DefaultControl)
                {
                    GUIUtility.hotControl = 0;
                }

                return;
            }

            // This prevents us from selecting other objects in the scene,
            // and allows for the selection of faces / vertices.
            m_DefaultControl = GUIUtility.GetControlID(FocusType.Passive);
            if (Event.current.type == EventType.Layout)
            {
                HandleUtility.AddDefaultControl(m_DefaultControl);
            }

            HandleMouseEvent(sceneView, m_DefaultControl);
        }
        void OnSceneGUI(SceneView sceneView)
        {
            SceneStyles.Init();

            m_CurrentEvent = Event.current;

            EditorHandleDrawing.DrawSceneHandles(SceneDragAndDropListener.isDragging ? SelectMode.None : selectMode);

            DrawHandleGUI(sceneView);

            if (m_CurrentEvent.type == EventType.KeyDown)
            {
                // Escape isn't assignable as a shortcut
                if (m_CurrentEvent.keyCode == KeyCode.Escape && selectMode != SelectMode.Object)
                {
                    selectMode = SelectMode.Object;

                    m_IsDragging          = false;
                    m_IsReadyForMouseDrag = false;

                    m_CurrentEvent.Use();
                }
            }

            if (selectMode == SelectMode.Object)
            {
                return;
            }

            bool pathSelectionModifier = EditorHandleUtility.IsSelectionPathModifier(m_CurrentEvent.modifiers);

            // Check mouse position in scene and determine if we should highlight something
            if (s_ShowHoverHighlight &&
                selectMode.IsMeshElementMode() &&
                (m_CurrentEvent.type == EventType.MouseMove ||
                 (m_wasSelectingPath != pathSelectionModifier && m_CurrentEvent.isKey)))
            {
                m_Hovering.CopyTo(m_HoveringPrevious);
                if (GUIUtility.hotControl != 0 ||
                    EditorSceneViewPicker.MouseRayHitTest(m_CurrentEvent.mousePosition, selectMode, m_ScenePickerPreferences, m_Hovering) > ScenePickerPreferences.maxPointerDistance)
                {
                    m_Hovering.Clear();
                }

                if (!m_Hovering.Equals(m_HoveringPrevious))
                {
                    if (pathSelectionModifier)
                    {
                        EditorSceneViewPicker.DoMouseHover(m_Hovering);
                    }

                    SceneView.RepaintAll();
                }
            }

            m_wasSelectingPath = pathSelectionModifier;

            if (Tools.current == Tool.View)
            {
                return;
            }

            switch (m_CurrentEvent.type)
            {
            case EventType.ValidateCommand:
            case EventType.ExecuteCommand:
                bool execute = m_CurrentEvent.type == EventType.ExecuteCommand;
                switch (m_CurrentEvent.commandName)
                {
                case "SelectAll":
                    if (execute)
                    {
                        SelectAll();
                    }
                    m_CurrentEvent.Use();
                    break;

                case "DeselectAll":
                    if (execute)
                    {
                        DeselectAll();
                    }
                    m_CurrentEvent.Use();
                    break;

                case "InvertSelection":
                    if (execute)
                    {
                        InvertSelection();
                    }
                    m_CurrentEvent.Use();
                    break;
                }
                break;
            }

            if (EditorHandleUtility.SceneViewInUse(m_CurrentEvent))
            {
                if (m_IsDragging)
                {
                    m_IsDragging = false;
                }

                if (GUIUtility.hotControl == m_DefaultControl)
                {
                    GUIUtility.hotControl = 0;
                }

                return;
            }

            // This prevents us from selecting other objects in the scene,
            // and allows for the selection of faces / vertices.
            m_DefaultControl = GUIUtility.GetControlID(FocusType.Passive);
            if (Event.current.type == EventType.Layout)
            {
                HandleUtility.AddDefaultControl(m_DefaultControl);
            }

            if (m_CurrentEvent.type == EventType.MouseDown && HandleUtility.nearestControl == m_DefaultControl)
            {
                // double clicking object
                if (m_CurrentEvent.clickCount > 1)
                {
                    DoubleClick(m_CurrentEvent);
                }

                m_InitialMousePosition = m_CurrentEvent.mousePosition;
                // readyForMouseDrag prevents a bug wherein after ending a drag an errant
                // MouseDrag event is sent with no corresponding MouseDown/MouseUp event.
                m_IsReadyForMouseDrag = true;

                GUIUtility.hotControl = m_DefaultControl;
            }

            if (m_CurrentEvent.type == EventType.MouseDrag && m_IsReadyForMouseDrag && GUIUtility.hotControl == m_DefaultControl)
            {
                if (!m_IsDragging && Vector2.Distance(m_CurrentEvent.mousePosition, m_InitialMousePosition) > k_MouseDragThreshold)
                {
                    sceneView.Repaint();
                    m_IsDragging = true;
                }
            }

            if (m_CurrentEvent.type == EventType.Ignore)
            {
                if (m_IsDragging)
                {
                    m_IsReadyForMouseDrag = false;
                    m_IsDragging          = false;
                    EditorSceneViewPicker.DoMouseDrag(m_MouseDragRect, selectMode, m_ScenePickerPreferences);
                }

                if (m_WasDoubleClick)
                {
                    m_WasDoubleClick = false;
                }

                if (GUIUtility.hotControl == m_DefaultControl)
                {
                    GUIUtility.hotControl = 0;
                }
            }

            if (m_CurrentEvent.type == EventType.MouseUp && GUIUtility.hotControl == m_DefaultControl)
            {
                GUIUtility.hotControl = 0;

                if (m_WasDoubleClick)
                {
                    m_WasDoubleClick = false;
                }
                else
                {
                    if (!m_IsDragging)
                    {
                        if (UVEditor.instance)
                        {
                            UVEditor.instance.ResetUserPivot();
                        }

                        EditorSceneViewPicker.DoMouseClick(m_CurrentEvent, selectMode, m_ScenePickerPreferences);
                        UpdateSelection();
                    }
                    else
                    {
                        m_IsDragging          = false;
                        m_IsReadyForMouseDrag = false;

                        if (UVEditor.instance)
                        {
                            UVEditor.instance.ResetUserPivot();
                        }

                        EditorSceneViewPicker.DoMouseDrag(m_MouseDragRect, selectMode, m_ScenePickerPreferences);

                        if (GUIUtility.hotControl == m_DefaultControl)
                        {
                            GUIUtility.hotControl = 0;
                        }
                    }
                }
            }
        }
        static float EdgeRaycast(Vector3 mousePosition, ScenePickerPreferences pickerPrefs, bool allowUnselected, SceneSelection selection)
        {
            selection.Clear();
            selection.gameObject = UHandleUtility.PickGameObject(mousePosition, false);
            var hoveredMesh = selection.gameObject != null?selection.gameObject.GetComponent <ProBuilderMesh>() : null;

            float bestDistance           = pickerPrefs.maxPointerDistance;
            float unselectedBestDistance = bestDistance;
            bool  hoveredIsInSelection   = MeshSelection.topInternal.Contains(hoveredMesh);

            if (hoveredMesh != null && (allowUnselected || hoveredIsInSelection))
            {
                var tup = GetNearestEdgeOnMesh(hoveredMesh, mousePosition);

                if (tup.edge.IsValid() && tup.distance < pickerPrefs.maxPointerDistance)
                {
                    selection.gameObject   = hoveredMesh.gameObject;
                    selection.mesh         = hoveredMesh;
                    selection.edge         = tup.edge;
                    unselectedBestDistance = tup.distance;

                    // if it's in the selection, it automatically wins as best. if not, treat this is a fallback.
                    if (hoveredIsInSelection)
                    {
                        return(tup.distance);
                    }
                }
            }

            foreach (var mesh in MeshSelection.topInternal)
            {
                var trs       = mesh.transform;
                var positions = mesh.positionsInternal;
                s_EdgeBuffer.Clear();

                //When the pointer is over another object, apply a modifier to the distance to prefer picking the object hovered over the currently selected
                var distMultiplier = (hoveredMesh == mesh || hoveredMesh == null) ? 1.0f : pickerPrefs.offPointerMultiplier;

                foreach (var face in mesh.facesInternal)
                {
                    foreach (var edge in face.edges)
                    {
                        int x = edge.a;
                        int y = edge.b;


                        float d = UHandleUtility.DistanceToLine(
                            trs.TransformPoint(positions[x]),
                            trs.TransformPoint(positions[y]));

                        d *= distMultiplier;

                        if (d == bestDistance)
                        {
                            s_EdgeBuffer.Add(new Edge(x, y));
                        }
                        else if (d < bestDistance)
                        {
                            s_EdgeBuffer.Clear();
                            s_EdgeBuffer.Add(new Edge(x, y));

                            selection.gameObject = mesh.gameObject;
                            selection.mesh       = mesh;
                            selection.edge       = new Edge(x, y);
                            bestDistance         = d;
                        }
                    }
                }

                //If more than 1 edge is closest, the closest is one of the vertex.
                //Get closest edge to the camera.
                if (s_EdgeBuffer.Count > 1)
                {
                    selection.edge = GetClosestEdgeToCamera(positions, s_EdgeBuffer);
                }
            }

            if (selection.gameObject != null)
            {
                if (bestDistance < pickerPrefs.maxPointerDistance)
                {
                    return(bestDistance);
                }
                return(unselectedBestDistance);
            }

            return(Mathf.Infinity);
        }
        public static float PickEdge(Camera camera, Vector3 mousePosition, float maxDistance, GameObject pickedObject, IEnumerable <ProBuilderMesh> meshes, bool depthTest, ref SceneSelection selection)
        {
            selection.Clear();
            selection.gameObject = pickedObject;
            ProBuilderMesh hoveredMesh = selection.gameObject != null?selection.gameObject.GetComponent <ProBuilderMesh>() : null;

            float bestDistance           = maxDistance;
            float unselectedBestDistance = maxDistance;

            if (hoveredMesh != null)
            {
                EdgeAndDistance tup = GetNearestEdgeOnMesh(camera, hoveredMesh, mousePosition);

                if (tup.edge.IsValid() && tup.distance < maxDistance)
                {
                    selection.gameObject   = hoveredMesh.gameObject;
                    selection.mesh         = hoveredMesh;
                    selection.edge         = tup.edge;
                    unselectedBestDistance = tup.distance;

                    // if it's in the selection, it automatically wins as best. if not, treat this is a fallback.
                    //if (hoveredIsInSelection)
                    {
                        return(tup.distance);
                    }
                }
            }

            ProBuilderMesh pickedMesh = pickedObject != null?pickedObject.GetComponent <ProBuilderMesh>() : null;

            HashSet <ProBuilderMesh> hs = new HashSet <ProBuilderMesh>();

            foreach (ProBuilderMesh mesh in meshes)
            {
                if (!hs.Contains(mesh))
                {
                    hs.Add(mesh);
                }
            }

            if (pickedMesh != null && !hs.Contains(pickedMesh))
            {
                hs.Add(pickedMesh);
            }

            foreach (ProBuilderMesh mesh in hs)
            {
                Transform       trs       = mesh.transform;
                IList <Vector3> positions = mesh.positions;
                m_edges.Clear();

                const float distMultiplier = 1.0f;

                foreach (Face face in mesh.faces)
                {
                    foreach (Edge edge in face.edges)
                    {
                        int x = edge.a;
                        int y = edge.b;

                        Vector3 projectedPoint;
                        Vector3 p0 = trs.TransformPoint(positions[x]);
                        Vector3 p1 = trs.TransformPoint(positions[y]);
                        float   d  = MathHelper.DistanceToLine(camera, mousePosition,
                                                               p0,
                                                               p1, out projectedPoint);

                        if (depthTest)
                        {
                            Ray     ray = camera.ScreenPointToRay(projectedPoint);
                            Vector3 cpl0;
                            Vector3 cpl1;

                            if (MathHelper.ClosestPointsOnTwoLines(out cpl0, out cpl1, ray.origin, ray.direction, p0, p1 - p0))
                            {
                                if (PointIsOccluded(camera, mesh, cpl1))
                                {
                                    continue;
                                }
                            }
                        }

                        d *= distMultiplier;

                        if (d == bestDistance)
                        {
                            m_edges.Add(new Edge(x, y));
                        }
                        else if (d < bestDistance)
                        {
                            m_edges.Clear();
                            m_edges.Add(new Edge(x, y));

                            selection.gameObject = mesh.gameObject;
                            selection.mesh       = mesh;
                            selection.edge       = new Edge(x, y);
                            bestDistance         = d;
                        }
                    }
                }

                //If more than 1 edge is closest, the closest is one of the vertex.
                //Get closest edge to the camera.
                if (m_edges.Count > 1)
                {
                    selection.edge = GetClosestEdgeToCamera(camera, mousePosition, positions, m_edges);
                }
            }

            if (selection.gameObject != null)
            {
                if (bestDistance < maxDistance)
                {
                    return(bestDistance);
                }

                return(Mathf.Infinity);// unselectedBestDistance;
            }

            return(Mathf.Infinity);
        }