using System.Collections.Generic; using UnityEngine; using System.Linq; using UnityEngine.ProBuilder; using UnityEngine.ProBuilder.MeshOperations; namespace UnityEditor.ProBuilder.Actions { sealed class DuplicateFaces : MenuAction { Pref m_DuplicateFaceSetting = new Pref("DuplicateFaces.target", DuplicateFaceSetting.GameObject); public override ToolbarGroup group { get { return ToolbarGroup.Geometry; } } public override Texture2D icon { get { return IconUtility.GetIcon("Toolbar/Face_Duplicate", IconSkin.Pro); } } //icon to be replaced public override TooltipContent tooltip { get { return s_Tooltip; } } static readonly TooltipContent s_Tooltip = new TooltipContent ( "Duplicate Faces", "Makes an exact copy of the selected faces, and either adds them to this mesh or creates a new Game Object" ); public override SelectMode validSelectModes { get { return SelectMode.Face; } } public override bool enabled { get { return base.enabled && MeshSelection.selectedFaceCount > 0; } } protected override MenuActionState optionsMenuState { get { return MenuActionState.VisibleAndEnabled; } } internal enum DuplicateFaceSetting { GameObject, Submesh }; protected override void OnSettingsGUI() { GUILayout.Label("Duplicate Face Settings", EditorStyles.boldLabel); EditorGUILayout.HelpBox("You can create a new Game Object with the selected face(s), or keep them as part of this object by using a Submesh.", MessageType.Info); EditorGUI.BeginChangeCheck(); m_DuplicateFaceSetting.value = (DuplicateFaceSetting)EditorGUILayout.EnumPopup("Duplicate To", m_DuplicateFaceSetting); if (EditorGUI.EndChangeCheck()) ProBuilderSettings.Save(); GUILayout.FlexibleSpace(); if (GUILayout.Button("Duplicate Selection")) EditorUtility.ShowNotification(PerformAction().notification); } protected override ActionResult PerformActionImplementation() { if (MeshSelection.selectedObjectCount < 1) return ActionResult.NoSelection; UndoUtility.RecordSelection("Duplicate Face(s)"); if (m_DuplicateFaceSetting == DuplicateFaceSetting.GameObject) return DuplicateFacesToObject(); return DuplicateFacesToSubmesh(); } static ActionResult DuplicateFacesToSubmesh() { int count = 0; foreach (ProBuilderMesh pb in MeshSelection.topInternal) { pb.ToMesh(); List res = pb.DetachFaces(pb.selectedFacesInternal, false); pb.Refresh(); pb.Optimize(); pb.SetSelectedFaces(res.ToArray()); count += pb.selectedFaceCount; } ProBuilderEditor.Refresh(); if (count > 0) return new ActionResult(ActionResult.Status.Success, "Duplicate " + count + (count > 1 ? " Faces" : " Face")); return new ActionResult(ActionResult.Status.Success, "Duplicate Faces"); } static ActionResult DuplicateFacesToObject() { int duplicatedFaceCount = 0; List duplicated = new List(); foreach (ProBuilderMesh mesh in MeshSelection.topInternal) { if (mesh.selectedFaceCount < 1) continue; var primary = mesh.selectedFaceIndexes; duplicatedFaceCount += primary.Count; List inverse = new List(); for (int i = 0; i < mesh.facesInternal.Length; i++) if (!primary.Contains(i)) inverse.Add(i); ProBuilderMesh copy = Object.Instantiate(mesh.gameObject, mesh.transform.parent).GetComponent(); EditorUtility.SynchronizeWithMeshFilter(copy); if (copy.transform.childCount > 0) { for (int i = copy.transform.childCount - 1; i > -1; i--) Object.DestroyImmediate(copy.transform.GetChild(i).gameObject); foreach (var child in mesh.transform.GetComponentsInChildren()) EditorUtility.SynchronizeWithMeshFilter(child); } Undo.RegisterCreatedObjectUndo(copy.gameObject, "Duplicate Selection"); copy.DeleteFaces(inverse); copy.Rebuild(); copy.Optimize(); mesh.ClearSelection(); copy.ClearSelection(); copy.SetSelectedFaces(copy.faces); copy.gameObject.name = GameObjectUtility.GetUniqueNameForSibling(mesh.transform.parent, mesh.gameObject.name); duplicated.Add(copy.gameObject); } MeshSelection.SetSelection(duplicated); ProBuilderEditor.Refresh(); if (duplicatedFaceCount > 0) return new ActionResult(ActionResult.Status.Success, "Duplicate " + duplicatedFaceCount + " faces to new Object"); return new ActionResult(ActionResult.Status.Failure, "No Faces Selected"); } } }