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); }
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 }; }
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 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).ToVector3())); 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).ToVector3())); 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 void TestGameWmo() { MpqManager.Initialize("S:\\WoW"); var root = new WorldModelRoot("world\\wmo\\Northrend\\Battleground\\ND_BG_Keep01.wmo"); }
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; }