Example #1
0
        public Detour.dtNavMeshQuery GetNavMeshQuery(uint mapId, uint instanceId, List <uint> swaps)
        {
            MMapData mmap = GetMMapData(mapId);

            if (mmap == null)
            {
                return(null);
            }

            if (!mmap.navMeshQueries.ContainsKey(instanceId))
            {
                // allocate mesh query
                Detour.dtNavMeshQuery query = new Detour.dtNavMeshQuery();
                if (Detour.dtStatusFailed(query.init(mmap.GetNavMesh(swaps), 1024)))
                {
                    Log.outError(LogFilter.Maps, "MMAP:GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId {0} instanceId {1}", mapId, instanceId);
                    return(null);
                }

                Log.outInfo(LogFilter.Maps, "MMAP:GetNavMeshQuery: created dtNavMeshQuery for mapId {0} instanceId {1}", mapId, instanceId);
                mmap.navMeshQueries.Add(instanceId, query);
            }

            return(mmap.navMeshQueries[instanceId]);
        }
Example #2
0
        bool loadMapInstanceImpl(string basePath, uint mapId, uint instanceId)
        {
            if (!loadMapData(basePath, mapId))
            {
                return(false);
            }

            MMapData mmap = loadedMMaps[mapId];

            if (mmap.navMeshQueries.ContainsKey(instanceId))
            {
                return(true);
            }

            // allocate mesh query
            Detour.dtNavMeshQuery query = new Detour.dtNavMeshQuery();
            if (Detour.dtStatusFailed(query.init(mmap.navMesh, 1024)))
            {
                Log.outError(LogFilter.Maps, "MMAP.GetNavMeshQuery: Failed to initialize dtNavMeshQuery for mapId {0:D4} instanceId {1}", mapId, instanceId);
                return(false);
            }

            Log.outDebug(LogFilter.Maps, "MMAP.GetNavMeshQuery: created dtNavMeshQuery for mapId {0:D4} instanceId {1}", mapId, instanceId);
            mmap.navMeshQueries.Add(instanceId, query);
            return(true);
        }
Example #3
0
        public bool ComputeSystem(byte[] tileRawData, int start)
        {
            m_ctx.enableLog(true);

            m_ctx.resetTimers();

            // Start the build process.
            m_ctx.startTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            m_rawTileData = new Detour.dtRawTileData();
            m_rawTileData.FromBytes(tileRawData, start);

            m_navMesh = new Detour.dtNavMesh();
            if (m_navMesh == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not create Detour navmesh");
                return(false);
            }

            dtStatus status;

            status = m_navMesh.init(m_rawTileData, (int)Detour.dtTileFlags.DT_TILE_FREE_DATA);
            if (Detour.dtStatusFailed(status))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh");
                return(false);
            }

            m_navQuery = new Detour.dtNavMeshQuery();
            status     = m_navQuery.init(m_navMesh, 2048);
            if (Detour.dtStatusFailed(status))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh query");
                return(false);
            }

            m_ctx.stopTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            //m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, ">> Polymesh: " + m_pmesh.nverts + " vertices  " + m_pmesh.npolys + " polygons");

            m_totalBuildTimeMs = (float)m_ctx.getAccumulatedTime(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            return(true);
        }
Example #4
0
        //Compute Recast and Detour navmesh
        public bool ComputeSystem()
        {
            ClearComputedData();

            Recast.rcCalcBounds(m_verts, m_vertCount, m_bmin, m_bmax);

            //
            // Step 1. Initialize build config.
            //

            // Init build configuration from GUI
            m_cfg = new Recast.rcConfig();

            m_cfg.cs = m_RecastMeshParams.m_cellSize;
            m_cfg.ch = m_RecastMeshParams.m_cellHeight;
            m_cfg.walkableSlopeAngle     = m_RecastMeshParams.m_agentMaxSlope;
            m_cfg.walkableHeight         = (int)Math.Ceiling(m_RecastMeshParams.m_agentHeight / m_cfg.ch);
            m_cfg.walkableClimb          = (int)Math.Floor(m_RecastMeshParams.m_agentMaxClimb / m_cfg.ch);
            m_cfg.walkableRadius         = (int)Math.Ceiling(m_RecastMeshParams.m_agentRadius / m_cfg.cs);
            m_cfg.maxEdgeLen             = (int)(m_RecastMeshParams.m_edgeMaxLen / m_RecastMeshParams.m_cellSize);
            m_cfg.maxSimplificationError = m_RecastMeshParams.m_edgeMaxError;
            m_cfg.minRegionArea          = (int)(m_RecastMeshParams.m_regionMinSize * m_RecastMeshParams.m_regionMinSize);              // Note: area = size*size
            m_cfg.mergeRegionArea        = (int)(m_RecastMeshParams.m_regionMergeSize * m_RecastMeshParams.m_regionMergeSize);          // Note: area = size*size
            m_cfg.maxVertsPerPoly        = (int)m_RecastMeshParams.m_vertsPerPoly;
            m_cfg.detailSampleDist       = m_RecastMeshParams.m_detailSampleDist < 0.9f ? 0 : m_RecastMeshParams.m_cellSize * m_RecastMeshParams.m_detailSampleDist;
            m_cfg.detailSampleMaxError   = m_RecastMeshParams.m_cellHeight * m_RecastMeshParams.m_detailSampleMaxError;

            // Set the area where the navigation will be build.
            // Here the bounds of the input mesh are used, but the
            // area could be specified by an user defined box, etc.
            Recast.rcVcopy(m_cfg.bmin, m_bmin);
            Recast.rcVcopy(m_cfg.bmax, m_bmax);
            Recast.rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, out m_cfg.width, out m_cfg.height);

            // Reset build times gathering.
            m_ctx.resetTimers();

            // Start the build process.
            m_ctx.startTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, "Building navigation:");
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, " - " + m_cfg.width + " x " + m_cfg.height + " cells");
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, " - " + m_vertCount / 1000.0f + "K verts, " + m_triCount / 1000.0f + "K tris");

            //
            // Step 2. Rasterize input polygon soup.
            //

            // Allocate voxel heightfield where we rasterize our input data to.
            m_solid = new Recast.rcHeightfield();
            if (m_solid == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'.");
                return(false);
            }
            if (!Recast.rcCreateHeightfield(m_ctx, m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield.");
                return(false);
            }

            // Allocate array that can hold triangle area types.
            // If you have multiple meshes you need to process, allocate
            // and array which can hold the max number of triangles you need to process.
            m_triareas = new byte[m_triCount];
            if (m_triareas == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (" + m_triCount + ").");
                return(false);
            }

            // Find triangles which are walkable based on their slope and rasterize them.
            // If your input data is multiple meshes, you can transform them here, calculate
            // the are type for each of the meshes and rasterize them.
            //memset(m_triareas, 0, ntris*sizeof(byte));

            Recast.rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, m_verts, m_vertCount, m_tris, m_triCount, m_triareas);
            Recast.rcRasterizeTriangles(m_ctx, m_verts, m_vertCount, m_tris, m_triareas, m_triCount, m_solid, m_cfg.walkableClimb);

            if (!m_keepInterResults)
            {
                m_triareas = null;
            }

            //
            // Step 3. Filter walkables surfaces.
            //

            // Once all geoemtry 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.
            Recast.rcFilterLowHangingWalkableObstacles(m_ctx, m_cfg.walkableClimb, m_solid);
            Recast.rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, m_solid);
            Recast.rcFilterWalkableLowHeightSpans(m_ctx, m_cfg.walkableHeight, m_solid);


            //
            // Step 4. Partition walkable surface to simple regions.
            //

            // Compact the heightfield so that it is faster to handle from now on.
            // This will result more cache coherent data as well as the neighbours
            // between walkable cells will be calculated.
            m_chf = new Recast.rcCompactHeightfield();
            if (m_chf == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
                return(false);
            }
            if (!Recast.rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, m_solid, m_chf))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
                return(false);
            }

            if (!m_keepInterResults)
            {
                m_solid = null;
            }

            // Erode the walkable area by agent radius.
            if (!Recast.rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, m_chf))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not erode.");
                return(false);
            }

            /*
             * // (Optional) Mark areas.
             * ConvexVolume[] vols = m_geom.getConvexVolumes();
             * for (int i  = 0; i < m_geom.getConvexVolumeCount(); ++i)
             * rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (byte)vols[i].area, *m_chf);
             */

            if (m_RecastMeshParams.m_monotonePartitioning)
            {
                // Partition the walkable surface into simple regions without holes.
                // Monotone partitioning does not need distancefield.
                if (!Recast.rcBuildRegionsMonotone(m_ctx, m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build regions.");
                    return(false);
                }
            }
            else
            {
                // Prepare for region partitioning, by calculating distance field along the walkable surface.
                if (!Recast.rcBuildDistanceField(m_ctx, m_chf))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
                    return(false);
                }

                // Partition the walkable surface into simple regions without holes.
                if (!Recast.rcBuildRegions(m_ctx, m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build regions.");
                    return(false);
                }
            }

            //
            // Step 5. Trace and simplify region contours.
            //

            // Create contours.
            m_cset = new Recast.rcContourSet();
            if (m_cset == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'.");
                return(false);
            }
            if (!Recast.rcBuildContours(m_ctx, m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, m_cset, -1))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not create contours.");
                return(false);
            }

            //m_cset.dumpToTxt("Data/CSET_dump.txt");

            //
            // Step 6. Build polygons mesh from contours.
            //

            // Build polygon navmesh from the contours.
            m_pmesh = new Recast.rcPolyMesh();
            if (m_pmesh == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'.");
                return(false);
            }
            if (!Recast.rcBuildPolyMesh(m_ctx, m_cset, m_cfg.maxVertsPerPoly, m_pmesh))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not triangulate contours.");
                return(false);
            }

            //m_pmesh.dumpToObj("Data/navmesh.obj");
            //m_pmesh.dumpToText("Data/navmesh.txt");

            //
            // Step 7. Create detail mesh which allows to access approximate height on each polygon.
            //

            m_dmesh = new Recast.rcPolyMeshDetail();            //rcAllocPolyMeshDetail();
            if (m_dmesh == null)
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'pmdtl'.");
                return(false);
            }

            if (!Recast.rcBuildPolyMeshDetail(m_ctx, m_pmesh, m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, m_dmesh))
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build detail mesh.");
                return(false);
            }

            //m_dmesh.dumpToText("Data/polymeshdetail_cs.txt");
            //m_dmesh.dumpToObj("Data/polymeshdetail_cs.obj");

            if (!m_keepInterResults)
            {
                m_chf  = null;
                m_cset = null;
            }

            // At this point the navigation mesh data is ready, you can access it from m_pmesh.
            // See duDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data.

            //
            // (Optional) Step 8. Create Detour data from Recast poly mesh.
            //

            // The GUI may allow more max points per polygon than Detour can handle.
            // Only build the detour navmesh if we do not exceed the limit.
            if (m_cfg.maxVertsPerPoly <= Detour.DT_VERTS_PER_POLYGON)
            {
                //unsigned char* navData = 0;
                Detour.dtRawTileData navData = null;
                //int navDataSize = 0;

                // Update poly flags from areas.
                for (int i = 0; i < m_pmesh.npolys; ++i)
                {
                    if (m_pmesh.areas[i] == Recast.RC_WALKABLE_AREA)
                    {
                        m_pmesh.areas[i] = (byte)SamplePolyAreas.GROUND;
                    }

                    if (m_pmesh.areas[i] == (byte)SamplePolyAreas.GROUND)
                    {
                        m_pmesh.flags[i] = (ushort)SamplePolyFlags.WALK;
                    }

                    /*
                     * if (m_pmesh.areas[i] == Recast.RC_WALKABLE_AREA)
                     * m_pmesh.areas[i] =  SAMPLE_POLYAREA_GROUND;
                     *
                     * if (m_pmesh.areas[i] == SAMPLE_POLYAREA_GROUND ||
                     * m_pmesh.areas[i] == SAMPLE_POLYAREA_GRASS ||
                     * m_pmesh.areas[i] == SAMPLE_POLYAREA_ROAD)
                     * {
                     * m_pmesh.flags[i] = SAMPLE_POLYFLAGS_WALK;
                     * }
                     * else if (m_pmesh.areas[i] == SAMPLE_POLYAREA_WATER)
                     * {
                     * m_pmesh.flags[i] = SAMPLE_POLYFLAGS_SWIM;
                     * }
                     * else if (m_pmesh.areas[i] == SAMPLE_POLYAREA_DOOR)
                     * {
                     * m_pmesh.flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR;
                     * }*/
                }

                Detour.dtNavMeshCreateParams navMeshCreateParams = new Detour.dtNavMeshCreateParams();
                navMeshCreateParams.verts            = m_pmesh.verts;
                navMeshCreateParams.vertCount        = m_pmesh.nverts;
                navMeshCreateParams.polys            = m_pmesh.polys;
                navMeshCreateParams.polyAreas        = m_pmesh.areas;
                navMeshCreateParams.polyFlags        = m_pmesh.flags;
                navMeshCreateParams.polyCount        = m_pmesh.npolys;
                navMeshCreateParams.nvp              = m_pmesh.nvp;
                navMeshCreateParams.detailMeshes     = m_dmesh.meshes;
                navMeshCreateParams.detailVerts      = m_dmesh.verts;
                navMeshCreateParams.detailVertsCount = m_dmesh.nverts;
                navMeshCreateParams.detailTris       = m_dmesh.tris;
                navMeshCreateParams.detailTriCount   = m_dmesh.ntris;
                navMeshCreateParams.offMeshConVerts  = null;            //m_geom.getOffMeshConnectionVerts();
                navMeshCreateParams.offMeshConRad    = null;            //m_geom.getOffMeshConnectionRads();
                navMeshCreateParams.offMeshConDir    = null;            //m_geom.getOffMeshConnectionDirs();
                navMeshCreateParams.offMeshConAreas  = null;            //m_geom.getOffMeshConnectionAreas();
                navMeshCreateParams.offMeshConFlags  = null;            //m_geom.getOffMeshConnectionFlags();
                navMeshCreateParams.offMeshConUserID = null;            //m_geom.getOffMeshConnectionId();
                navMeshCreateParams.offMeshConCount  = 0;               //m_geom.getOffMeshConnectionCount();
                navMeshCreateParams.walkableHeight   = m_RecastMeshParams.m_agentHeight;
                navMeshCreateParams.walkableRadius   = m_RecastMeshParams.m_agentRadius;
                navMeshCreateParams.walkableClimb    = m_RecastMeshParams.m_agentMaxClimb;
                Recast.rcVcopy(navMeshCreateParams.bmin, m_pmesh.bmin);
                Recast.rcVcopy(navMeshCreateParams.bmax, m_pmesh.bmax);
                navMeshCreateParams.cs          = m_cfg.cs;
                navMeshCreateParams.ch          = m_cfg.ch;
                navMeshCreateParams.buildBvTree = true;

                if (!Detour.dtCreateNavMeshData(navMeshCreateParams, out navData))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not build Detour navmesh.");
                    return(false);
                }

                m_navMesh = new Detour.dtNavMesh();
                if (m_navMesh == null)
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not create Detour navmesh");
                    return(false);
                }

                dtStatus status;

                status = m_navMesh.init(navData, (int)Detour.dtTileFlags.DT_TILE_FREE_DATA);
                if (Detour.dtStatusFailed(status))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh");
                    return(false);
                }

                m_navQuery = new Detour.dtNavMeshQuery();
                status     = m_navQuery.init(m_navMesh, 2048);
                if (Detour.dtStatusFailed(status))
                {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh query");
                    return(false);
                }

                m_rawTileData = navData;
            }
            else
            {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_WARNING, "Detour does not support more than " + Detour.DT_VERTS_PER_POLYGON + " verts per polygon. A navmesh has not been generated.");
            }

            m_ctx.stopTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            // Show performance stats.
            m_ctx.logBuildTimes();
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, ">> Polymesh: " + m_pmesh.nverts + " vertices  " + m_pmesh.npolys + " polygons");

            m_totalBuildTimeMs = (float)m_ctx.getAccumulatedTime(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            return(true);
        }
Example #5
0
    public Queue <Position> FindPathBetween(Position start, Position end, bool useStraightPath = false)
    {
        var path = new Queue <Position>();

        if (dtNavMesh == null)
        {
            return(path);
        }
        var startDetourPosition = start.ToDetourPosition();
        var endDetourPosition   = end.ToDetourPosition();

        var queryFilter  = new Detour.dtQueryFilter();
        var navMeshQuery = new Detour.dtNavMeshQuery();

        var status = navMeshQuery.init(dtNavMesh, MAX_PATH);

        if (Detour.dtStatusFailed(status))
        {
            return(path);
        }
        queryFilter.setIncludeFlags(0xffff);
        queryFilter.setExcludeFlags(0x0);

        uint startRef = 0;
        uint endRef   = 0;

        float[] startNearest = new float[3];
        float[] endNearest   = new float[3];

        float[] extents = new float[] { 10.0F, 25.0F, 10.0F };

        status = navMeshQuery.findNearestPoly(startDetourPosition, extents, queryFilter, ref startRef, ref startNearest);

        if (Detour.dtStatusFailed(status))
        {
            return(path);
        }

        status = navMeshQuery.findNearestPoly(endDetourPosition, extents, queryFilter, ref endRef, ref endNearest);

        if (Detour.dtStatusFailed(status))
        {
            return(path);
        }

        if (!dtNavMesh.isValidPolyRef(startRef) || !dtNavMesh.isValidPolyRef(endRef))
        {
            return(path);
        }

        uint[] pathPolys = new uint[MAX_PATH];
        int    pathCount = 0;

        float[] straightPath      = new float[MAX_PATH * 3];
        byte[]  straightPathFlags = new byte[MAX_PATH];
        uint[]  straightPathPolys = new uint[MAX_PATH];
        int     straightPathCount = 0;

        status = navMeshQuery.findPath(
            startRef,
            endRef,
            startNearest,
            endNearest,
            queryFilter,
            pathPolys,
            ref pathCount,
            MAX_PATH
            );

        if (Detour.dtStatusFailed(status))
        {
            path.Enqueue(start);
            path.Enqueue(end);
            return(path);
        }

        status = navMeshQuery.findStraightPath(
            startNearest,
            endNearest,
            pathPolys,
            pathCount,
            straightPath,
            straightPathFlags,
            straightPathPolys,
            ref straightPathCount,
            MAX_PATH,
            (int)Detour.dtStraightPathOptions.DT_STRAIGHTPATH_ALL_CROSSINGS
            );

        if (Detour.dtStatusFailed(status))
        {
            path.Enqueue(start);
            path.Enqueue(end);
            return(path);
        }

        if (straightPathCount > 0)
        {
            if (Detour.dtStatusFailed(status))
            {
                return(path);
            }

            for (int i = 3; i < straightPathCount * 3;)
            {
                float[] pathPos = new float[3];
                pathPos[0] = straightPath[i++];
                pathPos[1] = straightPath[i++];
                pathPos[2] = straightPath[i++];

                var position = ToFFXIPosition(pathPos);

                path.Enqueue(position);
            }
        }
        else
        {
            for (int i = 1; i < pathCount; i++)
            {
                float[] pathPos     = new float[3];
                bool    posOverPoly = false;
                if (Detour.dtStatusFailed(navMeshQuery.closestPointOnPoly(pathPolys[i], startDetourPosition, pathPos, ref posOverPoly)))
                {
                    return(path);
                }

                if (path.Count < 1)
                {
                    if (Detour.dtStatusFailed(navMeshQuery.closestPointOnPolyBoundary(pathPolys[i], startDetourPosition, pathPos)))
                    {
                        return(path);
                    }
                }

                var position = ToFFXIPosition(pathPos);

                path.Enqueue(position);
            }
        }

        if (path.Count < 1)
        {
            path.Enqueue(end);
        }

        return(path);
    }
Example #6
0
        //Compute Recast and Detour navmesh
        public bool ComputeSystem()
        {
            ClearComputedData();

            Recast.rcCalcBounds(m_verts, m_vertCount, m_bmin, m_bmax);

            //
            // Step 1. Initialize build config.
            //

            // Init build configuration from GUI
            m_cfg = new Recast.rcConfig();

            m_cfg.cs = m_RecastMeshParams.m_cellSize;
            m_cfg.ch = m_RecastMeshParams.m_cellHeight;
            m_cfg.walkableSlopeAngle = m_RecastMeshParams.m_agentMaxSlope;
            m_cfg.walkableHeight = (int)Math.Ceiling(m_RecastMeshParams.m_agentHeight / m_cfg.ch);
            m_cfg.walkableClimb = (int)Math.Floor(m_RecastMeshParams.m_agentMaxClimb / m_cfg.ch);
            m_cfg.walkableRadius = (int)Math.Ceiling(m_RecastMeshParams.m_agentRadius / m_cfg.cs);
            m_cfg.maxEdgeLen = (int)(m_RecastMeshParams.m_edgeMaxLen / m_RecastMeshParams.m_cellSize);
            m_cfg.maxSimplificationError = m_RecastMeshParams.m_edgeMaxError;
            m_cfg.minRegionArea = (int)(m_RecastMeshParams.m_regionMinSize * m_RecastMeshParams.m_regionMinSize);		// Note: area = size*size
            m_cfg.mergeRegionArea = (int)(m_RecastMeshParams.m_regionMergeSize * m_RecastMeshParams.m_regionMergeSize);	// Note: area = size*size
            m_cfg.maxVertsPerPoly = (int)m_RecastMeshParams.m_vertsPerPoly;
            m_cfg.detailSampleDist = m_RecastMeshParams.m_detailSampleDist < 0.9f ? 0 : m_RecastMeshParams.m_cellSize * m_RecastMeshParams.m_detailSampleDist;
            m_cfg.detailSampleMaxError = m_RecastMeshParams.m_cellHeight * m_RecastMeshParams.m_detailSampleMaxError;

            // Set the area where the navigation will be build.
            // Here the bounds of the input mesh are used, but the
            // area could be specified by an user defined box, etc.
            Recast.rcVcopy(m_cfg.bmin, m_bmin);
            Recast.rcVcopy(m_cfg.bmax, m_bmax);
            Recast.rcCalcGridSize(m_cfg.bmin, m_cfg.bmax, m_cfg.cs, out m_cfg.width, out m_cfg.height);

            // Reset build times gathering.
            m_ctx.resetTimers();

            // Start the build process.
            m_ctx.startTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, "Building navigation:");
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, " - " + m_cfg.width + " x " + m_cfg.height + " cells");
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, " - " + m_vertCount / 1000.0f + "K verts, " + m_triCount / 1000.0f + "K tris");

            //
            // Step 2. Rasterize input polygon soup.
            //

            // Allocate voxel heightfield where we rasterize our input data to.
            m_solid = new Recast.rcHeightfield();
            if (m_solid == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'solid'.");
                return false;
            }
            if (!Recast.rcCreateHeightfield(m_ctx, m_solid, m_cfg.width, m_cfg.height, m_cfg.bmin, m_cfg.bmax, m_cfg.cs, m_cfg.ch)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not create solid heightfield.");
                return false;
            }

            // Allocate array that can hold triangle area types.
            // If you have multiple meshes you need to process, allocate
            // and array which can hold the max number of triangles you need to process.
            m_triareas = new byte[m_triCount];
            if (m_triareas == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'm_triareas' (" + m_triCount + ").");
                return false;
            }

            // Find triangles which are walkable based on their slope and rasterize them.
            // If your input data is multiple meshes, you can transform them here, calculate
            // the are type for each of the meshes and rasterize them.
            //memset(m_triareas, 0, ntris*sizeof(byte));

            Recast.rcMarkWalkableTriangles(m_ctx, m_cfg.walkableSlopeAngle, m_verts, m_vertCount, m_tris, m_triCount, m_triareas);
            Recast.rcRasterizeTriangles(m_ctx, m_verts, m_vertCount, m_tris, m_triareas, m_triCount, m_solid, m_cfg.walkableClimb);

            if (!m_keepInterResults) {
                m_triareas = null;
            }

            //
            // Step 3. Filter walkables surfaces.
            //

            // Once all geoemtry 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.
            Recast.rcFilterLowHangingWalkableObstacles(m_ctx, m_cfg.walkableClimb, m_solid);
            Recast.rcFilterLedgeSpans(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, m_solid);
            Recast.rcFilterWalkableLowHeightSpans(m_ctx, m_cfg.walkableHeight, m_solid);

            //
            // Step 4. Partition walkable surface to simple regions.
            //

            // Compact the heightfield so that it is faster to handle from now on.
            // This will result more cache coherent data as well as the neighbours
            // between walkable cells will be calculated.
            m_chf = new Recast.rcCompactHeightfield();
            if (m_chf == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'chf'.");
                return false;
            }
            if (!Recast.rcBuildCompactHeightfield(m_ctx, m_cfg.walkableHeight, m_cfg.walkableClimb, m_solid, m_chf)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build compact data.");
                return false;
            }

            if (!m_keepInterResults) {
                m_solid = null;
            }

            // Erode the walkable area by agent radius.
            if (!Recast.rcErodeWalkableArea(m_ctx, m_cfg.walkableRadius, m_chf)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not erode.");
                return false;
            }

            /*
                // (Optional) Mark areas.
                ConvexVolume[] vols = m_geom.getConvexVolumes();
                for (int i  = 0; i < m_geom.getConvexVolumeCount(); ++i)
                    rcMarkConvexPolyArea(m_ctx, vols[i].verts, vols[i].nverts, vols[i].hmin, vols[i].hmax, (byte)vols[i].area, *m_chf);
                */

            if (m_RecastMeshParams.m_monotonePartitioning) {
                // Partition the walkable surface into simple regions without holes.
                // Monotone partitioning does not need distancefield.
                if (!Recast.rcBuildRegionsMonotone(m_ctx, m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build regions.");
                    return false;
                }
            } else {
                // Prepare for region partitioning, by calculating distance field along the walkable surface.
                if (!Recast.rcBuildDistanceField(m_ctx, m_chf)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build distance field.");
                    return false;
                }

                // Partition the walkable surface into simple regions without holes.
                if (!Recast.rcBuildRegions(m_ctx, m_chf, 0, m_cfg.minRegionArea, m_cfg.mergeRegionArea)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build regions.");
                    return false;
                }
            }

            //
            // Step 5. Trace and simplify region contours.
            //

            // Create contours.
            m_cset = new Recast.rcContourSet();
            if (m_cset == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'cset'.");
                return false;
            }
            if (!Recast.rcBuildContours(m_ctx, m_chf, m_cfg.maxSimplificationError, m_cfg.maxEdgeLen, m_cset, -1)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not create contours.");
                return false;
            }

            //m_cset.dumpToTxt("Data/CSET_dump.txt");

            //
            // Step 6. Build polygons mesh from contours.
            //

            // Build polygon navmesh from the contours.
            m_pmesh = new Recast.rcPolyMesh();
            if (m_pmesh == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'pmesh'.");
                return false;
            }
            if (!Recast.rcBuildPolyMesh(m_ctx, m_cset, m_cfg.maxVertsPerPoly, m_pmesh)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not triangulate contours.");
                return false;
            }

            //m_pmesh.dumpToObj("Data/navmesh.obj");
            //m_pmesh.dumpToText("Data/navmesh.txt");

            //
            // Step 7. Create detail mesh which allows to access approximate height on each polygon.
            //

            m_dmesh = new Recast.rcPolyMeshDetail();//rcAllocPolyMeshDetail();
            if (m_dmesh == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Out of memory 'pmdtl'.");
                return false;
            }

            if (!Recast.rcBuildPolyMeshDetail(m_ctx, m_pmesh, m_chf, m_cfg.detailSampleDist, m_cfg.detailSampleMaxError, m_dmesh)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "buildNavigation: Could not build detail mesh.");
                return false;
            }

            //m_dmesh.dumpToText("Data/polymeshdetail_cs.txt");
            //m_dmesh.dumpToObj("Data/polymeshdetail_cs.obj");

            if (!m_keepInterResults) {

                m_chf = null;
                m_cset = null;
            }

            // At this point the navigation mesh data is ready, you can access it from m_pmesh.
            // See duDebugDrawPolyMesh or dtCreateNavMeshData as examples how to access the data.

            //
            // (Optional) Step 8. Create Detour data from Recast poly mesh.
            //

            // The GUI may allow more max points per polygon than Detour can handle.
            // Only build the detour navmesh if we do not exceed the limit.
            if (m_cfg.maxVertsPerPoly <= Detour.DT_VERTS_PER_POLYGON) {
                //unsigned char* navData = 0;
                Detour.dtRawTileData navData = null;
                //int navDataSize = 0;

                // Update poly flags from areas.
                for (int i = 0; i < m_pmesh.npolys; ++i) {
                    if (m_pmesh.areas[i] == Recast.RC_WALKABLE_AREA)
                        m_pmesh.areas[i] = (byte)SamplePolyAreas.GROUND;

                    if (m_pmesh.areas[i] == (byte)SamplePolyAreas.GROUND) {
                        m_pmesh.flags[i] = (ushort)SamplePolyFlags.WALK;
                    }

                    /*
                        if (m_pmesh.areas[i] == Recast.RC_WALKABLE_AREA)
                            m_pmesh.areas[i] =  SAMPLE_POLYAREA_GROUND;

                        if (m_pmesh.areas[i] == SAMPLE_POLYAREA_GROUND ||
                            m_pmesh.areas[i] == SAMPLE_POLYAREA_GRASS ||
                            m_pmesh.areas[i] == SAMPLE_POLYAREA_ROAD)
                        {
                            m_pmesh.flags[i] = SAMPLE_POLYFLAGS_WALK;
                        }
                        else if (m_pmesh.areas[i] == SAMPLE_POLYAREA_WATER)
                        {
                            m_pmesh.flags[i] = SAMPLE_POLYFLAGS_SWIM;
                        }
                        else if (m_pmesh.areas[i] == SAMPLE_POLYAREA_DOOR)
                        {
                            m_pmesh.flags[i] = SAMPLE_POLYFLAGS_WALK | SAMPLE_POLYFLAGS_DOOR;
                        }*/
                }

                Detour.dtNavMeshCreateParams navMeshCreateParams = new Detour.dtNavMeshCreateParams();
                navMeshCreateParams.verts = m_pmesh.verts;
                navMeshCreateParams.vertCount = m_pmesh.nverts;
                navMeshCreateParams.polys = m_pmesh.polys;
                navMeshCreateParams.polyAreas = m_pmesh.areas;
                navMeshCreateParams.polyFlags = m_pmesh.flags;
                navMeshCreateParams.polyCount = m_pmesh.npolys;
                navMeshCreateParams.nvp = m_pmesh.nvp;
                navMeshCreateParams.detailMeshes = m_dmesh.meshes;
                navMeshCreateParams.detailVerts = m_dmesh.verts;
                navMeshCreateParams.detailVertsCount = m_dmesh.nverts;
                navMeshCreateParams.detailTris = m_dmesh.tris;
                navMeshCreateParams.detailTriCount = m_dmesh.ntris;
                navMeshCreateParams.offMeshConVerts = null;//m_geom.getOffMeshConnectionVerts();
                navMeshCreateParams.offMeshConRad = null;//m_geom.getOffMeshConnectionRads();
                navMeshCreateParams.offMeshConDir = null;//m_geom.getOffMeshConnectionDirs();
                navMeshCreateParams.offMeshConAreas = null;//m_geom.getOffMeshConnectionAreas();
                navMeshCreateParams.offMeshConFlags = null;//m_geom.getOffMeshConnectionFlags();
                navMeshCreateParams.offMeshConUserID = null;//m_geom.getOffMeshConnectionId();
                navMeshCreateParams.offMeshConCount = 0;//m_geom.getOffMeshConnectionCount();
                navMeshCreateParams.walkableHeight = m_RecastMeshParams.m_agentHeight;
                navMeshCreateParams.walkableRadius = m_RecastMeshParams.m_agentRadius;
                navMeshCreateParams.walkableClimb = m_RecastMeshParams.m_agentMaxClimb;
                Recast.rcVcopy(navMeshCreateParams.bmin, m_pmesh.bmin);
                Recast.rcVcopy(navMeshCreateParams.bmax, m_pmesh.bmax);
                navMeshCreateParams.cs = m_cfg.cs;
                navMeshCreateParams.ch = m_cfg.ch;
                navMeshCreateParams.buildBvTree = true;

                if (!Detour.dtCreateNavMeshData(navMeshCreateParams, out navData)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not build Detour navmesh.");
                    return false;
                }

                m_navMesh = new Detour.dtNavMesh();
                if (m_navMesh == null) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not create Detour navmesh");
                    return false;
                }

                dtStatus status;

                status = m_navMesh.init(navData, (int)Detour.dtTileFlags.DT_TILE_FREE_DATA);
                if (Detour.dtStatusFailed(status)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh");
                    return false;
                }

                m_navQuery = new Detour.dtNavMeshQuery();
                status = m_navQuery.init(m_navMesh, 2048);
                if (Detour.dtStatusFailed(status)) {
                    m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh query");
                    return false;
                }

                m_rawTileData = navData;
            } else {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_WARNING, "Detour does not support more than " + Detour.DT_VERTS_PER_POLYGON + " verts per polygon. A navmesh has not been generated.");
            }

            m_ctx.stopTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            // Show performance stats.
            m_ctx.logBuildTimes();
            m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, ">> Polymesh: " + m_pmesh.nverts + " vertices  " + m_pmesh.npolys + " polygons");

            m_totalBuildTimeMs = (float) m_ctx.getAccumulatedTime(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            return true;
        }
Example #7
0
        public bool ComputeSystem(byte[] tileRawData, int start)
        {
            m_ctx.enableLog(true);

            m_ctx.resetTimers();

            // Start the build process.
            m_ctx.startTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            m_rawTileData = new Detour.dtRawTileData();
            m_rawTileData.FromBytes(tileRawData, start);

            m_navMesh = new Detour.dtNavMesh();
            if (m_navMesh == null) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not create Detour navmesh");
                return false;
            }

            dtStatus status;

            status = m_navMesh.init(m_rawTileData, (int)Detour.dtTileFlags.DT_TILE_FREE_DATA);
            if (Detour.dtStatusFailed(status)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh");
                return false;
            }

            m_navQuery = new Detour.dtNavMeshQuery();
            status = m_navQuery.init(m_navMesh, 2048);
            if (Detour.dtStatusFailed(status)) {
                m_ctx.log(Recast.rcLogCategory.RC_LOG_ERROR, "Could not init Detour navmesh query");
                return false;
            }

            m_ctx.stopTimer(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            //m_ctx.log(Recast.rcLogCategory.RC_LOG_PROGRESS, ">> Polymesh: " + m_pmesh.nverts + " vertices  " + m_pmesh.npolys + " polygons");

            m_totalBuildTimeMs = (float) m_ctx.getAccumulatedTime(Recast.rcTimerLabel.RC_TIMER_TOTAL);

            return true;
        }
Example #8
0
    public Queue <Position> FindPathBetween(Position start, Position end, bool useStraightPath = false)
    {
        var path = new Queue <Position>();

        if (dtNavMesh == null)
        {
            EasyFarm.ViewModels.LogViewModel.Write("FindPathBetween: Unable to path due to lacking navigation mesh for zone " + _zone.ToString());
            return(path);
        }
        var startDetourPosition = start.ToDetourPosition();
        var endDetourPosition   = end.ToDetourPosition();

        var queryFilter  = new Detour.dtQueryFilter();
        var navMeshQuery = new Detour.dtNavMeshQuery();

        var status = navMeshQuery.init(dtNavMesh, 256);

        if (Detour.dtStatusFailed(status))
        {
            return(path);
        }

        queryFilter.setIncludeFlags(0xffff);
        queryFilter.setExcludeFlags(0x0);

        uint startRef = 0;
        uint endRef   = 0;

        float[] startNearest = new float[3];
        float[] endNearest   = new float[3];

        float[] extents = new float[] { 10.0F, (float)EasyFarm.UserSettings.Config.Instance.HeightThreshold, 10.0F };

        status = navMeshQuery.findNearestPoly(startDetourPosition, extents, queryFilter, ref startRef, ref startNearest);
        if (Detour.dtStatusFailed(status))
        {
            return(path);
        }

        status = navMeshQuery.findNearestPoly(endDetourPosition, extents, queryFilter, ref endRef, ref endNearest);
        if (Detour.dtStatusFailed(status))
        {
            return(path);
        }

        if (!dtNavMesh.isValidPolyRef(startRef) || !dtNavMesh.isValidPolyRef(endRef))
        {
            return(path);
        }

        uint[] pathPolys = new uint[256];

        int pathCount = 0;

        status = navMeshQuery.findPath(startRef, endRef, startNearest, endNearest, queryFilter, pathPolys, ref pathCount, 256);

        if (Detour.dtStatusFailed(status))
        {
            return(path);
        }

        if (path.Count < 1)
        {
            float[] straightPath      = new float[256 * 3];
            byte[]  straightPathFlags = new byte[256];
            uint[]  straightPathPolys = new uint[256];
            int     straightPathCount = 256 * 3;

            status = navMeshQuery.findStraightPath(
                startNearest,
                endNearest,
                pathPolys,
                pathCount,
                straightPath,
                straightPathFlags,
                straightPathPolys,
                ref straightPathCount,
                256,
                0
                );

            if (straightPathCount > 1)
            {
                if (Detour.dtStatusFailed(status))
                {
                    return(path);
                }

                path.Clear();

                // i starts at 3 so the start position is ignored
                for (int i = 3; i < straightPathCount * 3;)
                {
                    float[] pathPos = new float[3];
                    pathPos[0] = straightPath[i++];
                    pathPos[1] = straightPath[i++];
                    pathPos[2] = straightPath[i++];

                    var position = ToFFXIPosition(pathPos);

                    path.Enqueue(position);
                }
            }
        }
        else
        {
            // i starts at 3 so the start position is ignored
            for (int i = 1; i < pathCount; i++)
            {
                float[] pathPos     = new float[3];
                bool    posOverPoly = false;
                if (Detour.dtStatusFailed(navMeshQuery.closestPointOnPoly(pathPolys[i], startDetourPosition, pathPos, ref posOverPoly)))
                {
                    return(path);
                }

                if (path.Count < 1)
                {
                    if (Detour.dtStatusFailed(navMeshQuery.closestPointOnPolyBoundary(pathPolys[i], startDetourPosition, pathPos)))
                    {
                        return(path);
                    }
                }

                var position = ToFFXIPosition(pathPos);

                path.Enqueue(position);
            }
        }

        return(path);
    }