コード例 #1
0
        /// <summary>
        /// Given a <see cref="Face"/> with a list of <see cref="Vertex"/> objects and triangles, loads those
        /// vertices into a <see cref="Mesh"/> object and returns it.
        /// </summary>
        /// <param name="bsp">The <see cref="BSP"/> object <paramref name="face"/> came from.</param>
        /// <param name="face">The <see cref="Face"/> to build a <see cref="Mesh"/> from.</param>
        /// <returns>The <see cref="Mesh"/> generated from the vertices and triangles in <see cref="Face"/>.</returns>
        public static Mesh LoadVerticesFromFace(BSP bsp, Face face)
        {
            Mesh        mesh    = LoadVertices(bsp.GetReferencedObjects <Vertex>(face, "vertices"));
            List <long> indices = bsp.GetReferencedObjects <long>(face, "indices");

            int[] triangles = new int[indices.Count];
            for (int i = 0; i < indices.Count; ++i)
            {
                triangles[i] = (int)indices[i];
            }
            mesh.triangles = triangles;

            return(mesh);
        }
コード例 #2
0
        /// <summary>
        /// Builds a <see cref="Mesh"/> for all control vertices referenced by <paramref name="face"/> using
        /// <paramref name="curveTessellationLevel"/> to determine how many vertices will be used to build
        /// the curves.
        /// </summary>
        /// <param name="bsp">The <see cref="BSP"/> which <paramref name="face"/> came from.</param>
        /// <param name="face">The <see cref="Face"/> whose vertices will be interpreted as curve control points.</param>
        /// <param name="curveTessellationLevel">The number of times to tessellate the curves in this patch.</param>
        /// <returns>A <see cref="Mesh"/> built using the curve data in <paramref name="face"/>.</returns>
        public static Mesh CreatePatchMesh(BSP bsp, Face face, int curveTessellationLevel)
        {
            List <Mesh>   curveSubmeshes = new List <Mesh>();
            List <Vertex> controls       = bsp.GetReferencedObjects <Vertex>(face, "vertices");
            Vector2       size           = face.patchSize;
            int           xSize          = (int)Mathf.Round(size[0]);

            for (int i = 0; i < size[1] - 2; i += 2)
            {
                for (int j = 0; j < size[0] - 2; j += 2)
                {
                    int      rowOff            = (i * xSize);
                    Vertex[] thisCurveControls = new Vertex[9];

                    // Store control points
                    thisCurveControls[0] = controls[rowOff + j];
                    thisCurveControls[1] = controls[rowOff + j + 1];
                    thisCurveControls[2] = controls[rowOff + j + 2];
                    rowOff += xSize;
                    thisCurveControls[3] = controls[rowOff + j];
                    thisCurveControls[4] = controls[rowOff + j + 1];
                    thisCurveControls[5] = controls[rowOff + j + 2];
                    rowOff += xSize;
                    thisCurveControls[6] = controls[rowOff + j];
                    thisCurveControls[7] = controls[rowOff + j + 1];
                    thisCurveControls[8] = controls[rowOff + j + 2];

                    curveSubmeshes.Add(CreateQuadraticBezierMesh(thisCurveControls, curveTessellationLevel));
                }
            }

            return(CombineAllMeshes(curveSubmeshes.ToArray(), true, false));
        }
コード例 #3
0
        /// <summary>
        /// Gets all the <see cref="Face"/> objects associated with the given <paramref name="model"/>.
        /// </summary>
        /// <param name="bsp">This <see cref="BSP"/> object.</param>
        /// <param name="model">The <see cref="Model"/> object to get all <see cref="Face"/> objects for.</param>
        /// <returns>
        /// A <see cref="List"/>&lt;<see cref="Face"/>&gt; containing all the <see cref="Face"/> objects occurring
        /// within the passed <see cref="Model"/> object, or <c>null</c> if the BSP doesn't have faces.
        /// </returns>
        public static List <Face> GetFacesInModel(this BSP bsp, Model model)
        {
            if (model.firstFace >= 0)
            {
                return(bsp.GetReferencedObjects <Face>(model, "faces"));
            }

            return(new List <Face>(0));
        }
コード例 #4
0
        /// <summary>
        /// Gets all the <see cref="Brush"/> objects associated with the given <paramref name="model"/>.
        /// </summary>
        /// <param name="bsp">This <see cref="BSP"/> object.</param>
        /// <param name="model">The <see cref="Model"/> object to get all <see cref="Brush"/> objects for.</param>
        /// <returns>
        /// A <see cref="List"/>&lt;<see cref="Brush"/>&gt; containing all the <see cref="Brush"/> objects occurring
        /// within the passed <see cref="Model"/> object, or <c>null</c> if the BSP doesn't have brushes.
        /// </returns>
        /// <remarks>
        /// The proper way to go from a <see cref="Model"/> reference to a collection of <see cref="Brush"/> objects
        /// depends on the type of BSP we're operating on. In the case of Quake 3, for example, models directly reference
        /// brushes, but Quake 2 and Source require a full tree traversal.
        /// </remarks>
        public static List <Brush> GetBrushesInModel(this BSP bsp, Model model)
        {
            if (model.firstBrush >= 0)
            {
                return(bsp.GetReferencedObjects <Brush>(model, "brushes"));
            }

            if (model.firstLeaf >= 0)
            {
                List <Leaf> leavesInModel = bsp.GetReferencedObjects <Leaf>(model, "leaves");
                return(bsp.GetBrushesInLeafList(leavesInModel));
            }

            if (model.headNode >= 0)
            {
                return(bsp.GetBrushesInLeafList(bsp.GetLeavesInTree(bsp.nodes[model.headNode])));
            }

            return(new List <Brush>(0));
        }
コード例 #5
0
        /// <summary>
        /// Gets all <see cref="Brush"/> objects referenced from a list of <see cref="Leaf"/> objects.
        /// </summary>
        /// <param name="bsp">This <see cref="BSP"/>.</param>
        /// <param name="leaves">A <see cref="List"/> of <see cref="Leaf"/> objects to get <see cref="Brush"/> references from.</param>
        /// <returns>All the <see cref="Brush"/> objects referenced from the given <see cref="Leaf"/> objects.</returns>
        public static List <Brush> GetBrushesInLeafList(this BSP bsp, IEnumerable <Leaf> leaves)
        {
            // Use HashSet here. A Brush may be referenced through many Leafs. The default pointer hash should prevent that.
            HashSet <Brush> brushes = new HashSet <Brush>();

            foreach (Leaf leaf in leaves)
            {
                List <long> markBrushesInLeaf = bsp.GetReferencedObjects <long>(leaf, "markBrushes");
                foreach (long markBrush in markBrushesInLeaf)
                {
                    brushes.Add(bsp.brushes[(int)markBrush]);
                }
            }
            return(brushes.ToList <Brush>());
        }
コード例 #6
0
        /// <summary>
        /// Gets all <see cref="Brush"/> objects referenced from a list of <see cref="Leaf"/> objects.
        /// </summary>
        /// <param name="bsp">This <see cref="BSP"/>.</param>
        /// <param name="leaves">A <see cref="List"/> of <see cref="Leaf"/> objects to get <see cref="Brush"/> references from.</param>
        /// <returns>All the <see cref="Brush"/> objects referenced from the given <see cref="Leaf"/> objects.</returns>
        public static List <Brush> GetBrushesInLeafList(this BSP bsp, IEnumerable <Leaf> leaves)
        {
            List <Brush> brushes = new List <Brush>();

            bool[] brushesUsed = new bool[bsp.brushes.Count];
            foreach (Leaf leaf in leaves)
            {
                List <long> markBrushesInLeaf = bsp.GetReferencedObjects <long>(leaf, "markBrushes");
                foreach (long markBrush in markBrushesInLeaf)
                {
                    if (!brushesUsed[(int)markBrush])
                    {
                        brushes.Add(bsp.brushes[(int)markBrush]);
                        brushesUsed[(int)markBrush] = true;
                    }
                }
            }
            return(brushes);
        }
コード例 #7
0
        /// <summary>
        /// Processes an <see cref="Entity"/> into a state where it can be output into a file that map editors can read.
        /// </summary>
        /// <param name="entity">The <see cref="Entity"/> to process.</param>
        /// <remarks>This method does not return anything, since the <see cref="Entity"/> object is modified by reference.</remarks>
        private void ProcessEntity(Entity entity)
        {
            int modelNumber = entity.modelNumber;

            // If this Entity has no modelNumber, then this is a no-op. No processing is needed.
            // A modelnumber of 0 indicates the world entity.
            if (modelNumber >= 0)
            {
                Model model = _bsp.models[modelNumber];
                if (_bsp.brushes != null)
                {
                    List <Brush> brushes = _bsp.GetBrushesInModel(model);
                    if (brushes != null)
                    {
                        foreach (Brush brush in brushes)
                        {
                            MAPBrush result = ProcessBrush(brush, entity.origin);
                            result.isWater |= (entity.className == "func_water");
                            if (_master.settings.brushesToWorld)
                            {
                                _bsp.entities.GetWithAttribute("classname", "worldspawn").brushes.Add(result);
                            }
                            else
                            {
                                entity.brushes.Add(result);
                            }
                            ++_itemsProcessed;
                            ReportProgress();
                        }
                    }
                }
                if (model.numLeafPatches > 0 && _bsp.markSurfaces != null && _bsp.patches != null)
                {
                    HashSet <Patch> patches            = new HashSet <Patch>();
                    List <long>     leafPatchesInModel = _bsp.GetReferencedObjects <long>(model, "markSurfaces");
                    foreach (long leafPatch in leafPatchesInModel)
                    {
                        if (leafPatch >= 0)
                        {
                            patches.Add(_bsp.patches[(int)leafPatch]);
                        }
                    }
                    foreach (Patch patch in patches)
                    {
                        if (_bsp.version != MapType.CoD || patch.patchType == 0)
                        {
                            MAPPatch mappatch = ProcessPatch(patch);
                            MAPBrush newBrush = new MAPBrush();
                            newBrush.patch = mappatch;
                            entity.brushes.Add(newBrush);
                        }
                    }
                }
                if (_bsp.faces != null)
                {
                    List <Face> surfaces = _bsp.GetFacesInModel(model);
                    foreach (Face face in surfaces)
                    {
                        if (face.displacement >= 0)
                        {
                            if (modelNumber != 0)
                            {
                                _master.Print("WARNING: Displacement not part of world in " + _bsp.MapNameNoExtension);
                            }
                            MAPDisplacement displacement = ProcessDisplacement(_bsp.dispInfos[face.displacement]);
                            MAPBrush        newBrush     = face.CreateBrush(_bsp, 32);
                            newBrush.sides[0].displacement = displacement;
                            // If we are not decompiling to VMF, vis will need to skip this brush.
                            newBrush.isDetail = true;
                            entity.brushes.Add(newBrush);
                        }
                        else if (face.flags == 2)
                        {
                            MAPPatch patch    = ProcessPatch(face);
                            MAPBrush newBrush = new MAPBrush();
                            newBrush.patch = patch;
                            entity.brushes.Add(newBrush);
                        }
                        else if ((_bsp.version == MapType.STEF2 || _bsp.version == MapType.STEF2Demo) && face.flags == 5)
                        {
                            if (modelNumber != 0)
                            {
                                _master.Print("WARNING: Terrain not part of world in " + _bsp.MapNameNoExtension);
                            }
                            MAPTerrainEF2 terrain  = ProcessEF2Terrain(face);
                            MAPBrush      newBrush = new MAPBrush();
                            newBrush.ef2Terrain = terrain;
                            entity.brushes.Add(newBrush);
                        }
                    }
                }

                // If this is model 0 (worldspawn) there are other things that need to be taken into account.
                if (modelNumber == 0)
                {
                    if (_bsp.lodTerrains != null)
                    {
                        foreach (LODTerrain lodTerrain in _bsp.lodTerrains)
                        {
                            MAPTerrainMoHAA terrain  = ProcessTerrainMoHAA(lodTerrain);
                            MAPBrush        newBrush = new MAPBrush();
                            newBrush.mohTerrain = terrain;
                            entity.brushes.Add(newBrush);
                        }
                    }
                }
                entity.Remove("model");
            }
        }