- Home /
 
 
               Question by 
               ProtoTerminator · Mar 20, 2017 at 11:07 AM · 
                scriptableobjecteditorwindowmeshesundo  
              
 
              Undo issues in EditorWindow
I'm working on a mesh deformation tool, and I've run into a problem where if I put in a check to not run code when it's not needed (line 147 of VertexDeformWindow), it breaks the Undo functionality. Can anyone help me figure out what's going on?
 public class VertexDeformWindow : EditorWindow
 {
     [MenuItem("Window/Vertex Deform")]
     public static void ShowWindow()
     {
         if (window != null)
         {
             return;
         }
         window = GetWindow<VertexDeformWindow>();
         window.selection = new Texture2D(32, 32, TextureFormat.ARGB32, false);
         var pixels = window.selection.GetPixels();
         for(int i = 0; i < pixels.Length; i++)
         {
             pixels[i] = new Color(0, 0, 0, 0.3f);
         }
         window.selection.SetPixels(pixels);
         window.selection.Apply();
         window.meshes = CreateInstance<MultiObjectVerts>() as MultiObjectVerts;
 
         window.meshes.softSize = EditorPrefs.GetFloat("softSize", window.meshes.softSize);
         window.meshes.showUnselected = EditorPrefs.GetBool("showUnselected", window.meshes.showUnselected);
         window.meshes.meshEditType = (EditType)EditorPrefs.GetInt("editType", (int)window.meshes.meshEditType);
         window.meshes.type = (FalloffType)EditorPrefs.GetInt("falloffType", (int)window.meshes.type);
 
         Undo.undoRedoPerformed -= UndoDetected;
         Undo.undoRedoPerformed += UndoDetected;
     }
 
     static bool active = true;
     static void UndoDetected()
     {
         /*if (active != meshes.active)
         {
             window.Active = meshes.active;
         }*/
         //meshes.UpdateStrengths();
         if (active)
         {
             window.meshes.UpdateSelectedVerts();
         }
     }
         
     bool Active
     {
         get
         {
             return meshes.active;
         }
         set
         {
             active = value;
             meshes.active = value;
             if (value)
             {
                 if (selection == null)
                 {
                     selection = new Texture2D(32, 32, TextureFormat.ARGB32, false);
                     var pixels = selection.GetPixels();
                     for (int i = 0; i < pixels.Length; i++)
                     {
                         pixels[i] = new Color(0, 0, 0, 0.3f);
                     }
                     selection.SetPixels(pixels);
                     selection.Apply();
                         
                 }
                 Tools.hidden = true;
                 meshes.GetMeshVerts();
             }
             else
             {
                 Tools.hidden = false;
                 meshes.ReleaseMeshVerts();
             }
         }
     }
     [SerializeField]
     MultiObjectVerts meshes;
     static VertexDeformWindow window;
 
     void OnDisable()
     {
         EditorPrefs.SetFloat("softSize", meshes.softSize);
         EditorPrefs.SetBool("showUnselected", meshes.showUnselected);
         EditorPrefs.SetInt("editType", (int) meshes.meshEditType);
         EditorPrefs.SetInt("falloffType", (int) meshes.type);
     }
 
     // Window has been selected
     void OnFocus()
     {
         // Remove delegate listener if it has previously
         // been assigned.
         SceneView.onSceneGUIDelegate -= OnSceneGUI;
         // Add (or re-add) the delegate.
         SceneView.onSceneGUIDelegate += OnSceneGUI;
     }
 
     void OnDestroy()
     {
         // When the window is destroyed, remove the delegate
         // so that it will no longer do any drawing.
         SceneView.onSceneGUIDelegate -= OnSceneGUI;
         Undo.undoRedoPerformed -= UndoDetected;
         Active = false;
     }
 
     Rect NormalizeRect(Vector2 start, Vector2 end)
     {
         Rect rect = new Rect(new Vector2(Mathf.Min(start.x, end.x), Mathf.Min(start.y, end.y)), new Vector2(Mathf.Abs(start.x - end.x), Mathf.Abs(start.y - end.y)));
         return rect;
     }
 
     Vector2 startPos;
     Vector2 endPos;
     Rect dragRect = Rect.zero;
     bool moved = false;
     // Draw gizmos here.
     void OnSceneGUI(SceneView sceneView)
     {
         if (window == null || meshes == null)
         {
             ShowWindow();
         }
         if (active)
         {
             meshes.DrawVerts(sceneView);
             if (meshes.SelectedVerts > 0)
             {
                 EditorGUI.BeginChangeCheck();
                 Vector3 pos = meshes.GetTransformGizmoPosition();
                 Vector3 relativePos = Handles.PositionHandle(pos, Quaternion.identity) - pos;
                 if (EditorGUI.EndChangeCheck())
                 {
                     Undo.RecordObject(meshes, "changed meshes");
                 }
                 if (GUIUtility.hotControl != 0)
                 {
                     moved = true;
                 }
                 else if (moved)
                 {
                     moved = false;
                     meshes.UpdateStrengths();
                 }
                 //if (relativePos != Vector3.zero) // If uncommented, this line causes the Undo to not work!
                 {
                     meshes.MoveSelectedVertices(relativePos);
                 }
             }
             Event current = Event.current;
             if (current.button == 0)
             {
                 Vector3 mousePosition = current.mousePosition;
                 int controlID = GUIUtility.GetControlID(FocusType.Passive);
                     
                 if (current.type == EventType.MouseDown)
                 {
                     startPos = mousePosition;
                     dragRect = Rect.zero;
                     GUIUtility.hotControl = controlID;
                     current.Use();
                 }
                 if (current.type == EventType.MouseDrag)
                 {
                     endPos = mousePosition;
                     dragRect = NormalizeRect(startPos, endPos);
                     current.Use();
                 }
                 if (current.type == EventType.MouseUp)
                 {
                     Undo.RecordObject(meshes, "changed meshes");
                     endPos = mousePosition;
                     if (endPos == startPos)
                     {
                         // normal click
                         if (current.control || current.shift)
                         {
                             meshes.AddToSelectedVerts(endPos);
                         }
                         else if (current.alt)
                         {
                             meshes.SubtractFromSelectedVerts(endPos);
                         }
                         else
                         {
                             meshes.SelectVerts(endPos);
                         }
                     }
                     else
                     {
                         // drag select
                         if (current.control || current.shift)
                         {
                             meshes.AddToSelectedVerts(dragRect, sceneView.camera);
                         }
                         else if (current.alt)
                         {
                             meshes.SubtractFromSelectedVerts(dragRect, sceneView.camera);
                         }
                         else
                         {
                             meshes.SelectVerts(dragRect, sceneView.camera);
                         }
                     }
                     dragRect = Rect.zero;
                     GUIUtility.hotControl = 0;
                     current.Use();
                 }
             }
             if (dragRect != Rect.zero)
             {
                 Handles.BeginGUI();
                 GUI.DrawTexture(dragRect, selection);
                 Handles.EndGUI();
             }
         }
         Undo.CollapseUndoOperations(Undo.GetCurrentGroup());
         Undo.FlushUndoRecordObjects();
     }
 
     Texture2D selection;
 
     void OnGUI()
     {
         if (window == null || meshes == null)
         {
             ShowWindow();
         }
         Undo.RecordObject(meshes, "changed gizmo size");
         GUILayout.Label("Vertex Deform", EditorStyles.boldLabel);
         if (!Active)
         {
             if (Selection.gameObjects.Length == 0)
             {
                 GUILayout.Label("No objects selected. Please select an object with a MeshFilter and Renderer in the scene");
                 return;
             }
 
             foreach (var obj in Selection.gameObjects)
             {
                 if (!obj.GetComponent<MeshFilter>() || !obj.GetComponent<Renderer>())// || PrefabUtility.GetPrefabType(obj) == PrefabType.Prefab)
                 {
                     GUILayout.Label("Improper object(s) selected. Please select an object with a MeshFilter and Renderer in the scene");
                     return;
                 }
             }
 
             if (GUILayout.Button("Activate"))
             {
                 Active = true;
             }
 
             meshes.meshEditType = (EditType) EditorGUILayout.EnumPopup("Mesh Edit Type", meshes.meshEditType);
         }
         else
         {
             if (GUILayout.Button("Deactivate"))
             {
                 Active = false;
             }
 
             meshes.showUnselected = EditorGUILayout.Toggle("Show Unselected Verts", meshes.showUnselected);
             meshes.softSize = EditorGUILayout.FloatField("Soft Size: ", meshes.softSize);
             if (meshes.softSize < 0)
             {
                 meshes.softSize = 0;
             }
             else if (meshes.softSize > 0)
             {
                 meshes.type = (FalloffType) EditorGUILayout.EnumPopup("Falloff Type", meshes.type);
             }
 
             if (GUI.changed)
             {
                 meshes.UpdateStrengths();
             }
         }
         Undo.CollapseUndoOperations(Undo.GetCurrentGroup());
         Undo.FlushUndoRecordObjects();
 
         if (GUI.changed)
         {
             SceneView.RepaintAll();
         }
     }
 
     private void OnInspectorUpdate()
     {
         Repaint();
     }
 }
 
               ...
 public enum FalloffType
 {
     Linear,
     Sine
 }
 public enum EditType
 {
     Original,
     Copy
 }
 public class MultiObjectVerts : ScriptableObject
 {
     public static int vertPixels; // how many pixels to draw vertex, more pixels on higher dpi screens
     public float softSize = 5;
     public bool showUnselected = true;
     public FalloffType type = FalloffType.Sine;
     public EditType meshEditType = EditType.Copy;
         
     public List<MeshFilter> meshes = new List<MeshFilter>();
     public List<Vector3[]> vertices = new List<Vector3[]>();
     List<VertIndices> selectedVerts = new List<VertIndices>();
     List<VertIndices> softSelectedVerts = new List<VertIndices>();
     List<VertIndices> unselectedVerts = new List<VertIndices>();
     public List<VertIndices> vertIndices = new List<VertIndices>();
     public bool active;
 
     Color vertColor = Color.blue;
 
     public void UpdateSelectedVerts()
     {
         selectedVerts.Clear();
         unselectedVerts.Clear();
         foreach(var vert in vertIndices)
         {
             if (vert.strength == 1)
             {
                 selectedVerts.Add(vert);
             }
             else if (vert.strength > 0)
             {
                 softSelectedVerts.Add(vert);
             }
             else
             {
                 unselectedVerts.Add(vert);
             }
         }
         UpdateStrengths();
     }
 
     public int SelectedVerts
     {
         get
         {
             return selectedVerts.Count;
         }
     }
 
     public void GetMeshVerts()
     {
         ReleaseMeshVerts();
 
         vertPixels = Mathf.RoundToInt(Screen.dpi / 25);
         if (vertPixels < 1)
         {
             vertPixels = 1;
         }
         HashSet<int> meshInstances = new HashSet<int>();
         int index = 0;
         int vertCounter = 0;
         foreach (var obj in Selection.gameObjects)
         {
             var filter = obj.GetComponent<MeshFilter>();
             if (meshEditType == EditType.Copy && (!filter.sharedMesh.name.Contains("(Clone)") || meshInstances.Contains(filter.sharedMesh.GetInstanceID())))
             {
                 filter.sharedMesh = Instantiate(filter.sharedMesh);
             }
             meshInstances.Add(filter.sharedMesh.GetInstanceID());
             meshes.Add(filter);
             var vertexes = filter.sharedMesh.vertices;
             vertices.Add(vertexes);
 
             for (int i = 0; i < vertexes.Length; i++)
             {
                 var vert = vertexes[i];
                 bool cnt = false;
                 // Check if the vertex is in the same position as another vertex in the same mesh.
                 for (int j = vertCounter; j < vertIndices.Count; j++)
                 {
                     var vi = vertIndices[j];
                     if (vi.position == vert)
                     {
                         cnt = true;
                         vi.indices.Add(i);
                         break;
                     }
                 }
                 if (!cnt)
                 {
                     VertIndices item = new VertIndices();
                     item.position = vert;
                     item.worldPosition = obj.transform.TransformPoint(vert);
                     item.indices.Add(i);
                     item.index = index;
                     vertIndices.Add(item);
                     unselectedVerts.Add(item);
                 }
             }
             index++;
             vertCounter += vertexes.Length;
         }
         UpdateRects(SceneView.lastActiveSceneView.camera);
     }
 
     public void ReleaseMeshVerts()
     {
         meshes.Clear();
         vertices.Clear();
         selectedVerts.Clear();
         unselectedVerts.Clear();
         vertIndices.Clear();
     }
 
     Vector3 cameraStart;
     Vector3 cameraPos;
     Vector3 camPos;
     Quaternion camRot;
     Vector2 camScreenSize;
 
     // Update where the verts are drawn on screen.
     void UpdateRects(Camera cam)
     {
         foreach (var vert in vertIndices)
         {
             Vector2 screenPos = cam.WorldToScreenPoint(vert.worldPosition);
             screenPos.y = cam.pixelHeight - screenPos.y;
             vert.screenPos = screenPos;
             vert.rect = new Rect(screenPos - Vector2.one * (vertPixels / 2), Vector2.one * vertPixels);
         }
     }
 
     // Draw vertices on screen.
     public void DrawVerts(SceneView sceneView)
     {
         Camera camera;
         camera = sceneView.camera;
         if (camera.transform.position != camPos || camera.transform.rotation != camRot || camScreenSize != new Vector2(camera.pixelWidth, camera.pixelHeight))
         {
             UpdateRects(camera);
         }
         camPos = camera.transform.position;
         camRot = camera.transform.rotation;
         camScreenSize = new Vector2(camera.pixelWidth, camera.pixelHeight);
 
         Handles.BeginGUI();
         foreach (var vert in vertIndices)
         {
             if (!showUnselected && vert.strength == 0)
             {
                 continue;
             }
             if (vert.strength == 0)
             {
                 vertColor = Color.black;
             }
             else if (vert.strength == 1)
             {
                 vertColor = Color.red;
             }
             else
             {
                 vertColor = Color.Lerp(Color.green, Color.blue, vert.strength);
             }
             EditorGUI.DrawRect(vert.rect, vertColor);
         }
         Handles.EndGUI();
     }
 
     // Get position of move handle while vertices are selected.
     public Vector3 GetTransformGizmoPosition()
     {
         Vector3 point = Vector3.zero;
         foreach(var vert in selectedVerts)
         {
             point += vert.worldPosition;
         }
         point /= selectedVerts.Count;
         return point;
     }
 
     // Remove selected vertices.
     public void RemoveAllSelectedVerts()
     {
         int counter = selectedVerts.Count - 1;
         while (counter >= 0)
         {
             unselectedVerts.Add(selectedVerts[counter]);
             selectedVerts[counter].strength = 0;
             selectedVerts.RemoveAt(counter);
             counter--;
         }
     }
 
     // Select a vertex by a single mouse click.
     public void SelectVerts(Vector2 mousePosition)
     {
         RemoveAllSelectedVerts();
         AddToSelectedVerts(mousePosition);
     }
 
     // Select a vertex by a single mouse click while holding shift or ctrl.
     public void AddToSelectedVerts(Vector2 mousePosition)
     {
         for (int i = 0; i < unselectedVerts.Count; i++)
         {
             var vert = unselectedVerts[i];
             if (vert.rect.Contains(mousePosition))
             {
                 selectedVerts.Add(vert);
                 unselectedVerts.Remove(vert);
                 i--;
                 vert.strength = 1;
                 break;
             }
         }
         for (int i = 0; i < softSelectedVerts.Count; i++)
         {
             var vert = softSelectedVerts[i];
             if (vert.rect.Contains(mousePosition))
             {
                 selectedVerts.Add(vert);
                 unselectedVerts.Remove(vert);
                 i--;
                 vert.strength = 1;
                 break;
             }
         }
         UpdateStrengths();
     }
 
     // Unselect a vertex by a single mouse click while holding alt.
     public void SubtractFromSelectedVerts(Vector2 mousePosition)
     {
         for (int i = 0; i < selectedVerts.Count; i++)
         {
             var vert = selectedVerts[i];
             if (vert.rect.Contains(mousePosition))
             {
                 unselectedVerts.Add(vert);
                 selectedVerts.Remove(vert);
                 i--;
                 vert.strength = 0;
                 break;
             }
         }
         UpdateStrengths();
     }
         
     // Select vertices by mouse drag.
     public void SelectVerts(Rect rect, Camera cam)
     {
         RemoveAllSelectedVerts();
         AddToSelectedVerts(rect, cam);
     }
 
     // Select vertices by mouse drag while holding shift or ctrl.
     public void AddToSelectedVerts(Rect rect, Camera cam)
     {
         for (int i = 0; i < unselectedVerts.Count; i++)
         {
             var vert = unselectedVerts[i];
             if (rect.Contains(vert.screenPos, true))
             {
                 selectedVerts.Add(vert);
                 unselectedVerts.Remove(vert);
                 vert.strength = 1;
                 i--;
             }
         }
         for (int i = 0; i < softSelectedVerts.Count; i++)
         {
             var vert = softSelectedVerts[i];
             if (rect.Contains(vert.screenPos, true))
             {
                 selectedVerts.Add(vert);
                 unselectedVerts.Remove(vert);
                 vert.strength = 1;
                 i--;
             }
         }
         UpdateStrengths();
     }
 
     // Unselect vertices by mouse drag while holding shift or ctrl.
     public void SubtractFromSelectedVerts(Rect rect, Camera cam)
     {
         for (int i = 0; i < selectedVerts.Count; i++)
         {
             var vert = selectedVerts[i];
             if (rect.Contains(vert.screenPos, true))
             {
                 selectedVerts.Remove(vert);
                 unselectedVerts.Add(vert);
                 vert.strength = 0;
                 i--;
             }
         }
         UpdateStrengths();
     }
 
     // Update the softness of each vertex.
     public void UpdateStrengths()
     {
         if (softSize <= 0)
         {
             return;
         }
         for(int i = 0; i < unselectedVerts.Count; i++)
         {
             var vert = unselectedVerts[i];
             vert.strength = 0;
             foreach (var selectedVert in selectedVerts)
             {
                 float distPercent = Vector3.Distance(vert.worldPosition, selectedVert.worldPosition) / softSize;
                 float newStrength = 1 - distPercent;
                 if (distPercent < 1 && vert.strength < newStrength)
                 {
                     if (type == FalloffType.Sine)
                     {
                         newStrength = (Mathf.Cos(Mathf.PI * (newStrength - 1)) + 1) / 2;
                     }
                     vert.strength = newStrength;
                 }
             }
             if (vert.strength > 0)
             {
                 softSelectedVerts.Add(vert);
                 unselectedVerts.RemoveAt(i);
                 i--;
             }
         }
         for (int i = 0; i < softSelectedVerts.Count; i++)
         {
             var vert = softSelectedVerts[i];
             vert.strength = 0;
             foreach (var selectedVert in selectedVerts)
             {
                 float distPercent = Vector3.Distance(vert.worldPosition, selectedVert.worldPosition) / softSize;
                 float newStrength = 1 - distPercent;
                 if (distPercent < 1 && vert.strength < newStrength)
                 {
                     if (type == FalloffType.Sine)
                     {
                         newStrength = (Mathf.Cos(Mathf.PI * (newStrength - 1)) + 1) / 2;
                     }
                     vert.strength = newStrength;
                 }
             }
             if (vert.strength == 0)
             {
                 unselectedVerts.Add(vert);
                 softSelectedVerts.RemoveAt(i);
                 i--;
             }
         }
     }
         
     // Move selected vertices by offset. Moves soft selected vertices by a fraction of the offset.
     public void MoveSelectedVertices(Vector3 offset)
     {
         /*if (offset == Vector3.zero)
         {
             return;
         }*/
         var fixedOffset = meshes[selectedVerts[0].index].transform.InverseTransformVector(offset);
         foreach (var vert in selectedVerts)
         {
             foreach (var ind in vert.indices)
             {
                 vert.position += fixedOffset * vert.strength;
                 vert.worldPosition += offset * vert.strength;
                 vertices[vert.index][ind] = vert.position;
             }
             Vector2 screenPos = SceneView.lastActiveSceneView.camera.WorldToScreenPoint(vert.worldPosition);
             screenPos.y = SceneView.lastActiveSceneView.camera.pixelHeight - screenPos.y;
             vert.screenPos = screenPos;
             vert.rect = new Rect(screenPos - Vector2.one * (vertPixels / 2), Vector2.one * vertPixels);
         }
         foreach (var vert in softSelectedVerts)
         {
             foreach (var ind in vert.indices)
             {
                 vert.position += fixedOffset * vert.strength;
                 vert.worldPosition += offset * vert.strength;
                 vertices[vert.index][ind] = vert.position;
             }
             Vector2 screenPos = SceneView.lastActiveSceneView.camera.WorldToScreenPoint(vert.worldPosition);
             screenPos.y = SceneView.lastActiveSceneView.camera.pixelHeight - screenPos.y;
             vert.screenPos = screenPos;
             vert.rect = new Rect(screenPos - Vector2.one * (vertPixels / 2), Vector2.one * vertPixels);
         }
         for (int i = 0; i < meshes.Count; i++)
         {
             meshes[i].sharedMesh.vertices = vertices[i];
         }
     }
 }
 
 // Hold vertex information.
 [System.Serializable]
 public class VertIndices
 {
     public Vector2 screenPos;
     public Rect rect;
     public float strength = 0;
     public float distanceToSelected;
     public Vector3 position;
     public Vector3 worldPosition;
     public int index;
     public List<int> indices = new List<int>();
 }
 
              
               Comment
              
 
               
              Your answer