private void LoadBrushes(DirManager meshesDir, DirManager levelDir, List <VertexPositionColor> vertices, List <VertexPositionColor> collisionVertices, List <VertexPositionColor> lineVertices) { var brushlst = LevelLoadHelper.CreateBrushLstLoader(levelDir, "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; } //Debug.WriteLine("*Brush: " + cgf.m_path); //Debug.WriteLine($" entryIdx:{brush.entryIdx} meshIdx:{brush.meshIdx} pos:{brush.position} brRotMat:{brush.rotationMatrix}"); Matrix brushMatrix = LevelLoadHelper.GetBrushMatrix(brush); DrawCgfInWorld(cgf, ref brushMatrix, brush.position, CgfDrawStyle.Brush, vertices, collisionVertices, lineVertices); } } }
// 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}"); } }