示例#1
0
        public static void PointSnapToGrid(this BrushSelection selection, Camera camera)
        {
            var minWorldDeltaMovement = MathConstants.PositiveInfinityVector3;

            for (var t = 0; t < selection.States.Length; t++)
            {
                var brush = selection.Brushes[t];
                if (!brush)
                {
                    continue;
                }

                var controlMeshState  = selection.States[t];
                var brushTransform    = brush.GetComponent <Transform>();
                var brushLocalToWorld = brushTransform.localToWorldMatrix;
                var brushWorldToLocal = brushTransform.worldToLocalMatrix;

                var controlMesh = brush.ControlMesh;
                var points      = controlMesh.Vertices;

                var localPoints     = new List <Vector3>(points.Length);
                var selectedIndices = controlMeshState.GetSelectedPointIndices();
                foreach (var index in selectedIndices)
                {
                    localPoints.Add(points[index]);
                }

                if (localPoints.Count > 0)
                {
                    var worldDeltaMovement = RealtimeCSG.CSGGrid.SnapLocalPointToWorldGridDelta(camera, brushLocalToWorld, brushWorldToLocal, localPoints.ToArray());
                    if (Mathf.Abs(worldDeltaMovement.x) < Mathf.Abs(minWorldDeltaMovement.x))
                    {
                        minWorldDeltaMovement.x = worldDeltaMovement.x;
                    }
                    if (Mathf.Abs(worldDeltaMovement.y) < Mathf.Abs(minWorldDeltaMovement.y))
                    {
                        minWorldDeltaMovement.y = worldDeltaMovement.y;
                    }
                    if (Mathf.Abs(worldDeltaMovement.z) < Mathf.Abs(minWorldDeltaMovement.z))
                    {
                        minWorldDeltaMovement.z = worldDeltaMovement.z;
                    }
                }
            }

            if (float.IsInfinity(minWorldDeltaMovement.x))
            {
                return;                 // nothing to do
            }
            var brushModified = false;

            for (var t = 0; t < selection.States.Length; t++)
            {
                var brush = selection.Brushes[t];
                if (!brush)
                {
                    continue;
                }

                var controlMeshState = selection.States[t];

                var brushTransform    = brush.GetComponent <Transform>();
                var brushLocalToWorld = brushTransform.localToWorldMatrix;
                var brushWorldToLocal = brushTransform.worldToLocalMatrix;

                var  controlMesh     = brush.ControlMesh;
                var  points          = controlMesh.Vertices;
                var  selectedIndices = controlMeshState.GetSelectedPointIndices();
                bool vertexModified  = false;
                foreach (var index in selectedIndices)
                {
                    var worldPoint = brushLocalToWorld.MultiplyPoint(points[index]);
                    worldPoint += minWorldDeltaMovement;
                    var localPoint   = brushWorldToLocal.MultiplyPoint(worldPoint);
                    var snappedPoint = GridUtility.CleanPosition(localPoint);
                    if (controlMesh.Vertices[index].x == snappedPoint.x &&
                        controlMesh.Vertices[index].y == snappedPoint.y &&
                        controlMesh.Vertices[index].z == snappedPoint.z)
                    {
                        continue;
                    }
                    controlMesh.Vertices[index] = snappedPoint;
                    vertexModified = true;
                }
                if (vertexModified)
                {
                    brush.ControlMesh.SetDirty();
                    brushModified = true;
                }
            }
            if (brushModified)
            {
                InternalCSGModelManager.CheckForChanges();
            }
        }
示例#2
0
        public static void Flip(CSGBrush[] brushes, Matrix4x4 flipMatrix, string undoDescription = "Flip brushes")
        {
            var fail = false;

            Undo.IncrementCurrentGroup();
            Undo.RegisterCompleteObjectUndo(brushes.ToArray <UnityEngine.Object>(), undoDescription);

            var isGlobal = Tools.pivotRotation == PivotRotation.Global;

            var centerAll = BoundsUtilities.GetCenter(brushes);

            for (var t = 0; t < brushes.Length; t++)
            {
                var brush    = brushes[t];
                var position = brush.transform.position;

                Matrix4x4 brushFlip;
                Vector3   brushCenter;
                if (isGlobal)
                {
                    brushFlip = brush.transform.localToWorldMatrix *
                                flipMatrix *
                                brush.transform.worldToLocalMatrix;
                    brushCenter = brush.transform.InverseTransformPoint(centerAll) - position;
                }
                else
                {
                    brushFlip   = flipMatrix;
                    brushCenter = brush.transform.InverseTransformPoint(centerAll);
                }

                brushFlip = Matrix4x4.TRS(brushCenter, Quaternion.identity, Vector3.one) *
                            brushFlip *
                            Matrix4x4.TRS(-brushCenter, Quaternion.identity, Vector3.one);

                brush.EnsureInitialized();
                var shape = brush.Shape;
                for (var s = 0; s < shape.Surfaces.Length; s++)
                {
                    var plane = shape.Surfaces[s].Plane;

                    var normal   = brushFlip.MultiplyVector(plane.normal);
                    var biNormal = brushFlip.MultiplyVector(shape.Surfaces[s].BiNormal);
                    var tangent  = brushFlip.MultiplyVector(shape.Surfaces[s].Tangent);

                    var pointOnPlane = plane.pointOnPlane;
                    pointOnPlane = brushFlip.MultiplyPoint(pointOnPlane);

                    shape.Surfaces[s].Plane    = new CSGPlane(normal, pointOnPlane);
                    shape.Surfaces[s].BiNormal = biNormal;
                    shape.Surfaces[s].Tangent  = tangent;
                }

                var controlMesh = brush.ControlMesh;
                var vertices    = controlMesh.Vertices;
                for (var v = 0; v < vertices.Length; v++)
                {
                    vertices[v] = brushFlip.MultiplyPoint(vertices[v]);
                }

                var polygons = controlMesh.Polygons;
                for (var p = 0; p < polygons.Length; p++)
                {
                    Array.Reverse(polygons[p].EdgeIndices);
                }

                var edges        = controlMesh.Edges;
                var twinVertices = new short[edges.Length];
                for (var e = 0; e < edges.Length; e++)
                {
                    twinVertices[e] = edges[edges[e].TwinIndex].VertexIndex;
                }

                for (var e = 0; e < edges.Length; e++)
                {
                    edges[e].VertexIndex = twinVertices[e];
                }

                brush.ControlMesh.SetDirty();
                EditorUtility.SetDirty(brush);

                InternalCSGModelManager.CheckSurfaceModifications(brush, true);

                ControlMeshUtility.RebuildShape(brush);
            }
            if (fail)
            {
                Debug.LogWarning("Failed to perform operation");
                Undo.RevertAllInCurrentGroup();
            }
            InternalCSGModelManager.Refresh();
        }
示例#3
0
        /// <summary>
        /// Imports the specified world into the RealtimeCSG.
        /// </summary>
        /// <param name="rootTransform">Transform to be parent of RealtimeCSG brushes</param>
        /// <param name="world">The world to be imported.</param>
        public static void Import(Transform rootTransform, MapWorld world)
        {
            try
            {
                //model.BeginUpdate();

                // create a material searcher to associate materials automatically.
                MaterialSearcher materialSearcher = new MaterialSearcher();

                // group all the brushes together.
                //GroupBrush groupBrush = new GameObject("Quake 1 Map").AddComponent<GroupBrush>();
                //groupBrush.transform.SetParent(model.transform);

                var mapTransform = CreateGameObjectWithUniqueName(world.mapName, rootTransform);
                mapTransform.position = Vector3.zero;

                // Index of entities by trenchbroom id
                var entitiesById = new Dictionary <int, EntityContainer>();

                var layers = new List <EntityContainer>();

                for (int e = 0; e < world.Entities.Count; e++)
                {
                    var entity = world.Entities[e];

                    //EntityContainer eContainer = null;

                    if (entity.tbId >= 0)
                    {
                        var name       = String.IsNullOrEmpty(entity.tbName) ? "Unnamed" : entity.tbName;
                        var t          = CreateGameObjectWithUniqueName(name, mapTransform);
                        var eContainer = new EntityContainer(t, entity);
                        entitiesById.Add(entity.tbId, eContainer);

                        if (entity.tbType == "_tb_layer")
                        {
                            layers.Add(eContainer);
                            eContainer.transform.SetParent(null); // unparent until layers are sorted by sort index
                        }
                    }
                }

                var defaultLayer = CreateGameObjectWithUniqueName("Default Layer", mapTransform);

                //var worldSpawnModel = OperationsUtility.CreateModelInstanceInScene(defaultLayer);
                //worldSpawnModel.name = "WorldSpawn";
                //worldSpawnModel.transform.SetParent(mapTransform);

                layers = layers.OrderBy(l => l.entity.tbLayerSortIndex).ToList(); // sort layers by layer sort index

                foreach (var l in layers)
                {
                    l.transform.SetParent(mapTransform); // parent layers to map in order
                }

                bool valveFormat = world.valveFormat;

                // iterate through all entities.
                for (int e = 0; e < world.Entities.Count; e++)
                {
#if UNITY_EDITOR
                    UnityEditor.EditorUtility.DisplayProgressBar("Importing Quake 1 Map", "Converting Quake 1 Entities To Brushes (" + (e + 1) + " / " + world.Entities.Count + ")...", e / (float)world.Entities.Count);
#endif
                    MapEntity entity = world.Entities[e];

                    Transform brushParent = mapTransform;

                    bool isLayer   = false;
                    bool isTrigger = false;

                    if (entity.ClassName == "worldspawn")
                    {
                        brushParent = defaultLayer;
                    }
                    else if (entity.tbType == "_tb_layer")
                    {
                        isLayer = true;
                        if (entitiesById.TryGetValue(entity.tbId, out EntityContainer eContainer))
                        {
                            brushParent = eContainer.transform;
                        }
                    }
                    else if (entity.tbType == "_tb_group")
                    {
                        if (entitiesById.TryGetValue(entity.tbId, out EntityContainer eContainer))
                        {
                            brushParent = eContainer.transform;
                        }
                    }
                    else
                    {
                        if (entity.ClassName.Contains("trigger"))
                        {
                            isTrigger = true;
                        }

                        brushParent = CreateGameObjectWithUniqueName(entity.ClassName, mapTransform);
                    }

                    if (brushParent != mapTransform && brushParent != defaultLayer)
                    {
                        if (entity.tbGroup > 0)
                        {
                            if (entitiesById.TryGetValue(entity.tbGroup, out EntityContainer eContainer))
                            {
                                brushParent.SetParent(eContainer.transform);
                            }
                        }
                        else if (entity.tbLayer > 0)
                        {
                            if (entitiesById.TryGetValue(entity.tbLayer, out EntityContainer eContainer))
                            {
                                brushParent.SetParent(eContainer.transform);
                            }
                        }
                        else if (!isLayer)
                        {
                            brushParent.SetParent(defaultLayer);
                        }
                    }

                    if (entity.Brushes.Count == 0)
                    {
                        continue;
                    }


                    var model  = OperationsUtility.CreateModelInstanceInScene(brushParent);
                    var parent = model.transform;

                    if (isTrigger)
                    {
                        model.Settings = (model.Settings | ModelSettingsFlags.IsTrigger | ModelSettingsFlags.SetColliderConvex | ModelSettingsFlags.DoNotRender);
                    }

                    //GroupBrush entityGroup = new GameObject(entity.ClassName).AddComponent<GroupBrush>();
                    //entityGroup.transform.SetParent(groupBrush.transform);


                    // iterate through all entity solids.
                    for (int i = 0; i < entity.Brushes.Count; i++)
                    {
                        MapBrush brush = entity.Brushes[i];
#if UNITY_EDITOR
                        if (world.Entities[e].ClassName == "worldspawn")
                        {
                            UnityEditor.EditorUtility.DisplayProgressBar("RealtimeCSG: Importing Quake 1 Map", "Converting Quake 1 Brushes To RealtimeCSG Brushes (" + (i + 1) + " / " + entity.Brushes.Count + ")...", i / (float)entity.Brushes.Count);
                        }
#endif
                        // don't add triggers to the scene.
                        // Triggers will get placed in entity model now
                        //if (brush.Sides.Count > 0 && IsSpecialMaterial(brush.Sides[0].Material))
                        //    continue;


                        var name       = UnityEditor.GameObjectUtility.GetUniqueNameForSibling(parent, "Brush");
                        var gameObject = new GameObject(name);
                        var rcsgBrush  = gameObject.AddComponent <CSGBrush>();
                        var t          = gameObject.transform;

                        gameObject.transform.SetParent(parent, true);
                        gameObject.transform.position = new Vector3(0.5f, 0.5f, 0.5f); // this aligns it's vertices to the grid
                                                                                       //                                                               //BrushFactory.CreateCubeControlMesh(out brush.ControlMesh, out brush.Shape, Vector3.one);

                        var planes          = new Plane[brush.Sides.Count];
                        var textureMatrices = new Matrix4x4[brush.Sides.Count];
                        var materials       = new Material[brush.Sides.Count];


                        Debug.Log($"Brush sides {brush.Sides.Count}");

                        // Get planes for all sides of the brush
                        for (int j = 0; j < brush.Sides.Count; j++)
                        {
                            MapBrushSide side = brush.Sides[j];

                            var pa = t.transform.InverseTransformPoint(new Vector3(side.Plane.P1.X, side.Plane.P1.Z, side.Plane.P1.Y) / (float)s_Scale);
                            var pb = t.transform.InverseTransformPoint(new Vector3(side.Plane.P2.X, side.Plane.P2.Z, side.Plane.P2.Y) / (float)s_Scale);
                            var pc = t.transform.InverseTransformPoint(new Vector3(side.Plane.P3.X, side.Plane.P3.Z, side.Plane.P3.Y) / (float)s_Scale);

                            planes[j] = new Plane(pa, pb, pc);

                            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 texture name with '*' replaced by '#' so '#teleport'.
                            string materialName = side.Material.Replace("*", "#");
                            materials[j] = materialSearcher.FindMaterial(new string[] { materialName });
                            if (materials[j] == null)
                            {
                                materials[j] = CSGSettings.DefaultMaterial;
                                // Debug.Log("RealtimeCSG: Tried to find material '" + materialName + "' but it couldn't be found in the project.");
                            }

                            if (valveFormat)
                            {
                                // calculate the texture coordinates.
                                int w = 256;
                                int h = 256;
                                if (materials[j].mainTexture != null)
                                {
                                    w = materials[j].mainTexture.width;
                                    h = materials[j].mainTexture.height;
                                }

                                var uAxis = new VmfAxis(side.t1, side.Offset.X, side.Scale.X);
                                var vAxis = new VmfAxis(side.t2, side.Offset.Y, side.Scale.Y);
                                textureMatrices[j] = CalculateTextureCoordinates(planes[j], w, h, uAxis, vAxis);
                            }
                        }

                        bool controlMeshSuccess = true;

                        if (valveFormat)
                        {
                            controlMeshSuccess = BrushFactory.CreateControlMeshFromPlanes(out rcsgBrush.ControlMesh, out rcsgBrush.Shape, planes, null, null, materials, textureMatrices, TextureMatrixSpace.WorldSpace);
                        }
                        else
                        {
                            controlMeshSuccess = BrushFactory.CreateControlMeshFromPlanes(out rcsgBrush.ControlMesh, out rcsgBrush.Shape, planes, null, null, materials);
                        }

                        if (controlMeshSuccess)
                        {
                            for (int j = 0; j < brush.Sides.Count; j++)
                            {
                                MapBrushSide side = brush.Sides[j];

                                // calculate the texture coordinates.
                                int w = 32;
                                int h = 32;
                                if (materials[j].mainTexture != null)
                                {
                                    w = materials[j].mainTexture.width;
                                    h = materials[j].mainTexture.height;
                                }

                                var tScale = new Vector2(
                                    SafeDivision((32.0f / w), side.Scale.X),
                                    SafeDivision((32.0f / h), side.Scale.Y));

                                if (valveFormat)
                                {
                                    // This shouldn't be needed due to setting texture matrix
                                    rcsgBrush.Shape.TexGens[j].Scale = tScale;

                                    rcsgBrush.Shape.TexGens[j].Translation.x = SafeDivision(side.Offset.X, w);
                                    rcsgBrush.Shape.TexGens[j].Translation.y = SafeDivision(-side.Offset.Y, h);

                                    //rcsgBrush.Shape.TexGens[j].RotationAngle += 180 + side.Rotation; // Textures often need to be flipped or rotated 180 to match
                                }
                                else
                                {
                                    rcsgBrush.Shape.TexGens[j].Scale = tScale;

                                    if (side.Offset.X != 0)
                                    {
                                        rcsgBrush.Shape.TexGens[j].Translation.x = side.Offset.X / Mathf.Max(w, float.Epsilon);
                                    }
                                    else
                                    {
                                        rcsgBrush.Shape.TexGens[j].Translation.x = 0;
                                    }

                                    if (side.Offset.Y != 0)
                                    {
                                        rcsgBrush.Shape.TexGens[j].Translation.y = side.Offset.Y / Mathf.Max(h, float.Epsilon);
                                    }
                                    else
                                    {
                                        rcsgBrush.Shape.TexGens[j].Translation.y = 0;
                                    }

                                    rcsgBrush.Shape.TexGens[j].RotationAngle = 180 + side.Rotation;
                                }
                            }
                        }
                        else
                        {
                            GameObject.DestroyImmediate(rcsgBrush.gameObject);
                        }
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                InternalCSGModelManager.CheckForChanges();
                InternalCSGModelManager.UpdateMeshes();
                //model.EndUpdate();
            }

#if UNITY_EDITOR
            UnityEditor.EditorUtility.ClearProgressBar();
#endif
        }
示例#4
0
        public static void PointSnapToGrid(this BrushSelection selection)
        {
            var worldDeltaMovement = MathConstants.zeroVector3;

            for (var t = 0; t < selection.States.Length; t++)
            {
                var brush = selection.Brushes[t];
                if (!brush)
                {
                    continue;
                }

                var controlMeshState  = selection.States[t];
                var brushTransform    = brush.GetComponent <Transform>();
                var brushLocalToWorld = brushTransform.localToWorldMatrix;

                var controlMesh = brush.ControlMesh;
                var points      = controlMesh.Vertices;

                var worldPoints     = new List <Vector3>(points.Length);
                var selectedIndices = controlMeshState.GetSelectedPointIndices();
                foreach (var index in selectedIndices)
                {
                    worldPoints.Add(brushLocalToWorld.MultiplyPoint(points[index]));
                }

                if (worldPoints.Count > 0)
                {
                    worldDeltaMovement = Grid.SnapDeltaToGrid(worldDeltaMovement, worldPoints.ToArray(), snapToGridPlane: false, snapToSelf: false);
                }
            }

            if (worldDeltaMovement == MathConstants.zeroVector3)
            {
                return;
            }

            for (var t = 0; t < selection.States.Length; t++)
            {
                var brush = selection.Brushes[t];
                if (!brush)
                {
                    continue;
                }

                var controlMeshState = selection.States[t];

                var brushTransform    = brush.GetComponent <Transform>();
                var brushLocalToWorld = brushTransform.localToWorldMatrix;
                var brushWorldToLocal = brushTransform.worldToLocalMatrix;

                var controlMesh     = brush.ControlMesh;
                var points          = controlMesh.Vertices;
                var selectedIndices = controlMeshState.GetSelectedPointIndices();
                foreach (var index in selectedIndices)
                {
                    var oldPoint = brushWorldToLocal.MultiplyPoint(brushLocalToWorld.MultiplyPoint(points[index]) + worldDeltaMovement);
                    controlMesh.Vertices[index] = oldPoint;
                }
                brush.ControlMesh.SetDirty();
            }
            InternalCSGModelManager.Refresh();
        }
示例#5
0
        public static void Flip(CSGBrush[] brushes, Matrix4x4 flipMatrix, string undoDescription = "Flip brushes")
        {
            var fail = false;

            Undo.IncrementCurrentGroup();
            Undo.RegisterCompleteObjectUndo(brushes.ToArray <UnityEngine.Object>(), undoDescription);

            var isGlobal = Tools.pivotRotation == PivotRotation.Global;

            var centerAll = BoundsUtilities.GetCenter(brushes);

            for (var t = 0; t < brushes.Length; t++)
            {
                var brush    = brushes[t];
                var shape    = brush.Shape;
                var position = brush.transform.position;

                Matrix4x4 brushFlip;
                Vector3   brushCenter;
                if (isGlobal)
                {
                    brushFlip = brush.transform.localToWorldMatrix *
                                flipMatrix *
                                brush.transform.worldToLocalMatrix;
                    brushCenter = brush.transform.InverseTransformPoint(centerAll) - position;
                }
                else
                {
                    brushFlip   = flipMatrix;
                    brushCenter = brush.transform.InverseTransformPoint(centerAll);
                }

                for (var s = 0; s < shape.Surfaces.Length; s++)
                {
                    var plane = shape.Surfaces[s].Plane;

                    var normal   = brushFlip.MultiplyVector(plane.normal);
                    var biNormal = brushFlip.MultiplyVector(shape.Surfaces[s].BiNormal);
                    var tangent  = brushFlip.MultiplyVector(shape.Surfaces[s].Tangent);

                    var pointOnPlane = plane.pointOnPlane;
                    pointOnPlane -= brushCenter;
                    pointOnPlane  = brushFlip.MultiplyPoint(pointOnPlane);
                    pointOnPlane += brushCenter;

                    shape.Surfaces[s].Plane    = new CSGPlane(normal, pointOnPlane);
                    shape.Surfaces[s].BiNormal = biNormal;
                    shape.Surfaces[s].Tangent  = tangent;
                }

                var controlMesh = brush.ControlMesh;
                brush.Shape = shape;

                brush.ControlMesh = ControlMeshUtility.CreateFromShape(shape);
                if (brush.ControlMesh == null)
                {
                    brush.ControlMesh = controlMesh;
                    fail = true;
                    break;
                }

                ShapeUtility.CreateCutter(shape, brush.ControlMesh);
                brush.EnsureInitialized();

                brush.ControlMesh.SetDirty();
                EditorUtility.SetDirty(brush);

                InternalCSGModelManager.CheckSurfaceModifications(brush, true);

                ControlMeshUtility.RebuildShape(brush);
            }
            if (fail)
            {
                Debug.Log("Failed to perform operation");
                Undo.RevertAllInCurrentGroup();
            }
            InternalCSGModelManager.Refresh();
        }