Example #1
0
        public static void InsertEdgeLoop(PrimitiveBrush brush, Plane localClipPlane)
        {
            // Clip the polygons against the plane
            List <Polygon> polygonsFront;
            List <Polygon> polygonsBack;

            if (PolygonFactory.SplitPolygonsByPlane(new List <Polygon>(brush.GetPolygons()), localClipPlane, true, out polygonsFront, out polygonsBack))
            {
                List <Polygon> allPolygons = new List <Polygon>();
                // Concat back into one list
                allPolygons.AddRange(polygonsFront);
                allPolygons.AddRange(polygonsBack);
                // Remove the inserted polygons
                for (int i = 0; i < allPolygons.Count; i++)
                {
                    if (allPolygons[i].ExcludeFromFinal)
                    {
                        allPolygons.RemoveAt(i);
                        i--;
                    }
                }
                // Update the brush with the new polygons
                brush.SetPolygons(allPolygons.ToArray(), true);
            }
        }
Example #2
0
 public override void Invalidate(bool polygonsChanged)
 {
     generatedBrushes.RemoveAll(item => item == null);
     if (generatedBrushes.Count > BrushCount)
     {
         // Trim off the extraneous brushes
         for (int i = BrushCount; i < generatedBrushes.Count; i++)
         {
             if (generatedBrushes[i] != null)
             {
                 DestroyImmediate(generatedBrushes[i].gameObject);
             }
         }
         generatedBrushes.RemoveRange(BrushCount, generatedBrushes.Count - BrushCount);
     }
     else if (generatedBrushes.Count < BrushCount)
     {
         // Add in new brushes to fill the gap
         while (generatedBrushes.Count < BrushCount)
         {
             PrimitiveBrush newBrush = CreateBrush();
             newBrush.transform.SetParent(this.transform, false);
             newBrush.SetBrushController(this);
             generatedBrushes.Add(newBrush);
         }
     }
 }
Example #3
0
        /// <summary>
        /// Scales the brush by a local Vector3 scale from its pivot
        /// </summary>
        /// <param name="brush">The brush to be rescaled</param>
        /// <param name="rescaleValue">Local scale to apply</param>
        public static void Scale(PrimitiveBrush brush, Vector3 scaleValue)
        {
            Polygon[] polygons = brush.GetPolygons();

            for (int i = 0; i < polygons.Length; i++)
            {
                Polygon polygon = polygons[i];

                polygons[i].CalculatePlane();
                Vector3 previousPlaneNormal = polygons[i].Plane.normal;

                int vertexCount = polygon.Vertices.Length;

                Vector3[] newPositions = new Vector3[vertexCount];
                Vector2[] newUV        = new Vector2[vertexCount];

                for (int j = 0; j < vertexCount; j++)
                {
                    newPositions[j] = polygon.Vertices[j].Position;
                    newUV[j]        = polygon.Vertices[j].UV;
                }

                for (int j = 0; j < vertexCount; j++)
                {
                    Vertex vertex = polygon.Vertices[j];

                    Vector3 newPosition = vertex.Position.Multiply(scaleValue);
                    newPositions[j] = newPosition;

                    newUV[j] = GeometryHelper.GetUVForPosition(polygon, newPosition);
                }

                // Apply all the changes to the polygon
                for (int j = 0; j < vertexCount; j++)
                {
                    Vertex vertex = polygon.Vertices[j];
                    vertex.Position = newPositions[j];
                    vertex.UV       = newUV[j];
                }

                // Polygon geometry has changed, inform the polygon that it needs to recalculate its cached plane
                polygons[i].CalculatePlane();

                Vector3 newPlaneNormal = polygons[i].Plane.normal;

                // Find the rotation from the original polygon plane to the new polygon plane
                Quaternion normalRotation = Quaternion.FromToRotation(previousPlaneNormal, newPlaneNormal);

                // Rotate all the vertex normals by the new rotation
                for (int j = 0; j < vertexCount; j++)
                {
                    Vertex vertex = polygon.Vertices[j];
                    vertex.Normal = normalRotation * vertex.Normal;
                }
            }
#if UNITY_EDITOR
            EditorHelper.SetDirty(brush);
#endif
            brush.Invalidate(true);
        }
Example #4
0
        /// <summary>
        /// Resizes the brush so that it's local bounds match the specified extents
        /// </summary>
        /// <param name="brush">The brush to be resized</param>
        /// <param name="rescaleValue">The extents to match</param>
        public static void Resize(PrimitiveBrush brush, Vector3 resizeValue)
        {
            Bounds bounds = brush.GetBounds();
            // Calculate the rescale vector required to change the bounds to the resize vector
            Vector3 rescaleVector3 = resizeValue.Divide(bounds.size);

            Scale(brush, rescaleVector3);
        }
Example #5
0
        /// <summary>
        /// Create a brush at the origin using a specified set of polygons
        /// </summary>
        /// <returns>The custom brush game object.</returns>
        /// <param name="polygons">Polygons.</param>
        public GameObject CreateCustomBrush(Polygon[] polygons)
        {
            GameObject brushObject = new GameObject("AppliedBrush");

            brushObject.transform.parent = this.transform;
            PrimitiveBrush primitiveBrush = brushObject.AddComponent <PrimitiveBrush>();

            primitiveBrush.SetPolygons(polygons, true);

            return(brushObject);
        }
Example #6
0
        public GameObject CreateBrush(PrimitiveBrushType brushType)
        {
            GameObject brushObject = new GameObject("AppliedBrush");

            brushObject.transform.parent = this.transform;
            PrimitiveBrush primitiveBrush = brushObject.AddComponent <PrimitiveBrush>();

            primitiveBrush.BrushType = brushType;
            primitiveBrush.ResetPolygons();

            return(brushObject);
        }
Example #7
0
        /// <summary>
        /// Creates a brush under the CSG Model with the specified attributes.
        /// </summary>
        /// <returns>The created game object.</returns>
        /// <param name="brushType">Brush type.</param>
        /// <param name="localPosition">Local position of the brush's transform</param>
        /// <param name="localSize">Local bounds size of the brush (Optional, defaults to 2,2,2).</param>
        /// <param name="localRotation">Local rotation of the brush (Optional, defaults to identity quaternion).</param>
        /// <param name="material">Material to apply to all faces, (Optional, defaults to null for default material).</param>
        /// <param name="csgMode">Whether the brush is additive or subtractive (Optional, defaults to additive).</param>
        /// <param name="brushName">Name for the game object (Optional, defaults to "AppliedBrush").</param>
        public GameObject CreateBrush(PrimitiveBrushType brushType, Vector3 localPosition, Vector3 localSize = default(Vector3), Quaternion localRotation = default(Quaternion), Material material = null, CSGMode csgMode = CSGMode.Add, string brushName = null)
        {
            GameObject brushObject;

            if (!string.IsNullOrEmpty(brushName))
            {
                brushObject = new GameObject(brushName);
            }
            else
            {
                brushObject = new GameObject("");
            }

            brushObject.transform.localScale    = this.transform.lossyScale;
            brushObject.transform.parent        = this.transform;
            brushObject.transform.localPosition = localPosition;
            if (localRotation != default(Quaternion))
            {
                brushObject.transform.localRotation = localRotation;
            }
            PrimitiveBrush primitiveBrush = brushObject.AddComponent <PrimitiveBrush>();

            primitiveBrush.BrushType = brushType;
            primitiveBrush.Mode      = csgMode;
            primitiveBrush.ResetPolygons();

            if (localSize != default(Vector3) &&
                localSize != new Vector3(2, 2, 2))
            {
                BrushUtility.Resize(primitiveBrush, localSize);
            }
            else
            {
                // Resize automatically invalidates a brush with changed polygons set, if no resize took place we still need to make sure it happens
                primitiveBrush.Invalidate(true);
            }

            if (material != null)
            {
                SurfaceUtility.SetAllPolygonsMaterials(primitiveBrush, material);
            }

            return(brushObject);
        }
Example #8
0
        /// <summary>
        /// Rebuilds the volume, creating or deleting the volume component and applying new settings.
        /// </summary>
        internal void RebuildVolume()
        {
            // volumes can only be primitive brushes at the moment.
            if (GetType() != typeof(PrimitiveBrush))
            {
                return;
            }
            PrimitiveBrush self = (PrimitiveBrush)this;

            // remove volumes from brushes that are no longer volumes:
            if (Mode != CSGMode.Volume && Volume != null)
            {
                // set volume handle to null.
                Volume = null;
                // delete any built volume.
                Transform volume1 = transform.Find(Constants.GameObjectVolumeComponentIdentifier);
                if (volume1 != null)
                {
                    GameObject.DestroyImmediate(volume1.gameObject);
                }
            }

            // generate all of the volume brushes:
            if (Mode == CSGMode.Volume && Volume != null)
            {
                // remove any existing built volume:
                Transform volume2 = transform.Find(Constants.GameObjectVolumeComponentIdentifier);
                if (volume2 != null)
                {
                    GameObject.DestroyImmediate(volume2.gameObject);
                }

                // create the game object with convex mesh collider:
                Mesh mesh = new Mesh();
                BrushFactory.GenerateMeshFromPolygonsFast(self.GetPolygons(), ref mesh, 0.0f);
                GameObject gameObject = CreateVolumeMeshCollider(mesh);
                gameObject.transform.position = transform.position;
                gameObject.transform.rotation = transform.rotation;

                // execute custom volume generation code:
                Volume.OnCreateVolume(gameObject);
            }
        }
Example #9
0
        /// <summary>
        /// Applies a clip or split operation to a brush by supplying a plane local to the brush. Clipping allows you to cut away and discard parts of the brush, while splitting allows you to split a brush in two.
        /// </summary>
        /// <returns>If keepBothSides is <c>true</c>, this returns the second brush if one was created.</returns>
        /// <param name="brush">Brush to clip/split</param>
        /// <param name="localPlane">Local plane to clip/split against</param>
        /// <param name="keepBothSides">If set to <c>true</c> split the brush and keep both sides.</param>
        /// <param name="resetPivots">If set to <c>true</c> make sure the pivot clipped brush and any new brush are at their center.</param>
        public static GameObject ApplyClipPlane(PrimitiveBrush brush, Plane localPlane, bool keepBothSides, bool resetPivots = true)
        {
            // Clip the polygons against the plane
            List <Polygon> polygonsFront;
            List <Polygon> polygonsBack;

            List <Polygon> polygonList = new List <Polygon>(brush.GetPolygons());

            if (PolygonFactory.SplitPolygonsByPlane(polygonList, localPlane, false, out polygonsFront, out polygonsBack))
            {
                // Update the brush with the new polygons
                brush.SetPolygons(polygonsFront.ToArray(), true);

                GameObject newObject = null;
                // If they have decided to split instead of clip, create a second brush with the other side
                if (keepBothSides)
                {
                    newObject = brush.Duplicate();

                    // Finally give the new brush the other set of polygons
                    newObject.GetComponent <PrimitiveBrush>().SetPolygons(polygonsBack.ToArray(), true);
                    newObject.transform.SetSiblingIndex(brush.transform.GetSiblingIndex());
                    // Reset the new brush's pivot
                    if (resetPivots)
                    {
                        newObject.GetComponent <PrimitiveBrush>().ResetPivot();
                    }
                }

                // Can't reset the first brush pivot until after the second brush is made, otherwise the second
                // brush is effectively translated twice, ending up in the wrong position
                if (resetPivots)
                {
                    brush.ResetPivot();
                }

                return(newObject);
            }
            else
            {
                return(null);
            }
        }
Example #10
0
        private void OnMouseMove(SceneView sceneView, Event e)
        {
            // if the user stopped holding shift we cancel the automatic height.
            if (!e.shift)
            {
                startedSubtract = false;
            }

            UpdateCSGMode(e);

            if (selectingHeight)
            {
                // Mouse movement while selecting depth controls prism height
                OnMouseMoveSelectHeight(sceneView, e);
            }
            else
            {
                // Not currently drawing, so update the active polygon to whatever they are currently hovering over
                if (drawMode == DrawMode.None)
                {
                    PolygonRaycastHit?hit = CalculateHitPolygon(e.mousePosition);
                    if (hit.HasValue)
                    {
                        activePolygon = hit.Value.Polygon;
                        activeBrush   = hit.Value.GameObject.GetComponent <PrimitiveBrush>();
                    }
                    else
                    {
                        activePolygon = null;
                        activeBrush   = null;
                    }
                }

                // Find the snapped hover point based on any active polygon or the grid
                Vector3?hitPoint = GetHitPoint(e.mousePosition);
                if (hitPoint.HasValue)
                {
                    hoverPoint = hitPoint.Value;
                    SceneView.RepaintAll();
                }
            }
        }
        /// <summary>
        /// Creates a brush under the CSG Model with the specified attributes.
        /// </summary>
        /// <returns>The created game object.</returns>
        /// <param name="brushType">Brush type.</param>
        /// <param name="localPosition">Local position of the brush's transform</param>
        /// <param name="localSize">Local bounds size of the brush (Optional, defaults to 2,2,2).</param>
        /// <param name="localRotation">Local rotation of the brush (Optional, defaults to identity quaternion).</param>
        /// <param name="material">Material to apply to all faces, (Optional, defaults to null for default material).</param>
        /// <param name="csgMode">Whether the brush is additive or subtractive (Optional, defaults to additive).</param>
        /// <param name="brushName">Name for the game object (Optional, defaults to "AppliedBrush").</param>
        public GameObject CreateBrush(PrimitiveBrushType brushType, Vector3 localPosition, Vector3 localSize = default(Vector3), Quaternion localRotation = default(Quaternion), Material material = null, CSGMode csgMode = CSGMode.Add, string brushName = null)
        {
            GameObject brushObject;

            if (!string.IsNullOrEmpty(brushName))
            {
                brushObject = new GameObject(brushName);
            }
            else
            {
                brushObject = new GameObject("AppliedBrush");
            }

            brushObject.transform.parent        = this.transform;
            brushObject.transform.localPosition = localPosition;
            if (localRotation != default(Quaternion))
            {
                brushObject.transform.localRotation = localRotation;
            }
            PrimitiveBrush primitiveBrush = brushObject.AddComponent <PrimitiveBrush>();

            primitiveBrush.BrushType = brushType;
            primitiveBrush.Mode      = csgMode;
            primitiveBrush.ResetPolygons();

            if (localSize != default(Vector3) &&
                localSize != new Vector3(2, 2, 2))
            {
                BrushUtility.Resize(primitiveBrush, localSize);
//				primitiveBrush.Invalidate(true);
            }

            if (material != null)
            {
                SurfaceUtility.SetAllPolygonsMaterials(primitiveBrush, material);
            }

            return(brushObject);
        }
Example #12
0
        void OnSelectionChanged()
        {
            bool anyCSGObjectsSelected = false;
            bool anyNonCSGSelected     = false;

            List <CSGModel> foundModels = new List <CSGModel>();
            Dictionary <CSGModel, List <UnityEngine.Object> > selectedBrushes = new Dictionary <CSGModel, List <UnityEngine.Object> >();

            for (int i = 0; i < Selection.gameObjects.Length; i++)
            {
                PrimitiveBrush primitiveBrush = Selection.gameObjects[i].GetComponent <PrimitiveBrush>();
                CSGModel       csgModel       = Selection.gameObjects[i].GetComponent <CSGModel>();

                if (primitiveBrush != null)
                {
                    csgModel = primitiveBrush.GetCSGModel() as CSGModel;

                    if (!foundModels.Contains(csgModel))
                    {
                        foundModels.Add(csgModel);
                        selectedBrushes[csgModel] = new List <UnityEngine.Object>();
                    }

                    selectedBrushes[csgModel].Add(primitiveBrush.gameObject);
                }

                if (csgModel != null)
                {
                    anyCSGObjectsSelected = true;

                    if (!foundModels.Contains(csgModel))
                    {
                        foundModels.Add(csgModel);
                        selectedBrushes[csgModel] = new List <UnityEngine.Object>();
                    }
                }
                else
                {
                    CSGModel[] parentCSGModels = Selection.gameObjects[i].GetComponentsInParent <CSGModel>(true);
                    if (parentCSGModels.Length > 0)
                    {
                        csgModel = parentCSGModels[0];

                        if (Selection.gameObjects[i].GetComponent <MeshFilter>() != null ||
                            Selection.gameObjects[i].GetComponent <MeshCollider>() != null)
                        {
                            anyNonCSGSelected = true;
                        }
                        else
                        {
                            anyCSGObjectsSelected = true;

                            if (!foundModels.Contains(csgModel))
                            {
                                foundModels.Add(csgModel);
                                selectedBrushes[csgModel] = new List <UnityEngine.Object>();
                            }
                        }
                    }
                    else
                    {
                        anyNonCSGSelected = true;
                    }
                }
            }

            if (anyCSGObjectsSelected)
            {
                CSGModel activeModel = null;
                if (foundModels.Count == 1)
                {
                    if (!foundModels[0].EditMode)
                    {
                        foundModels[0].EditMode = true;
                    }
                    activeModel = foundModels[0];
                }
                else
                {
                    bool anyActive = false;

                    for (int i = 0; i < foundModels.Count; i++)
                    {
                        if (foundModels[i].EditMode)
                        {
                            anyActive   = true;
                            activeModel = foundModels[i];
                            break;
                        }
                    }

                    if (!anyActive)
                    {
                        foundModels[0].EditMode = true;
                        activeModel             = foundModels[0];
                    }
                }

                if (anyNonCSGSelected && activeModel != null)
                {
                    deferredSelection = selectedBrushes[activeModel].ToArray();
                }
            }
            else if (anyNonCSGSelected)
            {
                EditMode = false;
            }


            if (EditMode)
            {
                // Walk backwards until we find the last selected brush
                for (int i = Selection.gameObjects.Length - 1; i >= 0; i--)
                {
                    Brush brush = Selection.gameObjects[i].GetComponent <Brush>();

                    if (brush != null)
                    {
                        lastSelectedBrush = brush;
                        break;
                    }
                }
            }
        }
Example #13
0
 public void OnBrushDisabled(PrimitiveBrush brush)
 {
     polygonsRemoved = true;
 }
Example #14
0
        private void OnMouseDown(SceneView sceneView, Event e)
        {
            if (drawMode == DrawMode.None || drawMode == DrawMode.Ambiguous)
            {
                startedSubtract = e.shift;
            }

            UpdateCSGMode(e);

            if (selectingHeight)
            {
                return;
            }

            if (e.clickCount == 2)
            {
                // Double click, so finish the polygon
                if (drawMode == DrawMode.PolygonBase)
                {
                    if (Is3DView && !startedSubtract)
                    {
                        selectingHeight   = true;
                        prismHeight       = 0;
                        ignoreNextMouseUp = true;
                        SceneView.RepaintAll();
                    }
                    else
                    {
                        CreateBrush(hitPoints);

                        ResetTool();

                        sceneView.Repaint();
                    }
                }
            }
            else
            {
                if (drawMode == DrawMode.None)
                {
                    PolygonRaycastHit?hit = CalculateHitPolygon(e.mousePosition);
                    if (hit.HasValue)
                    {
                        activePolygon = hit.Value.Polygon;
                        activeBrush   = hit.Value.GameObject.GetComponent <PrimitiveBrush>();
                    }
                    else
                    {
                        activePolygon = null;
                        activeBrush   = null;
                    }

                    Vector3?hitPoint = GetHitPoint(e.mousePosition);
                    if (hitPoint.HasValue)
                    {
                        downPoint  = hitPoint.Value;
                        hoverPoint = downPoint;
                    }

                    hitPoints.Clear();

                    if (hitPoint.HasValue)
                    {
                        drawMode = DrawMode.Ambiguous;
                    }
                }
                else
                {
                    Vector3?hitPoint = GetHitPoint(e.mousePosition);
                    if (hitPoint.HasValue)
                    {
                        downPoint  = hitPoint.Value;
                        hoverPoint = downPoint;
                    }
                }
            }
        }
Example #15
0
        public void SetSelection(GameObject selectedGameObject, GameObject[] selectedGameObjects)
        {
            // Find the selected brush bases
            List <BrushBase> brushBases = new List <BrushBase>();

            for (int i = 0; i < Selection.gameObjects.Length; i++)
            {
                BrushBase matchedBrushBase = Selection.gameObjects[i].GetComponent <BrushBase>();

                // If we've selected a brush base that isn't a prefab in the project
                if (matchedBrushBase != null
#if UNITY_2018_2_OR_NEWER
                    && !(PrefabUtility.GetCorrespondingObjectFromSource(matchedBrushBase.gameObject) == null
#else
                    && !(PrefabUtility.GetPrefabParent(matchedBrushBase.gameObject) == null
#endif
#if !UNITY_2018_3_OR_NEWER
                         && PrefabUtility.GetPrefabObject(matchedBrushBase.transform) != null))
#else
                         && PrefabUtility.GetPrefabInstanceHandle(selectedGameObject.transform) != null))
#endif
                {
                    brushBases.Add(matchedBrushBase);
                }
            }

            // Also find an array of brushes (brush bases that aren't primitive brushes will have a null entry)
            PrimitiveBrush[] primitiveBrushes = brushBases.Select(item => item.GetComponent <PrimitiveBrush>()).ToArray();

            // Pick out the first brush base and primitive brush (or null if none)
            BrushBase      newPrimaryBrushBase = null;
            PrimitiveBrush newPrimaryBrush     = null;

            // Make sure it's not null and that it isn't a prefab in the project
            if (selectedGameObject != null
#if UNITY_2018_2_OR_NEWER
                && !(PrefabUtility.GetCorrespondingObjectFromSource(selectedGameObject) == null
#else
                && !(PrefabUtility.GetPrefabParent(selectedGameObject) == null
#endif
#if !UNITY_2018_3_OR_NEWER
                     && PrefabUtility.GetPrefabObject(selectedGameObject.transform) != null))
#else
                     && PrefabUtility.GetPrefabInstanceHandle(selectedGameObject.transform) != null))
#endif
            {
                newPrimaryBrushBase = selectedGameObject.GetComponent <BrushBase>();               // brushBases.FirstOrDefault();
                newPrimaryBrush     = selectedGameObject.GetComponent <PrimitiveBrush>();          // primitiveBrushes.Where(item => item != null).FirstOrDefault();
            }

            // If the primary brush base has changed
            if (primaryTargetBrushBase != newPrimaryBrushBase ||
                (primaryTargetBrushBase == null && newPrimaryBrushBase != null))                    // Special case for undo where references are equal but one is null
            {
                primaryTargetBrushBase = newPrimaryBrushBase;

                if (newPrimaryBrushBase != null)
                {
                    primaryTargetBrushTransform = newPrimaryBrushBase.transform;
                }
                else
                {
                    primaryTargetBrushTransform = null;
                }

                ResetTool();
            }

            BrushBase[] brushBasesArray = brushBases.ToArray();
            primaryTargetBrush = newPrimaryBrush;

            if (!targetBrushBases.ContentsEquals(brushBasesArray))
            {
                OnSelectionChanged();
                targetBrushBases      = brushBasesArray;
                targetBrushes         = primitiveBrushes;
                targetBrushTransforms = new Transform[brushBasesArray.Length];
                for (int i = 0; i < brushBasesArray.Length; i++)
                {
                    if (brushBasesArray[i] != null)
                    {
                        targetBrushTransforms[i] = brushBasesArray[i].transform;
                    }
                    else
                    {
                        targetBrushTransforms[i] = null;
                    }
                }
            }
        }
Example #16
0
        public override void OnInspectorGUI()
        {
//            DrawDefaultInspector();

            DrawBrushTypeField();

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

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

            GUILayout.BeginHorizontal();

            GUI.SetNextControlName("rescaleTextbox");

            rescaleString = EditorGUILayout.TextField(rescaleString);

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

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

            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") || 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;
                        foreach (PrimitiveBrush brush in brushes)
                        {
                            BrushUtility.Resize(brush, resizeVector3);
                        }
                    }
                }
            }

            GUILayout.EndHorizontal();

            GUILayout.BeginHorizontal();
            sourceMesh = EditorGUILayout.ObjectField(sourceMesh, typeof(Mesh), false) as Mesh;

            if (GUILayout.Button("Import"))
            {
                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();

            List <PrimitiveBrush> orderedTargets = BrushTargets.ToList();

            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
                    PrimitiveBrush 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++)
                {
                    orderedTargets[i].RecalculateIntersections();
                    orderedTargets[i].BrushCache.SetUnbuilt();
                }
            }

            if (GUILayout.Button("Send Earlier"))
            {
                for (int i = 0; i < orderedTargets.Count; i++)
                {
                    PrimitiveBrush 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++)
                {
                    orderedTargets[i].RecalculateIntersections();
                    orderedTargets[i].BrushCache.SetUnbuilt();
                }
            }

            if (GUILayout.Button("Send Later"))
            {
                for (int i = 0; i < orderedTargets.Count; i++)
                {
                    // REVERSED
                    PrimitiveBrush 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++)
                {
                    orderedTargets[i].RecalculateIntersections();
                    orderedTargets[i].BrushCache.SetUnbuilt();
                }
            }

            if (GUILayout.Button("Set As Last"))
            {
                for (int i = 0; i < orderedTargets.Count; i++)
                {
                    PrimitiveBrush 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++)
                {
                    orderedTargets[i].RecalculateIntersections();
                    orderedTargets[i].BrushCache.SetUnbuilt();
                }
            }

            serializedObject.ApplyModifiedProperties();



//            GUILayout.Label("UVs", EditorStyles.boldLabel);
//
//            if (GUILayout.Button("Flip XY"))
//            {
//                UVUtility.FlipUVsXY(thisBrush.Polygons);
//            }
//
//            GUILayout.BeginHorizontal();
//            if (GUILayout.Button("Flip X"))
//            {
//                UVUtility.FlipUVsX(thisBrush.Polygons);
//            }
//            if (GUILayout.Button("Flip Y"))
//            {
//                UVUtility.FlipUVsY(thisBrush.Polygons);
//            }
//            GUILayout.EndHorizontal();
//
//            GUILayout.BeginHorizontal();
//            if (GUILayout.Button("UVs x 2"))
//            {
//                UVUtility.ScaleUVs(thisBrush.Polygons, 2f);
//            }
//            if (GUILayout.Button("UVs / 2"))
//            {
//                UVUtility.ScaleUVs(thisBrush.Polygons, .5f);
//            }
//            GUILayout.EndHorizontal();
            // Ensure Edit Mode is on
//            csgModel.EditMode = true;
        }
Example #17
0
        private void CreateBrush(List <Vector3> positions)
        {
            Polygon sourcePolygon = PolygonFactory.ConstructPolygon(positions, true);

            // Early out if it wasn't possible to create the polygon
            if (sourcePolygon == null)
            {
                return;
            }

            if (activePolygon != null)
            {
                for (int i = 0; i < sourcePolygon.Vertices.Length; i++)
                {
                    Vector2 newUV = GeometryHelper.GetUVForPosition(activePolygon, sourcePolygon.Vertices[i].Position);
                    sourcePolygon.Vertices[i].UV = newUV;
                }
            }

            Vector3 planeNormal = GetActivePlane().normal;

            //			Debug.Log(Vector3.Dot(sourcePolygon.Plane.normal, planeNormal));

            // Flip the polygon if the winding order is wrong
            if (Vector3.Dot(sourcePolygon.Plane.normal, planeNormal) < 0)
            {
                sourcePolygon.Flip();

                // Need to flip the UVs across the U (X) direction
                for (int i = 0; i < sourcePolygon.Vertices.Length; i++)
                {
                    Vector2 uv = sourcePolygon.Vertices[i].UV;
                    uv.x = 1 - uv.x;
                    sourcePolygon.Vertices[i].UV = uv;
                }
            }

            float   extrusionDistance = 1;
            Vector3 positionOffset    = Vector3.zero;

            if (selectingHeight)
            {
                extrusionDistance = prismHeight;
            }
            else
            {
                if (activePolygon != null && activeBrush != null)
                {
                    extrusionDistance = activeBrush.CalculateExtentsInAxis(planeNormal);
                }
                else
                {
                    Brush lastSelectedBrush = csgModel.LastSelectedBrush;
                    if (lastSelectedBrush != null)
                    {
                        Bounds lastSelectedBrushBounds = lastSelectedBrush.GetBoundsTransformed();

                        for (int i = 0; i < 3; i++)
                        {
                            if (!planeNormal[i].EqualsWithEpsilon(0))
                            {
                                if (lastSelectedBrushBounds.size[i] != 0)
                                {
                                    extrusionDistance = lastSelectedBrushBounds.size[i];

                                    if (planeNormal[i] > 0)
                                    {
                                        positionOffset[i] = lastSelectedBrushBounds.center[i] - lastSelectedBrushBounds.extents[i];
                                    }
                                    else
                                    {
                                        positionOffset[i] = lastSelectedBrushBounds.center[i] + lastSelectedBrushBounds.extents[i];
                                    }
                                }
                            }
                        }
                    }
                }

                // Subtractions should go through
                if (csgMode == CSGMode.Subtract)
                {
                    sourcePolygon.Flip();
                }
            }

            Quaternion rotation;

            Polygon[] polygons;
            SurfaceUtility.ExtrudePolygon(sourcePolygon, extrusionDistance, out polygons, out rotation);

            GameObject newObject = csgModel.CreateCustomBrush(polygons);

            PrimitiveBrush newBrush = newObject.GetComponent <PrimitiveBrush>();

            newObject.transform.rotation  = rotation;
            newObject.transform.position += positionOffset;

            if (activePolygon != null &&
                activePolygon.Material != csgModel.GetDefaultMaterial())
            {
                for (int i = 0; i < polygons.Length; i++)
                {
                    polygons[i].Material = activePolygon.Material;
                }
            }
            // Finally give the new brush the other set of polygons
            newBrush.SetPolygons(polygons, true);

            newBrush.Mode = csgMode;

            newBrush.ResetPivot();

            // Use this brush as the basis for drawing the next brush
            csgModel.SetLastSelectedBrush(newBrush);

            Undo.RegisterCreatedObjectUndo(newObject, "Draw Brush");
        }
Example #18
0
        public static void SplitIntersecting(PrimitiveBrush[] brushes)
        {
            List <Brush> intersections = new List <Brush>();

            foreach (PrimitiveBrush brush in brushes)
            {
                intersections.AddRange(brush.BrushCache.IntersectingVisualBrushes);
            }

            foreach (PrimitiveBrush brush in brushes)
            {
                List <PrimitiveBrush> newBrushes = new List <PrimitiveBrush>();

                foreach (Brush intersectingBrush in intersections)
                {
                    PrimitiveBrush brushToClip = (PrimitiveBrush)intersectingBrush;

                    Polygon[] polygons = brush.GetPolygons();

                    // A brush may have several polygons that share a plane, find all the distinct polygon planes
                    List <Plane> distinctPlanes = new List <Plane>();

                    for (int polygonIndex = 0; polygonIndex < polygons.Length; polygonIndex++)
                    {
                        Polygon polygon = polygons[polygonIndex];
                        Vertex  vertex1, vertex2, vertex3;
                        SurfaceUtility.GetPrimaryPolygonDescribers(polygon, out vertex1, out vertex2, out vertex3);

                        Vector3 position1 = vertex1.Position;
                        Vector3 position2 = vertex2.Position;
                        Vector3 position3 = vertex3.Position;

                        // Transform from local to brush to local to intersectingBrush
                        position1 = intersectingBrush.transform.InverseTransformPoint(brush.transform.TransformPoint(position1));
                        position2 = intersectingBrush.transform.InverseTransformPoint(brush.transform.TransformPoint(position2));
                        position3 = intersectingBrush.transform.InverseTransformPoint(brush.transform.TransformPoint(position3));

                        // Calculate plane in intersectingBrush's local space
                        Plane polygonPlane = new Plane(position1, position2, position3);

                        bool found = false;
                        // See if it already exists
                        for (int i = 0; i < distinctPlanes.Count; i++)
                        {
                            if (MathHelper.PlaneEqualsLooser(distinctPlanes[i], polygonPlane))
                            {
                                found = true;
                                break;
                            }
                        }

                        // Not added to an existing group, so add new
                        if (!found)
                        {
                            // Add a new group for the polygon
                            distinctPlanes.Add(polygonPlane);
                        }
                    }

                    foreach (Plane clipPlane in distinctPlanes)
                    {
#if UNITY_EDITOR
                        UnityEditor.Undo.RecordObject(brushToClip, "Split Intersecting Brushes");
                        UnityEditor.Undo.RecordObject(brushToClip.transform, "Split Intersecting Brushes");
#endif

                        GameObject newObject = ClipUtility.ApplyClipPlane(brushToClip, clipPlane, true, false);

                        if (newObject != null)
                        {
#if UNITY_EDITOR
                            UnityEditor.Undo.RegisterCreatedObjectUndo(newObject, "Split Intersecting Brushes");
#endif
                            newBrushes.Add(newObject.GetComponent <PrimitiveBrush>());
                        }
                    }

                    brushToClip.ResetPivot();
                }

                foreach (PrimitiveBrush newBrush in newBrushes)
                {
                    newBrush.ResetPivot();
                }

                intersections.AddRange(newBrushes.ConvertAll <Brush>(item => (Brush)item));
            }
        }
Example #19
0
 public static void Rescale(PrimitiveBrush brush, Vector3 rescaleValue)
 {
     Scale(brush, rescaleValue);
 }
Example #20
0
        /// <summary>
        /// Flips brushes along the provided axis
        /// </summary>
        /// <param name="primaryTargetBrush">The brush considered to be the pivot brush, for use when localToPrimaryBrush is true</param>
        /// <param name="targetBrushes">All brushes to be flipped</param>
        /// <param name="axisIndex">Index of the axis component to flip along, 0 = X, 1 = Y, 2 = Z</param>
        /// <param name="localToPrimaryBrush">Whether the axis to flip in is local to the primary brush's rotation, if false global orientation is used</param>
        /// <param name="flipCenter">The point in world space at which to flip the geometry around</param>
        public static void Flip(PrimitiveBrush primaryTargetBrush, PrimitiveBrush[] targetBrushes, int axisIndex, bool localToPrimaryBrush, Vector3 flipCenter)
        {
            foreach (PrimitiveBrush brush in targetBrushes)
            {
                Polygon[] polygons = brush.GetPolygons();

                for (int i = 0; i < polygons.Length; i++)
                {
                    for (int j = 0; j < polygons[i].Vertices.Length; j++)
                    {
                        Vertex vertex = polygons[i].Vertices[j];

                        Vector3 position = vertex.Position;
                        Vector3 normal   = vertex.Normal;

                        if (localToPrimaryBrush)
                        {
                            // Rotate the position and normal to be relative to the primary brush's local space
                            position = primaryTargetBrush.transform.InverseTransformDirection(brush.transform.TransformDirection(position));
                            normal   = primaryTargetBrush.transform.InverseTransformDirection(brush.transform.TransformDirection(normal));
                        }
                        else
                        {
                            // Rotate the position and normal to be relative to the global axis orientation
                            position = brush.transform.TransformDirection(position);
                            normal   = brush.transform.TransformDirection(normal);
                        }

                        // Flip in relevant axis
                        position[axisIndex] = -position[axisIndex];
                        normal[axisIndex]   = -normal[axisIndex];

                        if (localToPrimaryBrush)
                        {
                            // Rotate the position and normal from the primary brush's local space back to the brush's local space
                            position = brush.transform.InverseTransformDirection(primaryTargetBrush.transform.TransformDirection(position));
                            normal   = brush.transform.InverseTransformDirection(primaryTargetBrush.transform.TransformDirection(normal));
                        }
                        else
                        {
                            // Rotate the position and normal from the global axis orientation back to the brush's original local space
                            position = brush.transform.InverseTransformDirection(position);
                            normal   = brush.transform.InverseTransformDirection(normal);
                        }

                        // Set the vertex position and normal to their new values
                        vertex.Position = position;
                        vertex.Normal   = normal;
                    }
                    // Because a flip has occurred we need to reverse the winding order
                    Array.Reverse(polygons[i].Vertices);
                    // Polygon plane has probably changed so it should now be recalculated
                    polygons[i].CalculatePlane();
                }

                if (targetBrushes.Length > 0) // Only need to move brushes if there's more than one
                {
                    // Calculate the difference between the brush position and the center of flipping
                    Vector3 deltaFromCenter = brush.transform.position - flipCenter;
                    if (localToPrimaryBrush)
                    {
                        // Rotate the delta so that it's in the primary brush's local space
                        deltaFromCenter = primaryTargetBrush.transform.InverseTransformDirection(deltaFromCenter);
                    }

                    // Negate the delta, so that the brush position will be flipped to the other side
                    deltaFromCenter[axisIndex] = -deltaFromCenter[axisIndex];

                    if (localToPrimaryBrush)
                    {
                        // Rotate the delta back to its original space
                        deltaFromCenter = primaryTargetBrush.transform.TransformDirection(deltaFromCenter);
                    }
                    // Set the brush's new position
                    brush.transform.position = flipCenter + deltaFromCenter;
                }
                // Notify the brush that it has changed
                brush.Invalidate(true);
            }
        }
Example #21
0
        public void OnSceneGUI(SceneView sceneView)
        {
            Event e = Event.current;

            //			if (e.type == EventType.Repaint)
            //			{
            //				if(CurrentSettings.GridMode == GridMode.SabreCSG)
            //				{
            //					CSGGrid.Activate();
            //				}
            //			}

            if (!EditMode)
            {
                return;
            }

            // Frame rate tracking
            if (e.type == EventType.Repaint)
            {
                currentFrameDelta     = Time.realtimeSinceStartup - currentFrameTimestamp;
                currentFrameTimestamp = Time.realtimeSinceStartup;
            }

            // Raw checks for tracking mouse events (use raw so that consumed events are not ignored)
            if (e.rawType == EventType.MouseDown)
            {
                mouseIsDragging = false;
                mouseIsHeld     = true;

                if (e.button == 0 && GUIUtility.hotControl == 0)
                {
                    GUIUtility.keyboardControl = 0;
                }
            }
            else if (e.rawType == EventType.MouseDrag)
            {
                mouseIsDragging = true;
            }
            else if (e.rawType == EventType.MouseUp)
            {
                mouseIsHeld = false;
            }

//			if (CurrentSettings.BrushesVisible)
            {
                // No idea what this line of code means, but it seems to stop normal mouse selection
                HandleUtility.AddDefaultControl(GUIUtility.GetControlID(FocusType.Passive));
            }

            if (EditMode)
            {
                // In CSG mode, prevent the normal tools, so that the user must use our tools instead
                Tools.current = UnityEditor.Tool.None;
            }

            int concaveBrushCount = 0;

            for (int i = 0; i < brushes.Count; i++)
            {
                if (brushes[i] != null && !brushes[i].IsBrushConvex)
                {
                    concaveBrushCount++;
                }
            }
            if (concaveBrushCount > 0)
            {
                Toolbar.WarningMessage = concaveBrushCount + " Concave Brush" + (concaveBrushCount > 1 ? "es" : "") + " Detected";
            }
            else
            {
                //				Toolbar.WarningMessage = "";
            }

            Toolbar.CSGModel = this;
            Toolbar.OnSceneGUI(sceneView, e);

            if (e.type == EventType.Repaint)            // || e.type == EventType.Layout)
            {
                if (tools[CurrentSettings.CurrentMode].BrushesHandleDrawing)
                {
                    SabreGraphics.GetSelectedBrushMaterial().SetPass(0);
                    // Selection
                    GL.Begin(GL.LINES);
                    Color outlineColor = Color.blue;

                    for (int brushIndex = 0; brushIndex < brushes.Count; brushIndex++)
                    {
                        Brush brush = brushes[brushIndex];
                        if (brush == null)
                        {
                            continue;
                        }
                        GameObject brushGameObject = brush.gameObject;

                        if (!brushGameObject.activeInHierarchy)
                        {
                            continue;
                        }

                        if (Selection.Contains(brushGameObject))
                        {
                            if (brushes[brushIndex].Mode == CSGMode.Add)
                            {
                                outlineColor = Color.cyan;
                            }
                            else
                            {
                                outlineColor = Color.yellow;
                            }
                        }
                        else if (CurrentSettings.BrushesVisible)
                        {
                            if (brushes[brushIndex].Mode == CSGMode.Add)
                            {
                                outlineColor = Color.blue;
                            }
                            else
                            {
                                outlineColor = new Color32(255, 130, 0, 255);
                            }
                        }
                        else
                        {
                            continue;
                        }

                        GL.Color(outlineColor);

                        Polygon[] polygons       = brush.GetPolygons();
                        Transform brushTransform = brush.transform;

                        // Brush Outline
                        for (int i = 0; i < polygons.Length; i++)
                        {
                            Polygon polygon = polygons[i];

                            for (int j = 0; j < polygon.Vertices.Length; j++)
                            {
                                Vector3 position = brushTransform.TransformPoint(polygon.Vertices[j].Position);
                                GL.Vertex(position);

                                if (j < polygon.Vertices.Length - 1)
                                {
                                    Vector3 position2 = brushTransform.TransformPoint(polygon.Vertices[j + 1].Position);
                                    GL.Vertex(position2);
                                }
                                else
                                {
                                    Vector3 position2 = brushTransform.TransformPoint(polygon.Vertices[0].Position);
                                    GL.Vertex(position2);
                                }
                            }
                        }
                    }

                    GL.End();

                    for (int i = 0; i < brushes.Count; i++)
                    {
                        if (brushes[i] is PrimitiveBrush && brushes[i] != null && brushes[i].gameObject.activeInHierarchy)
                        {
                            ((PrimitiveBrush)brushes[i]).OnRepaint(sceneView, e);
                        }
                    }
                }
            }

            if (e.type == EventType.Repaint)
            {
                Rect rect = new Rect(0, 0, Screen.width, Screen.height);
                EditorGUIUtility.AddCursorRect(rect, SabreMouse.ActiveCursor);
            }
            //

            //		int hotControl = GUIUtility.hotControl;
            //		if(hotControl != 0)
            //			Debug.Log (hotControl);
            //		Tools.viewTool = ViewTool.None;

            PrimitiveBrush primitiveBrush = null;

            if (Selection.activeGameObject != null)
            {
                primitiveBrush = Selection.activeGameObject.GetComponent <PrimitiveBrush>();
//				primitiveBrush = Selection.activeGameObject.GetComponentInChildren<PrimitiveBrush>();
            }

            List <PrimitiveBrush> primitiveBrushes = new List <PrimitiveBrush>();

            for (int i = 0; i < Selection.gameObjects.Length; i++)
            {
                PrimitiveBrush[] matchedBrushes = Selection.gameObjects[i].GetComponents <PrimitiveBrush>();
//				PrimitiveBrush[] matchedBrushes = Selection.gameObjects[i].GetComponentsInChildren<PrimitiveBrush>();
                if (matchedBrushes.Length > 0)
                {
                    primitiveBrushes.AddRange(matchedBrushes);
                }
            }

            Tool lastTool = activeTool;

            if (tools.ContainsKey(CurrentSettings.CurrentMode))
            {
                activeTool = tools[CurrentSettings.CurrentMode];
            }
            else
            {
                activeTool = null;
            }

            if (activeTool != null)
            {
                activeTool.CSGModel           = this;
                activeTool.PrimaryTargetBrush = primitiveBrush;
                activeTool.TargetBrushes      = primitiveBrushes.ToArray();
                activeTool.OnSceneGUI(sceneView, e);

                if (activeTool != lastTool)
                {
                    if (lastTool != null)
                    {
                        lastTool.Deactivated();
                    }
                    activeTool.ResetTool();
                }
            }

//			if(e.type == EventType.DragPerform)
//			{
//				Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
//
//				RaycastHit hit = new RaycastHit();
//
//				int layerMask = 1 << LayerMask.NameToLayer("CSGMesh");
//				// Invert the layer mask
//				layerMask = ~layerMask;
//
//				// Shift mode means only add what they click (clicking nothing does nothing)
//				if (Physics.Raycast(ray, out hit, float.PositiveInfinity, layerMask))
//				{
//										OnDragDrop(hit.collider.gameObject);
//				}
//			}

            if (e.type == EventType.MouseDown)
            {
            }
            else if (e.type == EventType.MouseDrag)
            {
            }
            else if (e.type == EventType.MouseUp)
            {
                OnMouseUp(sceneView, e);
                SabreMouse.ResetCursor();
            }
            else if (e.type == EventType.KeyDown || e.type == EventType.KeyUp)
            {
                OnKeyAction(sceneView, e);
            }

            if (CurrentSettings.OverrideFlyCamera)
            {
                LinearFPSCam.OnSceneGUI(sceneView);
            }
        }