public static void GetAllianceGunshipModelGeometry(List <Vector3> vertices, List <Triangle <uint> > triangles, string fileId) { var wmo = new WorldModelRoot(fileId); // no caching, we load it only once if (wmo.DoodadInstances.Count <= 0) { return; } foreach (var group in wmo.Groups) { if ((group.Flags & 0x80) != 0) // Here is a group of triangles that mess-up the WMO { continue; } int vertOffset = vertices.Count; if (group.Triangles != null) { bool one = false; for (int i = 0; i < group.Triangles.Length; i++) { // includes all triangles for AllianceGunship var tri = group.Triangles[i]; triangles.Add(new Triangle <uint>(TriangleType.Wmo, (uint)(tri.V0 + vertOffset), (uint)(tri.V1 + vertOffset), (uint)(tri.V2 + vertOffset))); one = true; } if (one) { vertices.AddRange(group.Vertices); } } } }
public void AddDungeon(WorldModelRoot model, WorldModelHandler.WorldModelDefinition def) { var verts = new List <Vector3>(); var tris = new List <Triangle <uint> >(); WorldModelHandler.InsertModelGeometry(verts, tris, def, model); AddData(verts, tris); }
protected override void ProcessInternal(ChunkedData subChunks) { if (!IsSane) { return; } var wmoReferencesChunk = subChunks.GetChunkByName("MCRW"); if (wmoReferencesChunk == null) { return; } var stream = wmoReferencesChunk.GetStream(); var reader = new BinaryReader(stream); var refCount = (int)(wmoReferencesChunk.Length / 4); for (int i = 0; i < refCount; i++) { int index = reader.ReadInt32(); if (index < 0 || index >= _definitions.Count) { continue; } var wmo = _definitions[index]; if (_drawn.Contains(wmo.UniqueId)) { continue; } _drawn.Add(wmo.UniqueId); if (wmo.MwidIndex >= _paths.Count) { continue; } var path = _paths[(int)wmo.MwidIndex]; var model = Cache.WorldModel.Get(path); if (model == null) { model = new WorldModelRoot(path); Cache.WorldModel.Insert(path, model); } if (Vertices == null) { Vertices = new List <Vector3>(1000); } if (Triangles == null) { Triangles = new List <Triangle <uint> >(1000); } InsertModelGeometry(Vertices, Triangles, wmo, model); } }
public void TestDungeonWithWater() { //MpqManager.Initialize("S:\\World of Warcraft"); var wdt = new WDT("world\\maps\\orgrimmarinstance\\orgrimmarinstance.wdt"); Assert.IsTrue(wdt.IsValid && wdt.IsGlobalModel); var file = wdt.ModelFile; var model = new WorldModelRoot(file); var verts = new System.Collections.Generic.List<Vector3>(); var tris = new System.Collections.Generic.List<Triangle<uint>>(); WorldModelHandler.InsertModelGeometry(verts, tris, wdt.ModelDefinition, model); Assert.IsFalse(verts.Any(v => float.IsNaN(v.X) || float.IsNaN(v.Y) || float.IsNaN(v.Z))); }
protected override void LoadContent() { var model = new WorldModelRoot(_path); var verts = new List <Vector3>(); var tris = new List <Triangle <uint> >(); WorldModelHandler.InsertModelGeometry(verts, tris, _def, model); SaveMeshToDisk(verts, tris); meshDisplay.Game.Camera.Camera.Position = new Vector3(verts[0].Y, verts[0].Z, verts[0].X); _drawer = new GeometryDrawer(); _drawer.Initialize(Game, Color.Red, verts, tris); _effect = new BasicEffect(GraphicsDevice); _depthState = new DepthStencilState { DepthBufferEnable = true }; }
public void TestGameWmo() { MpqManager.Initialize("S:\\WoW"); var root = new WorldModelRoot("world\\wmo\\Northrend\\Battleground\\ND_BG_Keep01.wmo"); }
public static void InsertModelGeometry(List <Vector3> vertices, List <Triangle <uint> > triangles, WorldModelDefinition def, WorldModelRoot root) { var transformation = Transformation.GetTransformation(def); foreach (var group in root.Groups) { int vertOffset = vertices.Count; vertices.AddRange(group.Vertices.Select(vert => Vector3.Transform(vert, transformation))); for (int i = 0; i < group.Triangles.Length; i++) { // only include collidable tris if ((group.TriangleFlags[i] & 0x04) != 0 && group.TriangleMaterials[i] != 0xFF) { continue; } var tri = group.Triangles[i]; triangles.Add(new Triangle <uint>(TriangleType.Wmo, (uint)(tri.V0 + vertOffset), (uint)(tri.V1 + vertOffset), (uint)(tri.V2 + vertOffset))); } } if (def.DoodadSet >= 0 && def.DoodadSet < root.DoodadSets.Count) { var set = root.DoodadSets[def.DoodadSet]; var instances = new List <DoodadInstance>((int)set.CountInstances); for (uint i = set.FirstInstanceIndex; i < (set.CountInstances + set.FirstInstanceIndex); i++) { if (i >= root.DoodadInstances.Count) { break; } instances.Add(root.DoodadInstances[(int)i]); } foreach (var instance in instances) { var model = Cache.Model.Get(instance.File); if (model == null) { model = new Model(instance.File); Cache.Model.Insert(instance.File, model); } if (!model.IsCollidable) { continue; } var doodadTransformation = Transformation.GetWmoDoodadTransformation(instance, def); int vertOffset = vertices.Count; vertices.AddRange(model.Vertices.Select(vert => Vector3.Transform(vert, doodadTransformation))); foreach (var tri in model.Triangles) { triangles.Add(new Triangle <uint>(TriangleType.Wmo, (uint)(tri.V0 + vertOffset), (uint)(tri.V1 + vertOffset), (uint)(tri.V2 + vertOffset))); } } } foreach (var group in root.Groups) { if (!group.HasLiquidData) { continue; } for (int y = 0; y < group.LiquidDataHeader.Height; y++) { for (int x = 0; x < group.LiquidDataHeader.Width; x++) { if (!group.LiquidDataGeometry.ShouldRender(x, y)) { continue; } var vertOffset = (uint)vertices.Count; vertices.Add(GetLiquidVert(transformation, group.LiquidDataHeader.BaseLocation, group.LiquidDataGeometry.HeightMap[x, y], x, y)); vertices.Add(GetLiquidVert(transformation, group.LiquidDataHeader.BaseLocation, group.LiquidDataGeometry.HeightMap[x + 1, y], x + 1, y)); vertices.Add(GetLiquidVert(transformation, group.LiquidDataHeader.BaseLocation, group.LiquidDataGeometry.HeightMap[x, y + 1], x, y + 1)); vertices.Add(GetLiquidVert(transformation, group.LiquidDataHeader.BaseLocation, group.LiquidDataGeometry.HeightMap[x + 1, y + 1], x + 1, y + 1)); triangles.Add(new Triangle <uint>(TriangleType.Water, vertOffset, vertOffset + 2, vertOffset + 1)); triangles.Add(new Triangle <uint>(TriangleType.Water, vertOffset + 2, vertOffset + 3, vertOffset + 1)); } } } }
public byte[] Build(BaseLog log) { var wdt = new WDT("World\\maps\\" + Dungeon + "\\" + Dungeon + ".wdt"); if (!wdt.IsGlobalModel || !wdt.IsValid) { return(null); } InitializeProgress(12); Geometry = new Geometry { Transform = true }; var model = new WorldModelRoot(wdt.ModelFile); Geometry.AddDungeon(model, wdt.ModelDefinition); CompleteWorkUnit(); if (Geometry.Vertices.Count == 0 && Geometry.Triangles.Count == 0) { throw new InvalidOperationException("Can't build mesh with empty geometry"); } Log = log; Context = new RecastContext(); Context.SetContextHandler(Log); // get raw geometry - lots of slowness here float[] vertices; int[] triangles; byte[] areas; Geometry.GetRawData(out vertices, out triangles, out areas); Geometry.Triangles.Clear(); float[] bmin, bmax; Geometry.CalculateBoundingBox(out bmin, out bmax); Geometry.Vertices.Clear(); // Allocate voxel heightfield where we rasterize our input data to. Heightfield hf; int width, height; Recast.CalcGridSize(bmin, bmax, Config.CellSize, out width, out height); if (!Context.CreateHeightfield(out hf, width, height, bmin, bmax, Config.CellSize, Config.CellHeight)) { throw new OutOfMemoryException("CreateHeightfield ran out of memory"); } CompleteWorkUnit(); // Find triangles which are walkable based on their slope and rasterize them. Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas); Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb); CompleteWorkUnit(); // Once all geometry is rasterized, we do initial pass of filtering to // remove unwanted overhangs caused by the conservative rasterization // as well as filter spans where the character cannot possibly stand. Context.FilterLowHangingWalkableObstacles(Config.WalkableClimb, hf); Context.FilterLedgeSpans(Config.WalkableHeight, Config.WalkableClimb, hf); Context.FilterWalkableLowHeightSpans(Config.WalkableHeight, hf); CompleteWorkUnit(); // Compact the heightfield so that it is faster to handle from now on. // This will result in more cache coherent data as well as the neighbours // between walkable cells will be calculated. CompactHeightfield chf; if (!Context.BuildCompactHeightfield(Config.WalkableHeight, Config.WalkableClimb, hf, out chf)) { throw new OutOfMemoryException("BuildCompactHeightfield ran out of memory"); } CompleteWorkUnit(); hf.Delete(); // Erode the walkable area by agent radius. if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf)) { throw new OutOfMemoryException("ErodeWalkableArea ran out of memory"); } CompleteWorkUnit(); // Prepare for region partitioning, by calculating distance field along the walkable surface. if (!Context.BuildDistanceField(chf)) { throw new OutOfMemoryException("BuildDistanceField ran out of memory"); } CompleteWorkUnit(); // Partition the walkable surface into simple regions without holes. if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea)) { throw new OutOfMemoryException("BuildRegions ran out of memory"); } CompleteWorkUnit(); // Create contours. ContourSet cset; if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset)) { throw new OutOfMemoryException("BuildContours ran out of memory"); } CompleteWorkUnit(); // Build polygon navmesh from the contours. PolyMesh pmesh; if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh)) { throw new OutOfMemoryException("BuildPolyMesh ran out of memory"); } CompleteWorkUnit(); // Build detail mesh. PolyMeshDetail dmesh; if (!Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError, out dmesh)) { throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory"); } CompleteWorkUnit(); chf.Delete(); cset.Delete(); // Set flags according to area types (e.g. Swim for Water) pmesh.MarkAll(); byte[] meshData; if (!Detour.CreateNavMeshData(out meshData, pmesh, dmesh, 0, 0, bmin, bmax, Config.WorldWalkableHeight, Config.WorldWalkableRadius, Config.WorldWalkableClimb, Config.CellSize, Config.CellHeight, Config.TileWidth, null)) { pmesh.Delete(); dmesh.Delete(); return(null); } CompleteWorkUnit(); pmesh.Delete(); dmesh.Delete(); return(meshData); }
public static void InsertGameObjectModelGeometry(List <Vector3> vertices, List <Triangle <uint> > triangles, string m2path, Matrix transformation) { uint fileId; uint.TryParse(m2path, out fileId); bool isWMO = false; if (fileId > 0) { // do something to try and get the good type. var t = MpqManager.GetFileExtension((int)fileId); //Console.WriteLine("fileId: " + fileId + ", fileExt: " + t); var _stream = MpqManager.GetFile(fileId); var binary = new BinaryReader(_stream); var magic = binary.ReadBytes(4); if (t != ".m2" && System.Text.Encoding.Default.GetString(magic) != "MD21" && System.Text.Encoding.Default.GetString(magic) != "MD20") { if (string.IsNullOrEmpty(t)) { return; } if (String.Equals(t, ".wmo", StringComparison.CurrentCultureIgnoreCase)) { isWMO = true; } else { return; } } if (m2path.EndsWith(".WMO", StringComparison.InvariantCultureIgnoreCase) || isWMO) { var wmo = Cache.WorldModel.Get(m2path); if (wmo == null) { try { wmo = new WorldModelRoot(m2path); } catch { } Cache.WorldModel.Insert(m2path, wmo); //System.Console.WriteLine(m2path); foreach (var group in wmo.Groups) { if ((group.Flags & 0x80) != 0) // Here is a group of triangles that mess-up the WMO { continue; } int vertOffset = vertices.Count; if (group.Triangles != null) { bool one = false; for (int i = 0; i < group.Triangles.Length; i++) { // the commented code exclude "non-collidable triangles" so adding them anyway is not breaking a path // it's just adding more bytes into the mesh, but... // fact is removing them can remove "ground" in some big gameobject, creating holes in the meshes. // so that's why it's now commented. // // only include collidable triangles //if ((group.TriangleFlags[i] & 0x04) == 0 && group.TriangleMaterials[i] != 0xFF) //continue; var tri = group.Triangles[i]; triangles.Add(new Triangle <uint>(TriangleType.Wmo, (uint)(tri.V0 + vertOffset), (uint)(tri.V1 + vertOffset), (uint)(tri.V2 + vertOffset))); one = true; } if (one) { vertices.AddRange(group.Vertices.Select(vert => Vector3.TransformCoordinate(vert, transformation))); } } } } } else // .M2 { var model = Cache.Model.Get(m2path); if (model == null) { model = new Model(m2path); Cache.Model.Insert(m2path, model); } //System.Console.WriteLine(m2path); if (!model.IsCollidable) { return; } int vertOffset = vertices.Count; vertices.AddRange(model.Vertices.Select(vert => Vector3.TransformCoordinate(vert, transformation))); foreach (var tri in model.Triangles) { triangles.Add(new Triangle <uint>(TriangleType.Doodad, (uint)(tri.V0 + vertOffset), (uint)(tri.V1 + vertOffset), (uint)(tri.V2 + vertOffset))); } } } }