Example #1
0
        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);
                    }
                }
            }
        }
Example #2
0
        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);
        }
Example #3
0
        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);
            }
        }
Example #4
0
 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)));
 }
Example #5
0
        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
            };
        }
Example #6
0
 public void TestGameWmo()
 {
     MpqManager.Initialize("S:\\WoW");
     var root = new WorldModelRoot("world\\wmo\\Northrend\\Battleground\\ND_BG_Keep01.wmo");
 }
Example #7
0
        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));
                    }
                }
            }
        }
Example #8
0
        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);
        }
Example #9
0
        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)));
                    }
                }
            }
        }