Example #1
0
        public void handle_partial_result()
        {
            using (var ctx = new RecastContext())
            {
                var navMesh      = LoadNavMeshBinFile(ctx);
                var navMeshQuery = ctx.CreateNavMeshQuery(navMesh);

                var stopwatch = Stopwatch.StartNew();
                var pointA    = new PolyPointResult
                {
                    status  = 1073741824,
                    point   = new[] { -373.413f, 107.4798f, -271.1656f },
                    polyRef = 281474994536448
                };
                var pointB = new PolyPointResult
                {
                    status  = 1073741824,
                    point   = new[] { -370.4435f, 100.7469f, -221.2217f },
                    polyRef = 281475063742464
                };
                var result       = FindPathSafer(pointA, pointB, ctx, navMeshQuery, stopwatch);
                var smoothResult = ctx.FindSmoothPath(navMeshQuery, navMesh, result, pointA, pointB);

                Assert.AreEqual(5, result.pathCount);
                Assert.True(PartialResult(result.status));
                Assert.AreEqual(3, smoothResult.pathCount);
            }
        }
Example #2
0
        private InputGeom GetInputGeom(RecastContext ctx)
        {
            var mesh = ctx.LoadInputGeom(TestUtils.ResolveResource("./Resources/Tile_+007_+006_L21.obj"), true);

            ctx.CalcGridSize(ref _config, mesh);
            return(mesh);
        }
Example #3
0
        private float be_fast_work(RecastContext ctx, NavMesh navMesh)
        {
            var navMeshQuery = ctx.CreateNavMeshQuery(navMesh);

            const int N         = 10000;
            var       NRan      = 0;
            var       stopwatch = Stopwatch.StartNew();

            stopwatch.Stop();
            for (var i = 0; i < N; i++)
            {
                var pointA = FindRandomPointSafer(ctx, navMeshQuery);
                var pointB = FindRandomPointSafer(ctx, navMeshQuery);
                var result = FindPathSafer(pointA, pointB, ctx, navMeshQuery, stopwatch);
                if (Success(result.status))
                {
                    var smoothResult = ctx.FindSmoothPath(navMeshQuery, navMesh, result, pointA, pointB);

                    if (!PartialResult(result.status))
                    {
                        Assert.GreaterOrEqual(smoothResult.pathCount, result.pathCount,
                                              $"smoothResult.pathCount [{smoothResult.pathCount}] < result.pathCount [{result.pathCount}]. PointA = {pointA}, PointB={pointB}");
                    }
                }
                NRan++;
            }

            float avg = (float)stopwatch.ElapsedMilliseconds / NRan;

            Console.WriteLine($"\nAverage time (ms) for {NRan} run(s): {avg}");
            return(avg);
        }
Example #4
0
 public void create_a_context()
 {
     using (var ctx = new RecastContext())
     {
         Assert.IsNotNull(ctx);
     }
 }
Example #5
0
 public void load_nav_mesh_tiled_bin_file()
 {
     using (var ctx = new RecastContext())
     {
         NavMesh navMesh = LoadNavMeshBinFile(ctx);
         Assert.IsNotNull(navMesh);
     }
 }
Example #6
0
        private NavMesh LoadNavMeshBinFile(RecastContext ctx)
        {
            var navMesh =
                ctx.LoadTiledNavMeshBinFile(TestUtils.ResolveResource("./Resources/Tile_+007_+006_L21.obj.tiled.bin64"));

            Assert.IsNotNull(navMesh);
            return(navMesh);
        }
Example #7
0
 public void load_a_mesh()
 {
     using (var ctx = new RecastContext())
     {
         var mesh = GetInputGeom(ctx);
         Assert.IsNotNull(mesh);
     }
 }
Example #8
0
 public void be_fast_from_obj()
 {
     using (var ctx = new RecastContext())
     {
         var navMesh = CreateNavMesh(ctx);
         var avg     = be_fast_work(ctx, navMesh);
         Assert.LessOrEqual(avg, 0.1);
     }
 }
Example #9
0
 public void create_compact_heightfield()
 {
     using (var ctx = new RecastContext())
     {
         var mesh = GetInputGeom(ctx);
         var chf  = ctx.CreateCompactHeightfield(_config, mesh);
         Assert.IsNotNull(chf);
     }
 }
Example #10
0
 public void be_fast_from_bin()
 {
     using (var ctx = new RecastContext())
     {
         var navMesh = LoadNavMeshBinFile(ctx);
         var avg     = be_fast_work(ctx, navMesh);
         Assert.LessOrEqual(avg, 0.1);
     }
 }
Example #11
0
 public void create_polymesh_detail()
 {
     using (var ctx = new RecastContext())
     {
         var mesh           = GetInputGeom(ctx);
         var chf            = ctx.CreateCompactHeightfield(_config, mesh);
         var polyMesh       = ctx.CreatePolyMesh(_config, chf);
         var polyMeshDetail = ctx.CreatePolyMeshDetail(_config, polyMesh, chf);
     }
 }
Example #12
0
 public void find_random_point()
 {
     using (var ctx = new RecastContext())
     {
         var navMesh      = CreateNavMesh(ctx);
         var navMeshQuery = ctx.CreateNavMeshQuery(navMesh);
         var result       = ctx.FindRandomPoint(navMeshQuery);
         Assert.IsTrue(Success(result.status));
         Assert.AreEqual(result.point.Length, 3);
     }
 }
Example #13
0
 public void find_path()
 {
     using (var ctx = new RecastContext())
     {
         var navMesh      = CreateNavMesh(ctx);
         var navMeshQuery = ctx.CreateNavMeshQuery(navMesh);
         var pointA       = FindRandomPointSafer(ctx, navMeshQuery);
         var pointB       = FindRandomPointSafer(ctx, navMeshQuery);
         var result       = FindPathSafer(pointA, pointB, ctx, navMeshQuery);
         Assert.IsTrue(Success(result.status));
     }
 }
Example #14
0
        private PolyPointResult FindRandomPointSafer(RecastContext ctx, NavMeshQuery navMeshQuery)
        {
            int             retries = 10;
            PolyPointResult result;

            do
            {
                result = ctx.FindRandomPoint(navMeshQuery);
                retries--;
            } while ((!Success(result.status)) && (0 < retries));
            return(result);
        }
        /// <summary>
        /// Initialize a new DefaultMeshNavigator given a mesh file and halfExtents parameters.
        /// </summary>
        /// <param name="navMeshFile">Mesh file</param>
        /// <param name="halfExtents">Half extents</param>
        /// <exception cref="Exception">Throws an exception if the mesh file cannot be loaded.</exception>
        public DefaultMeshNavigator(string navMeshFile, float[] halfExtents)
        {
            _ctx     = new RecastContext();
            _navMesh = _ctx.LoadTiledNavMeshBinFile(navMeshFile);

            if (_navMesh.IsInvalid)
            {
                throw new Exception("Failed to load nav mesh");
            }

            _navMeshQuery = _ctx.CreateNavMeshQuery(_navMesh);
            _halfExtents  = halfExtents;
        }
Example #16
0
        public void find_nearest_poly()
        {
            using (var ctx = new RecastContext()) {
                var navMesh = CreateNavMesh(ctx);

                var navMeshQuery = ctx.CreateNavMeshQuery(navMesh);

                var point       = new float[] { -575f, -69.1874f, 54f };
                var halfExtents = new float[] { 10.0f, 10.0f, 10.0f };
                var result      = ctx.FindNearestPoly(navMeshQuery, point, halfExtents);
                Assert.AreEqual(result.polyRef, 281474976711211L);
            }
        }
Example #17
0
 public void create_navmesh()
 {
     using (var ctx = new RecastContext())
     {
         var mesh           = GetInputGeom(ctx);
         var chf            = ctx.CreateCompactHeightfield(_config, mesh);
         var polyMesh       = ctx.CreatePolyMesh(_config, chf);
         var polyMeshDetail = ctx.CreatePolyMeshDetail(_config, polyMesh, chf);
         var navMeshData    = ctx.CreateNavMeshData(_config, polyMeshDetail, polyMesh, mesh, 0, 0,
                                                    BuildSettings.agentHeight, BuildSettings.agentRadius, BuildSettings.agentMaxClimb);
         var navMesh = ctx.CreateNavMesh(navMeshData);
         Assert.IsNotNull(navMesh);
     }
 }
Example #18
0
        private NavMesh CreateNavMesh(RecastContext ctx)
        {
            var mesh = ctx.LoadInputGeom(TestUtils.ResolveResource("Resources/Tile_+007_+006_L21.obj"), true);

            Assert.IsNotNull(mesh);
            ctx.CalcGridSize(ref _config, mesh);
            var chf            = ctx.CreateCompactHeightfield(_config, mesh);
            var polyMesh       = ctx.CreatePolyMesh(_config, chf);
            var polyMeshDetail = ctx.CreatePolyMeshDetail(_config, polyMesh, chf);
            var navMeshData    = ctx.CreateNavMeshData(_config, polyMeshDetail, polyMesh, mesh, 0, 0,
                                                       BuildSettings.agentHeight, BuildSettings.agentRadius,
                                                       BuildSettings.agentMaxClimb);

            return(ctx.CreateNavMesh(navMeshData));
        }
Example #19
0
        public void create_navmesh_data()
        {
            using (var ctx = new RecastContext())
            {
                var mesh           = GetInputGeom(ctx);
                var chf            = ctx.CreateCompactHeightfield(_config, mesh);
                var polyMesh       = ctx.CreatePolyMesh(_config, chf);
                var polyMeshDetail = ctx.CreatePolyMeshDetail(_config, polyMesh, chf);
                var navMeshData    = ctx.CreateNavMeshData(_config, polyMeshDetail, polyMesh, mesh, 0, 0,
                                                           BuildSettings.agentHeight, BuildSettings.agentRadius, BuildSettings.agentMaxClimb);
                // TODO: This is different to Java!!
                Assert.AreEqual(114764, navMeshData.size);

                var bytes = navMeshData.GetData();
                Assert.AreEqual(bytes.Length, navMeshData.size);
            }
        }
Example #20
0
        public void find_nearest_poly_fail()
        {
            using (var ctx = new RecastContext())
            {
                var navMesh      = CreateNavMesh(ctx);
                var navMeshQuery = ctx.CreateNavMeshQuery(navMesh);

                var point       = new float[] { -5750.0f, -6900.1874f, 5400.0f };
                var halfExtents = new float[] { 10.0f, 10.0f, 10.0f };
                var result      = ctx.FindNearestPoly(navMeshQuery, point, halfExtents);

                Assert.IsFalse(Success(result.status));
                Assert.AreEqual(result.polyRef, 0);
                Assert.AreEqual(result.point[0], 0);
                Assert.AreEqual(result.point[1], 0);
                Assert.AreEqual(result.point[2], 0);
            }
        }
Example #21
0
        public void find_smooth_path()
        {
            using (var ctx = new RecastContext())
            {
                var navMesh      = CreateNavMesh(ctx);
                var navMeshQuery = ctx.CreateNavMeshQuery(navMesh);
                var pointA       = FindRandomPointSafer(ctx, navMeshQuery);
                var pointB       = FindRandomPointSafer(ctx, navMeshQuery);

                var result = FindPathSafer(pointA, pointB, ctx, navMeshQuery);
                Assert.IsTrue(Success(result.status));

                var smoothResult = ctx.FindSmoothPath(navMeshQuery, navMesh, result, pointA, pointB);
                Assert.IsNotNull(smoothResult);
                Assert.GreaterOrEqual(smoothResult.pathCount, result.pathCount);
                Assert.AreEqual(3 * Constants.MaxSmoothPathLength, smoothResult.path.Length);
                Assert.IsTrue(smoothResult.pathCount < Constants.MaxSmoothPathLength * 3);
                Assert.AreEqual(smoothResult.path[0], pointA.point[0], 0.00001);
                Assert.AreEqual(smoothResult.path[1], pointA.point[1], 0.00001);
                Assert.AreEqual(smoothResult.path[2], pointA.point[2], 0.00001);
            }
        }
Example #22
0
        private FindPathResult FindPathSafer(PolyPointResult pointA, PolyPointResult pointB,
                                             RecastContext ctx, NavMeshQuery navMeshQuery,
                                             Stopwatch stopwatch = null)
        {
            Assert.IsTrue(Success(pointA.status), "Point A not a success.");
            Assert.IsTrue(Success(pointB.status), "Point A not a success.");

            if (null != stopwatch)
            {
                stopwatch.Start();
            }
            int            retries = 10;
            FindPathResult result;

            do
            {
                result = ctx.FindPath(navMeshQuery, pointA, pointB);
                retries--;
            } while ((!Success(result.status)) && (0 < retries));
            if (null != stopwatch)
            {
                stopwatch.Stop();
            }

            if (Success(result.status))
            {
                Assert.IsNotNull(result, "result NULL");
                Assert.AreEqual(Constants.MaxPathLength, result.path.Length, $"Constants.MaxPathLength != result.path.Length [{Constants.MaxPathLength} != {result.path.Length}]");
                Assert.GreaterOrEqual(result.pathCount, 1, $"result.pathCount [{result.pathCount}] < 1");
                Assert.AreEqual(pointA.polyRef, result.path[0], $"point A polyref does not match [{pointA.polyRef} != {result.path[0]}]");
                if (!PartialResult(result.status))
                {
                    Assert.AreEqual(pointB.polyRef, result.path[result.pathCount - 1],
                                    $"point B polyref does not match [{pointA.polyRef} != {result.path[result.pathCount - 1]}] (status={result.status} [{Convert.ToString(result.status, 2)}])");
                }
            }

            return(result);
        }
Example #23
0
        public void disposes_work()
        {
            var ctx            = new RecastContext();
            var mesh           = GetInputGeom(ctx);
            var chf            = ctx.CreateCompactHeightfield(_config, mesh);
            var polyMesh       = ctx.CreatePolyMesh(_config, chf);
            var polyMeshDetail = ctx.CreatePolyMeshDetail(_config, polyMesh, chf);
            var navMeshData    = ctx.CreateNavMeshData(_config, polyMeshDetail, polyMesh, mesh, 0, 0,
                                                       BuildSettings.agentHeight, BuildSettings.agentRadius, BuildSettings.agentMaxClimb);
            var navMesh      = ctx.CreateNavMesh(navMeshData);
            var navMeshQuery = ctx.CreateNavMeshQuery(navMesh);

            Assert.IsNotNull(navMeshQuery);

            navMeshQuery.Dispose();
            navMesh.Dispose();
            polyMeshDetail.Dispose();
            polyMesh.Dispose();
            chf.Dispose();
            mesh.Dispose();
            ctx.Dispose();
        }
Example #24
0
        public byte[] Build()
        {
            Geometry = new Geometry.Geometry {Transform = true };
            {
                var main = new ADT(World, X, Y);
                main.Read();
               // main.Generate();
                Geometry.AddADT(main);
            }

            if (Geometry.Vertices.Count == 0 && Geometry.Indices.Count == 0)
                throw new InvalidOperationException("Can't build tile with empty geometry");

            float[] bbMin, bbMax;
            CalculateTileBounds(out bbMin, out bbMax);
            Geometry.CalculateMinMaxHeight(out bbMin[1], out bbMax[1]);



            // again, we load everything - wasteful but who cares
            /* for (int ty = Y - 1; ty <= Y + 1; ty++)
             {
                 for (int tx = X - 1; tx <= X + 1; tx++)
                 {
                     try
                     {
                         // don't load main tile again
                         if (tx == X && ty == Y)
                             continue;

                         var adt = new ADT(World, tx, ty);
                         adt.Read();
                         Geometry.AddADT(adt);
                     }
                     catch (FileNotFoundException)
                     {
                         // don't care - no file means no geometry
                     }
                 }
             }*/

            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.SaveWavefrontObject($"{World}_{X}_{Y}.obj");
            Geometry.Indices.Clear();
            Geometry.Vertices.Clear();

            // add border
            bbMin[0] -= Config.BorderSize * Config.CellSize;
            bbMin[2] -= Config.BorderSize * Config.CellSize;
            bbMax[0] += Config.BorderSize * Config.CellSize;
            bbMax[2] += Config.BorderSize * Config.CellSize;


            Heightfield hf;
            int width = Config.TileWidth + (Config.BorderSize * 2);
            if (!Context.CreateHeightfield(out hf, width, width, bbMin, bbMax, Config.CellSize, Config.CellHeight))
                throw new OutOfMemoryException("CreateHeightfield ran out of memory");
            Context.MarkWalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles,out areas);
          //  Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas);
            Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb);

            // 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);

            // 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");

            hf.Delete();

            // Erode the walkable area by agent radius.
            if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf))
                throw new OutOfMemoryException("ErodeWalkableArea ran out of memory");

            // Prepare for region partitioning, by calculating distance field along the walkable surface.
            if (!Context.BuildDistanceField(chf))
                throw new OutOfMemoryException("BuildDistanceField ran out of memory");

            // Partition the walkable surface into simple regions without holes.
            if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea))
                throw new OutOfMemoryException("BuildRegionsMonotone ran out of memory");

            // Create contours.
            ContourSet cset;
            if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset))
                throw new OutOfMemoryException("BuildContours ran out of memory");

            // Build polygon navmesh from the contours.
            PolyMesh pmesh;
            if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh))
                throw new OutOfMemoryException("BuildPolyMesh ran out of memory");

            // Build detail mesh.
            PolyMeshDetail dmesh;
            if (
                !Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError,
                                             out dmesh))
                throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory");

            chf.Delete();
            cset.Delete();

            // Remove padding from the polymesh data. (Remove this odditity)
            pmesh.RemovePadding(Config.BorderSize);

            // Set flags according to area types (e.g. Swim for Water)
            pmesh.MarkAll();

            // get original bounds
            float[] tilebMin, tilebMax;
            CalculateTileBounds(out tilebMin, out tilebMax);
            tilebMin[1] = bbMin[1];
            tilebMax[1] = bbMax[1];

            // build off mesh connections for flightmasters
            // bMax and bMin are switched here because of the coordinate system transformation

            var connections = new List<OffMeshConnection>();


            byte[] tileData;
            if (!Detour.CreateNavMeshData(out tileData, pmesh, dmesh,
                                          X, Y, tilebMin, tilebMax,
                                          Config.WorldWalkableHeight, Config.WorldWalkableRadius,
                                          Config.WorldWalkableClimb, Config.CellSize,
                                          Config.CellHeight, Config.TileWidth,
                                          connections.ToArray()))
            {
                pmesh.Delete();
                dmesh.Delete();
                return null;
            }

            pmesh.Delete();
            dmesh.Delete();
            GC.Collect();
            return tileData;
        }
Example #25
0
        public void PrepareData(BaseLog log)
        {
            if (log == null)
            {
                throw new ArgumentNullException("log");
            }

            Log = log;
            Cache.Clear();

            Geometry = new Geometry {
                Transform = true
            };
            //List<ADT> adtList = new List<ADT>();

            bool hasHandle = false;

            try
            {
                try
                {
                    hasHandle = _mutex.WaitOne(Timeout.Infinite, false);
                    if (hasHandle == false)
                    {
                        throw new TimeoutException("Timeout waiting for exclusive access");
                    }
                }
                catch (AbandonedMutexException)
                {
                    // The mutex was abandoned in another process, it will still get aquired
                    hasHandle = true;
                }

                // Do the work which require this mutex locking (useless with CACS)
                //{
                ADT main = GetAdt(World, X, Y);
                Geometry.AddAdt(main);
                InsertAllGameobjectGeometry(X, Y, MapId);
                // Geometry.CreateDemoDump("X:\\Meshes\\" + MapId + "_" + X + "_" + Y + ".obj");
                //}

                if (Geometry.Vertices.Count == 0 && Geometry.Triangles.Count == 0)
                {
                    throw new InvalidOperationException("Can't build tile with empty geometry");
                }

                // again, we load everything - wasteful but who cares
                for (int ty = Y - 1; ty <= Y + 1; ty++)
                {
                    for (int tx = X - 1; tx <= X + 1; tx++)
                    {
                        // don't load main tile again
                        if (tx == X && ty == Y)
                        {
                            continue;
                        }

                        ADT adt = GetAdt(World, tx, ty);
                        if (adt.HasObjectData)
                        {
                            //Console.WriteLine("-> " + World + "_" + tx + "_" + ty);
                            Geometry.AddAdt(adt);
                            InsertAllGameobjectGeometry(tx, ty, MapId);
                        }
                        else
                        {
                            string parentMap = PhaseHelper.GetParentMap(World);
                            if (parentMap != string.Empty)
                            {
                                ADT adtParent = GetAdt(parentMap, tx, ty);
                                if (adtParent.HasObjectData)
                                {
                                    Console.WriteLine("-> " + parentMap + "_" + tx + "_" + ty);
                                    Geometry.AddAdt(adtParent);
                                    InsertAllGameobjectGeometry(tx, ty, PhaseHelper.GetMapIdByName(parentMap));
                                }
                            }
                        }
                    }
                }
            }
            finally
            {
                if (hasHandle)
                {
                    _mutex.ReleaseMutex();
                }
            }

            Context = new RecastContext();
            Context.SetContextHandler(Log);
        }
Example #26
0
        public byte[] Build(BaseLog log)
        {
            Log      = log;
            Geometry = new Geometry {
                Transform = true
            };

            {
                var main = GetAdt(World, X, Y);
                Geometry.AddAdt(main);
            }

            if (Geometry.Vertices.Count == 0 && Geometry.Triangles.Count == 0)
            {
                throw new InvalidOperationException("Can't build tile with empty geometry");
            }

            float[] bbMin, bbMax;
            CalculateTileBounds(out bbMin, out bbMax);
            Geometry.CalculateMinMaxHeight(out bbMin[1], out bbMax[1]);

            // again, we load everything - wasteful but who cares
            for (int ty = Y - 1; ty <= Y + 1; ty++)
            {
                for (int tx = X - 1; tx <= X + 1; tx++)
                {
                    try
                    {
                        // don't load main tile again
                        if (tx == X && ty == Y)
                        {
                            continue;
                        }

                        var adt = GetAdt(World, tx, ty);
                        Geometry.AddAdt(adt);
                    }
                    catch (FileNotFoundException)
                    {
                        // don't care - no file means no geometry
                    }
                }
            }

            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();
            Geometry.Vertices.Clear();

            // add border
            bbMin[0] -= Config.BorderSize * Config.CellSize;
            bbMin[2] -= Config.BorderSize * Config.CellSize;
            bbMax[0] += Config.BorderSize * Config.CellSize;
            bbMax[2] += Config.BorderSize * Config.CellSize;

            Heightfield hf;
            int         width = Config.TileWidth + (Config.BorderSize * 2);

            if (!Context.CreateHeightfield(out hf, width, width, bbMin, bbMax, Config.CellSize, Config.CellHeight))
            {
                throw new OutOfMemoryException("CreateHeightfield ran out of memory");
            }

            Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas);
            Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb);

            // 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);

            // 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");
            }

            hf.Delete();

            // Erode the walkable area by agent radius.
            if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf))
            {
                throw new OutOfMemoryException("ErodeWalkableArea ran out of memory");
            }

            // Prepare for region partitioning, by calculating distance field along the walkable surface.
            if (!Context.BuildDistanceField(chf))
            {
                throw new OutOfMemoryException("BuildDistanceField ran out of memory");
            }

            // Partition the walkable surface into simple regions without holes.
            if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea))
            {
                throw new OutOfMemoryException("BuildRegionsMonotone ran out of memory");
            }

            // Create contours.
            ContourSet cset;

            if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset))
            {
                throw new OutOfMemoryException("BuildContours ran out of memory");
            }

            // Build polygon navmesh from the contours.
            PolyMesh pmesh;

            if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh))
            {
                throw new OutOfMemoryException("BuildPolyMesh ran out of memory");
            }

            // Build detail mesh.
            PolyMeshDetail dmesh;

            if (
                !Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError,
                                             out dmesh))
            {
                throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory");
            }

            chf.Delete();
            cset.Delete();

            // Remove padding from the polymesh data. (Remove this odditity)
            pmesh.RemovePadding(Config.BorderSize);

            // Set flags according to area types (e.g. Swim for Water)
            pmesh.MarkAll();

            // get original bounds
            float[] tilebMin, tilebMax;
            CalculateTileBounds(out tilebMin, out tilebMax);
            tilebMin[1] = bbMin[1];
            tilebMax[1] = bbMax[1];

            // build off mesh connections for flightmasters
            // bMax and bMin are switched here because of the coordinate system transformation
            /// This is not needed for our particular use.
            var connections = new List <OffMeshConnection>();

            /*var taxis = TaxiHelper.GetNodesInBBox(MapId, tilebMax.ToWoW(), tilebMin.ToWoW());
             * foreach (var taxi in taxis)
             * {
             *  Log.Log(LogCategory.Warning,
             *          "Flightmaster \"" + taxi.Name + "\", Id: " + taxi.Id + " Horde: " + taxi.IsHorde + " Alliance: " +
             *          taxi.IsAlliance);
             *
             *  var data = TaxiHelper.GetTaxiData(taxi);
             *  var from = taxi.Location.ToRecast().ToFloatArray();
             *  connections.AddRange(data.To.Select(to => new OffMeshConnection
             *                                                {
             *                                                    AreaId = PolyArea.Road,
             *                                                    Flags = PolyFlag.FlightMaster,
             *                                                    From = from,
             *                                                    To = to.Value.Location.ToRecast().ToFloatArray(),
             *                                                    Radius = Config.WorldWalkableRadius,
             *                                                    Type = ConnectionType.OneWay,
             *                                                    UserID = (uint) to.Key
             *                                                }));
             *
             *  foreach (var target in data.To)
             *      Log.Log(LogCategory.Warning,
             *              "\tPath to: \"" + target.Value.Name + "\" Id: " + target.Value.Id + " Path Id: " +
             *              target.Key);
             * }*/

            byte[] tileData;
            if (!Detour.CreateNavMeshData(out tileData, pmesh, dmesh,
                                          X, Y, tilebMin, tilebMax,
                                          Config.WorldWalkableHeight, Config.WorldWalkableRadius,
                                          Config.WorldWalkableClimb, Config.CellSize,
                                          Config.CellHeight, Config.TileWidth,
                                          connections.ToArray()))
            {
                pmesh.Delete();
                dmesh.Delete();
                return(null);
            }

            pmesh.Delete();
            dmesh.Delete();
            Cache.Clear();
            GC.Collect();
            return(tileData);
        }
Example #27
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 #28
0
        public byte[] Build(BaseLog log)
        {
            Log = log;
            Geometry = new Geometry {Transform = true};

            {
                var main = new ADT(GetAdtPath(World, X, Y));
                main.Read();
                Geometry.AddAdt(main);
            }

            if (Geometry.Vertices.Count == 0 && Geometry.Triangles.Count == 0)
                throw new InvalidOperationException("Can't build tile with empty geometry");

            float[] bbMin, bbMax;
            CalculateTileBounds(out bbMin, out bbMax);
            Geometry.CalculateMinMaxHeight(out bbMin[1], out bbMax[1]);

            // again, we load everything - wasteful but who cares
            for (int ty = Y - 1; ty <= Y + 1; ty++)
            {
                for (int tx = X - 1; tx <= X + 1; tx++)
                {
                    try
                    {
                        // don't load main tile again
                        if (tx == X && ty == Y)
                            continue;

                        var adt = new ADT(GetAdtPath(World, tx, ty));
                        adt.Read();
                        Geometry.AddAdt(adt);
                    }
                    catch (FileNotFoundException)
                    {
                        // don't care - no file means no geometry
                    }
                }
            }

            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();
            Geometry.Vertices.Clear();

            // add border
            bbMin[0] -= Config.BorderSize*Config.CellSize;
            bbMin[2] -= Config.BorderSize*Config.CellSize;
            bbMax[0] += Config.BorderSize*Config.CellSize;
            bbMax[2] += Config.BorderSize*Config.CellSize;

            Heightfield hf;
            int width = Config.TileWidth + (Config.BorderSize*2);
            if (!Context.CreateHeightfield(out hf, width, width, bbMin, bbMax, Config.CellSize, Config.CellHeight))
                throw new OutOfMemoryException("CreateHeightfield ran out of memory");

            Context.ClearUnwalkableTriangles(Config.WalkableSlopeAngle, ref vertices, ref triangles, areas);
            Context.RasterizeTriangles(ref vertices, ref triangles, ref areas, hf, Config.WalkableClimb);

            // 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);

            // 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");

            hf.Delete();

            // Erode the walkable area by agent radius.
            if (!Context.ErodeWalkableArea(Config.WalkableRadius, chf))
                throw new OutOfMemoryException("ErodeWalkableArea ran out of memory");

            // Prepare for region partitioning, by calculating distance field along the walkable surface.
            if (!Context.BuildDistanceField(chf))
                throw new OutOfMemoryException("BuildDistanceField ran out of memory");

            // Partition the walkable surface into simple regions without holes.
            if (!Context.BuildRegions(chf, Config.BorderSize, Config.MinRegionArea, Config.MergeRegionArea))
                throw new OutOfMemoryException("BuildRegionsMonotone ran out of memory");

            // Create contours.
            ContourSet cset;
            if (!Context.BuildContours(chf, Config.MaxSimplificationError, Config.MaxEdgeLength, out cset))
                throw new OutOfMemoryException("BuildContours ran out of memory");

            // Build polygon navmesh from the contours.
            PolyMesh pmesh;
            if (!Context.BuildPolyMesh(cset, Config.MaxVertsPerPoly, out pmesh))
                throw new OutOfMemoryException("BuildPolyMesh ran out of memory");

            // Build detail mesh.
            PolyMeshDetail dmesh;
            if (
                !Context.BuildPolyMeshDetail(pmesh, chf, Config.DetailSampleDistance, Config.DetailSampleMaxError,
                                             out dmesh))
                throw new OutOfMemoryException("BuildPolyMeshDetail ran out of memory");

            chf.Delete();
            cset.Delete();

            // Remove padding from the polymesh data. (Remove this odditity)
            pmesh.RemovePadding(Config.BorderSize);

            // Set flags according to area types (e.g. Swim for Water)
            pmesh.MarkAll();

            // get original bounds
            float[] tilebMin, tilebMax;
            CalculateTileBounds(out tilebMin, out tilebMax);
            tilebMin[1] = bbMin[1];
            tilebMax[1] = bbMax[1];

            // build off mesh connections for flightmasters
            // bMax and bMin are switched here because of the coordinate system transformation
            var taxis = TaxiHelper.GetNodesInBBox(MapId, tilebMax.ToWoW(), tilebMin.ToWoW());
            var connections = new List<OffMeshConnection>();
            foreach (var taxi in taxis)
            {
                Log.Log(LogCategory.Warning,
                        "Flightmaster \"" + taxi.Name + "\", Id: " + taxi.Id + " Horde: " + taxi.IsHorde + " Alliance: " +
                        taxi.IsAlliance);

                var data = TaxiHelper.GetTaxiData(taxi);
                var from = taxi.Location.ToRecast().ToFloatArray();
                connections.AddRange(data.To.Select(to => new OffMeshConnection
                                                              {
                                                                  AreaId = PolyArea.Road,
                                                                  Flags = PolyFlag.FlightMaster,
                                                                  From = from,
                                                                  To = to.Value.Location.ToRecast().ToFloatArray(),
                                                                  Radius = Config.WorldWalkableRadius,
                                                                  Type = ConnectionType.OneWay,
                                                                  UserID = (uint) to.Key
                                                              }));

                foreach (var target in data.To)
                    Log.Log(LogCategory.Warning,
                            "\tPath to: \"" + target.Value.Name + "\" Id: " + target.Value.Id + " Path Id: " +
                            target.Key);
            }

            byte[] tileData;
            if (!Detour.CreateNavMeshData(out tileData, pmesh, dmesh,
                                          X, Y, tilebMin, tilebMax,
                                          Config.WorldWalkableHeight, Config.WorldWalkableRadius,
                                          Config.WorldWalkableClimb, Config.CellSize,
                                          Config.CellHeight, Config.TileWidth,
                                          connections.ToArray()))
            {
                pmesh.Delete();
                dmesh.Delete();
                return null;
            }

            pmesh.Delete();
            dmesh.Delete();
            Cache.Clear();
            GC.Collect();
            return tileData;
        }
Example #29
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 #30
0
 public void use_64bit_polyref()
 {
     Assert.IsTrue(RecastContext.IsUsing64BitPolyRefs());
 }