示例#1
0
        private static void AddCgfToWorld(CgfLoader cgf, ref Matrix xform,
                                          Vector3 position, GeoSpace geoSpace)
        {
            s_tempVertices.Clear();

            // traverse nodes
            cgf.TraverseNodes((node, transform) =>
                              NodeHandler(cgf, node, position, transform), ref xform);

            // Add collected vertices as a new mesh.
            geoSpace.AddCollidableMeshToTree(s_tempVertices);
        }
示例#2
0
        // generates navmesh data for the selected levels.
        public static void GenerateAllNav(WorldIdXmlLoader worldIdXmlLoader,
                                          DirManager meshesDir, DirManager levelsDir, string levelId,
                                          bool skipExistingNav, string outputPath)
        {
            int curFolderIndex = -1;

            foreach (var pairs in worldIdXmlLoader.FolderNamesById)
            {
                curFolderIndex++;

                string clientLevelId = pairs.Key;
                string levelFolder   = pairs.Value;

                if (!string.IsNullOrEmpty(levelId) && levelId != clientLevelId)
                {
                    // skip excluded
                    continue;
                }

                string outputNavFilename = Path.Combine(outputPath, clientLevelId + ".nav");

                if (skipExistingNav && File.Exists(outputNavFilename))
                {
                    Console.WriteLine($"    ** Skipping (already exists): {clientLevelId} - {levelFolder}");
                    continue;
                }


                Console.WriteLine($"    Loading meshes for {clientLevelId} - {levelFolder}");

                var LEVEL_TIME = DateTime.Now;
                var TIMER      = DateTime.Now;
                var geoSpace   = new GeoSpace();

                // brushes
                var brushlst = LevelLoadHelper.CreateBrushLstLoader(levelsDir,
                                                                    Path.Combine(levelFolder, "brush.lst"));
                if (brushlst != null)
                {
                    var cgfMap = LevelLoadHelper.CreateBrushLstCgfLoaderMap(meshesDir, brushlst);

                    foreach (var brush in brushlst.brushEntries)
                    {
                        CgfLoader cgf;
                        if (!cgfMap.TryGetValue(brush.meshIdx, out cgf))
                        {
                            continue;
                        }

                        Matrix brushMatrix = LevelLoadHelper.GetBrushMatrix(brush);
                        AddCgfToWorld(cgf, ref brushMatrix, brush.position, geoSpace);
                    }
                }

                // objects
                var ctx = LevelLoadHelper.LoadObjectsLst(meshesDir, levelsDir, levelFolder);
                if (ctx != null)
                {
                    foreach (var o in ctx.objects)
                    {
                        CgfLoader cgf;
                        if (!ctx.cgfMap.TryGetValue(o.ObjectId, out cgf))
                        {
                            continue;
                        }

                        var xform = LevelLoadHelper.GetObjectMatrix(o);
                        AddCgfToWorld(cgf, ref xform, o.Position, geoSpace);
                    }
                }

                // terrain
                bool   loadedH32 = false;
                string h32path   = Path.Combine(levelFolder, @"terrain\land_map.h32");
                if (levelsDir.Exists(h32path))
                {
                    using (var landMapStream = levelsDir.OpenFile(h32path))
                        new H32Loader(landMapStream).LoadIntoGeoSpace(geoSpace);
                    loadedH32 = true;
                }

                Console.WriteLine("      Data load time: " + (DateTime.Now - TIMER));

                if (brushlst == null && ctx == null && !loadedH32)
                {
                    Console.WriteLine("      ** Skipping (no level data found)");
                    continue;
                }

                // build geo
                TIMER = DateTime.Now;
                geoSpace.BuildTree();
                geoSpace.Validate();
                Console.WriteLine("      Geo build time: " + (DateTime.Now - TIMER));

                // get size of level for scanning
                var   bb     = geoSpace.GetBoundingBox();
                float startX = Math.Max(0, bb.Min.X);
                float endX   = bb.Max.X;
                float startY = Math.Max(0, bb.Min.Y);
                float endY   = bb.Max.Y;
                int   top    = (int)Math.Ceiling(bb.Max.Z);
                int   bot    = Math.Max(0, (int)bb.Min.Z);

                // TODO - print bounding box
                // TODO - save log file

                if (endX <= startX || endY <= startY || top < bot)
                {
                    throw new InvalidOperationException(
                              $"unexpected level size for {clientLevelId} {levelFolder} bb: {bb}");
                }

                // compile mesh
                TIMER = DateTime.Now;
                float step           = 1f;
                var   navMeshBuilder = new NavMeshBuilder(startX, startY, bot, endX, endY, top, step);
                CompiledNavMeshSet compiledMeshSet = navMeshBuilder.ScanFloor(geoSpace);
                Console.WriteLine("      Raycast time: " + (DateTime.Now - TIMER));

                // save to file
                using (var fs = File.OpenWrite(outputNavFilename))
                    compiledMeshSet.Save(fs);

                Console.WriteLine($"      Level {clientLevelId} finished in {DateTime.Now - LEVEL_TIME}");
            }
        }
示例#3
0
        // load terrain vertices for collision testing
        public void LoadIntoGeoSpace(GeoSpace geoSpace)
        {
            if (isEmpty)
            {
                return;
            }

            // Rules:
            // - subdivide X & Y to create smaller AABBs for geospace.
            // - remove steep slopes.

            const int subdivide = 8;

            var meshTriangleVertices = new List <Vector3>();

            for (int sectorY = 0; sectorY < width - 1; sectorY += subdivide)
            {
                for (int sectorX = 0; sectorX < width - 1; sectorX += subdivide)
                {
                    meshTriangleVertices.Clear();

                    // can reduce to 2 triangles only if all vertices are the same height and none are removed.
                    // TODO - use a real poly reduction algorithm instead of fixed size.
                    bool optimizationAllowed = true;

                    int endX = Math.Min(width - 1, sectorX + subdivide);
                    int endY = Math.Min(width - 1, sectorY + subdivide);
                    for (int y = sectorY; y < endY; y++)
                    {
                        for (int x = sectorX; x < endX; x++)
                        {
                            var p1 = VertexLookup(x, y);
                            var p2 = VertexLookup(x, y + 1);
                            var p3 = VertexLookup(x + 1, y);
                            var p4 = VertexLookup(x + 1, y + 1);

                            // TODO - replace with a correct slope test.
                            // TODO - test if any maps have unit size other than 2.
                            if (Math.Abs(p1.Z - p2.Z) >= 2 || Math.Abs(p1.Z - p3.Z) >= 2)
                            {
                                optimizationAllowed = false;
                                continue;
                            }

                            meshTriangleVertices.Add(p1);
                            meshTriangleVertices.Add(p3);
                            meshTriangleVertices.Add(p2);

                            meshTriangleVertices.Add(p2);
                            meshTriangleVertices.Add(p4);
                            meshTriangleVertices.Add(p3);
                        }
                    }

                    if (meshTriangleVertices.Count == 0)
                    {
                        continue;
                    }

                    if (optimizationAllowed)
                    {
                        // if all points have the same Z, replace with 2 triangles.
                        if (meshTriangleVertices.All(v => v.Z == meshTriangleVertices[0].Z))
                        {
                            // don't optimize if there is a mix of 3F and non-3F mats, as this would break cutouts.
                            // a mix would be rare, so for simplicity, just don't optimize when 3F is found.
                            bool anyMat3F = false;
                            for (int y = sectorY; y < endY; y++)
                            {
                                for (int x = sectorX; x < endX; x++)
                                {
                                    if (IsCutout(x, y))
                                    {
                                        anyMat3F = true;
                                        goto exitMatCheck;
                                    }
                                }
                            }
exitMatCheck:


                            if (!anyMat3F)
                            {
                                var p1 = VertexLookup(sectorX, sectorY);
                                var p2 = VertexLookup(sectorX, endY);
                                var p3 = VertexLookup(endX, sectorY);
                                var p4 = VertexLookup(endX, endY);

                                if (p1.Z != meshTriangleVertices[0].Z ||
                                    p2.Z != meshTriangleVertices[0].Z ||
                                    p3.Z != meshTriangleVertices[0].Z ||
                                    p4.Z != meshTriangleVertices[0].Z)
                                {
                                    throw new InvalidOperationException("Z mismatch");
                                }

                                meshTriangleVertices.Clear();

                                meshTriangleVertices.Add(p1);
                                meshTriangleVertices.Add(p3);
                                meshTriangleVertices.Add(p2);

                                meshTriangleVertices.Add(p2);
                                meshTriangleVertices.Add(p4);
                                meshTriangleVertices.Add(p3);
                            }
                        }
                    }

                    geoSpace.AddCollidableMeshToTree(meshTriangleVertices);
                }
            }
        }