internal static void SetSelection(IList <GameObject> newSelection)
        {
            UndoUtility.RecordSelection(topInternal.ToArray(), "Change Selection");
            ClearElementAndObjectSelection();

            // if the previous tool was set to none, use Tool.Move
            if (Tools.current == Tool.None)
            {
                Tools.current = Tool.Move;
            }

            var newCount = newSelection != null ? newSelection.Count : 0;

            if (newCount > 0)
            {
                Selection.activeTransform = newSelection[newCount - 1].transform;
                Selection.objects         = newSelection.ToArray();
            }
            else
            {
                Selection.activeTransform = null;
            }

            OnObjectSelectionChanged();
        }
        /// <summary>
        /// Called from ProGrids.
        /// </summary>
        /// <param name="snapVal"></param>
        void PushToGrid(float snapVal)
        {
            UndoUtility.RecordSelection(selection.ToArray(), "Push elements to Grid");

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

            for (int i = 0, c = MeshSelection.selectedObjectCount; i < c; i++)
            {
                ProBuilderMesh mesh = selection[i];
                if (mesh.selectedVertexCount < 1)
                {
                    continue;
                }

                var indexes = mesh.GetCoincidentVertices(mesh.selectedIndexesInternal);
                ProGridsSnapping.SnapVertices(mesh, indexes, Vector3.one * snapVal);

                mesh.ToMesh();
                mesh.Refresh();
                mesh.Optimize();
            }

            UpdateSelection();
        }
        internal static void OnObjectSelectionChanged()
        {
            // GameObjects returns both parent and child when both are selected, where transforms only returns the top-most
            // transform.
            s_UnitySelectionChangeMeshes.Clear();
            s_ElementSelection.Clear();
            s_ActiveMesh = null;

            var gameObjects = Selection.gameObjects;

            for (int i = 0, c = gameObjects.Length; i < c; i++)
            {
#if UNITY_2019_3_OR_NEWER
                ProBuilderMesh mesh;
                if (gameObjects[i].TryGetComponent <ProBuilderMesh>(out mesh))
#else
                var mesh = gameObjects[i].GetComponent <ProBuilderMesh>();
                if (mesh != null)
#endif
                {
                    if (gameObjects[i] == Selection.activeGameObject)
                    {
                        s_ActiveMesh = mesh;
                    }

                    s_UnitySelectionChangeMeshes.Add(mesh);
                }
            }

            for (int i = 0, c = s_TopSelection.Count; i < c; i++)
            {
                if (!s_UnitySelectionChangeMeshes.Contains(s_TopSelection[i]))
                {
                    if (s_TopSelection[i] != null)
                    {
                        UndoUtility.RecordSelection(s_TopSelection[i], "Selection Change");
                    }
                    s_TopSelection[i].ClearSelection();
                }
            }

            s_TopSelection.Clear();

            foreach (var i in s_UnitySelectionChangeMeshes)
            {
                s_TopSelection.Add(i);
            }

            selectedObjectCount = s_TopSelection.Count;

            OnComponentSelectionChanged();

            if (objectSelectionChanged != null)
            {
                objectSelectionChanged();
            }

            s_UnitySelectionChangeMeshes.Clear();
        }
Exemple #4
0
        void SelectAll()
        {
            if (MeshSelection.selectedObjectCount < 1)
            {
                return;
            }

            UndoUtility.RecordSelection("Select all");

            switch (selectMode)
            {
            case SelectMode.Vertex:
                foreach (var mesh in MeshSelection.topInternal)
                {
                    var sharedIndexes = mesh.sharedVerticesInternal;
                    var all           = new List <int>();

                    for (var i = 0; i < sharedIndexes.Length; i++)
                    {
                        all.Add(sharedIndexes[i][0]);
                    }

                    mesh.SetSelectedVertices(all);
                }
                break;

            case SelectMode.Face:
            case SelectMode.TextureFace:
                foreach (var mesh in MeshSelection.topInternal)
                {
                    mesh.SetSelectedFaces(mesh.facesInternal);
                }
                break;

            case SelectMode.Edge:

                foreach (var mesh in MeshSelection.topInternal)
                {
                    var universalEdges = mesh.GetSharedVertexHandleEdges(mesh.facesInternal.SelectMany(x => x.edges)).ToArray();
                    var all            = new Edge[universalEdges.Length];

                    for (var n = 0; n < universalEdges.Length; n++)
                    {
                        all[n] = new Edge(mesh.sharedVerticesInternal[universalEdges[n].a][0], mesh.sharedVerticesInternal[universalEdges[n].b][0]);
                    }

                    mesh.SetSelectedEdges(all);
                }
                break;
            }

            Refresh();
            SceneView.RepaintAll();
        }
Exemple #5
0
 private static void SetFill(AutoUnwrapSettings.Fill fill, ProBuilderMesh[] sel)
 {
     UndoUtility.RecordSelection(sel, "Fill UVs");
     for (int i = 0; i < sel.Length; i++)
     {
         foreach (Face q in sel[i].GetSelectedFaces())
         {
             var uv = q.uv;
             uv.fill = fill;
             q.uv    = uv;
         }
     }
 }
Exemple #6
0
 private static void SetUseWorldSpace(bool useWorldSpace, ProBuilderMesh[] sel)
 {
     UndoUtility.RecordSelection(sel, "Use World Space UVs");
     for (int i = 0; i < sel.Length; i++)
     {
         foreach (Face q in sel[i].GetSelectedFaces())
         {
             var uv = q.uv;
             uv.useWorldSpace = useWorldSpace;
             q.uv             = uv;
         }
     }
 }
Exemple #7
0
 private static void SetSwapUV(bool swapUV, ProBuilderMesh[] sel)
 {
     UndoUtility.RecordSelection(sel, "Swap U, V");
     for (int i = 0; i < sel.Length; i++)
     {
         foreach (Face q in sel[i].GetSelectedFaces())
         {
             var uv = q.uv;
             uv.swapUV = swapUV;
             q.uv      = uv;
         }
     }
 }
Exemple #8
0
 private static void SetFlipV(bool flipV, ProBuilderMesh[] sel)
 {
     UndoUtility.RecordSelection(sel, "Flip V");
     for (int i = 0; i < sel.Length; i++)
     {
         foreach (Face q in sel[i].GetSelectedFaces())
         {
             var uv = q.uv;
             uv.flipV = flipV;
             q.uv     = uv;
         }
     }
 }
 private static void SetFlipU(bool flipU, ProBuilderMesh[] sel)
 {
     UndoUtility.RecordSelection(sel, "Flip U");
     for (int i = 0; i < sel.Length; i++)
     {
         foreach (Face q in sel[i].GetSelectedFaces())
         {
             var uv = q.uv;
             uv.flipU = flipU;
             q.uv     = uv;
             sel[i].SetGroupUV(q.uv, q.textureGroup);
         }
     }
 }
Exemple #10
0
        private static void SetRotation(float rot, ProBuilderMesh[] sel)
        {
            UndoUtility.RecordSelection(sel, "Rotate UVs");

            for (int i = 0; i < sel.Length; i++)
            {
                foreach (Face q in sel[i].GetSelectedFaces())
                {
                    var uv = q.uv;
                    uv.rotation = rot;
                    q.uv        = uv;
                }
            }
        }
Exemple #11
0
        private static void SetAnchor(AutoUnwrapSettings.Anchor anchor, ProBuilderMesh[] sel)
        {
            UndoUtility.RecordSelection(sel, "Set UV Anchor");

            for (int i = 0; i < sel.Length; i++)
            {
                foreach (Face q in sel[i].GetSelectedFaces())
                {
                    var uv = q.uv;
                    uv.anchor = anchor;
                    q.uv      = uv;
                }
            }
        }
        static void SelectGroups(ProBuilderMesh pb, HashSet <int> groups)
        {
            UndoUtility.RecordSelection(pb, "Select with Smoothing Group");

            if ((Event.current.modifiers & EventModifiers.Shift) == EventModifiers.Shift ||
                (Event.current.modifiers & EventModifiers.Control) == EventModifiers.Control)
            {
                pb.SetSelectedFaces(pb.facesInternal.Where(x => groups.Contains(x.smoothingGroup) || pb.selectedFacesInternal.Contains(x)));
            }
            else
            {
                pb.SetSelectedFaces(pb.facesInternal.Where(x => groups.Contains(x.smoothingGroup)));
            }
            ProBuilderEditor.Refresh();
        }
Exemple #13
0
        static ActionResult MenuBooleanOperation(BooleanOperation operation, ProBuilderMesh lhs, ProBuilderMesh rhs)
        {
            if (lhs == null || rhs == null)
            {
                return(new ActionResult(ActionResult.Status.Failure, "Must Select 2 Objects"));
            }

            string op_string = operation == BooleanOperation.Union ? "Union" : (operation == BooleanOperation.Subtract ? "Subtract" : "Intersect");

            ProBuilderMesh[] sel = new ProBuilderMesh[] { lhs, rhs };

            UndoUtility.RecordSelection(sel, op_string);

            UnityEngine.ProBuilder.Csg.Model result;

            switch (operation)
            {
            case BooleanOperation.Union:
                result = Boolean.Union(lhs.gameObject, rhs.gameObject);
                break;

            case BooleanOperation.Subtract:
                result = Boolean.Subtract(lhs.gameObject, rhs.gameObject);
                break;

            default:
                result = Boolean.Intersect(lhs.gameObject, rhs.gameObject);
                break;
            }

            var            materials = result.materials.ToArray();
            ProBuilderMesh pb        = ProBuilderMesh.Create();

            pb.GetComponent <MeshFilter>().sharedMesh        = (Mesh)result;
            pb.GetComponent <MeshRenderer>().sharedMaterials = materials;
            MeshImporter importer = new MeshImporter(pb.gameObject);

            importer.Import(new MeshImportSettings()
            {
                quads = true, smoothing = true, smoothingAngle = 1f
            });
            pb.Rebuild();
            pb.CenterPivot(null);
            Selection.objects = new Object[] { pb.gameObject };

            return(new ActionResult(ActionResult.Status.Success, op_string));
        }
Exemple #14
0
        static void ApplyMaterial(IEnumerable<ProBuilderMesh> selection, Material mat)
        {
            if (mat == null)
                return;

            UndoUtility.RecordSelection(selection.ToArray(), "Set Face Materials");

            foreach (var mesh in selection)
            {
                var applyPerFace = ProBuilderEditor.selectMode.ContainsFlag(SelectMode.Face) && mesh.faceCount > 0;
                mesh.SetMaterial(applyPerFace ? mesh.GetSelectedFaces() : mesh.facesInternal, mat);
                InternalMeshUtility.FilterUnusedSubmeshIndexes(mesh);
                mesh.Rebuild();
                mesh.Optimize();
            }

            if (ProBuilderEditor.instance != null && MeshSelection.selectedFaceCount > 0)
                EditorUtility.ShowNotification("Set Material\n" + mat.name);
        }
Exemple #15
0
        static ActionResult MenuBooleanOperation(BooleanOperation operation, ProBuilderMesh lhs, ProBuilderMesh rhs)
        {
            if (lhs == null || rhs == null)
            {
                return(new ActionResult(ActionResult.Status.Failure, "Must Select 2 Objects"));
            }

            string op_string = operation == BooleanOperation.Union ? "Union" : (operation == BooleanOperation.Subtract ? "Subtract" : "Intersect");

            ProBuilderMesh[] sel = new ProBuilderMesh[] { lhs, rhs };

            UndoUtility.RecordSelection(sel, op_string);

            Mesh c;

            switch (operation)
            {
            case BooleanOperation.Union:
                c = CSG.Union(lhs.gameObject, rhs.gameObject);
                break;

            case BooleanOperation.Subtract:
                c = CSG.Subtract(lhs.gameObject, rhs.gameObject);
                break;

            default:
                c = CSG.Intersect(lhs.gameObject, rhs.gameObject);
                break;
            }

            GameObject go = new GameObject();

            go.AddComponent <MeshRenderer>().sharedMaterial = EditorMaterialUtility.GetUserMaterial();
            go.AddComponent <MeshFilter>().sharedMesh       = c;

            ProBuilderMesh pb = InternalMeshUtility.CreateMeshWithTransform(go.transform, false);

            DestroyImmediate(go);

            Selection.objects = new Object[] { pb.gameObject };

            return(new ActionResult(ActionResult.Status.Success, op_string));
        }
        private static void TextureGroupSelectedFaces(ProBuilderMesh pb)//, pb_Face face)
        {
            if (pb.selectedFaceCount < 1)
            {
                return;
            }

            Face[] faces = pb.GetSelectedFaces();

            AutoUnwrapSettings cont_uv = faces[0].uv;

            int texGroup = pb.GetUnusedTextureGroup();

            UndoUtility.RecordSelection(pb, "Create Texture Group" + textureGroup);

            foreach (Face f in faces)
            {
                f.uv           = new AutoUnwrapSettings(cont_uv);
                f.textureGroup = texGroup;
            }
        }
Exemple #17
0
        static void ApplyMaterial(IEnumerable <ProBuilderMesh> selection, Material mat)
        {
            if (mat == null)
            {
                return;
            }

            UndoUtility.RecordSelection(selection.ToArray(), "Set Face Materials");

            foreach (var mesh in selection)
            {
                mesh.SetMaterial(mesh.selectedFaceCount > 0 ? mesh.GetSelectedFaces() : mesh.facesInternal, mat);
                mesh.Rebuild();
                mesh.Optimize();
            }

            if (ProBuilderEditor.instance != null && MeshSelection.selectedFaceCount > 0)
            {
                EditorUtility.ShowNotification("Set Material\n" + mat.name);
            }
        }
        private static void SetTextureGroup(ProBuilderMesh[] selection, int tex)
        {
            UndoUtility.RecordSelection(selection, "Set Texture Group " + textureGroup);

            foreach (ProBuilderMesh pb in selection)
            {
                if (pb.selectedFaceCount < 1)
                {
                    continue;
                }

                Face[]             faces = pb.GetSelectedFaces();
                AutoUnwrapSettings cuv   = faces[0].uv;

                foreach (Face f in faces)
                {
                    f.textureGroup = tex;
                    f.uv           = new AutoUnwrapSettings(cuv);
                }
            }
        }
        private static void SetScale(Vector2 scale, Axis2D axis, ProBuilderMesh[] sel)
        {
            UndoUtility.RecordSelection(sel, "Scale UVs");

            for (int i = 0; i < sel.Length; i++)
            {
                foreach (Face q in sel[i].GetSelectedFaces())
                {
                    switch (axis)
                    {
                    case Axis2D.XY:
                    {
                        var uv = q.uv;
                        uv.scale = scale;
                        q.uv     = uv;
                        break;
                    }

                    case Axis2D.X:
                    {
                        var uv = q.uv;
                        uv.scale = new Vector2(scale.x, q.uv.scale.y);
                        q.uv     = uv;
                        break;
                    }

                    case Axis2D.Y:
                    {
                        var uv = q.uv;
                        uv.scale = new Vector2(q.uv.scale.x, scale.y);
                        q.uv     = uv;
                        break;
                    }
                    }

                    sel[i].SetGroupUV(q.uv, q.textureGroup);
                }
            }
        }
        private static void SetOffset(Vector2 offset, Axis2D axis, ProBuilderMesh[] sel)
        {
            UndoUtility.RecordSelection(sel, "Offset UVs");

            for (int i = 0; i < sel.Length; i++)
            {
                foreach (Face q in sel[i].GetSelectedFaces())
                {
                    switch (axis)
                    {
                    case Axis2D.XY:
                    {
                        var uv = q.uv;
                        uv.offset = offset;
                        q.uv      = uv;
                        break;
                    }

                    case Axis2D.X:
                    {
                        var uv = q.uv;
                        uv.offset = new Vector2(offset.x, q.uv.offset.y);
                        q.uv      = uv;
                        break;
                    }

                    case Axis2D.Y:
                    {
                        var uv = q.uv;
                        uv.offset = new Vector2(q.uv.offset.x, offset.y);
                        q.uv      = uv;
                        break;
                    }
                    }

                    sel[i].SetGroupUV(q.uv, q.textureGroup);
                }
            }
        }
Exemple #21
0
        void DeselectAll()
        {
            if (MeshSelection.selectedObjectCount < 1)
            {
                return;
            }

            UndoUtility.RecordSelection("Deselect All");

            switch (selectMode)
            {
            case SelectMode.Vertex:
                foreach (var mesh in MeshSelection.topInternal)
                {
                    mesh.SetSelectedVertices(null);
                }
                break;

            case SelectMode.Face:
            case SelectMode.TextureFace:
                foreach (var mesh in MeshSelection.topInternal)
                {
                    mesh.SetSelectedFaces((IEnumerable <Face>)null);
                }
                break;

            case SelectMode.Edge:

                foreach (var mesh in MeshSelection.topInternal)
                {
                    mesh.SetSelectedEdges(null);
                }
                break;
            }

            Refresh();
            SceneView.RepaintAll();
        }
        private static void SetRotation(float rot, ProBuilderMesh[] sel)
        {
            UndoUtility.RecordSelection(sel, "Rotate UVs");

            for (int i = 0; i < sel.Length; i++)
            {
                foreach (Face q in sel[i].GetSelectedFaces())
                {
                    var uv = q.uv;
                    uv.rotation = rot;
                    if (uv.rotation > 360f)
                    {
                        uv.rotation = uv.rotation % 360f;
                    }
                    else if (uv.rotation < 0f)
                    {
                        uv.rotation = 360f + (uv.rotation % 360f);
                    }
                    q.uv = uv;
                    sel[i].SetGroupUV(uv, q.textureGroup);
                }
            }
        }
Exemple #23
0
        public static void SetFaceColors(Color col)
        {
            col = PlayerSettings.colorSpace == ColorSpace.Linear ? col.linear : col;

            ProBuilderMesh[] selection = InternalUtility.GetComponents <ProBuilderMesh>(Selection.transforms);

            UndoUtility.RecordSelection(selection, "Apply Vertex Colors");

            ProBuilderEditor editor = ProBuilderEditor.instance;

            if (editor && ProBuilderEditor.selectMode.ContainsFlag(SelectMode.Vertex | SelectMode.Edge | SelectMode.Face))
            {
                switch (ProBuilderEditor.selectMode)
                {
                case SelectMode.Face:
                case SelectMode.TextureFace:
                    foreach (ProBuilderMesh mesh in selection)
                    {
                        Color[] colors = mesh.GetColors();

                        foreach (int i in mesh.selectedIndexesInternal)
                        {
                            colors[i] = col;
                        }

                        mesh.colors = colors;
                    }
                    break;

                case SelectMode.Edge:
                case SelectMode.Vertex:
                    foreach (var mesh in selection)
                    {
                        Color[] colors = mesh.GetColors();

                        foreach (int i in mesh.GetCoincidentVertices(mesh.selectedIndexesInternal))
                        {
                            colors[i] = col;
                        }

                        mesh.colors = colors;
                    }
                    break;
                }
            }
            else
            {
                foreach (ProBuilderMesh pb in selection)
                {
                    foreach (Face face in pb.facesInternal)
                    {
                        pb.SetFaceColor(face, col);
                    }
                }
            }

            foreach (ProBuilderMesh pb in selection)
            {
                pb.ToMesh();
                pb.Refresh();
                pb.Optimize();
            }

            EditorUtility.ShowNotification("Set Vertex Colors\n" + ColorUtility.GetColorName(col));
        }
Exemple #24
0
 internal static void SetSelection(GameObject go)
 {
     UndoUtility.RecordSelection(topInternal.ToArray(), "Change Selection");
     ClearElementAndObjectSelection();
     AddToSelection(go);
 }
        public static ProBuilderMesh DoMouseClick(Event evt, SelectMode selectionMode, ScenePickerPreferences pickerPreferences)
        {
            bool appendModifier = EditorHandleUtility.IsAppendModifier(evt.modifiers);

            if (!appendModifier)
            {
                MeshSelection.SetSelection((GameObject)null);
            }

            float pickedElementDistance = Mathf.Infinity;

            if (selectionMode.ContainsFlag(SelectMode.Edge | SelectMode.TextureEdge))
            {
                pickedElementDistance = EdgeRaycast(evt.mousePosition, pickerPreferences, true, s_Selection);
            }
            else if (selectionMode.ContainsFlag(SelectMode.Vertex | SelectMode.TextureVertex))
            {
                pickedElementDistance = VertexRaycast(evt.mousePosition, pickerPreferences, true, s_Selection);
            }
            else
            {
                pickedElementDistance = FaceRaycast(evt.mousePosition, pickerPreferences, true, s_Selection, evt.clickCount > 1 ? -1 : 0, false);
            }

            evt.Use();

            if (pickedElementDistance > pickerPreferences.maxPointerDistance)
            {
                if (appendModifier && Selection.gameObjects.Contains(s_Selection.gameObject))
                {
                    MeshSelection.RemoveFromSelection(s_Selection.gameObject);
                }
                else
                {
                    MeshSelection.AddToSelection(s_Selection.gameObject);
                }

                return(null);
            }

            MeshSelection.AddToSelection(s_Selection.gameObject);

            if (s_Selection.mesh != null)
            {
                var mesh = s_Selection.mesh;

                if (s_Selection.face != null)
                {
                    // Check for other editor mouse shortcuts first (todo proper event handling for mouse shortcuts)
                    MaterialEditor matEditor = MaterialEditor.instance;

                    if (matEditor != null && matEditor.ClickShortcutCheck(Event.current.modifiers, mesh, s_Selection.face))
                    {
                        return(null);
                    }

                    UVEditor uvEditor = UVEditor.instance;

                    if (uvEditor != null && uvEditor.ClickShortcutCheck(mesh, s_Selection.face))
                    {
                        return(null);
                    }

                    var faces = mesh.faces as Face[] ?? mesh.faces.ToArray();
                    var ind   = Array.IndexOf <Face>(faces, s_Selection.face);
                    var sel   = mesh.selectedFaceIndexes.IndexOf(ind);

                    UndoUtility.RecordSelection(mesh, "Select Face");

                    if (sel > -1)
                    {
                        mesh.RemoveFromFaceSelectionAtIndex(sel);
                    }
                    else
                    {
                        mesh.AddToFaceSelection(ind);
                    }
                }
                else if (s_Selection.edge != Edge.Empty)
                {
                    int ind = mesh.IndexOf(mesh.selectedEdges, s_Selection.edge);

                    UndoUtility.RecordSelection(mesh, "Select Edge");

                    if (ind > -1)
                    {
                        mesh.SetSelectedEdges(mesh.selectedEdges.ToArray().RemoveAt(ind));
                    }
                    else
                    {
                        mesh.SetSelectedEdges(mesh.selectedEdges.ToArray().Add(s_Selection.edge));
                    }
                }
                else if (s_Selection.vertex > -1)
                {
                    int ind = Array.IndexOf(mesh.selectedIndexesInternal, s_Selection.vertex);

                    UndoUtility.RecordSelection(mesh, "Select Vertex");

                    if (ind > -1)
                    {
                        mesh.SetSelectedVertices(mesh.selectedIndexesInternal.RemoveAt(ind));
                    }
                    else
                    {
                        mesh.SetSelectedVertices(mesh.selectedIndexesInternal.Add(s_Selection.vertex));
                    }
                }

                return(mesh);
            }

            return(null);
        }
        public static void DoMouseDrag(Rect mouseDragRect, SelectMode selectionMode, ScenePickerPreferences scenePickerPreferences)
        {
            var pickingOptions = new PickerOptions()
            {
                depthTest      = scenePickerPreferences.cullMode == CullingMode.Back,
                rectSelectMode = scenePickerPreferences.rectSelectMode
            };

            UndoUtility.RecordSelection("Drag Select");
            bool isAppendModifier = EditorHandleUtility.IsAppendModifier(Event.current.modifiers);

            if (!isAppendModifier)
            {
                MeshSelection.ClearElementSelection();
            }

            bool elementsInDragRect = false;

            switch (selectionMode)
            {
            case SelectMode.Vertex:
            case SelectMode.TextureVertex:
            {
                Dictionary <ProBuilderMesh, HashSet <int> > selected = SelectionPicker.PickVerticesInRect(
                    SceneView.lastActiveSceneView.camera,
                    mouseDragRect,
                    MeshSelection.topInternal,
                    pickingOptions,
                    EditorGUIUtility.pixelsPerPoint);

                foreach (var kvp in selected)
                {
                    var            mesh          = kvp.Key;
                    SharedVertex[] sharedIndexes = mesh.sharedVerticesInternal;
                    HashSet <int>  common;

                    if (isAppendModifier)
                    {
                        common = mesh.GetSharedVertexHandles(mesh.selectedIndexesInternal);

                        if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Add)
                        {
                            common.UnionWith(kvp.Value);
                        }
                        else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Subtract)
                        {
                            common.RemoveWhere(x => kvp.Value.Contains(x));
                        }
                        else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Difference)
                        {
                            common.SymmetricExceptWith(kvp.Value);
                        }
                    }
                    else
                    {
                        common = kvp.Value;
                    }

                    elementsInDragRect |= kvp.Value.Any();
                    mesh.SetSelectedVertices(common.SelectMany(x => sharedIndexes[x]));
                }

                break;
            }

            case SelectMode.Face:
            case SelectMode.TextureFace:
            {
                Dictionary <ProBuilderMesh, HashSet <Face> > selected = SelectionPicker.PickFacesInRect(
                    SceneView.lastActiveSceneView.camera,
                    mouseDragRect,
                    MeshSelection.topInternal,
                    pickingOptions,
                    EditorGUIUtility.pixelsPerPoint);

                foreach (var kvp in selected)
                {
                    HashSet <Face> current;

                    if (isAppendModifier)
                    {
                        current = new HashSet <Face>(kvp.Key.selectedFacesInternal);

                        if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Add)
                        {
                            current.UnionWith(kvp.Value);
                        }
                        else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Subtract)
                        {
                            current.RemoveWhere(x => kvp.Value.Contains(x));
                        }
                        else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Difference)
                        {
                            current.SymmetricExceptWith(kvp.Value);
                        }
                    }
                    else
                    {
                        current = kvp.Value;
                    }

                    elementsInDragRect |= kvp.Value.Any();
                    kvp.Key.SetSelectedFaces(current);
                }

                break;
            }

            case SelectMode.Edge:
            case SelectMode.TextureEdge:
            {
                var selected = SelectionPicker.PickEdgesInRect(
                    SceneView.lastActiveSceneView.camera,
                    mouseDragRect,
                    MeshSelection.topInternal,
                    pickingOptions,
                    EditorGUIUtility.pixelsPerPoint);

                foreach (var kvp in selected)
                {
                    ProBuilderMesh        mesh          = kvp.Key;
                    Dictionary <int, int> common        = mesh.sharedVertexLookup;
                    HashSet <EdgeLookup>  selectedEdges = EdgeLookup.GetEdgeLookupHashSet(kvp.Value, common);
                    HashSet <EdgeLookup>  current;

                    if (isAppendModifier)
                    {
                        current = EdgeLookup.GetEdgeLookupHashSet(mesh.selectedEdges, common);

                        if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Add)
                        {
                            current.UnionWith(selectedEdges);
                        }
                        else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Subtract)
                        {
                            current.RemoveWhere(x => selectedEdges.Contains(x));
                        }
                        else if (scenePickerPreferences.selectionModifierBehavior == SelectionModifierBehavior.Difference)
                        {
                            current.SymmetricExceptWith(selectedEdges);
                        }
                    }
                    else
                    {
                        current = selectedEdges;
                    }

                    elementsInDragRect |= kvp.Value.Any();
                    mesh.SetSelectedEdges(current.Select(x => x.local));
                }

                break;
            }
            }

            // if nothing was selected in the drag rect, clear the object selection too
            if (!elementsInDragRect && !isAppendModifier)
            {
                MeshSelection.ClearElementAndObjectSelection();
            }

            ProBuilderEditor.Refresh();
            SceneView.RepaintAll();
        }
        void InvertSelection()
        {
            if (MeshSelection.selectedObjectCount < 1)
            {
                return;
            }

            UndoUtility.RecordSelection("Invert Selection");

            switch (selectMode)
            {
            case SelectMode.Vertex:
                foreach (var mesh in MeshSelection.topInternal)
                {
                    var sharedIndexes         = mesh.sharedVerticesInternal;
                    var selectedSharedIndexes = new List <int>();

                    foreach (int i in mesh.selectedIndexesInternal)
                    {
                        selectedSharedIndexes.Add(mesh.GetSharedVertexHandle(i));
                    }

                    var inverse = new List <int>();

                    for (int i = 0; i < sharedIndexes.Length; i++)
                    {
                        if (!selectedSharedIndexes.Contains(i))
                        {
                            inverse.Add(sharedIndexes[i][0]);
                        }
                    }

                    mesh.SetSelectedVertices(inverse.ToArray());
                }

                break;

            case SelectMode.Face:
            case SelectMode.TextureFace:
                foreach (var mesh in MeshSelection.topInternal)
                {
                    var inverse = mesh.facesInternal.Where(x => !mesh.selectedFacesInternal.Contains(x));
                    mesh.SetSelectedFaces(inverse.ToArray());
                }

                break;

            case SelectMode.Edge:

                foreach (var mesh in MeshSelection.topInternal)
                {
                    var universalEdges =
                        mesh.GetSharedVertexHandleEdges(mesh.facesInternal.SelectMany(x => x.edges)).ToArray();
                    var universalSelectedEdges =
                        EdgeUtility.GetSharedVertexHandleEdges(mesh, mesh.selectedEdges).Distinct();
                    var inverseUniversal =
                        System.Array.FindAll(universalEdges, x => !universalSelectedEdges.Contains(x));
                    var inverse = new Edge[inverseUniversal.Length];

                    for (var n = 0; n < inverseUniversal.Length; n++)
                    {
                        inverse[n] = new Edge(mesh.sharedVerticesInternal[inverseUniversal[n].a][0],
                                              mesh.sharedVerticesInternal[inverseUniversal[n].b][0]);
                    }

                    mesh.SetSelectedEdges(inverse);
                }

                break;
            }

            Refresh();
        }
        public static ProBuilderMesh DoMouseClick(Event evt, SelectMode selectionMode, ScenePickerPreferences pickerPreferences)
        {
            bool appendModifier         = EditorHandleUtility.IsAppendModifier(evt.modifiers);
            bool addToSelectionModifier = EditorHandleUtility.IsSelectionAddModifier(evt.modifiers);
            bool addOrRemoveIfPresentFromSelectionModifier = EditorHandleUtility.IsSelectionAppendOrRemoveIfPresentModifier(evt.modifiers);
            bool pathSelectionModifier = EditorHandleUtility.IsSelectionPathModifier(evt.modifiers);

            float pickedElementDistance;

            if (selectionMode.ContainsFlag(SelectMode.Edge | SelectMode.TextureEdge))
            {
                pickedElementDistance = EdgeRaycast(evt.mousePosition, pickerPreferences, k_AllowUnselected, s_Selection);
            }
            else if (selectionMode.ContainsFlag(SelectMode.Vertex | SelectMode.TextureVertex))
            {
                pickedElementDistance = VertexRaycast(evt.mousePosition, pickerPreferences, k_AllowUnselected, s_Selection);
            }
            else
            {
                pickedElementDistance = FaceRaycast(evt.mousePosition, pickerPreferences, k_AllowUnselected, s_Selection, evt.clickCount > 1 ? -1 : 0, false);
            }

            evt.Use();

            if (!appendModifier)
            {
                if (s_Selection.mesh != null)
                {
                    s_Selection.mesh.ClearSelection();
                }
                MeshSelection.SetSelection((GameObject)null);
            }

            if (pickedElementDistance > ScenePickerPreferences.maxPointerDistance)
            {
                if (appendModifier && Selection.gameObjects.Contains(s_Selection.gameObject))
                {
                    MeshSelection.RemoveFromSelection(s_Selection.gameObject);
                }
                else
                {
                    MeshSelection.AddToSelection(s_Selection.gameObject);
                }

                return(null);
            }

            GameObject candidateNewActiveObject     = s_Selection.gameObject;
            bool       activeObjectSelectionChanged = Selection.gameObjects.Contains(s_Selection.gameObject) && s_Selection.gameObject != Selection.activeGameObject;

            if (s_Selection.mesh != null)
            {
                var mesh = s_Selection.mesh;

                foreach (var face in s_Selection.faces)
                {
                    // Check for other editor mouse shortcuts first (todo proper event handling for mouse shortcuts)
                    MaterialEditor matEditor = MaterialEditor.instance;

                    if (matEditor != null && matEditor.ClickShortcutCheck(Event.current.modifiers, mesh, face))
                    {
                        return(null);
                    }

                    UVEditor uvEditor = UVEditor.instance;

                    if (uvEditor != null && uvEditor.ClickShortcutCheck(mesh, face))
                    {
                        return(null);
                    }

                    var faces = mesh.faces as Face[] ?? mesh.faces.ToArray();
                    var ind   = Array.IndexOf <Face>(faces, face);
                    var sel   = mesh.selectedFaceIndexes.IndexOf(ind);

                    UndoUtility.RecordSelection(mesh, "Select Face");

                    if (sel > -1)
                    {
                        if (!appendModifier || addOrRemoveIfPresentFromSelectionModifier ||
                            (addToSelectionModifier && face == mesh.GetActiveFace() && !activeObjectSelectionChanged))
                        {
                            mesh.RemoveFromFaceSelectionAtIndex(sel);

                            if (addOrRemoveIfPresentFromSelectionModifier && activeObjectSelectionChanged)
                            {
                                candidateNewActiveObject = Selection.activeGameObject;
                            }
                            else if (mesh.selectedFaceCount == 0)
                            {
                                for (var i = MeshSelection.topInternal.Count - 1; i >= 0; i--)
                                {
                                    if (MeshSelection.topInternal[i].selectedFaceCount > 0)
                                    {
                                        candidateNewActiveObject     = MeshSelection.topInternal[i].gameObject;
                                        activeObjectSelectionChanged = true;
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            mesh.selectedFaceIndicesInternal = mesh.selectedFaceIndicesInternal.Remove(ind);
                            mesh.SetSelectedFaces(mesh.selectedFaceIndicesInternal.Add(ind));
                        }
                    }
                    else if (pathSelectionModifier && mesh.GetActiveFace() != null)
                    {
                        var pathFaces = SelectPathFaces.GetPath(mesh, Array.IndexOf <Face>(faces, mesh.GetActiveFace()),
                                                                Array.IndexOf <Face>(faces, face));
                        foreach (var pathFace in pathFaces)
                        {
                            mesh.AddToFaceSelection(pathFace);
                        }
                    }
                    else
                    {
                        mesh.AddToFaceSelection(ind);
                    }
                }

                foreach (var edge in s_Selection.edges)
                {
                    int ind = mesh.IndexOf(mesh.selectedEdges, edge);

                    UndoUtility.RecordSelection(mesh, "Select Edge");

                    if (ind > -1)
                    {
                        if (!appendModifier || addOrRemoveIfPresentFromSelectionModifier ||
                            (addToSelectionModifier && edge == mesh.GetActiveEdge() && !activeObjectSelectionChanged))
                        {
                            mesh.SetSelectedEdges(mesh.selectedEdges.ToArray().RemoveAt(ind));

                            if (addOrRemoveIfPresentFromSelectionModifier && activeObjectSelectionChanged)
                            {
                                candidateNewActiveObject = Selection.activeGameObject;
                            }
                            else if (mesh.selectedEdgeCount == 0)
                            {
                                for (var i = MeshSelection.topInternal.Count - 1; i >= 0; i--)
                                {
                                    if (MeshSelection.topInternal[i].selectedEdgeCount > 0)
                                    {
                                        candidateNewActiveObject     = MeshSelection.topInternal[i].gameObject;
                                        activeObjectSelectionChanged = true;
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            mesh.selectedEdgesInternal = mesh.selectedEdgesInternal.Remove(edge);
                            mesh.SetSelectedEdges(mesh.selectedEdgesInternal.Add(edge));
                        }
                    }
                    else
                    {
                        mesh.SetSelectedEdges(mesh.selectedEdges.ToArray().Add(edge));
                    }
                }
                foreach (var vertex in s_Selection.vertexes)
                {
                    int ind = Array.IndexOf(mesh.selectedIndexesInternal, vertex);

                    UndoUtility.RecordSelection(mesh, "Select Vertex");

                    if (ind > -1)
                    {
                        var sharedIndex  = mesh.sharedVertexLookup[vertex];
                        var sharedVertex = mesh.sharedVerticesInternal[sharedIndex];
                        s_IndexBuffer.Clear();
                        foreach (var sVertex in sharedVertex)
                        {
                            var index = Array.IndexOf(mesh.selectedIndexesInternal, sVertex);
                            if (index < 0)
                            {
                                continue;
                            }

                            s_IndexBuffer.Add(index);
                        }
                        s_IndexBuffer.Sort();

                        if (!appendModifier || addOrRemoveIfPresentFromSelectionModifier ||
                            (addToSelectionModifier && vertex == mesh.GetActiveVertex() && !activeObjectSelectionChanged))
                        {
                            mesh.selectedIndexesInternal = mesh.selectedIndexesInternal.SortedRemoveAt(s_IndexBuffer);
                            mesh.SetSelectedVertices(mesh.selectedIndexesInternal);

                            if (addOrRemoveIfPresentFromSelectionModifier && activeObjectSelectionChanged)
                            {
                                candidateNewActiveObject = Selection.activeGameObject;
                            }
                            else if (mesh.selectedIndexesInternal.Length == 0)
                            {
                                for (var i = MeshSelection.topInternal.Count - 1; i >= 0; i--)
                                {
                                    if (MeshSelection.topInternal[i].selectedIndexesInternal.Length > 0)
                                    {
                                        candidateNewActiveObject     = MeshSelection.topInternal[i].gameObject;
                                        activeObjectSelectionChanged = true;
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            mesh.selectedIndexesInternal = mesh.selectedIndexesInternal.SortedRemoveAt(s_IndexBuffer);
                            mesh.SetSelectedVertices(mesh.selectedIndexesInternal.Add(vertex));
                        }
                    }
                    else
                    {
                        mesh.SetSelectedVertices(mesh.selectedIndexesInternal.Add(vertex));
                    }
                }

                if (activeObjectSelectionChanged)
                {
                    MeshSelection.MakeActiveObject(candidateNewActiveObject);
                }
                else
                {
                    MeshSelection.AddToSelection(candidateNewActiveObject);
                }

                return(mesh);
            }

            return(null);
        }
        public static bool OnGUI(ProBuilderMesh[] selection, float width)
        {
            UpdateDiffDictionary(selection);

            s_ScrollPosition = EditorGUILayout.BeginScrollView(s_ScrollPosition);
            float tempFloat = 0f;

            EditorGUI.BeginChangeCheck();

            /**
             * Set Tile mode
             */
            GUILayout.Label("Tiling & Alignment", EditorStyles.boldLabel);

            GUILayout.BeginHorizontal();
            EditorGUI.showMixedValue = s_AutoUVSettingsDiff["fill"];
            GUILayout.Label("Fill Mode", GUILayout.MaxWidth(80), GUILayout.MinWidth(80));
            EditorGUI.BeginChangeCheck();
            s_AutoUVSettings.fill = (AutoUnwrapSettings.Fill)EditorGUILayout.EnumPopup(s_AutoUVSettings.fill);
            if (EditorGUI.EndChangeCheck())
            {
                SetFill(s_AutoUVSettings.fill, selection);
            }
            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            bool enabled = GUI.enabled;

            GUI.enabled = !s_AutoUVSettings.useWorldSpace;
            EditorGUI.showMixedValue = s_AutoUVSettingsDiff["anchor"];
            EditorGUI.BeginChangeCheck();
            GUILayout.Label("Anchor", GUILayout.MaxWidth(80), GUILayout.MinWidth(80));
            s_AutoUVSettings.anchor = (AutoUnwrapSettings.Anchor)EditorGUILayout.EnumPopup(s_AutoUVSettings.anchor);
            if (EditorGUI.EndChangeCheck())
            {
                SetAnchor(s_AutoUVSettings.anchor, selection);
            }
            GUI.enabled = enabled;
            GUILayout.EndHorizontal();

            GUI.backgroundColor = PreferenceKeys.proBuilderLightGray;
            UI.EditorGUIUtility.DrawSeparator(1);
            GUI.backgroundColor = Color.white;

            GUILayout.Label("Transform", EditorStyles.boldLabel);

            /**
             * Offset
             */
            EditorGUI.showMixedValue = s_AutoUVSettingsDiff["offsetx"] || s_AutoUVSettingsDiff["offsety"];
            var tempVec2 = s_AutoUVSettings.offset;

            UnityEngine.GUI.SetNextControlName("offset");
            s_AutoUVSettings.offset = EditorGUILayout.Vector2Field("Offset", s_AutoUVSettings.offset, GUILayout.MaxWidth(width));
            if (tempVec2.x != s_AutoUVSettings.offset.x)
            {
                SetOffset(s_AutoUVSettings.offset, Axis2D.X, selection);
            }
            if (tempVec2.y != s_AutoUVSettings.offset.y)
            {
                SetOffset(s_AutoUVSettings.offset, Axis2D.Y, selection);
            }

            /**
             * Rotation
             */
            tempFloat = s_AutoUVSettings.rotation;
            EditorGUI.showMixedValue = s_AutoUVSettingsDiff["rotation"];
            GUILayout.Label(new GUIContent("Rotation", "Rotation around the center of face UV bounds."), GUILayout.MaxWidth(width - 64));
            UnityEngine.GUI.SetNextControlName("rotation");
            EditorGUI.BeginChangeCheck();
            tempFloat = EditorGUILayout.Slider(tempFloat, 0f, 360f, GUILayout.MaxWidth(width));
            if (EditorGUI.EndChangeCheck())
            {
                SetRotation(tempFloat, selection);
            }

            /**
             * Scale
             */
            EditorGUI.showMixedValue = s_AutoUVSettingsDiff["scalex"] || s_AutoUVSettingsDiff["scaley"];
            tempVec2 = s_AutoUVSettings.scale;
            GUI.SetNextControlName("scale");
            EditorGUI.BeginChangeCheck();
            s_AutoUVSettings.scale = EditorGUILayout.Vector2Field("Tiling", s_AutoUVSettings.scale, GUILayout.MaxWidth(width));

            if (EditorGUI.EndChangeCheck())
            {
                if (tempVec2.x != s_AutoUVSettings.scale.x)
                {
                    SetScale(s_AutoUVSettings.scale, Axis2D.X, selection);
                }
                if (tempVec2.y != s_AutoUVSettings.scale.y)
                {
                    SetScale(s_AutoUVSettings.scale, Axis2D.Y, selection);
                }
            }

            // Draw tiling shortcuts
            GUILayout.BeginHorizontal();
            if (GUILayout.Button(".5", EditorStyles.miniButtonLeft))
            {
                SetScale(Vector2.one * 2f, Axis2D.XY, selection);
            }
            if (GUILayout.Button("1", EditorStyles.miniButtonMid))
            {
                SetScale(Vector2.one, Axis2D.XY, selection);
            }
            if (GUILayout.Button("2", EditorStyles.miniButtonMid))
            {
                SetScale(Vector2.one * .5f, Axis2D.XY, selection);
            }
            if (GUILayout.Button("4", EditorStyles.miniButtonMid))
            {
                SetScale(Vector2.one * .25f, Axis2D.XY, selection);
            }
            if (GUILayout.Button("8", EditorStyles.miniButtonMid))
            {
                SetScale(Vector2.one * .125f, Axis2D.XY, selection);
            }
            if (GUILayout.Button("16", EditorStyles.miniButtonRight))
            {
                SetScale(Vector2.one * .0625f, Axis2D.XY, selection);
            }
            GUILayout.EndHorizontal();

            GUILayout.Space(4);

            UnityEngine.GUI.backgroundColor = PreferenceKeys.proBuilderLightGray;
            UI.EditorGUIUtility.DrawSeparator(1);
            UnityEngine.GUI.backgroundColor = Color.white;

            /**
             * Special
             */
            GUILayout.Label("Special", EditorStyles.boldLabel);

            EditorGUI.showMixedValue = s_AutoUVSettingsDiff["useWorldSpace"];
            EditorGUI.BeginChangeCheck();
            s_AutoUVSettings.useWorldSpace = EditorGUILayout.Toggle("World Space", s_AutoUVSettings.useWorldSpace);
            if (EditorGUI.EndChangeCheck())
            {
                SetUseWorldSpace(s_AutoUVSettings.useWorldSpace, selection);
            }

            GUI.backgroundColor = PreferenceKeys.proBuilderLightGray;
            UI.EditorGUIUtility.DrawSeparator(1);
            GUI.backgroundColor = Color.white;


            // Flip U
            EditorGUI.showMixedValue = s_AutoUVSettingsDiff["flipU"];
            EditorGUI.BeginChangeCheck();
            s_AutoUVSettings.flipU = EditorGUILayout.Toggle("Flip U", s_AutoUVSettings.flipU);
            if (EditorGUI.EndChangeCheck())
            {
                SetFlipU(s_AutoUVSettings.flipU, selection);
            }

            // Flip V
            EditorGUI.showMixedValue = s_AutoUVSettingsDiff["flipV"];
            EditorGUI.BeginChangeCheck();
            s_AutoUVSettings.flipV = EditorGUILayout.Toggle("Flip V", s_AutoUVSettings.flipV);
            if (EditorGUI.EndChangeCheck())
            {
                SetFlipV(s_AutoUVSettings.flipV, selection);
            }

            EditorGUI.showMixedValue = s_AutoUVSettingsDiff["swapUV"];
            EditorGUI.BeginChangeCheck();
            s_AutoUVSettings.swapUV = EditorGUILayout.Toggle("Swap U/V", s_AutoUVSettings.swapUV);
            if (EditorGUI.EndChangeCheck())
            {
                SetSwapUV(s_AutoUVSettings.swapUV, selection);
            }

            /**
             * Texture Groups
             */
            GUILayout.Label("Texture Groups", EditorStyles.boldLabel);

            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = s_AutoUVSettingsDiff["textureGroup"];

            GUI.SetNextControlName("textureGroup");
            textureGroup = UI.EditorGUIUtility.IntFieldConstrained(new GUIContent("Texture Group", "Faces in a texture group will be UV mapped as a group, just as though you had selected these faces and used the \"Planar Project\" action"), textureGroup, (int)width);

            if (EditorGUI.EndChangeCheck())
            {
                SetTextureGroup(selection, textureGroup);

                foreach (var kvp in MeshSelection.selectedFacesInEditZone)
                {
                    kvp.Key.RefreshUV(kvp.Value);
                }

                SceneView.RepaintAll();

                s_AutoUVSettingsDiff["textureGroup"] = false;
            }

            if (GUILayout.Button(new GUIContent("Group Selected Faces", "This sets all selected faces to share a texture group.  What that means is that the UVs on these faces will all be projected as though they are a single plane.  Ideal candidates for texture groups are floors with multiple faces, walls with edge loops, flat surfaces, etc.")))
            {
                for (int i = 0; i < selection.Length; i++)
                {
                    TextureGroupSelectedFaces(selection[i]);
                }

                ProBuilderEditor.Refresh();
            }

            if (GUILayout.Button(new GUIContent("Break Selected Groups", "This resets all the selected face Texture Groups.")))
            {
                SetTextureGroup(selection, -1);

                foreach (var kvp in MeshSelection.selectedFacesInEditZone)
                {
                    kvp.Key.ToMesh();
                    kvp.Key.Refresh();
                    kvp.Key.Optimize();
                }

                SceneView.RepaintAll();

                s_AutoUVSettingsDiff["textureGroup"] = false;

                ProBuilderEditor.Refresh();
            }

            /* Select all in current texture group */
            if (GUILayout.Button(new GUIContent("Select Texture Group", "Selects all faces contained in this texture group.")))
            {
                for (int i = 0; i < selection.Length; i++)
                {
                    selection[i].SetSelectedFaces(System.Array.FindAll(selection[i].facesInternal, x => x.textureGroup == textureGroup));
                }

                ProBuilderEditor.Refresh();
            }

            if (GUILayout.Button(new GUIContent("Reset UVs", "Reset UV projection parameters.")))
            {
                UndoUtility.RecordSelection(selection, "Reset UVs");

                for (int i = 0; i < selection.Length; i++)
                {
                    foreach (Face face in selection[i].GetSelectedFaces())
                    {
                        face.uv           = AutoUnwrapSettings.tile;
                        face.textureGroup = -1;
                        face.elementGroup = -1;
                    }

                    UVEditing.SplitUVs(selection[i], selection[i].GetSelectedFaces());
                }

                ProBuilderEditor.Refresh();
            }

            GUI.backgroundColor = PreferenceKeys.proBuilderLightGray;
            UI.EditorGUIUtility.DrawSeparator(1);
            GUI.backgroundColor = Color.white;

            /**
             * Clean up
             */
            GUILayout.EndScrollView();
            EditorGUI.showMixedValue = false;

            return(EditorGUI.EndChangeCheck());
        }
        internal static void OnObjectSelectionChanged()
        {
            // GameObjects returns both parent and child when both are selected, where transforms only returns the
            // top-most transform.
            s_UnitySelectionChangeMeshes.Clear();
            s_ElementSelection.Clear();
            s_ActiveMesh = null;

            var gameObjects = Selection.gameObjects;

            for (int i = 0, c = gameObjects.Length; i < c; i++)
            {
#if UNITY_2019_3_OR_NEWER
                ProBuilderMesh mesh;
                if (gameObjects[i].TryGetComponent <ProBuilderMesh>(out mesh))
#else
                var mesh = gameObjects[i].GetComponent <ProBuilderMesh>();
                if (mesh != null)
#endif
                {
                    if (gameObjects[i] == Selection.activeGameObject)
                    {
                        s_ActiveMesh = mesh;
                    }

                    s_UnitySelectionChangeMeshes.Add(mesh);
                }
            }

            for (int i = 0, c = s_TopSelection.Count; i < c; i++)
            {
                if (!s_UnitySelectionChangeMeshes.Contains(s_TopSelection[i]))
                {
                    if (s_TopSelection[i] != null)
                    {
                        UndoUtility.RecordSelection(s_TopSelection[i], "Selection Change");
                    }
                    s_TopSelection[i].ClearSelection();
                }
            }

            s_TopSelection.Clear();

            foreach (var mesh in s_UnitySelectionChangeMeshes)
            {
                // don't add prefabs or assets to the mesh selection
                if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(mesh.gameObject)))
                {
                    EditorUtility.SynchronizeWithMeshFilter(mesh);
                    s_TopSelection.Add(mesh);
                }
            }

            InvalidateCaches();

            if (objectSelectionChanged != null)
            {
                objectSelectionChanged();
            }

            s_UnitySelectionChangeMeshes.Clear();
        }