Exemplo n.º 1
0
        public static uint allocLink(dtMeshTile tile)
        {
            if (tile.linksFreeList == Detour.DT_NULL_LINK)
            {
                return(DT_NULL_LINK);
            }
            uint link = tile.linksFreeList;

            tile.linksFreeList = tile.links[link].next;
            return(link);
        }
Exemplo n.º 2
0
        /// Builds internal polygons links for a tile.
        public void connectIntLinks(dtMeshTile tile)
        {
            if (tile == null)
                return;

            dtPolyRef polyRefBase = getPolyRefBase(tile);

            for (int i = 0; i < tile.header.polyCount; ++i)
            {
                dtPoly poly = tile.polys[i];
                poly.firstLink = DT_NULL_LINK;

                if (poly.getType() == (byte) dtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION)
                    continue;

                // Build edge links backwards so that the links will be
                // in the linked list from lowest index to highest.
                for (int j = poly.vertCount-1; j >= 0; --j)
                {
                    // Skip hard and non-internal edges.
                    if (poly.neis[j] == 0 || (poly.neis[j] & DT_EXT_LINK) != 0)
                        continue;

                    uint idx = allocLink(tile);
                    if (idx != DT_NULL_LINK)
                    {
                        dtLink link = tile.links[idx];
                        link.polyRef = polyRefBase | (dtPolyRef)(poly.neis[j]-1);
                        link.edge = (byte)j;
                        link.side = 0xff;
                        link.bmin = link.bmax = 0;
                        // Add to linked list.
                        link.next = poly.firstLink;
                        poly.firstLink = idx;
                    }
                }
            }
        }
Exemplo n.º 3
0
        /// Builds external polygon links for a tile.
        public void connectExtOffMeshLinks(dtMeshTile tile, dtMeshTile target, int side)
        {
            if (tile == null)
                return;

            // Connect off-mesh links.
            // We are interested on links which land from target tile to this tile.
            byte oppositeSide = (side == -1) ? (byte)0xff : (byte)dtOppositeTile(side);

            for (int i = 0; i < target.header.offMeshConCount; ++i)
            {
                dtOffMeshConnection targetCon = target.offMeshCons[i];
                if (targetCon.side != oppositeSide)
                    continue;

                dtPoly targetPoly = target.polys[targetCon.poly];
                // Skip off-mesh connections which start location could not be connected at all.
                if (targetPoly.firstLink == DT_NULL_LINK)
                    continue;

                float[] ext = new float[] { targetCon.rad, target.header.walkableClimb, targetCon.rad };

                // Find polygon to connect to.
                //const float* p = &targetCon.pos[3];
                int pIndex = 3;
                float[] nearestPt = new float[3];
                dtPolyRef polyRef = findNearestPolyInTile(tile, targetCon.pos, pIndex, ext, nearestPt);
                if (polyRef == 0)
                    continue;
                // findNearestPoly may return too optimistic results, further check to make sure.
                if (dtSqr(nearestPt[0]-targetCon.pos[pIndex])+dtSqr(nearestPt[2]-targetCon.pos[pIndex + 2]) > dtSqr(targetCon.rad))
                    continue;
                // Make sure the location is on current mesh.
                //float* v = &target.verts[targetPoly.verts[1]*3];
                int vIndex = targetPoly.verts[1]*3;
                dtVcopy(target.verts, vIndex, nearestPt, 0);

                // Link off-mesh connection to target poly.
                uint idx = allocLink(target);
                if (idx != DT_NULL_LINK)
                {
                    dtLink link = target.links[idx];
                    link.polyRef = polyRef;
                    link.edge = (byte)1;
                    link.side = oppositeSide;
                    link.bmin = link.bmax = 0;
                    // Add to linked list.
                    link.next = targetPoly.firstLink;
                    targetPoly.firstLink = idx;
                }

                // Link target poly to off-mesh connection.
                if ((targetCon.flags & DT_OFFMESH_CON_BIDIR )!= 0)
                {
                    uint tidx = allocLink(tile);
                    if (tidx != DT_NULL_LINK)
                    {
                        ushort landPolyIdx = (ushort)decodePolyIdPoly(polyRef);
                        dtPoly landPoly = tile.polys[landPolyIdx];
                        dtLink link = tile.links[tidx];
                        link.polyRef = getPolyRefBase(target) | (dtPolyRef)(targetCon.poly);
                        link.edge = 0xff;
                        link.side = (byte)(side == -1 ? 0xff : side);
                        link.bmin = link.bmax = 0;
                        // Add to linked list.
                        link.next = landPoly.firstLink;
                        landPoly.firstLink = tidx;
                    }
                }
            }
        }
Exemplo n.º 4
0
        /// Builds external polygon links for a tile.
        public void connectExtLinks(dtMeshTile tile, dtMeshTile target, int side)
        {
            if (tile == null)
                return;

            // Connect border links.
            for (int i = 0; i < tile.header.polyCount; ++i)
            {
                dtPoly poly = tile.polys[i];

                // Create new links.
            //		ushort m = DT_EXT_LINK | (ushort)side;

                int nv = (int)poly.vertCount;
                for (int j = 0; j < nv; ++j)
                {
                    // Skip non-portal edges.
                    if ((poly.neis[j] & DT_EXT_LINK) == 0)
                        continue;

                    int dir = (int)(poly.neis[j] & 0xff);
                    if (side != -1 && dir != side)
                        continue;

                    // Create new links
                    //const float* va = &tile.verts[poly.verts[j]*3];
                    //const float* vb = &tile.verts[poly.verts[(j+1) % nv]*3];
                    int vaStart = poly.verts[j]*3;
                    int vbStart = poly.verts[(j+1) % nv]*3;

                    dtPolyRef[] nei = new dtPolyRef[4];
                    float[] neia = new float[4*2];
                    int nnei = findConnectingPolys(tile.verts,vaStart,tile.verts,vbStart, target, dtOppositeTile(dir), nei,neia,4);
                    for (int k = 0; k < nnei; ++k)
                    {
                        uint idx = allocLink(tile);
                        if (idx != DT_NULL_LINK)
                        {
                            dtLink link = tile.links[idx];
                            link.polyRef = nei[k];
                            link.edge = (byte)j;
                            link.side = (byte)dir;

                            link.next = poly.firstLink;
                            poly.firstLink = idx;

                            // Compress portal limits to a byte value.
                            if (dir == 0 || dir == 4)
                            {
                                float tmin = (neia[k*2+0]-tile.verts[vaStart + 2]) / (tile.verts[vbStart + 2]-tile.verts[vaStart + 2]);
                                float tmax = (neia[k*2+1]-tile.verts[vaStart + 2]) / (tile.verts[vbStart +2]-tile.verts[vaStart + 2]);
                                if (tmin > tmax)
                                    dtSwap(ref tmin,ref tmax);
                                link.bmin = (byte)(dtClamp(tmin, 0.0f, 1.0f)*255.0f);
                                link.bmax = (byte)(dtClamp(tmax, 0.0f, 1.0f)*255.0f);
                            }
                            else if (dir == 2 || dir == 6)
                            {
                                float tmin = (neia[k*2+0]-tile.verts[vaStart + 0]) / (tile.verts[vbStart +0]-tile.verts[vaStart + 0]);
                                float tmax = (neia[k*2+1]-tile.verts[vaStart + 0]) / (tile.verts[vbStart +0]-tile.verts[vaStart + 0]);
                                if (tmin > tmax)
                                    dtSwap(ref tmin,ref tmax);
                                link.bmin = (byte)(dtClamp(tmin, 0.0f, 1.0f)*255.0f);
                                link.bmax = (byte)(dtClamp(tmax, 0.0f, 1.0f)*255.0f);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 5
0
 /// @par
 ///
 /// Example use case:
 /// @code
 ///
 /// const dtPolyRef base = navmesh.getPolyRefBase(tile);
 /// for (int i = 0; i < tile.header.polyCount; ++i)
 /// {
 ///     const dtPoly* p = &tile.polys[i];
 ///     const dtPolyRef ref = base | (dtPolyRef)i;
 ///     
 ///     // Use the reference to access the polygon data.
 /// }
 /// @endcode
 /// Gets the polygon reference for the tile's base polygon.
 ///  @param[in]	tile		The tile.
 /// @return The polygon reference for the base polygon in the specified tile.
 public dtPolyRef getPolyRefBase(dtMeshTile tile)
 {
     if (tile == null) return 0;
     uint it = (uint) Array.IndexOf(m_tiles, tile);
     return encodePolyId(tile.salt, it, 0);
 }
Exemplo n.º 6
0
        dtStatus getEdgeMidPoint(dtPolyRef from, dtPoly fromPoly, dtMeshTile fromTile,
										         dtPolyRef to, dtPoly toPoly, dtMeshTile toTile,
										         float[] mid)
        {
	        float[] left = new float[3];//, right[3];
            float[] right = new float[3];
	        if (dtStatusFailed(getPortalPoints(from, fromPoly, fromTile, to, toPoly, toTile, left, right)))
		        return DT_FAILURE | DT_INVALID_PARAM;
	        mid[0] = (left[0]+right[0])*0.5f;
	        mid[1] = (left[1]+right[1])*0.5f;
	        mid[2] = (left[2]+right[2])*0.5f;
	        return DT_SUCCESS;
        }
Exemplo n.º 7
0
        /// Finds polygons that overlap the search box.
        ///  @param[in]		center		The center of the search box. [(x, y, z)]
        ///  @param[in]		extents		The search distance along each axis. [(x, y, z)]
        ///  @param[in]		filter		The polygon filter to apply to the query.
        ///  @param[out]	polys		The reference ids of the polygons that overlap the query box.
        ///  @param[out]	polyCount	The number of polygons in the search result.
        ///  @param[in]		maxPolys	The maximum number of polygons the search result can hold.
        /// @returns The status flags for the query.
        /// @par 
        ///
        /// If no polygons are found, the function will return #DT_SUCCESS with a
        /// @p polyCount of zero.
        ///
        /// If @p polys is too small to hold the entire result set, then the array will 
        /// be filled to capacity. The method of choosing which polygons from the 
        /// full set are included in the partial result set is undefined.
        ///
		public dtStatus queryPolygons(float[] center, float[] extents,
									           dtQueryFilter filter,
									           dtPolyRef[] polys, ref int polyCount, int maxPolys)
        {
	        Debug.Assert(m_nav != null);
	
	        float[] bmin = new float[3];//, bmax[3];
            float[] bmax = new float[3];
	        dtVsub(bmin, center, extents);
	        dtVadd(bmax, center, extents);
	
	        // Find tiles the query touches.
	        int minx = 0, miny = 0, maxx = 0 , maxy = 0;
	        m_nav.calcTileLoc(bmin, ref minx, ref miny);
	        m_nav.calcTileLoc(bmax, ref maxx, ref maxy);

	        int MAX_NEIS = 32;
	        dtMeshTile[] neis = new dtMeshTile[MAX_NEIS];
	
	        int n = 0;
	        for (int y = miny; y <= maxy; ++y)
	        {
		        for (int x = minx; x <= maxx; ++x)
		        {
			        int nneis = m_nav.getTilesAt(x,y,neis,MAX_NEIS);
			        for (int j = 0; j < nneis; ++j)
			        {
				        n += queryPolygonsInTile(neis[j], bmin, bmax, filter, polys, n, maxPolys-n);
				        if (n >= maxPolys)
				        {
					        polyCount = n;
					        return DT_SUCCESS | DT_BUFFER_TOO_SMALL;
				        }
			        }
		        }
	        }
	        polyCount = n;
	
	        return DT_SUCCESS;
        }
Exemplo n.º 8
0
        public int queryPolygonsInTile(dtMeshTile tile, float[] qmin, float[] qmax,
                                dtPolyRef[] polys, int maxPolys)
        {
            if (tile.bvTree != null)
            {
                // tile.bvTree[0];
                //dtBVNode end = tile.bvTree[tile.header.bvNodeCount];
                int endNodeIndex = tile.header.bvNodeCount;
                float[] tbmin = tile.header.bmin;
                float[] tbmax = tile.header.bmax;
                float qfac = tile.header.bvQuantFactor;

                // Calculate quantized box
                ushort[] bmin = new ushort[3];//, bmax[3];
                ushort[] bmax = new ushort[3];
                // dtClamp query box to world box.
                float minx = dtClamp(qmin[0], tbmin[0], tbmax[0]) - tbmin[0];
                float miny = dtClamp(qmin[1], tbmin[1], tbmax[1]) - tbmin[1];
                float minz = dtClamp(qmin[2], tbmin[2], tbmax[2]) - tbmin[2];
                float maxx = dtClamp(qmax[0], tbmin[0], tbmax[0]) - tbmin[0];
                float maxy = dtClamp(qmax[1], tbmin[1], tbmax[1]) - tbmin[1];
                float maxz = dtClamp(qmax[2], tbmin[2], tbmax[2]) - tbmin[2];
                // Quantize
                bmin[0] = (ushort)((ushort)(qfac * minx) & 0xfffe);
                bmin[1] = (ushort)((ushort)(qfac * miny) & 0xfffe);
                bmin[2] = (ushort)((ushort)(qfac * minz) & 0xfffe);
                bmax[0] = (ushort)((ushort)(qfac * maxx + 1) | 1);
                bmax[1] = (ushort)((ushort)(qfac * maxy + 1) | 1);
                bmax[2] = (ushort)((ushort)(qfac * maxz + 1) | 1);

                // Traverse tree
                dtPolyRef polyRefBase = getPolyRefBase(tile);
                int n = 0;
                int curNode = 0;
                dtBVNode node = null;
                while (curNode < endNodeIndex)
                {
                    node = tile.bvTree[curNode];

                    bool overlap = dtOverlapQuantBounds(bmin, bmax, node.bmin, node.bmax);
                    bool isLeafNode = node.i >= 0;

                    if (isLeafNode && overlap)
                    {
                        if (n < maxPolys){
                            polys[n++] = polyRefBase | (dtPolyRef)node.i;
                        }
                    }

                    if (overlap || isLeafNode){
                        //node++;
                        ++curNode;
                    }
                    else
                    {
                        int escapeIndex = - node.i;
                        curNode += escapeIndex;
                    }
                }

                return n;
            }
            else
            {
                float[] bmin = new float[3];//, bmax[3];
                float[] bmax = new float[3];
                int n = 0;
                dtPolyRef polyRefBase = getPolyRefBase(tile);
                for (int i = 0; i < tile.header.polyCount; ++i)
                {
                    dtPoly p = tile.polys[i];

                    // Do not return off-mesh connection polygons.
                    if (p.getType() == (byte) dtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION)
                        continue;
                    // Calc polygon bounds.
                    //float[] v = tile.verts[p.verts[0]*3];
                    int vIndex = p.verts[0]*3;
                    dtVcopy(bmin,0 ,tile.verts, vIndex);
                    dtVcopy(bmax,0 ,tile.verts, vIndex);
                    for (int j = 1; j < p.vertCount; ++j)
                    {
                        //v = &tile.verts[p.verts[j]*3];
                        vIndex = p.verts[j]*3;
                        dtVmin(bmin, 0 ,tile.verts, vIndex);
                        dtVmax(bmax, 0 ,tile.verts, vIndex);
                    }
                    if (dtOverlapBounds(qmin,qmax, bmin,bmax))
                    {
                        if (n < maxPolys)
                            polys[n++] = polyRefBase | (dtPolyRef)i;
                    }
                }
                return n;
            }
        }
Exemplo n.º 9
0
        /// @par
        ///
        /// This function will not fail if the tiles array is too small to hold the
        /// entire result set.  It will simply fill the array to capacity.
        /// Gets all tiles at the specified grid location. (All layers.)
        ///  @param[in]		x			The tile's x-location. (x, y)
        ///  @param[in]		y			The tile's y-location. (x, y)
        ///  @param[out]	tiles		A pointer to an array of tiles that will hold the result.
        ///  @param[in]		maxTiles	The maximum tiles the tiles parameter can hold.
        /// @return The number of tiles returned in the tiles array.
        public int getTilesAt(int x, int y, dtMeshTile[] tiles, int maxTiles)
        {
            int n = 0;

            // Find tile based on hash.
            int h = computeTileHash(x,y,m_tileLutMask);
            dtMeshTile tile = m_posLookup[h];
            while (tile != null)
            {
                if (tile.header != null &&
                    tile.header.x == x &&
                    tile.header.y == y)
                {
                    if (n < maxTiles)
                        tiles[n++] = tile;
                }
                tile = tile.next;
            }

            return n;
        }
Exemplo n.º 10
0
        /// @{
        /// @name Initialization and Tile Management
        /// Initializes the navigation mesh for tiled use.
        ///  @param[in]	params		Initialization parameters.
        /// @return The status flags for the operation.
        public dtStatus init(dtNavMeshParams navMeshParams)
        {
            //memcpy(&m_params, params, sizeof(dtNavMeshParams));
            m_params = navMeshParams.Clone();
            dtVcopy(m_orig, navMeshParams.orig);
            m_tileWidth = navMeshParams.tileWidth;
            m_tileHeight = navMeshParams.tileHeight;

            // Init tiles
            m_maxTiles = navMeshParams.maxTiles;
            m_tileLutSize = (int)dtNextPow2((uint)(navMeshParams.maxTiles/4));
            if (m_tileLutSize == 0)
                m_tileLutSize = 1;
            m_tileLutMask = m_tileLutSize-1;

            //m_tiles = (dtMeshTile*)dtAlloc(sizeof(dtMeshTile)*m_maxTiles, DT_ALLOC_PERM);
            m_tiles = new dtMeshTile[m_maxTiles];
            dtcsArrayItemsCreate(m_tiles);

            if (m_tiles == null)
                return (DT_FAILURE | DT_OUT_OF_MEMORY);
            //m_posLookup = (dtMeshTile**)dtAlloc(sizeof(dtMeshTile*)*m_tileLutSize, DT_ALLOC_PERM);
            m_posLookup = new dtMeshTile[m_tileLutSize];
            dtcsArrayItemsCreate(m_posLookup);
            if (m_posLookup == null)
                return DT_FAILURE | DT_OUT_OF_MEMORY;
            //memset(m_tiles, 0, sizeof(dtMeshTile)*m_maxTiles);
            //memset(m_posLookup, 0, sizeof(dtMeshTile*)*m_tileLutSize);
            m_nextFree = null;
            for (int i = m_maxTiles-1; i >= 0; --i)
            {
                m_tiles[i].salt = 1;
                m_tiles[i].next = m_nextFree;
                m_nextFree = m_tiles[i];
            }

            // Init ID generator values.
            #if DT_POLYREF64
            #else
            m_tileBits = (dtStatus)dtIlog2(dtNextPow2((uint)navMeshParams.maxTiles));
            m_polyBits = (dtStatus)dtIlog2(dtNextPow2((uint)navMeshParams.maxPolys));
            // Only allow 31 salt bits, since the salt mask is calculated using 32bit uint and it will overflow.
            m_saltBits = Math.Min((uint)31, 32 - m_tileBits - m_polyBits);

            if (m_saltBits < 10)
                return DT_FAILURE | DT_INVALID_PARAM;
            #endif

            return DT_SUCCESS;
        }
Exemplo n.º 11
0
 /// Gets the tile reference for the specified tile.
 ///  @param[in]	tile	The tile.
 /// @return The tile reference of the tile.
 public dtTileRef getTileRef(dtMeshTile tile)
 {
     if (tile == null) return 0;
     uint it = (uint) Array.IndexOf(m_tiles, tile); //(uint)(tile - m_tiles);
     return encodePolyId(tile.salt, it, 0);
 }
Exemplo n.º 12
0
 public void getTileAndPolyByRefUnsafe(dtPolyRef polyRef, ref dtMeshTile tile, ref dtPoly poly, ref uint ip)
 {
     uint salt = 0, it = 0;
     decodePolyId(polyRef,ref salt,ref it,ref ip);
     tile = m_tiles[it];
     poly = m_tiles[it].polys[ip];
 }
Exemplo n.º 13
0
 //C# port : also return ip because the code used to do pointer arithmetics on the
 // array's addresses, which is a no in C# because managed array may not be contiguous in memory
 public dtStatus getTileAndPolyByRef(dtPolyRef polyRef, ref dtMeshTile tile, ref dtPoly poly, ref uint ip)
 {
     if (polyRef == 0)
         return DT_FAILURE;
     uint salt = 0, it = 0;
     decodePolyId(polyRef, ref salt, ref it, ref ip);
     if (it >= (uint)m_maxTiles)
         return DT_FAILURE | DT_INVALID_PARAM;
     if (m_tiles[it].salt != salt || m_tiles[it].header == null)
         return DT_FAILURE | DT_INVALID_PARAM;
     if (ip >= (uint)m_tiles[it].header.polyCount)
         return DT_FAILURE | DT_INVALID_PARAM;
     tile = m_tiles[it];
     poly = m_tiles[it].polys[ip];
     return DT_SUCCESS;
 }
Exemplo n.º 14
0
        //////////////////////////////////////////////////////////////////////////////////////////
        /// Returns all polygons in neighbour tile based on portal defined by the segment.
        public int findConnectingPolys(float[] va, int vaStart, float[] vb, int vbStart,
								           dtMeshTile tile, int side,
								           dtPolyRef[] con, float[] conarea, int maxcon)
        {
            if (tile == null)
                return 0;

            float[] amin = new float[2];
            float[] amax = new float[2];
            calcSlabEndPoints(va, vaStart,vb, vbStart, amin,amax, side);
            float apos = getSlabCoord(va, vaStart, side);

            // Remove links pointing to 'side' and compact the links array.
            float[] bmin = new float[2];
            float[] bmax = new float[2];
            ushort m =(ushort)( DT_EXT_LINK | (ushort)side );
            int n = 0;

            dtPolyRef polyRefBase = getPolyRefBase(tile);

            for (int i = 0; i < tile.header.polyCount; ++i)
            {
                dtPoly poly = tile.polys[i];
                int nv = (int)poly.vertCount;
                for (int j = 0; j < nv; ++j)
                {
                    // Skip edges which do not point to the right side.
                    if (poly.neis[j] != m)
                        continue;

                    //const float* vc = &tile.verts[poly.verts[j]*3];
                    //const float* vd = &tile.verts[poly.verts[(j+1) % nv]*3];
                    int vcStart = poly.verts[j]*3;
                    int vdStart = poly.verts[(j+1) % nv]*3;
                    float bpos = getSlabCoord(tile.verts, vcStart, side);

                    // Segments are not close enough.
                    if (Math.Abs(apos-bpos) > 0.01f)
                        continue;

                    // Check if the segments touch.
                    calcSlabEndPoints(tile.verts,vcStart,tile.verts,vdStart, bmin,bmax, side);

                    if (!overlapSlabs(amin,amax, bmin,bmax, 0.01f, tile.header.walkableClimb))
                        continue;

                    // Add return value.
                    if (n < maxcon)
                    {
                        conarea[n*2+0] = Math.Max(amin[0], bmin[0]);
                        conarea[n*2+1] = Math.Min(amax[0], bmax[0]);
                        con[n] = polyRefBase | (dtPolyRef)i;
                        n++;
                    }
                    break;
                }
            }
            return n;
        }
Exemplo n.º 15
0
        /// @par
        ///
        /// This function returns the data for the tile so that, if desired,
        /// it can be added back to the navigation mesh at a later point.
        ///
        /// @see #addTile
        /// Removes the specified tile from the navigation mesh.
        ///  @param[in]		ref			The reference of the tile to remove.
        ///  @param[out]	data		Data associated with deleted tile.
        ///  @param[out]	dataSize	Size of the data associated with deleted tile.
        /// @return The status flags for the operation.
        public dtStatus removeTile(dtTileRef tileRef, out dtRawTileData rawTileData)
        {
            rawTileData = null;

            if (tileRef == 0)
                return DT_FAILURE | DT_INVALID_PARAM;
            uint tileIndex = decodePolyIdTile((dtPolyRef)tileRef);
            uint tileSalt = decodePolyIdSalt((dtPolyRef)tileRef);
            if ((int)tileIndex >= m_maxTiles)
                return DT_FAILURE | DT_INVALID_PARAM;
            dtMeshTile tile = m_tiles[tileIndex];
            if (tile.salt != tileSalt)
                return DT_FAILURE | DT_INVALID_PARAM;

            // Remove tile from hash lookup.
            int h = computeTileHash(tile.header.x,tile.header.y,m_tileLutMask);
            dtMeshTile prev = null;
            dtMeshTile cur = m_posLookup[h];
            while (cur != null)
            {
                if (cur == tile)
                {
                    if (prev != null)
                        prev.next = cur.next;
                    else
                        m_posLookup[h] = cur.next;
                    break;
                }
                prev = cur;
                cur = cur.next;
            }

            // Remove connections to neighbour tiles.
            // Create connections with neighbour tiles.
            const int MAX_NEIS = 32;
            dtMeshTile[] neis = new dtMeshTile[MAX_NEIS];
            int nneis;

            // Connect with layers in current tile.
            nneis = getTilesAt(tile.header.x, tile.header.y, neis, MAX_NEIS);
            for (int j = 0; j < nneis; ++j)
            {
                if (neis[j] == tile) continue;
                unconnectExtLinks(neis[j], tile);
            }

            // Connect with neighbour tiles.
            for (int i = 0; i < 8; ++i)
            {
                nneis = getNeighbourTilesAt(tile.header.x, tile.header.y, i, neis, MAX_NEIS);
                for (int j = 0; j < nneis; ++j)
                    unconnectExtLinks(neis[j], tile);
            }

            // Reset tile.
            if ((tile.flags & (int)dtTileFlags.DT_TILE_FREE_DATA) != 0)
            {
                // Owns data
                //dtFree(tile.data);
                tile.data = null;
                //tile.dataSize = 0;
                //if (data) *data = 0;
                //if (dataSize) *dataSize = 0;
                rawTileData = null;

            }
            else
            {
                //if (data) *data = tile.data;
                //if (dataSize) *dataSize = tile.dataSize;
                rawTileData = tile.data;
            }

            tile.header = null;
            tile.flags = 0;
            tile.linksFreeList = 0;
            tile.polys = null;
            tile.verts = null;
            tile.links = null;
            tile.detailMeshes = null;
            tile.detailVerts = null;
            tile.detailTris = null;
            tile.bvTree = null;
            tile.offMeshCons = null;

            // Update salt, salt should never be zero.
            #if DT_POLYREF64
            tile.salt = (tile.salt+1) & ((1<<DT_SALT_BITS)-1);
            #else
            tile.salt = (dtTileRef)( (tile.salt+1) & ((1<<(int)m_saltBits)-1) );
            #endif
            if (tile.salt == 0)
                tile.salt++;

            // Add to free list.
            tile.next = m_nextFree;
            m_nextFree = tile;

            return DT_SUCCESS;
        }
Exemplo n.º 16
0
        public dtPolyRef findNearestPolyInTile(dtMeshTile tile,
								        float[] center, int centerStart, 
                                        float[] extents,
								        float[] nearestPt)
        {
            float[] bmin = new float[3];//, bmax[3];
            float[] bmax = new float[3];
            dtVsub(bmin, 0, center, centerStart, extents, 0);
            dtVadd(bmax, 0, center, centerStart, extents, 0);

            // Get nearby polygons from proximity grid.
            dtPolyRef[] polys = new dtPolyRef[128];
            int polyCount = queryPolygonsInTile(tile, bmin, bmax, polys, 128);

            // Find nearest polygon amongst the nearby polygons.
            dtPolyRef nearest = 0;
            float nearestDistanceSqr = float.MaxValue;
            for (int i = 0; i < polyCount; ++i)
            {
                dtPolyRef polyRef = polys[i];
                float[] closestPtPoly = new float[3];
                float[] diff = new float[3];
                bool posOverPoly = false;
                float d = 0;
                closestPointOnPoly(polyRef, center, centerStart, closestPtPoly, ref posOverPoly);

                // If a point is directly over a polygon and closer than
                // climb height, favor that instead of straight line nearest point.
                dtVsub(diff, 0, center, centerStart, closestPtPoly, 0);
                if (posOverPoly)
                {
                    d = Math.Abs(diff[1]) - tile.header.walkableClimb;
                    d = d > 0 ? d*d : 0;
                }
                else
                {
                    d = dtVlenSqr(diff);
                }

                if (d < nearestDistanceSqr)
                {
                    dtVcopy(nearestPt, closestPtPoly);
                    nearestDistanceSqr = d;
                    nearest = polyRef;
                }
            }

            return nearest;
        }
Exemplo n.º 17
0
        /// Removes external links at specified side.
        public void unconnectExtLinks(dtMeshTile tile, dtMeshTile target)
        {
            if (tile == null || target == null)
                return;

            uint targetNum = decodePolyIdTile(getTileRef(target));

            for (int i = 0; i < tile.header.polyCount; ++i)
            {
                dtPoly poly = tile.polys[i];
                uint j = poly.firstLink;
                uint pj = DT_NULL_LINK;
                while (j != DT_NULL_LINK)
                {
                    if (tile.links[j].side != 0xff &&
                        decodePolyIdTile(tile.links[j].polyRef) == targetNum)
                    {
                        // Revove link.
                        uint nj = tile.links[j].next;
                        if (pj == DT_NULL_LINK)
                            poly.firstLink = nj;
                        else
                            tile.links[pj].next = nj;
                        freeLink(tile, j);
                        j = nj;
                    }
                    else
                    {
                        // Advance
                        pj = j;
                        j = tile.links[j].next;
                    }
                }
            }
        }
Exemplo n.º 18
0
 public static void freeLink(dtMeshTile tile, uint link)
 {
     tile.links[link].next = tile.linksFreeList;
     tile.linksFreeList    = link;
 }
Exemplo n.º 19
0
        /// @par
        ///
        /// The add operation will fail if the data is in the wrong format, the allocated tile
        /// space is full, or there is a tile already at the specified reference.
        ///
        /// The lastRef parameter is used to restore a tile with the same tile
        /// reference it had previously used.  In this case the #dtPolyRef's for the
        /// tile will be restored to the same values they were before the tile was 
        /// removed.
        ///
        /// @see dtCreateNavMeshData, #removeTile
        /// Adds a tile to the navigation mesh.
        ///  @param[in]		data		Data for the new tile mesh. (See: #dtCreateNavMeshData)
        ///  @param[in]		dataSize	Data size of the new tile mesh.
        ///  @param[in]		flags		Tile flags. (See: #dtTileFlags)
        ///  @param[in]		lastRef		The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
        ///  @param[out]	result		The tile reference. (If the tile was succesfully added.) [opt]
        /// @return The status flags for the operation.
        public dtStatus addTile(dtRawTileData rawTileData, int flags, dtTileRef lastRef, ref dtTileRef result)
        {
            //C#: Using an intermediate class dtRawTileData because Cpp uses a binary buffer.

            // Make sure the data is in right format.
            dtMeshHeader header = rawTileData.header;
            if (header.magic != DT_NAVMESH_MAGIC)
                return DT_FAILURE | DT_WRONG_MAGIC;
            if (header.version != DT_NAVMESH_VERSION)
                return DT_FAILURE | DT_WRONG_VERSION;

            // Make sure the location is free.
            if (getTileAt(header.x, header.y, header.layer) != null)
                return DT_FAILURE;

            // Allocate a tile.
            dtMeshTile tile = null;
            if (lastRef == 0)
            {
                if (m_nextFree != null)
                {
                    tile = m_nextFree;
                    m_nextFree = tile.next;
                    tile.next = null;
                }
            }
            else
            {
                // Try to relocate the tile to specific index with same salt.
                int tileIndex = (int)decodePolyIdTile((dtPolyRef)lastRef);
                if (tileIndex >= m_maxTiles)
                    return DT_FAILURE | DT_OUT_OF_MEMORY;
                // Try to find the specific tile id from the free list.
                dtMeshTile target = m_tiles[tileIndex];
                dtMeshTile prev = null;
                tile = m_nextFree;
                while (tile != null && tile != target)
                {
                    prev = tile;
                    tile = tile.next;
                }
                // Could not find the correct location.
                if (tile != target)
                    return DT_FAILURE | DT_OUT_OF_MEMORY;
                // Remove from freelist
                if (prev == null)
                    m_nextFree = tile.next;
                else
                    prev.next = tile.next;

                // Restore salt.
                tile.salt = decodePolyIdSalt((dtPolyRef)lastRef);
            }

            // Make sure we could allocate a tile.
            if (tile == null)
                return DT_FAILURE | DT_OUT_OF_MEMORY;

            // Insert tile into the position lut.
            int h = computeTileHash(header.x, header.y, m_tileLutMask);
            tile.next = m_posLookup[h];
            m_posLookup[h] = tile;

            // Patch header pointers.

            //int vertsCount = 3*header.vertCount;
            //int polysSize = header.polyCount;
            //int linksSize = header.maxLinkCount;
            //int detailMeshesSize = header.detailMeshCount;
            //int detailVertsSize = 3*header.detailVertCount;
            //int detailTrisSize = 4*header.detailTriCount;
            //int bvtreeSize = header.bvNodeCount;
            //int offMeshLinksSize = header.offMeshConCount;

            //byte* d = data + headerSize;
            tile.verts = rawTileData.verts;
            tile.polys = rawTileData.polys;
            tile.links = rawTileData.links;
            tile.detailMeshes = rawTileData.detailMeshes;
            tile.detailVerts = rawTileData.detailVerts;
            tile.detailTris = rawTileData.detailTris;
            tile.bvTree = rawTileData.bvTree;
            tile.offMeshCons = rawTileData.offMeshCons;

            // If there are no items in the bvtree, reset the tree pointer.
            //c#: unnecessary, Cpp is afraid to point to whatever data ends up here
            //if (bvtreeSize == 0)
            //	tile.bvTree = null;

            // Build links freelist
            tile.linksFreeList = 0;
            tile.links[header.maxLinkCount-1].next = DT_NULL_LINK;
            for (int i = 0; i < header.maxLinkCount-1; ++i){
                tile.links[i].next = (dtTileRef) (i+1);
            }

            // Init tile.
            tile.header = header;
            tile.data = rawTileData;
            //tile.dataSize = dataSize;
            tile.flags = flags;

            connectIntLinks(tile);
            baseOffMeshLinks(tile);

            // Create connections with neighbour tiles.
            const int MAX_NEIS = 32;
            dtMeshTile[] neis = new dtMeshTile[MAX_NEIS];
            int nneis;

            // Connect with layers in current tile.
            nneis = getTilesAt(header.x, header.y, neis, MAX_NEIS);
            for (int j = 0; j < nneis; ++j)
            {
                if (neis[j] != tile)
                {
                    connectExtLinks(tile, neis[j], -1);
                    connectExtLinks(neis[j], tile, -1);
                }
                connectExtOffMeshLinks(tile, neis[j], -1);
                connectExtOffMeshLinks(neis[j], tile, -1);
            }

            // Connect with neighbour tiles.
            for (int i = 0; i < 8; ++i)
            {
                nneis = getNeighbourTilesAt(header.x, header.y, i, neis, MAX_NEIS);
                for (int j = 0; j < nneis; ++j)
                {
                    connectExtLinks(tile, neis[j], i);
                    connectExtLinks(neis[j], tile, dtOppositeTile(i));
                    connectExtOffMeshLinks(tile, neis[j], i);
                    connectExtOffMeshLinks(neis[j], tile, dtOppositeTile(i));
                }
            }

            result = getTileRef(tile);

            return DT_SUCCESS;
        }
Exemplo n.º 20
0
        // Returns portal points between two polygons.
        dtStatus getPortalPoints(dtPolyRef from, dtPoly fromPoly, dtMeshTile fromTile,
										         dtPolyRef to, dtPoly toPoly, dtMeshTile toTile,
										         float[] left, float[] right)
        {
	        // Find the link that points to the 'to' polygon.
	        dtLink link = null;
	        for (uint i = fromPoly.firstLink; i != DT_NULL_LINK; i = fromTile.links[i].next)
	        {
		        if (fromTile.links[i].polyRef == to)
		        {
			        link = fromTile.links[i];
			        break;
		        }
	        }
	        if (link == null)
		        return DT_FAILURE | DT_INVALID_PARAM;
	
	        // Handle off-mesh connections.
	        if (fromPoly.getType() == (byte) dtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION)
	        {
		        // Find link that points to first vertex.
		        for (uint i = fromPoly.firstLink; i != DT_NULL_LINK; i = fromTile.links[i].next)
		        {
			        if (fromTile.links[i].polyRef == to)
			        {
				        int v = fromTile.links[i].edge;
				        dtVcopy(left, 0, fromTile.verts,fromPoly.verts[v]*3);
				        dtVcopy(right, 0, fromTile.verts,fromPoly.verts[v]*3);
				        return DT_SUCCESS;
			        }
		        }
		        return DT_FAILURE | DT_INVALID_PARAM;
	        }
	
	        if (toPoly.getType() == (byte) dtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION)
	        {
		        for (uint i = toPoly.firstLink; i != DT_NULL_LINK; i = toTile.links[i].next)
		        {
			        if (toTile.links[i].polyRef == from)
			        {
				        int v = toTile.links[i].edge;
				        dtVcopy(left, 0, toTile.verts, toPoly.verts[v]*3);
				        dtVcopy(right, 0, toTile.verts, toPoly.verts[v]*3);
				        return DT_SUCCESS;
			        }
		        }
		        return DT_FAILURE | DT_INVALID_PARAM;
	        }
	
	        // Find portal vertices.
	        int v0 = fromPoly.verts[link.edge];
	        int v1 = fromPoly.verts[(link.edge+1) % (int)fromPoly.vertCount];
	        dtVcopy(left, 0, fromTile.verts,v0*3);
	        dtVcopy(right, 0, fromTile.verts,v1*3);
	
	        // If the link is at tile boundary, dtClamp the vertices to
	        // the link width.
	        if (link.side != 0xff)
	        {
		        // Unpack portal limits.
		        if (link.bmin != 0 || link.bmax != 255)
		        {
			        float s = 1.0f/255.0f;
			        float tmin = link.bmin*s;
			        float tmax = link.bmax*s;
			        dtVlerp(left, 0, fromTile.verts, v0*3, fromTile.verts, v1*3, tmin);
			        dtVlerp(right, 0, fromTile.verts, v0*3, fromTile.verts, v1*3, tmax);
		        }
	        }
	
	        return DT_SUCCESS;
        }
Exemplo n.º 21
0
        /// Builds internal polygons links for a tile.
        public void baseOffMeshLinks(dtMeshTile tile)
        {
            if (tile == null)
                return;

            dtPolyRef polyRefBase = getPolyRefBase(tile);

            // Base off-mesh connection start points.
            for (int i = 0; i < tile.header.offMeshConCount; ++i)
            {
                dtOffMeshConnection con = tile.offMeshCons[i];
                dtPoly poly = tile.polys[con.poly];

                float[] ext = new float[] { con.rad, tile.header.walkableClimb, con.rad };

                // Find polygon to connect to.
                //const float* p = &con.pos[0]; // First vertex

                float[] nearestPt = new float[3];
                dtPolyRef polyRef = findNearestPolyInTile(tile, con.pos, 0, ext, nearestPt);
                if (polyRef == 0)
                    continue;
                // findNearestPoly may return too optimistic results, further check to make sure.
                if (dtSqr(nearestPt[0]-con.pos[0])+dtSqr(nearestPt[2]-con.pos[2]) > dtSqr(con.rad))
                    continue;
                // Make sure the location is on current mesh.
                //float* v = &tile.verts[poly.verts[0]*3];
                int vIndex = poly.verts[0]*3;
                dtVcopy(tile.verts, vIndex, nearestPt, 0);

                // Link off-mesh connection to target poly.
                uint idx = allocLink(tile);
                if (idx != DT_NULL_LINK)
                {
                    dtLink link = tile.links[idx];
                    link.polyRef = polyRef;
                    link.edge = (byte)0;
                    link.side = 0xff;
                    link.bmin = link.bmax = 0;
                    // Add to linked list.
                    link.next = poly.firstLink;
                    poly.firstLink = idx;
                }

                // Start end-point is always connect back to off-mesh connection.
                uint tidx = allocLink(tile);
                if (tidx != DT_NULL_LINK)
                {
                    ushort landPolyIdx = (ushort)decodePolyIdPoly(polyRef);
                    dtPoly landPoly = tile.polys[landPolyIdx];
                    dtLink link = tile.links[tidx];
                    link.polyRef = polyRefBase | (dtPolyRef)(con.poly);
                    link.edge = 0xff;
                    link.side = 0xff;
                    link.bmin = link.bmax = 0;
                    // Add to linked list.
                    link.next = landPoly.firstLink;
                    landPoly.firstLink = tidx;
                }
            }
        }
Exemplo n.º 22
0
        /// Queries polygons within a tile.
		public int queryPolygonsInTile(dtMeshTile tile, float[] qmin, float[] qmax,
										        dtQueryFilter filter,
										        dtPolyRef[] polys, int polyStart, int maxPolys)
        {
	        Debug.Assert(m_nav != null);

	        if (tile.bvTree != null)
	        {
		        dtBVNode node = tile.bvTree[0];
		        //dtBVNode* end = &tile.bvTree[tile.header.bvNodeCount];
                int endIndex = tile.header.bvNodeCount;
		        float[] tbmin = tile.header.bmin;
		        float[] tbmax = tile.header.bmax;
		        float qfac = tile.header.bvQuantFactor;
		
		        // Calculate quantized box
		        ushort[] bmin = new ushort[3];//, bmax[3];
                ushort[] bmax = new ushort[3];
		        // dtClamp query box to world box.
		        float minx = dtClamp(qmin[0], tbmin[0], tbmax[0]) - tbmin[0];
		        float miny = dtClamp(qmin[1], tbmin[1], tbmax[1]) - tbmin[1];
		        float minz = dtClamp(qmin[2], tbmin[2], tbmax[2]) - tbmin[2];
		        float maxx = dtClamp(qmax[0], tbmin[0], tbmax[0]) - tbmin[0];
		        float maxy = dtClamp(qmax[1], tbmin[1], tbmax[1]) - tbmin[1];
		        float maxz = dtClamp(qmax[2], tbmin[2], tbmax[2]) - tbmin[2];
		        // Quantize
		        bmin[0] = (ushort)((int)(qfac * minx) & 0xfffe);
		        bmin[1] = (ushort)((int)(qfac * miny) & 0xfffe);
		        bmin[2] = (ushort)((int)(qfac * minz) & 0xfffe);
		        bmax[0] = (ushort)((int)(qfac * maxx + 1) | 1);
		        bmax[1] = (ushort)((int)(qfac * maxy + 1) | 1);
		        bmax[2] = (ushort)((int)(qfac * maxz + 1) | 1);
		
		        // Traverse tree
		        dtPolyRef polyRefBase = m_nav.getPolyRefBase(tile);
		        int n = 0;
                int nodeIndex = 0;
		        while (nodeIndex < endIndex)
		        {
                    node = tile.bvTree[nodeIndex];

			        bool overlap = dtOverlapQuantBounds(bmin, bmax, node.bmin, node.bmax);
			        bool isLeafNode = node.i >= 0;
			
			        if (isLeafNode && overlap)
			        {
				        dtPolyRef polyRef = polyRefBase | (dtPolyRef)node.i;
				        if (filter.passFilter(polyRef, tile, tile.polys[node.i]))
				        {
					        if (n < maxPolys)
						        polys[polyStart + n++] = polyRef;
				        }
			        }
			
			        if (overlap || isLeafNode){
                        nodeIndex++;
			        }
                    else
			        {
				        int escapeIndex = -node.i;
				        nodeIndex += escapeIndex;
			        }
		        }
		
		        return n;
	        }
	        else
	        {
		        float[] bmin = new float[3];//, bmax[3];
                float[] bmax = new float[3];
		        int n = 0;
		        dtPolyRef polyRefBase = m_nav.getPolyRefBase(tile);
		        for (int i = 0; i < tile.header.polyCount; ++i)
		        {
			        dtPoly p = tile.polys[i];
			        // Do not return off-mesh connection polygons.
			        if (p.getType() == (byte)dtPolyTypes.DT_POLYTYPE_OFFMESH_CONNECTION)
				        continue;
			        // Must pass filter
			        dtPolyRef polyRef = polyRefBase | (dtPolyRef)i;
			        if (!filter.passFilter(polyRef, tile, p))
				        continue;
			        // Calc polygon bounds.
			        //const float* v = &tile.verts[p.verts[0]*3];
                    int vStart = p.verts[0]*3;
			        dtVcopy(bmin,0, tile.verts,vStart);
			        dtVcopy(bmax,0, tile.verts,vStart);
			        for (int j = 1; j < p.vertCount; ++j)
			        {
				        //v = &tile.verts[p.verts[j]*3];
                        vStart = p.verts[j]*3;
				        dtVmin(bmin,0, tile.verts,vStart);
				        dtVmax(bmax,0, tile.verts,vStart);
			        }
			        if (dtOverlapBounds(qmin,qmax, bmin,bmax))
			        {
				        if (n < maxPolys)
					        polys[polyStart + n++] = polyRef;
			        }
		        }
		        return n;
	        }
        }
Exemplo n.º 23
0
        public int getNeighbourTilesAt(int x, int y, int side, dtMeshTile[] tiles, int maxTiles)
        {
            int nx = x, ny = y;
            switch (side)
            {
                case 0: nx++; break;
                case 1: nx++; ny++; break;
                case 2: ny++; break;
                case 3: nx--; ny++; break;
                case 4: nx--; break;
                case 5: nx--; ny--; break;
                case 6: ny--; break;
                case 7: nx++; ny--; break;
            };

            return getTilesAt(nx, ny, tiles, maxTiles);
        }