// TODO: somehow get rid of this
 public static void Reset()
 {
     s_Points.Clear();
     s_Transformation      = Matrix4x4.identity;
     s_ModelBeneathCursor  = null;
     s_ModifyMode          = false;
     s_DefaultHeight       = 0;
     s_NextHeight          = 0;
     s_LastBounds          = new Bounds();
     GUIUtility.hotControl = 0;
     PointDrawing.Reset();
 }
Ejemplo n.º 2
0
        static void MoveTargetsUnderModel(UnityEngine.Object[] targetObjects, ChiselModel model)
        {
            var modelTransform  = model.transform;
            var modelGameObject = model.gameObject;

            for (int t = 0; t < targetObjects.Length; t++)
            {
                var targetComponent = (targetObjects[t] as MonoBehaviour);
                var targetTransform = targetComponent.transform;
                Undo.SetTransformParent(targetTransform, modelTransform, "Moved GameObject under Model");
            }

            Selection.activeObject         = modelGameObject;
            ChiselModelManager.ActiveModel = model;

            // This forces the model to be opened when we create it
            EditorGUIUtility.PingObject(modelGameObject);
            for (int t = 0; t < targetObjects.Length; t++)
            {
                EditorGUIUtility.PingObject(targetObjects[t]);
            }
        }
        internal static GameObject PickNodeOrGameObject(Camera camera, Vector2 pickposition, int layers, ref GameObject[] ignore, ref GameObject[] filter, out ChiselModel model, out ChiselNode node, out CSGTreeBrushIntersection intersection)
        {
TryNextSelection:
            intersection = new CSGTreeBrushIntersection {
                surfaceID = -1, brushUserID = -1
            };

            model = null;
            node  = null;
            Material sharedMaterial;
            var      gameObject = PickModel(camera, pickposition, layers, ref ignore, ref filter, out model, out sharedMaterial);

            if (object.Equals(gameObject, null))
            {
                return(null);
            }

            if (model)
            {
                int filterLayerParameter0 = (sharedMaterial) ? sharedMaterial.GetInstanceID() : 0;
                {
                    var worldRay       = camera.ScreenPointToRay(pickposition);
                    var worldRayStart  = worldRay.origin;
                    var worldRayVector = (worldRay.direction * (camera.farClipPlane - camera.nearClipPlane));
                    var worldRayEnd    = worldRayStart + worldRayVector;

                    CSGTreeBrushIntersection tempIntersection;
                    if (ChiselSceneQuery.FindFirstWorldIntersection(model, worldRayStart, worldRayEnd, filterLayerParameter0, layers, ignore, filter, out tempIntersection))
                    {
                        var clickedBrush = tempIntersection.brush;
                        node = CSGNodeHierarchyManager.FindCSGNodeByInstanceID(clickedBrush.UserID);
                        if (node)
                        {
                            if (ignore != null &&
                                ignore.Contains(node.gameObject))
                            {
                                node = null;
                                return(null);
                            }
                            intersection = tempIntersection;
                            return(node.gameObject);
                        }
                        else
                        {
                            node = null;
                        }
                    }
                }

                if (ignore == null)
                {
                    return(null);
                }

                ArrayUtility.Add(ref ignore, gameObject);
                goto TryNextSelection;
            }

            if (object.Equals(gameObject, null))
            {
                return(null);
            }

            if (ignore != null &&
                ignore.Contains(gameObject))
            {
                return(null);
            }

            return(gameObject);
        }
        internal static GameObject PickModel(Camera camera, Vector2 pickposition, int layers, ref GameObject[] ignore, ref GameObject[] filter, out ChiselModel model, out Material material)
        {
            model    = null;
            material = null;
            var        flagState       = ChiselGeneratedComponentManager.BeginPicking();
            GameObject gameObject      = null;
            bool       foundGameObject = false;

            try
            {
                int materialIndex = -1;
                if (pickClosestGO == null ||
                    pickClosestGameObjectDelegate == null)
                {
                    gameObject = HandleUtility.PickGameObject(pickposition, ignore, out materialIndex);
                }
                else
                {
                    gameObject = pickClosestGO(camera, layers, pickposition, ignore, filter, out materialIndex);
                }
            }
            finally
            {
                foundGameObject = ChiselGeneratedComponentManager.EndPicking(flagState, gameObject, out model) && model;
            }
            if (object.Equals(gameObject, null))
            {
                return(null);
            }

            if (!foundGameObject)
            {
                return(gameObject);
            }

            var renderer = gameObject.GetComponent <Renderer>();

            if (renderer)
            {
                material = renderer.sharedMaterial;
                if (!material)
                {
                    material = null;
                }
            }
            return(gameObject);
        }
 public PlaneIntersection(CSGTreeBrushIntersection brushIntersection, ChiselNode node, ChiselModel model)
 {
     this.point = brushIntersection.surfaceIntersection.worldIntersection;
     this.plane = brushIntersection.surfaceIntersection.worldPlane;
     this.node  = node;
     this.model = model;
 }
Ejemplo n.º 6
0
        public static ShapeExtrusionState Do(Rect dragArea, out Curve2D shape, out float height, out ChiselModel modelBeneathCursor, out Matrix4x4 transformation, Axis axis)
        {
            try
            {
                if (!s_ExtrusionMode)
                {
                    // TODO: handle snapping against own points
                    // TODO: handle ability to 'commit'
                    PointDrawing.PointDrawHandle(dragArea, ref s_Points, out s_Transformation, out s_ModelBeneathCursor, releaseOnMouseUp: true, UnitySceneExtensions.SceneHandles.OutlinedDotHandleCap);

                    if (s_Points.Count <= 1)
                    {
                        return(ShapeExtrusionState.HoverMode);
                    }

                    if (s_Points.Count <= 3)
                    {
                        return(ShapeExtrusionState.ShapeMode);
                    }

                    if ((s_Points[s_Points.Count - 2] - s_Points[0]).sqrMagnitude < PointDrawing.kDistanceEpsilon)
                    {
                        s_ExtrusionMode = true;
                        s_Points[s_Points.Count - 1] = s_Points[0];
                        return(ShapeExtrusionState.Create);
                    }
                    return(ShapeExtrusionState.ShapeMode);
                }
                else
                {
                    var tempPoint = s_Points[s_Points.Count - 1];
                    var oldMatrix = UnityEditor.Handles.matrix;
                    UnityEditor.Handles.matrix = UnityEditor.Handles.matrix * s_Transformation;
                    var extrusionState = ExtrusionHandle.DoHandle(dragArea, ref tempPoint, axis);
                    UnityEditor.Handles.matrix   = oldMatrix;
                    s_Points[s_Points.Count - 1] = tempPoint;

                    switch (extrusionState)
                    {
                    case ExtrusionState.Cancel:             { s_ExtrusionMode = false; return(ShapeExtrusionState.Cancel); }

                    case ExtrusionState.Commit:             { s_ExtrusionMode = false; return(ShapeExtrusionState.Commit); }

                    case ExtrusionState.Modified:   { return(ShapeExtrusionState.Modified); }
                    }
                    return(ShapeExtrusionState.ExtrusionMode);
                }
            }
            finally
            {
                modelBeneathCursor = s_ModelBeneathCursor;
                transformation     = s_Transformation;
                shape  = GetShape();
                height = GetHeight(axis);
            }
        }
Ejemplo n.º 7
0
        public static BoxExtrusionState Do(Rect dragArea, out Bounds bounds, out float height, out ChiselModel modelBeneathCursor, out Matrix4x4 transformation, BoxExtrusionFlags flags, Axis axis, float?snappingSteps = null)
        {
            try
            {
                if (SceneHandles.InCameraOrbitMode)
                {
                    return(BoxExtrusionState.None);
                }

                if (s_Points.Count <= 2)
                {
                    PointDrawing.PointDrawHandle(dragArea, ref s_Points, out s_Transformation, out s_ModelBeneathCursor, UnitySceneExtensions.SceneHandles.OutlinedDotHandleCap);

                    if (s_Points.Count <= 1)
                    {
                        return(BoxExtrusionState.HoverMode);
                    }

                    if (s_Points.Count > 2)
                    {
                        s_Points[2] = s_Points[0];
                        return(BoxExtrusionState.Create);
                    }

                    return(BoxExtrusionState.SquareMode);
                }
                else
                {
                    var tempPoint = s_Points[2];
                    var oldMatrix = UnityEditor.Handles.matrix;
                    UnityEditor.Handles.matrix = UnityEditor.Handles.matrix * s_Transformation;
                    var extrusionState = ExtrusionHandle.DoHandle(dragArea, ref tempPoint, axis, snappingSteps: snappingSteps);
                    UnityEditor.Handles.matrix = oldMatrix;
                    s_Points[2] = tempPoint;

                    switch (extrusionState)
                    {
                    case ExtrusionState.Cancel:             { return(BoxExtrusionState.Cancel); }

                    case ExtrusionState.Commit:             { return(BoxExtrusionState.Commit); }

                    case ExtrusionState.Modified:   { return(BoxExtrusionState.Modified); }
                    }
                    return(BoxExtrusionState.BoxMode);
                }
            }
            finally
            {
                modelBeneathCursor = s_ModelBeneathCursor;
                bounds             = GetBounds(flags, axis);
                height             = GetHeight(axis);

                var center = bounds.center;
                if ((flags & BoxExtrusionFlags.GenerateFromCenterY) != BoxExtrusionFlags.GenerateFromCenterY)
                {
                    center[(int)axis] -= height * 0.5f;
                }

                transformation = s_Transformation * Matrix4x4.TRS(center, Quaternion.identity, Vector3.one);
#if true
                //if (height > 0)
                {
                    if ((flags & BoxExtrusionFlags.AlwaysFaceUp) == BoxExtrusionFlags.AlwaysFaceUp)
                    {
                        var currentUp      = transformation.MultiplyVector(Vector3.up);
                        var currentForward = transformation.MultiplyVector(Vector3.forward);
                        var currentRight   = transformation.MultiplyVector(Vector3.right);

                        var desiredUp = Grid.ActiveGrid.Up;

                        var dotX = Vector3.Dot(currentRight, desiredUp);
                        var dotY = Vector3.Dot(currentUp, desiredUp);
                        var dotZ = Vector3.Dot(currentForward, desiredUp);

                        var absDotX = Mathf.Abs(dotX);
                        var absDotY = Mathf.Abs(dotY);
                        var absDotZ = Mathf.Abs(dotZ);

                        if (absDotX > absDotZ)
                        {
                            if (absDotX > absDotY)
                            {
                                var size = bounds.size;
                                var t    = size.x; size.x = size.y; size.y = t;
                                bounds.size = size;
                                axis        = Axis.X;
                                var position = transformation.GetColumn(3);
                                transformation.SetColumn(3, new Vector4(0, 0, 0, 1));
                                transformation *= Matrix4x4.TRS(position, Quaternion.identity, Vector3.one);
                                transformation *= new Matrix4x4(new Vector4(0, 1, 0, 0),
                                                                new Vector4(1, 0, 0, 0),
                                                                new Vector4(0, 0, 1, 0),
                                                                new Vector4(0, 0, 0, 1));
                                transformation.SetColumn(3, position);
                            }
                        }
                        else
                        {
                            if (absDotZ > absDotY)
                            {
                                var size = bounds.size;
                                var t    = size.z; size.z = size.y; size.y = t;
                                bounds.size = size;
                                axis        = Axis.Z;
                                var position = transformation.GetColumn(3);
                                transformation.SetColumn(3, new Vector4(0, 0, 0, 1));
                                transformation *= Matrix4x4.TRS(position, Quaternion.identity, Vector3.one);
                                transformation *= new Matrix4x4(new Vector4(1, 0, 0, 0),
                                                                new Vector4(0, 0, 1, 0),
                                                                new Vector4(0, 1, 0, 0),
                                                                new Vector4(0, 0, 0, 1));
                                transformation.SetColumn(3, position);
                            }
                        }
                    }

                    if (!s_ModelBeneathCursor &&
                        (flags & BoxExtrusionFlags.AlwaysFaceCameraXZ) == BoxExtrusionFlags.AlwaysFaceCameraXZ)
                    {
                        // TODO: take grid orientation into account to decide what is "X" and what is "Z"
                        var currentForward = transformation.MultiplyVector(Vector3.forward);
                        var currentRight   = transformation.MultiplyVector(Vector3.right);
                        var cameraOffset   = Camera.current.transform.forward;
                        var cameraForward  = (new Vector3(cameraOffset.x, 0, cameraOffset.z)).normalized;
                        var dotZ           = Vector3.Dot(currentForward, cameraForward);
                        var dotX           = Vector3.Dot(currentRight, cameraForward);

                        var angle = 0;
                        if (Mathf.Abs(dotX) < Mathf.Abs(dotZ))
                        {
                            if (dotZ > 0)
                            {
                                angle += 180;
                            }
                        }
                        else
                        {
                            if (dotX < 0)
                            {
                                angle += 90;
                            }
                            else
                            {
                                angle -= 90;
                            }

                            if (axis == Axis.X)
                            {
                                axis = Axis.Z;
                            }
                            var size = bounds.size;
                            var t    = size.x; size.x = size.z; size.z = t;
                            bounds.size = size;
                        }

                        var position = transformation.GetColumn(3);
                        transformation.SetColumn(3, new Vector4(0, 0, 0, 1));
                        transformation *= Matrix4x4.TRS(position, Quaternion.identity, Vector3.one);
                        transformation *= Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0, angle, 0), Vector3.one);
                        transformation.SetColumn(3, position);
                    }
                }
#endif

                center = Vector3.zero;
                if ((flags & BoxExtrusionFlags.GenerateFromCenterY) != BoxExtrusionFlags.GenerateFromCenterY)
                {
                    center[(int)axis] = height * 0.5f;
                }
                bounds.center = center;
            }
        }
        static GameObject PickNodeOrGameObject(Camera camera, Vector2 pickposition, int layers, ref GameObject[] ignore, ref GameObject[] filter, out ChiselModel model, out ChiselNode node, out ChiselIntersection intersection)
        {
TryNextSelection:
            intersection = ChiselIntersection.None;

            node = null;
            Material sharedMaterial;
            var      gameObject = PickModelOrGameObject(camera, pickposition, layers, ref ignore, ref filter, out model, out sharedMaterial);

            if (object.Equals(gameObject, null))
            {
                return(null);
            }

            if (ChiselGeneratedComponentManager.IsValidModelToBeSelected(model))
            {
                int filterLayerParameter0 = (sharedMaterial) ? sharedMaterial.GetInstanceID() : 0;
                {
                    var worldRay       = camera.ScreenPointToRay(pickposition);
                    var worldRayStart  = worldRay.origin;
                    var worldRayVector = (worldRay.direction * (camera.farClipPlane - camera.nearClipPlane));
                    var worldRayEnd    = worldRayStart + worldRayVector;

                    if (ChiselSceneQuery.FindFirstWorldIntersection(model, worldRayStart, worldRayEnd, filterLayerParameter0, layers, ignore, filter, out var tempIntersection))
                    {
                        node = tempIntersection.node;
                        if (node)
                        {
                            if (ignore != null &&
                                ignore.Contains(node.gameObject))
                            {
                                node = null;
                                return(null);
                            }
                            intersection = tempIntersection;
                            return(node.gameObject);
                        }
                        else
                        {
                            node = null;
                        }
                    }
                }

                if (ignore == null)
                {
                    return(null);
                }

                ArrayUtility.Add(ref ignore, gameObject);
                goto TryNextSelection;
            }

            if (object.Equals(gameObject, null))
            {
                return(null);
            }

            if (ignore != null &&
                ignore.Contains(gameObject))
            {
                return(null);
            }

            return(gameObject);
        }
        static GameObject PickModelOrGameObject(Camera camera, Vector2 pickposition, int layers, ref GameObject[] ignore, ref GameObject[] filter, out ChiselModel model, out Material material)
        {
            model    = null;
            material = null;
            var        flagState       = ChiselGeneratedComponentManager.BeginPicking();
            GameObject gameObject      = null;
            bool       foundGameObject = false;
            int        materialIndex   = -1;

            try
            {
                if (PickClosestGO == null)
                {
                    gameObject = HandleUtility.PickGameObject(pickposition, ignore, out materialIndex);
                }
                else
                {
                    gameObject = PickClosestGO(camera, layers, pickposition, ignore, filter, out materialIndex);
                }
            }
            finally
            {
                foundGameObject = ChiselGeneratedComponentManager.EndPicking(flagState, gameObject, out model) && model;
            }
            if (object.Equals(gameObject, null))
            {
                return(null);
            }

            if (!foundGameObject)
            {
                return(gameObject);
            }

            if (materialIndex >= 0 &&
                gameObject.TryGetComponent <Renderer>(out var renderer))
            {
                renderer.GetSharedMaterials(sSharedMaterials);
                material = materialIndex < sSharedMaterials.Count ? sSharedMaterials[materialIndex] : null;
                sSharedMaterials.Clear(); // We don't want to keep references to Materials alive
                if (!material)
                {
                    material = null;
                }
            }
            return(gameObject);
        }
Ejemplo n.º 10
0
        public static void Do(int id, Rect dragArea, ref List <Vector3> points, out Matrix4x4 transformation, out ChiselModel modelBeneathCursor, UnitySceneExtensions.SceneHandles.CapFunction capFunction)
        {
            modelBeneathCursor = null;
            var evt  = Event.current;
            var type = evt.GetTypeForControl(id);

            switch (type)
            {
            case EventType.ValidateCommand: { if (evt.commandName == kSoftDeleteCommand)
                                              {
                                                  evt.Use(); break;
                                              }
                                              break; }

            case EventType.ExecuteCommand:  { if (evt.commandName == kSoftDeleteCommand)
                                              {
                                                  Cancel(evt, ref points); break;
                                              }
                                              break; }

            case EventType.KeyDown:                 { if (evt.keyCode == kCancelKey ||
                                                          evt.keyCode == kCommitKey)
                                                      {
                                                          evt.Use(); break;
                                                      }
                                                      break; }

            case EventType.KeyUp:                   { if (evt.keyCode == kCancelKey)
                                                      {
                                                          Cancel(evt, ref points); break;
                                                      }
                                                      else
                                                      if (evt.keyCode == kCommitKey)
                                                      {
                                                          Commit(evt, dragArea, ref points); break;
                                                      }
                                                      break; }

            case EventType.Layout:
            {
                if (SceneHandles.InCameraOrbitMode)
                {
                    break;
                }

                if (s_StartIntersection == null)
                {
                    break;
                }

                // We set the id at the maximum handle distance so that other things, such as the axis gizmo,
                // will block the click to create a point. If we don't we wouldn't be able to use the axis gizmo.
                UnityEditor.HandleUtility.AddControl(id, kMaxHandleDistance);
                break;
            }

            case EventType.Repaint:
            {
                if (s_StartIntersection == null)
                {
                    break;
                }

                if (points.Count == 0)
                {
                    break;
                }

                if (SceneHandleUtility.focusControl != id)
                {
                    break;
                }

                using (new UnityEditor.Handles.DrawingScope(Matrix4x4.identity))
                {
                    var orientation = s_StartIntersection.orientation;
                    if (capFunction != null)
                    {
                        using (new UnityEditor.Handles.DrawingScope(s_Transform))
                        {
                            for (int i = 0; i < points.Count; i++)
                            {
                                capFunction(id, points[i], orientation, UnityEditor.HandleUtility.GetHandleSize(points[i]) * kPointScale, type);
                            }
                        }
                    }

                    var selectedColor = UnityEditor.Handles.selectedColor;
                    selectedColor.a = 0.5f;
                    using (new UnityEditor.Handles.DrawingScope(selectedColor))
                    {
                        HandleRendering.RenderSnapping3D(s_Snapping2D.WorldSlideGrid, s_Snapping2D.WorldSnappedExtents, s_Snapping2D.GridSnappedPosition, s_Snapping2D.SnapResult, true);
                    }
                }
                break;
            }

            case EventType.MouseMove:
            {
                if (GUIUtility.hotControl != 0 &&
                    GUIUtility.hotControl != id)
                {
                    break;
                }

                UpdatePoints(points, GetPointAtPosition(evt.mousePosition, dragArea));
                SceneView.RepaintAll();
                break;
            }

            case EventType.MouseDrag:
            {
                if (GUIUtility.hotControl != id)
                {
                    break;
                }

                UpdatePoints(points, GetPointAtPosition(evt.mousePosition, dragArea));
                GUI.changed = true;
                evt.Use();
                break;
            }

            case EventType.MouseDown:
            {
                if (SceneHandles.InCameraOrbitMode)
                {
                    break;
                }

                if (GUIUtility.hotControl != 0)
                {
                    break;
                }

                if ((UnityEditor.HandleUtility.nearestControl != id || evt.button != 0) &&
                    (GUIUtility.keyboardControl != id || evt.button != 2))
                {
                    break;
                }

                if (s_StartIntersection == null)
                {
                    break;
                }

                s_CurrentPointIndex++;
                GUIUtility.hotControl = GUIUtility.keyboardControl = id;
                EditorGUIUtility.SetWantsMouseJumping(1);
                evt.Use();
                break;
            }

            case EventType.MouseUp:
            {
                if (GUIUtility.hotControl != id || (evt.button != 0 && evt.button != 2))
                {
                    break;
                }

                GUIUtility.hotControl      = 0;
                GUIUtility.keyboardControl = 0;
                evt.Use();
                EditorGUIUtility.SetWantsMouseJumping(0);

                // reset the starting position
                UpdatePoints(points, GetPointAtPosition(evt.mousePosition, dragArea));
                break;
            }
            }
            if (s_StartIntersection != null)
            {
                modelBeneathCursor = s_StartIntersection.model;
                transformation     = s_Transform;
            }
            else
            {
                transformation = Matrix4x4.identity;
            }
        }
Ejemplo n.º 11
0
        public static void PointDrawHandle(Rect dragArea, ref List <Vector3> points, out Matrix4x4 transformation, out ChiselModel modelBeneathCursor, UnitySceneExtensions.SceneHandles.CapFunction capFunction)
        {
            var id = GUIUtility.GetControlID(s_PointDrawingHash, FocusType.Keyboard);

            PointDrawing.Do(id, dragArea, ref points, out transformation, out modelBeneathCursor, capFunction);
        }
        public static BoxExtrusionState Do(Rect dragArea, out Bounds bounds, out float height, out ChiselModel modelBeneathCursor, out Matrix4x4 transformation, BoxExtrusionFlags flags, Axis axis, float?snappingSteps = null)
        {
            try
            {
                if (SceneHandles.InCameraOrbitMode)
                {
                    return(BoxExtrusionState.None);
                }

                if (s_Points.Count <= 2)
                {
                    PointDrawing.PointDrawHandle(dragArea, ref s_Points, out s_Transformation, out s_ModelBeneathCursor, UnitySceneExtensions.SceneHandles.OutlinedDotHandleCap);

                    if (s_Points.Count <= 1)
                    {
                        return(BoxExtrusionState.HoverMode);
                    }

                    if (s_Points.Count > 2)
                    {
                        s_Points[2] = s_Points[0];
                        return(BoxExtrusionState.Create);
                    }

                    return(BoxExtrusionState.SquareMode);
                }
                else
                {
                    var tempPoint = s_Points[2];
                    var oldMatrix = UnityEditor.Handles.matrix;
                    UnityEditor.Handles.matrix = UnityEditor.Handles.matrix * s_Transformation;
                    var extrusionState = ExtrusionHandle.DoHandle(dragArea, ref tempPoint, axis, snappingSteps: snappingSteps);
                    UnityEditor.Handles.matrix = oldMatrix;
                    s_Points[2] = tempPoint;

                    switch (extrusionState)
                    {
                    case ExtrusionState.Cancel:             { return(BoxExtrusionState.Cancel); }

                    case ExtrusionState.Commit:             { return(BoxExtrusionState.Commit); }

                    case ExtrusionState.Modified:   { return(BoxExtrusionState.Modified); }
                    }
                    return(BoxExtrusionState.BoxMode);
                }
            }
            finally
            {
                modelBeneathCursor = s_ModelBeneathCursor;
                bounds             = GetBounds(flags, axis);
                height             = GetHeight(axis);

                var center = bounds.center;
                if ((flags & BoxExtrusionFlags.GenerateFromCenterY) != BoxExtrusionFlags.GenerateFromCenterY)
                {
                    center[(int)axis] -= height * 0.5f;
                }

                transformation = s_Transformation * Matrix4x4.TRS(center, Quaternion.identity, Vector3.one);

                center = Vector3.zero;
                if ((flags & BoxExtrusionFlags.GenerateFromCenterY) != BoxExtrusionFlags.GenerateFromCenterY)
                {
                    center[(int)axis] = height * 0.5f;
                }
                bounds.center = center;
            }
        }
        /// <summary>
        /// Imports the specified world into the Chisel model.
        /// </summary>
        /// <param name="model">The model to import into.</param>
        /// <param name="world">The world to be imported.</param>
        public static void Import(ChiselModel model, VmfWorld world)
        {
            // create a material searcher to associate materials automatically.
            MaterialSearcher materialSearcher         = new MaterialSearcher();
            HashSet <string> materialSearcherWarnings = new HashSet <string>();

            // iterate through all world solids.
            for (int i = 0; i < world.Solids.Count; i++)
            {
#if UNITY_EDITOR
                UnityEditor.EditorUtility.DisplayProgressBar("Chisel: Importing Source Engine Map (1/3)", "Converting Hammer Solids To Chisel Brushes (" + (i + 1) + " / " + world.Solids.Count + ")...", i / (float)world.Solids.Count);
#endif
                VmfSolid solid = world.Solids[i];

                // don't add triggers to the scene.
                if (solid.Sides.Count > 0 && IsSpecialMaterial(solid.Sides[0].Material))
                {
                    continue;
                }

                // HACK: Fix me in the future!
                // HACK: Chisel doesn't support collision brushes yet- skip them completely!
                if (solid.Sides.Count > 0 && IsInvisibleMaterial(solid.Sides[0].Material))
                {
                    continue;
                }
                // HACK: Fix me in the future!

                // build a very large cube brush.
                ChiselBrush go = ChiselComponentFactory.Create <ChiselBrush>(model);
                go.definition.surfaceDefinition = new ChiselSurfaceDefinition();
                go.definition.surfaceDefinition.EnsureSize(6);
                BrushMesh brushMesh = new BrushMesh();
                go.definition.brushOutline = brushMesh;
                BrushMeshFactory.CreateBox(ref brushMesh, new Vector3(-4096, -4096, -4096), new Vector3(4096, 4096, 4096), in go.definition.surfaceDefinition);

                // prepare for any displacements.
                List <DisplacementSide> DisplacementSurfaces = new List <DisplacementSide>();

                // prepare for uv calculations of clip planes after cutting.
                var planes        = new float4[solid.Sides.Count];
                var planeSurfaces = new ChiselSurface[solid.Sides.Count];

                // compute all the sides of the brush that will be clipped.
                for (int j = solid.Sides.Count; j-- > 0;)
                {
                    VmfSolidSide side = solid.Sides[j];

                    // detect excluded polygons.
                    //if (IsExcludedMaterial(side.Material))
                    //polygon.UserExcludeFromFinal = true;
                    // detect collision-only brushes.
                    //if (IsInvisibleMaterial(side.Material))
                    //pr.IsVisible = false;

                    // find the material in the unity project automatically.
                    Material material;

                    // try finding the fully qualified texture name with '/' replaced by '.' so 'BRICK.BRICKWALL052D'.
                    string materialName = side.Material.Replace("/", ".");
                    if (materialName.Contains("."))
                    {
                        // try finding both 'BRICK.BRICKWALL052D' and 'BRICKWALL052D'.
                        string tiny = materialName.Substring(materialName.LastIndexOf('.') + 1);
                        material = materialSearcher.FindMaterial(new string[] { materialName, tiny });
                        if (material == null && materialSearcherWarnings.Add(materialName))
                        {
                            Debug.Log("Chisel: Tried to find material '" + materialName + "' and also as '" + tiny + "' but it couldn't be found in the project.");
                        }
                    }
                    else
                    {
                        // only try finding 'BRICKWALL052D'.
                        material = materialSearcher.FindMaterial(new string[] { materialName });
                        if (material == null && materialSearcherWarnings.Add(materialName))
                        {
                            Debug.Log("Chisel: Tried to find material '" + materialName + "' but it couldn't be found in the project.");
                        }
                    }

                    // fallback to default material.
                    if (material == null)
                    {
                        material = ChiselMaterialManager.DefaultFloorMaterial;
                    }

                    // create chisel surface for the clip.
                    ChiselSurface surface = new ChiselSurface();
                    surface.brushMaterial      = ChiselBrushMaterial.CreateInstance(material, ChiselMaterialManager.DefaultPhysicsMaterial);
                    surface.surfaceDescription = SurfaceDescription.Default;

                    // detect collision-only polygons.
                    if (IsInvisibleMaterial(side.Material))
                    {
                        surface.brushMaterial.LayerUsage &= ~LayerUsageFlags.RenderReceiveCastShadows;
                    }
                    // detect excluded polygons.
                    if (IsExcludedMaterial(side.Material))
                    {
                        surface.brushMaterial.LayerUsage &= LayerUsageFlags.CastShadows;
                        surface.brushMaterial.LayerUsage |= LayerUsageFlags.Collidable;
                    }

                    // calculate the clipping planes.
                    Plane clip = new Plane(go.transform.InverseTransformPoint(new Vector3(side.Plane.P1.X, side.Plane.P1.Z, side.Plane.P1.Y) * inchesInMeters), go.transform.InverseTransformPoint(new Vector3(side.Plane.P2.X, side.Plane.P2.Z, side.Plane.P2.Y) * inchesInMeters), go.transform.InverseTransformPoint(new Vector3(side.Plane.P3.X, side.Plane.P3.Z, side.Plane.P3.Y) * inchesInMeters));
                    planes[j]        = new float4(clip.normal, clip.distance);
                    planeSurfaces[j] = surface;

                    // check whether this surface is a displacement.
                    if (side.Displacement != null)
                    {
                        // disable the brush.
                        go.gameObject.GetComponent <ChiselBrush>().enabled = false;

                        // keep track of the surface used to cut the mesh.
                        DisplacementSurfaces.Add(new DisplacementSide {
                            side = side, surface = surface
                        });
                    }
                }

                // cut all the clipping planes out of the brush in one go.
                brushMesh.Cut(planes, planeSurfaces);

                // now iterate over the planes to calculate UV coordinates.
                int[] indices = new int[solid.Sides.Count];
                for (int k = 0; k < planes.Length; k++)
                {
                    var   plane           = planes[k];
                    int   closestIndex    = 0;
                    float closestDistance = math.lengthsq(plane - brushMesh.planes[0]);
                    for (int j = 1; j < brushMesh.planes.Length; j++)
                    {
                        float testDistance = math.lengthsq(plane - brushMesh.planes[j]);
                        if (testDistance < closestDistance)
                        {
                            closestIndex    = j;
                            closestDistance = testDistance;
                        }
                    }
                    indices[k] = closestIndex;
                }

                for (int j = 0; j < indices.Length; j++)
                {
                    brushMesh.planes[indices[j]] = planes[j];
                }

                for (int j = solid.Sides.Count; j-- > 0;)
                {
                    VmfSolidSide side     = solid.Sides[j];
                    var          surface  = brushMesh.polygons[indices[j]].surface;
                    var          material = surface.brushMaterial.RenderMaterial;

                    // calculate the texture coordinates.
                    int w = 256;
                    int h = 256;
                    if (material.mainTexture != null)
                    {
                        w = material.mainTexture.width;
                        h = material.mainTexture.height;
                    }
                    var clip = new Plane(planes[j].xyz, planes[j].w);
                    CalculateTextureCoordinates(go, surface, clip, w, h, side.UAxis, side.VAxis);
                }

                // build displacements.
                foreach (DisplacementSide displacement in DisplacementSurfaces)
                {
                    // find the brush mesh polygon:
                    for (int polyidx = 0; polyidx < brushMesh.polygons.Length; polyidx++)
                    {
                        if (brushMesh.polygons[polyidx].surface == displacement.surface)
                        {
                            // find the polygon plane.
                            Plane plane = new Plane(brushMesh.planes[polyidx].xyz, brushMesh.planes[polyidx].w);

                            // find all vertices that belong to this polygon:
                            List <Vector3> vertices = new List <Vector3>();
                            {
                                var polygon   = brushMesh.polygons[polyidx];
                                var firstEdge = polygon.firstEdge;
                                var edgeCount = polygon.edgeCount;
                                var lastEdge  = firstEdge + edgeCount;
                                for (int e = firstEdge; e < lastEdge; e++)
                                {
                                    vertices.Add(brushMesh.vertices[brushMesh.halfEdges[e].vertexIndex]);
                                }
                            }
                            // reverse the winding order.
                            vertices.Reverse();

                            var first = vertices[0];
                            vertices.RemoveAt(0);
                            vertices.Add(first);

                            // build displacement:
                            BuildDisplacementSurface(go, displacement.side, displacement.surface, vertices, plane);
                        }
                    }
                }

                // finalize the brush by snapping planes and centering the pivot point.
                go.transform.position += brushMesh.CenterAndSnapPlanes();
                foreach (Transform child in go.transform)
                {
                    child.position -= go.transform.position;
                }
            }

            // iterate through all entities.
            for (int e = 0; e < world.Entities.Count; e++)
            {
#if UNITY_EDITOR
                UnityEditor.EditorUtility.DisplayProgressBar("Chisel: Importing Source Engine Map (2/3)", "Converting Hammer Entities To Chisel Brushes (" + (e + 1) + " / " + world.Entities.Count + ")...", e / (float)world.Entities.Count);
#endif
                VmfEntity entity = world.Entities[e];

                // skip entities that chisel can't handle.
                switch (entity.ClassName)
                {
                case "func_areaportal":
                case "func_areaportalwindow":
                case "func_capturezone":
                case "func_changeclass":
                case "func_combine_ball_spawner":
                case "func_dustcloud":
                case "func_dustmotes":
                case "func_nobuild":
                case "func_nogrenades":
                case "func_occluder":
                case "func_precipitation":
                case "func_proprespawnzone":
                case "func_regenerate":
                case "func_respawnroom":
                case "func_smokevolume":
                case "func_viscluster":
                    continue;
                }

                // iterate through all entity solids.
                for (int i = 0; i < entity.Solids.Count; i++)
                {
                    VmfSolid solid = entity.Solids[i];

                    // don't add triggers to the scene.
                    if (solid.Sides.Count > 0 && IsSpecialMaterial(solid.Sides[0].Material))
                    {
                        continue;
                    }

                    // HACK: Fix me in the future!
                    // HACK: Chisel doesn't support collision brushes yet- skip them completely!
                    if (solid.Sides.Count > 0 && IsInvisibleMaterial(solid.Sides[0].Material))
                    {
                        continue;
                    }
                    // HACK: Fix me in the future!

                    // build a very large cube brush.
                    ChiselBrush go = ChiselComponentFactory.Create <ChiselBrush>(model);
                    go.definition.surfaceDefinition = new ChiselSurfaceDefinition();
                    go.definition.surfaceDefinition.EnsureSize(6);
                    BrushMesh brushMesh = new BrushMesh();
                    go.definition.brushOutline = brushMesh;
                    BrushMeshFactory.CreateBox(ref brushMesh, new Vector3(-4096, -4096, -4096), new Vector3(4096, 4096, 4096), in go.definition.surfaceDefinition);

                    // prepare for uv calculations of clip planes after cutting.
                    var planes        = new float4[solid.Sides.Count];
                    var planeSurfaces = new ChiselSurface[solid.Sides.Count];

                    // clip all the sides out of the brush.
                    for (int j = solid.Sides.Count; j-- > 0;)
                    {
                        VmfSolidSide side = solid.Sides[j];

                        // detect excluded polygons.
                        //if (IsExcludedMaterial(side.Material))
                        //    polygon.UserExcludeFromFinal = true;
                        // detect collision-only brushes.
                        //if (IsInvisibleMaterial(side.Material))
                        //    pr.IsVisible = false;

                        // find the material in the unity project automatically.
                        Material material;

                        // try finding the fully qualified texture name with '/' replaced by '.' so 'BRICK.BRICKWALL052D'.
                        string materialName = side.Material.Replace("/", ".");
                        if (materialName.Contains("."))
                        {
                            // try finding both 'BRICK.BRICKWALL052D' and 'BRICKWALL052D'.
                            string tiny = materialName.Substring(materialName.LastIndexOf('.') + 1);
                            material = materialSearcher.FindMaterial(new string[] { materialName, tiny });
                            if (material == null && materialSearcherWarnings.Add(materialName))
                            {
                                Debug.Log("Chisel: Tried to find material '" + materialName + "' and also as '" + tiny + "' but it couldn't be found in the project.");
                            }
                        }
                        else
                        {
                            // only try finding 'BRICKWALL052D'.
                            material = materialSearcher.FindMaterial(new string[] { materialName });
                            if (material == null && materialSearcherWarnings.Add(materialName))
                            {
                                Debug.Log("Chisel: Tried to find material '" + materialName + "' but it couldn't be found in the project.");
                            }
                        }

                        // fallback to default material.
                        if (material == null)
                        {
                            material = ChiselMaterialManager.DefaultFloorMaterial;
                        }

                        // create chisel surface for the clip.
                        ChiselSurface surface = new ChiselSurface();
                        surface.brushMaterial      = ChiselBrushMaterial.CreateInstance(material, ChiselMaterialManager.DefaultPhysicsMaterial);
                        surface.surfaceDescription = SurfaceDescription.Default;

                        // detect collision-only polygons.
                        if (IsInvisibleMaterial(side.Material))
                        {
                            surface.brushMaterial.LayerUsage &= ~LayerUsageFlags.RenderReceiveCastShadows;
                        }
                        // detect excluded polygons.
                        if (IsExcludedMaterial(side.Material))
                        {
                            surface.brushMaterial.LayerUsage &= LayerUsageFlags.CastShadows;
                            surface.brushMaterial.LayerUsage |= LayerUsageFlags.Collidable;
                        }

                        // calculate the clipping planes.
                        Plane clip = new Plane(go.transform.InverseTransformPoint(new Vector3(side.Plane.P1.X, side.Plane.P1.Z, side.Plane.P1.Y) * inchesInMeters), go.transform.InverseTransformPoint(new Vector3(side.Plane.P2.X, side.Plane.P2.Z, side.Plane.P2.Y) * inchesInMeters), go.transform.InverseTransformPoint(new Vector3(side.Plane.P3.X, side.Plane.P3.Z, side.Plane.P3.Y) * inchesInMeters));
                        planes[j]        = new float4(clip.normal, clip.distance);
                        planeSurfaces[j] = surface;
                    }

                    // cut all the clipping planes out of the brush in one go.
                    brushMesh.Cut(planes, planeSurfaces);

                    // now iterate over the planes to calculate UV coordinates.
                    int[] indices = new int[solid.Sides.Count];
                    for (int k = 0; k < planes.Length; k++)
                    {
                        var   plane           = planes[k];
                        int   closestIndex    = 0;
                        float closestDistance = math.lengthsq(plane - brushMesh.planes[0]);
                        for (int j = 1; j < brushMesh.planes.Length; j++)
                        {
                            float testDistance = math.lengthsq(plane - brushMesh.planes[j]);
                            if (testDistance < closestDistance)
                            {
                                closestIndex    = j;
                                closestDistance = testDistance;
                            }
                        }
                        indices[k] = closestIndex;
                    }

                    for (int j = 0; j < indices.Length; j++)
                    {
                        brushMesh.planes[indices[j]] = planes[j];
                    }

                    for (int j = solid.Sides.Count; j-- > 0;)
                    {
                        VmfSolidSide side     = solid.Sides[j];
                        var          surface  = brushMesh.polygons[indices[j]].surface;
                        var          material = surface.brushMaterial.RenderMaterial;

                        // calculate the texture coordinates.
                        int w = 256;
                        int h = 256;
                        if (material.mainTexture != null)
                        {
                            w = material.mainTexture.width;
                            h = material.mainTexture.height;
                        }
                        var clip = new Plane(planes[j].xyz, planes[j].w);
                        CalculateTextureCoordinates(go, surface, clip, w, h, side.UAxis, side.VAxis);
                    }

                    // finalize the brush by snapping planes and centering the pivot point.
                    go.transform.position += brushMesh.CenterAndSnapPlanes();

                    // detail brushes that do not affect the CSG world.
                    //if (entity.ClassName == "func_detail")
                    //pr.IsNoCSG = true;
                    // collision only brushes.
                    //if (entity.ClassName == "func_vehicleclip")
                    //pr.IsVisible = false;
                }
            }
        }
        public static GeneratorModeState Do(Rect dragArea, out Bounds bounds, out float height, out ChiselModel modelBeneathCursor, out Matrix4x4 transformation, PlacementFlags flags, Axis upAxis, float?snappingSteps = null)
        {
            // TODO: shift should do SameLengthXZ, shift control includes Y
            // TODO: fixed height should be possible to change sign

            // TODO: have some sort of click placement of previously used bounds (alt?)
            //bounds = s_LastBounds;

            bool doCommit = false;

            try
            {
                if (SceneHandles.InCameraOrbitMode)
                {
                    return(GeneratorModeState.None);
                }

                height = GetHeight(flags, upAxis);
                if (s_Points.Count <= 2)
                {
                    PointDrawing.PointDrawHandle(dragArea, ref s_Points, out s_Transformation, out s_ModelBeneathCursor, releaseOnMouseUp: false, UnitySceneExtensions.SceneHandles.OutlinedDotHandleCap);
                    if (s_Points.Count <= 1)
                    {
                        return(GeneratorModeState.None);
                    }
                }
                if (s_Points.Count > 2)
                {
                    if (!s_ModifyMode)
                    {
                        PointDrawing.Release();
                        if ((flags & PlacementFlags.HeightEqualsHalfXZ) == PlacementFlags.HeightEqualsHalfXZ ||
                            (flags & PlacementFlags.HeightEqualsXZ) == PlacementFlags.HeightEqualsXZ ||
                            (flags & PlacementFlags.UseLastHeight) == PlacementFlags.UseLastHeight)
                        {
                            if (height > 0)
                            {
                                s_ModifyMode = false;
                                doCommit     = true;
                                return(GeneratorModeState.Commit);
                            }
                        }

                        s_Points[2]  = s_Points[1];
                        s_ModifyMode = true;
                        return(GeneratorModeState.Update);
                    }
                    if (s_ModifyMode)
                    {
                        var oldMatrix = UnityEditor.Handles.matrix;
                        UnityEditor.Handles.matrix *= s_Transformation;
                        var tempPoint      = s_Points[2];
                        var extrusionState = ExtrusionHandle.DoHandle(ref tempPoint, upAxis, snappingSteps: snappingSteps);
                        s_Points[2] = tempPoint;
                        UnityEditor.Handles.matrix = oldMatrix;

                        switch (extrusionState)
                        {
                        case ExtrusionState.Cancel:     { s_ModifyMode = false; return(GeneratorModeState.Cancel); }

                        case ExtrusionState.Commit:
                        {
                            s_ModifyMode = false;
                            doCommit     = true;
                            return(GeneratorModeState.Commit);
                        }
                        }
                    }
                }
                return(GeneratorModeState.Update);
            }
            finally
            {
                modelBeneathCursor = s_ModelBeneathCursor;
                bounds             = GetBounds(flags, upAxis);
                height             = bounds.size[(int)upAxis];

                var center = bounds.center;
                if ((flags & PlacementFlags.GenerateFromCenterY) != PlacementFlags.GenerateFromCenterY)
                {
                    center[(int)upAxis] -= height * 0.5f;
                }

                transformation = s_Transformation * Matrix4x4.TRS(center, Quaternion.identity, Vector3.one);
#if true
                //if (height > 0)
                {
                    if ((flags & PlacementFlags.AlwaysFaceUp) == PlacementFlags.AlwaysFaceUp)
                    {
                        var currentUp      = transformation.MultiplyVector(Vector3.up);
                        var currentForward = transformation.MultiplyVector(Vector3.forward);
                        var currentRight   = transformation.MultiplyVector(Vector3.right);

                        var desiredUp = Grid.ActiveGrid.Up;

                        var dotX = Vector3.Dot(currentRight, desiredUp);
                        var dotY = Vector3.Dot(currentUp, desiredUp);
                        var dotZ = Vector3.Dot(currentForward, desiredUp);

                        var absDotX = Mathf.Abs(dotX);
                        var absDotY = Mathf.Abs(dotY);
                        var absDotZ = Mathf.Abs(dotZ);

                        if (absDotX > absDotZ)
                        {
                            if (absDotX > absDotY)
                            {
                                var size = bounds.size;
                                var t    = size.x; size.x = size.y; size.y = t;
                                bounds.size = size;
                                upAxis      = Axis.X;
                                var position = transformation.GetColumn(3);
                                transformation.SetColumn(3, new Vector4(0, 0, 0, 1));
                                transformation *= Matrix4x4.TRS(position, Quaternion.identity, Vector3.one);
                                transformation *= new Matrix4x4(new Vector4(0, 1, 0, 0),
                                                                new Vector4(1, 0, 0, 0),
                                                                new Vector4(0, 0, 1, 0),
                                                                new Vector4(0, 0, 0, 1));
                                transformation.SetColumn(3, position);
                            }
                        }
                        else
                        {
                            if (absDotZ > absDotY)
                            {
                                var size = bounds.size;
                                var t    = size.z; size.z = size.y; size.y = t;
                                bounds.size = size;
                                upAxis      = Axis.Z;
                                var position = transformation.GetColumn(3);
                                transformation.SetColumn(3, new Vector4(0, 0, 0, 1));
                                transformation *= Matrix4x4.TRS(position, Quaternion.identity, Vector3.one);
                                transformation *= new Matrix4x4(new Vector4(1, 0, 0, 0),
                                                                new Vector4(0, 0, 1, 0),
                                                                new Vector4(0, 1, 0, 0),
                                                                new Vector4(0, 0, 0, 1));
                                transformation.SetColumn(3, position);
                            }
                        }
                    }

                    if (!s_ModelBeneathCursor &&
                        (flags & PlacementFlags.AlwaysFaceCameraXZ) == PlacementFlags.AlwaysFaceCameraXZ)
                    {
                        // TODO: take grid orientation into account to decide what is "X" and what is "Z"
                        var currentForward = transformation.MultiplyVector(Vector3.forward);
                        var currentRight   = transformation.MultiplyVector(Vector3.right);
                        var cameraOffset   = Camera.current.transform.forward;
                        var cameraForward  = (new Vector3(cameraOffset.x, 0, cameraOffset.z)).normalized;
                        var dotZ           = Vector3.Dot(currentForward, cameraForward);
                        var dotX           = Vector3.Dot(currentRight, cameraForward);

                        var angle = 0;
                        if (Mathf.Abs(dotX) < Mathf.Abs(dotZ))
                        {
                            if (dotZ > 0)
                            {
                                angle += 180;
                            }
                        }
                        else
                        {
                            if (dotX < 0)
                            {
                                angle += 90;
                            }
                            else
                            {
                                angle -= 90;
                            }

                            if (upAxis == Axis.X)
                            {
                                upAxis = Axis.Z;
                            }
                            var size = bounds.size;
                            var t    = size.x; size.x = size.z; size.z = t;
                            bounds.size = size;
                        }

                        var position = transformation.GetColumn(3);
                        transformation.SetColumn(3, new Vector4(0, 0, 0, 1));
                        transformation *= Matrix4x4.TRS(position, Quaternion.identity, Vector3.one);
                        transformation *= Matrix4x4.TRS(Vector3.zero, Quaternion.Euler(0, angle, 0), Vector3.one);
                        transformation.SetColumn(3, position);
                    }
                }
#endif

                center = Vector3.zero;
                if ((flags & PlacementFlags.GenerateFromCenterY) != PlacementFlags.GenerateFromCenterY)
                {
                    center[(int)upAxis] = height * 0.5f;
                }
                else
                {
                    center[(int)upAxis] = 0;
                }
                bounds.center = center;
                if (doCommit)
                {
                    s_LastBounds = bounds;
                    s_LastHeight = s_NextHeight;
                }
            }
        }