private void ResetBounds()
 {
     // Reset the bounds to a 2,2,2 cube
     Undo.RecordObjects(targets, "Reset Bounds");
     PrimitiveBrush[] brushes = BrushTargets.Cast <PrimitiveBrush>().ToArray();
     foreach (PrimitiveBrush brush in brushes)
     {
         BrushUtility.Resize(brush, new Vector3(2, 2, 2));
     }
 }
        /// <summary>
        /// Rotates the selected brushes so that their transform.up matches the specified axis
        /// </summary>
        /// <param name="newUpAxis">Axis to match transform.up to</param>
        /// <param name="counterAlignment">If specified, when the brush is rotated the vertices will be counter rotated so they remain in their old positions and orientations</param>
        void AlignUpToAxis(Vector3 newUpAxis, bool counterAlignment)
        {
            PrimitiveBrush[] brushes = BrushTargets.Cast <PrimitiveBrush>().ToArray();
            foreach (PrimitiveBrush brush in brushes)
            {
                Vector3 perpendicularDirection = Vector3.up;
                if (Mathf.Abs(Vector3.Dot(perpendicularDirection, newUpAxis)) > 0.9f)
                {
                    perpendicularDirection = Vector3.back;
                }

                // Calculate the new rotation for the brush so that it's new transform.up is at the axis. Note the parameter order
                Quaternion rotation        = Quaternion.LookRotation(-perpendicularDirection, newUpAxis);
                Quaternion inverseRotation = Quaternion.Inverse(rotation * Quaternion.Inverse(brush.transform.localRotation));

                //Debug.Log("Rotating from " + brush.transform.up + " to " + axis + ". Produces " + rotation.eulerAngles);

                // Apply the rotation
                brush.transform.localRotation = rotation;

                // If they want to realign the brush but keep original world positions
                if (counterAlignment)
                {
                    Polygon[] polygons = brush.GetPolygons();

                    for (int polygonIndex = 0; polygonIndex < polygons.Length; polygonIndex++)
                    {
                        Vertex[] vertices = polygons[polygonIndex].Vertices;

                        // Rotate positions and vertices so they remain in their original place
                        for (int vertexIndex = 0; vertexIndex < vertices.Length; vertexIndex++)
                        {
                            vertices[vertexIndex].Position = inverseRotation * vertices[vertexIndex].Position;
                            vertices[vertexIndex].Normal   = inverseRotation * vertices[vertexIndex].Normal;
                        }
                    }

                    // Polygon vertices have changed, so recalculate the planes
                    for (int polygonIndex = 0; polygonIndex < polygons.Length; polygonIndex++)
                    {
                        polygons[polygonIndex].CalculatePlane();
                    }
                }
            }
        }
        private void ResetPolygonsKeepScale()
        {
            PrimitiveBrush[] brushes = BrushTargets.Cast <PrimitiveBrush>().ToArray();
            foreach (PrimitiveBrush brush in brushes)
            {
                Bounds localBounds = brush.GetBounds();
                brush.ResetPolygons();

                if (localBounds.size != new Vector3(2, 2, 2))
                {
                    BrushUtility.Resize(brush, localBounds.size);
                }
                else
                {
                    brush.Invalidate(true);
                }
            }
        }
        private void ChangeBrushesToType(PrimitiveBrushType newType)
        {
            Undo.RecordObjects(targets, "Change Brush Type");
            PrimitiveBrush[] brushes = BrushTargets.Cast <PrimitiveBrush>().ToArray();
            foreach (PrimitiveBrush brush in brushes)
            {
                Bounds localBounds = brush.GetBounds();
                brush.BrushType = newType;
                brush.ResetPolygons();

                if (localBounds.size != new Vector3(2, 2, 2))
                {
                    BrushUtility.Resize(brush, localBounds.size);
                }
                else
                {
                    brush.Invalidate(true);
                }
            }
        }
        public override void OnInspectorGUI()
        {
            float drawableWidth = EditorGUIUtility.currentViewWidth;

            drawableWidth -= 42;             // Take some off for scroll bars and padding

            PrimitiveBrushType[] selectedTypes = BrushTargets.Select(item => ((PrimitiveBrush)item).BrushType).ToArray();

            PrimitiveBrushType?activeType = (selectedTypes.Length == 1) ? (PrimitiveBrushType?)selectedTypes[0] : null;

            using (new NamedVerticalScope("Type"))
            {
                GUILayout.BeginHorizontal();

                float areaWidth          = drawableWidth - 18;
                int   buttonWidth        = Mathf.RoundToInt(areaWidth / 5f);
                int   stretchButtonWidth = Mathf.RoundToInt(areaWidth - buttonWidth * 4); // To ensure a justified alignment one button must be stretched slightly
                int   buttonHeight       = 50;

                GUIStyle brushButtonStyle = new GUIStyle(GUI.skin.button);
                brushButtonStyle.imagePosition = ImagePosition.ImageAbove;
                brushButtonStyle.fontSize      = 10;

                GUIStyle labelStyle = new GUIStyle(GUI.skin.label);
                labelStyle.alignment = TextAnchor.LowerCenter;
                labelStyle.fontSize  = brushButtonStyle.fontSize;

                bool shortMode = (areaWidth < 260); // Whether certain words need to be abbreviated to fit in the box

                DrawBrushButton(PrimitiveBrushType.Cube, activeType, brushButtonStyle, labelStyle, buttonWidth, buttonHeight, shortMode);
                DrawBrushButton(PrimitiveBrushType.Prism, activeType, brushButtonStyle, labelStyle, buttonWidth, buttonHeight, shortMode);
                DrawBrushButton(PrimitiveBrushType.Cylinder, activeType, brushButtonStyle, labelStyle, stretchButtonWidth, buttonHeight, shortMode);
                DrawBrushButton(PrimitiveBrushType.Sphere, activeType, brushButtonStyle, labelStyle, buttonWidth, buttonHeight, shortMode);
                DrawBrushButton(PrimitiveBrushType.IcoSphere, activeType, brushButtonStyle, labelStyle, buttonWidth, buttonHeight, shortMode);

                GUILayout.EndHorizontal();
                GUILayout.BeginHorizontal();

                DrawBrushButton(PrimitiveBrushType.Cone, activeType, brushButtonStyle, labelStyle, buttonWidth, buttonHeight, shortMode);

                GUI.enabled = true; // Reset GUI enabled so that the next items aren't disabled
                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();

                if (activeType.HasValue)
                {
                    GUILayout.Label("Active: " + selectedTypes[0]);
                }
                else
                {
                    GUILayout.Label("Active: Mixed");
                }

                if (activeType.HasValue)
                {
                    EditorGUIUtility.labelWidth = 60;
                    EditorGUIUtility.fieldWidth = 50;
                    EditorGUI.BeginChangeCheck();
                    if (activeType.Value == PrimitiveBrushType.Prism)
                    {
                        EditorGUILayout.PropertyField(prismSideCountProp, new GUIContent("Sides"));
                    }
                    else if (activeType.Value == PrimitiveBrushType.Cylinder)
                    {
                        EditorGUILayout.PropertyField(cylinderSideCountProp, new GUIContent("Sides"));
                    }
                    else if (activeType.Value == PrimitiveBrushType.Sphere)
                    {
                        EditorGUILayout.PropertyField(sphereSideCountProp, new GUIContent("Sides"));
                    }
                    else if (activeType.Value == PrimitiveBrushType.IcoSphere)
                    {
                        EditorGUILayout.PropertyField(icoSphereIterationCountProp, new GUIContent("Iterations"));
                    }
                    else if (activeType.Value == PrimitiveBrushType.Cone)
                    {
                        EditorGUILayout.PropertyField(coneSideCountProp, new GUIContent("Sides"));
                    }
                    if (EditorGUI.EndChangeCheck())
                    {
                        // One of the properties has changed
                        serializedObject.ApplyModifiedProperties();
                        ResetPolygonsKeepScale();
                    }
                }

                GUILayout.EndHorizontal();
            }

            using (new NamedVerticalScope("Size"))
            {
                if (GUILayout.Button(new GUIContent("Reset Bounds", "Resets the bounds of the brush to [2,2,2]")))
                {
                    ResetBounds();
                }

                GUILayout.BeginHorizontal();

                GUI.SetNextControlName("rescaleTextbox");

                scaleString = EditorGUILayout.TextField(scaleString);

                bool keyboardEnter = Event.current.isKey &&
                                     Event.current.keyCode == KeyCode.Return &&
                                     Event.current.type == EventType.KeyUp &&
                                     GUI.GetNameOfFocusedControl() == "rescaleTextbox";

                if (GUILayout.Button("Scale", GUILayout.MaxWidth(drawableWidth / 3f)) || keyboardEnter)
                {
                    // Try to parse a Vector3 scale from the input string
                    Vector3 scaleVector3;
                    if (StringHelper.TryParseScale(scaleString, out scaleVector3))
                    {
                        // None of the scale components can be zero
                        if (scaleVector3.x != 0 && scaleVector3.y != 0 && scaleVector3.z != 0)
                        {
                            // Rescale all the brushes
                            Undo.RecordObjects(targets, "Scale Polygons");
                            foreach (var thisBrush in targets)
                            {
                                BrushUtility.Scale((PrimitiveBrush)thisBrush, scaleVector3);
                            }
                        }
                    }
                }

                GUILayout.EndHorizontal();

                GUILayout.BeginHorizontal();

                GUI.SetNextControlName("resizeTextbox");

                resizeString = EditorGUILayout.TextField(resizeString);

                keyboardEnter = Event.current.isKey &&
                                Event.current.keyCode == KeyCode.Return &&
                                Event.current.type == EventType.KeyUp &&
                                GUI.GetNameOfFocusedControl() == "resizeTextbox";

                if (GUILayout.Button("Resize", GUILayout.MaxWidth(drawableWidth / 3f)) || keyboardEnter)
                {
                    // Try to parse a Vector3 scale from the input string
                    Vector3 resizeVector3;
                    if (StringHelper.TryParseScale(resizeString, out resizeVector3))
                    {
                        // None of the size components can be zero
                        if (resizeVector3.x != 0 && resizeVector3.y != 0 && resizeVector3.z != 0)
                        {
                            // Rescale all the brushes so that the local bounds is the same size as the resize vector
                            Undo.RecordObjects(targets, "Resize Polygons");
                            PrimitiveBrush[] brushes = BrushTargets.Cast <PrimitiveBrush>().ToArray();
                            foreach (PrimitiveBrush brush in brushes)
                            {
                                BrushUtility.Resize(brush, resizeVector3);
                            }
                        }
                    }
                }

                GUILayout.EndHorizontal();
            }

            using (new NamedVerticalScope("Rotation"))
            {
                GUILayout.Label("Align up direction", EditorStyles.boldLabel);
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("X"))
                {
                    AlignUpToAxis(new Vector3(1, 0, 0), false);
                }
                if (GUILayout.Button("Y"))
                {
                    AlignUpToAxis(new Vector3(0, 1, 0), false);
                }
                if (GUILayout.Button("Z"))
                {
                    AlignUpToAxis(new Vector3(0, 0, 1), false);
                }
                GUILayout.EndHorizontal();

                GUILayout.Label("Align up direction (keep positions)", EditorStyles.boldLabel);

                GUILayout.BeginHorizontal();
                if (GUILayout.Button("X"))
                {
                    AlignUpToAxis(new Vector3(1, 0, 0), true);
                }
                if (GUILayout.Button("Y"))
                {
                    AlignUpToAxis(new Vector3(0, 1, 0), true);
                }
                if (GUILayout.Button("Z"))
                {
                    AlignUpToAxis(new Vector3(0, 0, 1), true);
                }
                GUILayout.EndHorizontal();
            }

            using (new NamedVerticalScope("Misc"))
            {
                // Import Row
                GUILayout.BeginHorizontal();
                sourceMesh = EditorGUILayout.ObjectField(sourceMesh, typeof(Mesh), false) as Mesh;

                if (GUILayout.Button("Import", GUILayout.MaxWidth(drawableWidth / 3f)))
                {
                    if (sourceMesh != null)
                    {
                        Undo.RecordObjects(targets, "Import Polygons From Mesh");

                        Polygon[] polygons = BrushFactory.GeneratePolygonsFromMesh(sourceMesh).ToArray();
                        bool      convex   = GeometryHelper.IsBrushConvex(polygons);
                        if (!convex)
                        {
                            Debug.LogError("Concavities detected in imported mesh. This may result in issues during CSG, please change the source geometry so that it is convex");
                        }
                        foreach (var thisBrush in targets)
                        {
                            ((PrimitiveBrush)thisBrush).SetPolygons(polygons, true);
                        }
                    }
                }

                GUILayout.EndHorizontal();

                // Shell Row
                GUILayout.BeginHorizontal();

                if (shellDistance == 0)
                {
                    shellDistance = CurrentSettings.PositionSnapDistance;
                }

                shellDistance = EditorGUILayout.FloatField("Distance", shellDistance);

                if (GUILayout.Button("Shell", GUILayout.MaxWidth(drawableWidth / 3f)))
                {
                    List <GameObject> newSelection = new List <GameObject>();
                    foreach (var thisBrush in targets)
                    {
                        GameObject newObject = ((PrimitiveBrush)thisBrush).Duplicate();
                        Polygon[]  polygons  = newObject.GetComponent <PrimitiveBrush>().GetPolygons();
                        VertexUtility.DisplacePolygons(polygons, -shellDistance);
                        Bounds newBounds = newObject.GetComponent <PrimitiveBrush>().GetBounds();
                        // Verify the new geometry
                        if (GeometryHelper.IsBrushConvex(polygons) &&
                            newBounds.GetSmallestExtent() > 0)
                        {
                            Undo.RegisterCreatedObjectUndo(newObject, "Shell");
                            newSelection.Add(newObject);
                        }
                        else
                        {
                            // Produced a concave brush, delete it and pretend nothing happened
                            GameObject.DestroyImmediate(newObject);
                            Debug.LogWarning("Could not shell " + thisBrush.name + " as shelled geometry would not be valid. Try lowering the shell distance and attempt Shell again.");
                        }
                    }

                    if (newSelection.Count > 0)
                    {
                        Selection.objects = newSelection.ToArray();
                    }
                }

                GUILayout.EndHorizontal();

                // Split Intersecting Row
                if (GUILayout.Button("Split Intersecting Brushes"))
                {
                    // Chop up the intersecting brushes by the brush planes, ideally into as few new brushes as possible

                    PrimitiveBrush[] brushes = BrushTargets.Cast <PrimitiveBrush>().ToArray();

                    BrushUtility.SplitIntersecting(brushes);
                }


                //			BrushOrder brushOrder = BrushTarget.GetBrushOrder();
                //			string positionString = string.Join(",", brushOrder.Position.Select(item => item.ToString()).ToArray());
                //            GUILayout.Label(positionString, EditorStyles.boldLabel);

                //List<BrushCache> intersections = ((PrimitiveBrush)BrushTarget).BrushCache.IntersectingVisualBrushCaches;
                //GUILayout.Label("Intersecting brushes " + intersections.Count, EditorStyles.boldLabel);

                //for (int i = 0; i < intersections.Count; i++)
                //{
                //    GUILayout.Label(intersections[i].Mode.ToString(), EditorStyles.boldLabel);
                //}
            }

            base.OnInspectorGUI();
        }
        public sealed override void OnInspectorGUI()
        {
            // group editing:
            if (ShowGroupInspector)
            {
                using (new NamedVerticalScope("Group"))
                {
                    GUILayout.BeginHorizontal();

                    // find whether we are currently inside of a group:
                    GroupBrush group = null;
                    if (BrushTarget.transform.parent)
                    {
                        group = BrushTarget.transform.parent.GetComponent <GroupBrush>();
                    }

                    // we are in a group:
                    if (group != null)
                    {
                        if (GUILayout.Button("Select Group"))
                        {
                            // select the group.
                            Selection.objects = new Object[] { BrushTarget.transform.parent.gameObject };
                        }
                    }

                    if (GUILayout.Button("Create Group"))
                    {
                        // create a group.
                        TransformHelper.GroupSelection();
                    }

                    GUILayout.EndHorizontal();
                }
            }

            // volume editing:
            if (BrushTargets.Any(b => b.Mode == CSGMode.Volume))
            {
                using (new NamedVerticalScope("Volume"))
                {
                    // find all of the volume types in the project:
                    List <System.Type> volumeTypes = Volume.FindAllInAssembly();
                    if (volumeTypes.Count == 0)
                    {
                        EditorGUILayout.LabelField("No volume types could be found!");
                    }
                    else
                    {
                        // find all of the volume brushes that are currently selected.
                        BrushBase[] volumeBrushes = BrushTargets.Where(b => b.Mode == CSGMode.Volume).ToArray();
                        BrushBase   volumeTarget  = volumeBrushes.Contains(BrushTarget) ? BrushTarget : volumeBrushes.Last();

                        // make sure all volume brushes are of the same type (for multi-editing).
                        object brushTargetVolumeType = volumeTarget.Volume ? volumeTarget.Volume.GetType() : null;
                        if (volumeBrushes.Length > 1 && !volumeBrushes.All(b => b.Volume.GetType() == brushTargetVolumeType))
                        {
                            EditorGUILayout.LabelField("Cannot multi-edit volumes of different types!");
                        }
                        else
                        {
                            // let the user pick a volume type:
                            int selected = 0;
                            if (volumeTarget.Volume != null)
                            {
                                for (int i = 0; i < volumeTypes.Count; i++)
                                {
                                    selected = i;
                                    if (volumeTarget.Volume.GetType() == volumeTypes[i])
                                    {
                                        break;
                                    }
                                }
                            }
                            selected = EditorGUILayout.Popup("Volume Type", selected, volumeTypes.Select(v => v.Name + " (" + v.Namespace + ")").ToArray());

                            // set the brush volume type:
                            for (int i = 0; i < volumeBrushes.Length; i++)
                            {
                                BrushBase target = volumeBrushes[i];

                                // if the brush does not have a volume yet or the wrong one, create the selected type now:
                                if (target.Volume == null || target.Volume.GetType() != volumeTypes[selected])
                                {
                                    target.Volume = (Volume)ScriptableObject.CreateInstance(volumeTypes[selected]);
                                    if (serializedObject.targetObject != null)
                                    {
                                        serializedObject.ApplyModifiedProperties();
                                        System.Array.ForEach(volumeBrushes, item => item.Invalidate(true));
                                    }
                                }
                            }

                            // custom volume inspector:
                            if (volumeTarget.Volume.OnInspectorGUI(volumeBrushes.Select(b => b.Volume).ToArray()))
                            {
                                if (serializedObject.targetObject != null)
                                {
                                    serializedObject.ApplyModifiedProperties();
                                    System.Array.ForEach(volumeBrushes, item => item.Invalidate(true));
                                }
                            }
                        }
                    }
                }
            }

            // custom inspector:
            DoInspectorGUI();

            // generic brush editing:
            using (new NamedVerticalScope("Order"))
            {
                List <BrushBase> orderedTargets = BrushTargets.ToList();
                orderedTargets.RemoveAll(item => (item == null));
                orderedTargets.Sort((x, y) => x.transform.GetSiblingIndex().CompareTo(y.transform.GetSiblingIndex()));

                if (GUILayout.Button("Set As First"))
                {
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        // REVERSED
                        BrushBase thisBrush = orderedTargets[orderedTargets.Count - 1 - i];

                        Undo.SetTransformParent(thisBrush.transform, thisBrush.transform.parent, "Change Order");
                        thisBrush.transform.SetAsFirstSibling();
                    }

                    // Force all the brushes to recalculate their intersections and get ready for rebuilding
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        if (orderedTargets[i] is PrimitiveBrush)
                        {
                            ((PrimitiveBrush)orderedTargets[i]).RecalculateIntersections();
                            ((PrimitiveBrush)orderedTargets[i]).BrushCache.SetUnbuilt();
                        }
                    }
                }

                if (GUILayout.Button("Send Earlier"))
                {
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        BrushBase thisBrush = orderedTargets[i];

                        int siblingIndex = thisBrush.transform.GetSiblingIndex();
                        if (siblingIndex > 0)
                        {
                            Undo.SetTransformParent(thisBrush.transform, thisBrush.transform.parent, "Change Order");
                            siblingIndex--;
                            thisBrush.transform.SetSiblingIndex(siblingIndex);
                        }
                    }

                    // Force all the brushes to recalculate their intersections and get ready for rebuilding
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        if (orderedTargets[i] is PrimitiveBrush)
                        {
                            ((PrimitiveBrush)orderedTargets[i]).RecalculateIntersections();
                            ((PrimitiveBrush)orderedTargets[i]).BrushCache.SetUnbuilt();
                        }
                    }
                }

                if (GUILayout.Button("Send Later"))
                {
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        // REVERSED
                        BrushBase thisBrush = orderedTargets[orderedTargets.Count - 1 - i];

                        int siblingIndex = thisBrush.transform.GetSiblingIndex();
                        Undo.SetTransformParent(thisBrush.transform, thisBrush.transform.parent, "Change Order");
                        siblingIndex++;
                        thisBrush.transform.SetSiblingIndex(siblingIndex);
                    }

                    // Force all the brushes to recalculate their intersections and get ready for rebuilding
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        if (orderedTargets[i] is PrimitiveBrush)
                        {
                            ((PrimitiveBrush)orderedTargets[i]).RecalculateIntersections();
                            ((PrimitiveBrush)orderedTargets[i]).BrushCache.SetUnbuilt();
                        }
                    }
                }

                if (GUILayout.Button("Set As Last"))
                {
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        BrushBase thisBrush = orderedTargets[i];

                        Undo.SetTransformParent(thisBrush.transform, thisBrush.transform.parent, "Change Order");
                        thisBrush.transform.SetAsLastSibling();
                    }

                    // Force all the brushes to recalculate their intersections and get ready for rebuilding
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        if (orderedTargets[i] is PrimitiveBrush)
                        {
                            ((PrimitiveBrush)orderedTargets[i]).RecalculateIntersections();
                            ((PrimitiveBrush)orderedTargets[i]).BrushCache.SetUnbuilt();
                        }
                    }
                }

                if (serializedObject.targetObject != null)
                {
                    serializedObject.ApplyModifiedProperties();
                }
            }
        }
示例#7
0
        public sealed override void OnInspectorGUI()
        {
            // group editing:
            if (ShowGroupInspector)
            {
                using (new NamedVerticalScope("Group"))
                {
                    GUILayout.BeginHorizontal();

                    // find whether we are currently inside of a group:
                    GroupBrush group = null;
                    if (BrushTarget.transform.parent)
                    {
                        group = BrushTarget.transform.parent.GetComponent <GroupBrush>();
                    }

                    // we are in a group:
                    if (group != null)
                    {
                        if (GUILayout.Button("Select Group"))
                        {
                            // select the group.
                            Selection.objects = new Object[] { BrushTarget.transform.parent.gameObject };
                        }
                    }

                    if (GUILayout.Button("Create Group"))
                    {
                        // create a group.
                        TransformHelper.GroupSelection();
                    }

                    GUILayout.EndHorizontal();
                }
            }

            // custom inspector:
            DoInspectorGUI();


            // generic brush editing:
            using (new NamedVerticalScope("Order"))
            {
                List <BrushBase> orderedTargets = BrushTargets.ToList();
                orderedTargets.RemoveAll(item => (item == null));
                orderedTargets.Sort((x, y) => x.transform.GetSiblingIndex().CompareTo(y.transform.GetSiblingIndex()));

                if (GUILayout.Button("Set As First"))
                {
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        // REVERSED
                        BrushBase thisBrush = orderedTargets[orderedTargets.Count - 1 - i];

                        Undo.SetTransformParent(thisBrush.transform, thisBrush.transform.parent, "Change Order");
                        thisBrush.transform.SetAsFirstSibling();
                    }

                    // Force all the brushes to recalculate their intersections and get ready for rebuilding
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        if (orderedTargets[i] is PrimitiveBrush)
                        {
                            ((PrimitiveBrush)orderedTargets[i]).RecalculateIntersections();
                            ((PrimitiveBrush)orderedTargets[i]).BrushCache.SetUnbuilt();
                        }
                    }
                }

                if (GUILayout.Button("Send Earlier"))
                {
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        BrushBase thisBrush = orderedTargets[i];

                        int siblingIndex = thisBrush.transform.GetSiblingIndex();
                        if (siblingIndex > 0)
                        {
                            Undo.SetTransformParent(thisBrush.transform, thisBrush.transform.parent, "Change Order");
                            siblingIndex--;
                            thisBrush.transform.SetSiblingIndex(siblingIndex);
                        }
                    }

                    // Force all the brushes to recalculate their intersections and get ready for rebuilding
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        if (orderedTargets[i] is PrimitiveBrush)
                        {
                            ((PrimitiveBrush)orderedTargets[i]).RecalculateIntersections();
                            ((PrimitiveBrush)orderedTargets[i]).BrushCache.SetUnbuilt();
                        }
                    }
                }

                if (GUILayout.Button("Send Later"))
                {
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        // REVERSED
                        BrushBase thisBrush = orderedTargets[orderedTargets.Count - 1 - i];

                        int siblingIndex = thisBrush.transform.GetSiblingIndex();
                        Undo.SetTransformParent(thisBrush.transform, thisBrush.transform.parent, "Change Order");
                        siblingIndex++;
                        thisBrush.transform.SetSiblingIndex(siblingIndex);
                    }

                    // Force all the brushes to recalculate their intersections and get ready for rebuilding
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        if (orderedTargets[i] is PrimitiveBrush)
                        {
                            ((PrimitiveBrush)orderedTargets[i]).RecalculateIntersections();
                            ((PrimitiveBrush)orderedTargets[i]).BrushCache.SetUnbuilt();
                        }
                    }
                }

                if (GUILayout.Button("Set As Last"))
                {
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        BrushBase thisBrush = orderedTargets[i];

                        Undo.SetTransformParent(thisBrush.transform, thisBrush.transform.parent, "Change Order");
                        thisBrush.transform.SetAsLastSibling();
                    }

                    // Force all the brushes to recalculate their intersections and get ready for rebuilding
                    for (int i = 0; i < orderedTargets.Count; i++)
                    {
                        if (orderedTargets[i] is PrimitiveBrush)
                        {
                            ((PrimitiveBrush)orderedTargets[i]).RecalculateIntersections();
                            ((PrimitiveBrush)orderedTargets[i]).BrushCache.SetUnbuilt();
                        }
                    }
                }

                if (serializedObject.targetObject != null)
                {
                    serializedObject.ApplyModifiedProperties();
                }
            }
        }