Example #1
0
        public static void DoMouseHover(SceneSelection selection)
        {
            if (selection.faces.Count == 0)
            {
                return;
            }
            var mesh       = selection.mesh;
            var face       = selection.faces[0];
            var activeFace = mesh.GetActiveFace();

            if (activeFace == null || activeFace == face)
            {
                return;
            }

            var faces     = mesh.facesInternal;
            var pathFaces = SelectPathFaces.GetPath(mesh, Array.IndexOf <Face>(faces, activeFace), Array.IndexOf <Face>(faces, face));

            if (pathFaces != null)
            {
                foreach (var path in pathFaces)
                {
                    selection.faces.Add(faces[path]);
                }
            }
        }
 public static void DrawHighlight(SceneSelection highlight)
 {
     if (Event.current.type == EventType.Repaint && highlight != null)
     {
         UnityEditorProBuilderDynamic.EditorMeshHandles.DrawSceneSelection(highlight);
     }
 }
Example #3
0
        public static void DrawHighlight(SceneSelection highlight)
        {
            if (Event.current.type == EventType.Repaint && highlight != null)
            {
#if PROBUILDER_4_4_OR_NEWER
                UnityEditorProBuilderDynamic.EditorHandleDrawing.DrawSceneSelection(highlight);
#else
                UnityEditorProBuilderDynamic.EditorMeshHandles.DrawSceneSelection(highlight);
#endif
            }
        }
Example #4
0
        public static void OpenSceneSelection()
        {
            var lastScene = Instance.currentScene;
            var selection = new SceneSelection();

            selection.Load();
            Instance.currentScene   = selection;
            Instance.sceneSelection = selection;

            SceneManager.LoadSceneAsync("Scenes/SceneSelection");

            CloseScene(lastScene);
        }
Example #5
0
        public static void DrawSceneSelection(SceneSelection selection)
        {
            var mesh = selection.mesh;

            if (mesh == null)
            {
                return;
            }

            var positions = mesh.positionsInternal;

            // Draw nearest edge
            if (selection.face != null)
            {
                using (new TriangleDrawingScope(s_PreselectionColor))
                {
                    GL.MultMatrix(mesh.transform.localToWorldMatrix);

                    var face = selection.face;
                    var ind  = face.indexes;

                    for (int i = 0, c = ind.Count; i < c; i += 3)
                    {
                        GL.Vertex(positions[ind[i]]);
                        GL.Vertex(positions[ind[i + 1]]);
                        GL.Vertex(positions[ind[i + 2]]);
                    }
                }
            }
            else if (selection.edge != Edge.Empty)
            {
                using (var drawingScope = new LineDrawingScope(s_PreselectionColor, -1f, CompareFunction.Always))
                {
                    GL.MultMatrix(mesh.transform.localToWorldMatrix);
                    drawingScope.DrawLine(positions[selection.edge.a], positions[selection.edge.b]);
                }
            }
            else if (selection.vertex > -1)
            {
                using (var drawingScope = new PointDrawingScope(s_PreselectionColor, CompareFunction.Always)
                {
                    matrix = mesh.transform.localToWorldMatrix
                })
                {
                    drawingScope.Draw(positions[selection.vertex]);
                }
            }
        }
Example #6
0
        void DrawSceneSelectionInternal(SceneSelection selection)
        {
            var mesh = selection.mesh;

            if (mesh == null)
            {
                return;
            }

            var positions = mesh.positionsInternal;

            // Draw nearest edge
            if (selection.face != null)
            {
                using (new TriangleDrawingScope(preselectionColor))
                {
                    GL.MultMatrix(mesh.transform.localToWorldMatrix);

                    var face = selection.face;
                    var ind  = face.indexes;

                    for (int i = 0, c = ind.Count; i < c; i += 3)
                    {
                        GL.Vertex(positions[ind[i]]);
                        GL.Vertex(positions[ind[i + 1]]);
                        GL.Vertex(positions[ind[i + 2]]);
                    }
                }
            }
            else if (selection.edge != Edge.Empty)
            {
                using (var drawingScope = new LineDrawingScope(preselectionColor, -1f, CompareFunction.Always))
                {
                    GL.MultMatrix(mesh.transform.localToWorldMatrix);
                    drawingScope.DrawLine(positions[selection.edge.a], positions[selection.edge.b]);
                }
            }
            else if (selection.vertex > -1)
            {
                var size = dotCapSize;

                using (new Handles.DrawingScope(preselectionColor, mesh.transform.localToWorldMatrix))
                {
                    var pos = positions[selection.vertex];
                    Handles.DotHandleCap(-1, pos, Quaternion.identity, HandleUtility.GetHandleSize(pos) * size, Event.current.type);
                }
            }
        }
        // Get the object & mesh selection that the mouse is currently nearest.
        // A ProBuilderMesh is returned because double click actions need to know what the last selected pb_Object was.
        // If deepClickOffset is specified, the object + deepClickOffset in the deep select stack will be returned (instead of next).
        internal static float MouseRayHitTest(
            Vector3 mousePosition,
            SelectMode selectionMode,
            ScenePickerPreferences pickerOptions,
            SceneSelection selection,
            bool allowUnselected = false)
        {
            if (selectionMode.ContainsFlag(SelectMode.Edge | SelectMode.TextureEdge))
            {
                return(EdgeRaycast(mousePosition, pickerOptions, allowUnselected, selection));
            }

            if (selectionMode.ContainsFlag(SelectMode.Vertex | SelectMode.TextureVertex))
            {
                return(VertexRaycast(mousePosition, pickerOptions, allowUnselected, selection));
            }

            return(FaceRaycast(mousePosition, pickerOptions, allowUnselected, selection, 0, true));
        }
Example #8
0
        public bool Click(Camera camera, Vector3 pointer)
        {
            if (!m_isEditing)
            {
                return(false);
            }

            SceneSelection selection = new SceneSelection();
            float          result    = PBUtility.PickVertex(camera, pointer, 20, m_selection.Transform, m_selection.Positions, ref selection);

            if (result != Mathf.Infinity)
            {
                if (m_selection.Positions.Count >= 3)
                {
                    m_selection.Unselect();
                    m_selection.Select(selection.vertex);
                    return(true);
                }
            }
            else
            {
                if (Stage == 0)
                {
                    Ray   ray = camera.ScreenPointToRay(pointer);
                    float enter;

                    Plane plane = new Plane(m_selection.transform.up, m_selection.transform.position);
                    if (plane.Raycast(ray, out enter))
                    {
                        Vector3 position = ray.GetPoint(enter);
                        position = m_selection.Transform.InverseTransformPoint(position);
                        m_selection.Add(position);
                        m_positions.Add(position);
                    }

                    m_target.CreateShapeFromPolygon(m_selection.Positions, 0.001f, false);
                }
            }

            return(false);
        }
        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);
        }
        /// <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);
        }
        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);
        }
        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);
        }
Example #15
0
 public static void ClearProBuilderHighlight()
 {
     highlight           = null;
     proBuilderHighlight = null;
     SceneView.RepaintAll();
 }
Example #16
0
 public static void ProBuilderHighlight(SceneSelection selection)
 {
     highlight           = selection.gameObject;
     proBuilderHighlight = selection;
     SceneView.RepaintAll();
 }
        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);
        }
        public static float PickVertex(Camera camera, Vector3 mousePosition, float maxDistance, GameObject pickedObject, IEnumerable <ProBuilderMesh> meshes, 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));

            for (int i = 0; i < m_nearestVertices.Count; i++)
            {
                if (!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 static void DrawSceneSelection(SceneSelection selection)
 {
     Get().DrawSceneSelectionInternal(selection);
 }
        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);
        }