using System.Collections.Generic; using System.Linq; using System; using System.Collections.ObjectModel; namespace UnityEngine.ProBuilder { public sealed partial class ProBuilderMesh { [SerializeField] bool m_IsSelectable = true; // Serialized for undo in the editor [SerializeField] int[] m_SelectedFaces = new int[] {}; [SerializeField] Edge[] m_SelectedEdges = new Edge[] {}; [SerializeField] int[] m_SelectedVertices = new int[] {}; bool m_SelectedCacheDirty; int m_SelectedSharedVerticesCount = 0; int m_SelectedCoincidentVertexCount = 0; HashSet m_SelectedSharedVertices = new HashSet(); List m_SelectedCoincidentVertices = new List(); /// /// Gets or sets whether elements can be selected. /// Used by . /// /// False if mesh elements are not selectable. public bool selectable { get { return m_IsSelectable; } set { m_IsSelectable = value; } } /// /// Gets the number of faces that are currently selected on this object. /// /// Number of selected faces. public int selectedFaceCount { get { return m_SelectedFaces.Length; } } /// /// Gets the number of selected vertex indices. /// /// Number of selected vertices. public int selectedVertexCount { get { return m_SelectedVertices.Length; } } /// /// Gets the number of selected edges. /// /// Number of selected edges. public int selectedEdgeCount { get { return m_SelectedEdges.Length; } } internal int selectedSharedVerticesCount { get { CacheSelection(); return m_SelectedSharedVerticesCount; } } internal int selectedCoincidentVertexCount { get { CacheSelection(); return m_SelectedCoincidentVertexCount; } } internal IEnumerable selectedSharedVertices { get { CacheSelection(); return m_SelectedSharedVertices; } } /// /// Gets all selected vertices and their coincident neighbors. /// internal IEnumerable selectedCoincidentVertices { get { CacheSelection(); return m_SelectedCoincidentVertices; } } void CacheSelection() { if (m_SelectedCacheDirty) { m_SelectedCacheDirty = false; m_SelectedSharedVertices.Clear(); m_SelectedCoincidentVertices.Clear(); var lookup = sharedVertexLookup; m_SelectedSharedVerticesCount = 0; m_SelectedCoincidentVertexCount = 0; try { foreach (var i in m_SelectedVertices) { if (m_SelectedSharedVertices.Add(lookup[i])) { var coincident = sharedVerticesInternal[lookup[i]]; m_SelectedSharedVerticesCount++; m_SelectedCoincidentVertexCount += coincident.Count; m_SelectedCoincidentVertices.AddRange(coincident); } } } catch { ClearSelection(); } } } /// /// Returns a copy of the array of selected faces. /// /// Array of currently selected faces. public Face[] GetSelectedFaces() { int len = m_SelectedFaces.Length; var selected = new Face[len]; for (var i = 0; i < len; i++) selected[i] = m_Faces[m_SelectedFaces[i]]; return selected; } /// /// Gets a collection of the currently selected faces by their index in the array. /// /// Array of indices representing the currently selected faces. public ReadOnlyCollection selectedFaceIndexes { get { return new ReadOnlyCollection(m_SelectedFaces); } } /// /// Gets a collection of the currently selected vertices by their index in the array. /// /// Array of indices representing the currently selected vertices. public ReadOnlyCollection selectedVertices { get { return new ReadOnlyCollection(m_SelectedVertices); } } /// /// Gets a collection of the currently selected edges. /// /// Collection of objects representing the currently selected edges. public ReadOnlyCollection selectedEdges { get { return new ReadOnlyCollection(m_SelectedEdges); } } internal Face[] selectedFacesInternal { get { return GetSelectedFaces(); } set { m_SelectedFaces = value.Select(x => Array.IndexOf(m_Faces, x)).ToArray(); } } internal int[] selectedFaceIndicesInternal { get { return m_SelectedFaces; } set { m_SelectedFaces = value; } } internal Edge[] selectedEdgesInternal { get { return m_SelectedEdges; } set { m_SelectedEdges = value; } } internal int[] selectedIndexesInternal { get { return m_SelectedVertices; } set { m_SelectedVertices = value; } } internal Face GetActiveFace() { if (selectedFaceCount < 1) return null; return m_Faces[selectedFaceIndicesInternal[selectedFaceCount - 1]]; } internal Edge GetActiveEdge() { if (selectedEdgeCount < 1) return Edge.Empty; return m_SelectedEdges[selectedEdgeCount - 1]; } internal int GetActiveVertex() { if (selectedVertexCount < 1) return -1; return m_SelectedVertices[selectedVertexCount - 1]; } internal void AddToFaceSelection(int index) { if (index > -1) SetSelectedFaces(m_SelectedFaces.Add(index)); } /// /// Sets the face selection for this mesh. Also sets the vertex and edge selection to match. /// /// A set of faces to select. public void SetSelectedFaces(IEnumerable selected) { SetSelectedFaces(selected != null ? selected.Select(x => Array.IndexOf(facesInternal, x)) : null); } internal void SetSelectedFaces(IEnumerable selected) { if (selected == null) { ClearSelection(); } else { m_SelectedFaces = selected.ToArray(); m_SelectedVertices = m_SelectedFaces.SelectMany(x => facesInternal[x].distinctIndexesInternal).ToArray(); m_SelectedEdges = m_SelectedFaces.SelectMany(x => facesInternal[x].edges).ToArray(); } m_SelectedCacheDirty = true; if (elementSelectionChanged != null) elementSelectionChanged(this); } /// /// Sets the edge selection for this mesh. Also sets the vertex selection to match and clears the selected faces. /// /// A set of edges to select. public void SetSelectedEdges(IEnumerable edges) { if (edges == null) { ClearSelection(); } else { m_SelectedFaces = new int[0]; m_SelectedEdges = edges.ToArray(); m_SelectedVertices = m_SelectedEdges.AllTriangles(); } m_SelectedCacheDirty = true; if (elementSelectionChanged != null) elementSelectionChanged(this); } /// /// Sets the selected vertices array. Clears the selected faces and selected edges arrays. /// /// The new vertices to select. public void SetSelectedVertices(IEnumerable vertices) { m_SelectedFaces = new int[0]; m_SelectedEdges = new Edge[0]; m_SelectedVertices = vertices != null ? vertices.Distinct().ToArray() : new int[0]; m_SelectedCacheDirty = true; if (elementSelectionChanged != null) elementSelectionChanged(this); } /// /// Removes the specified face from the selection. Also updates the SelectedTriangles and SelectedEdges arrays to match. /// /// The index from the selected faces array that corresponds to the face to remove from the selection. internal void RemoveFromFaceSelectionAtIndex(int index) { SetSelectedFaces(m_SelectedFaces.RemoveAt(index)); } /// /// Clears the arrays of selected faces, edges, and vertices. You don't need to call this when setting /// an individual array, as the setter methods handle updating the associated caches. /// public void ClearSelection() { m_SelectedFaces = new int[0]; m_SelectedEdges = new Edge[0]; m_SelectedVertices = new int[0]; m_SelectedCacheDirty = true; } } }