예제 #1
0
        /// Returns the segments for the specified polygon, optionally including portals.
        ///  @param[in]		ref				The reference id of the polygon.
        ///  @param[in]		filter			The polygon filter to apply to the query.
        ///  @param[out]	segmentVerts	The segments. [(ax, ay, az, bx, by, bz) * segmentCount]
        ///  @param[out]	segmentRefs		The reference ids of each segment's neighbor polygon. 
        ///  								Or zero if the segment is a wall. [opt] [(parentRef) * @p segmentCount] 
        ///  @param[out]	segmentCount	The number of segments returned.
        ///  @param[in]		maxSegments		The maximum number of segments the result arrays can hold.
        /// @returns The status flags for the query.
        /// @par
        ///
        /// If the @p segmentRefs parameter is provided, then all polygon segments will be returned. 
        /// Otherwise only the wall segments are returned.
        /// 
        /// A segment that is normally a portal will be included in the result set as a 
        /// wall if the @p filter results in the neighbor polygon becoomming impassable.
        /// 
        /// The @p segmentVerts and @p segmentRefs buffers should normally be sized for the 
        /// maximum segments per polygon of the source navigation mesh.
        /// 
        dtStatus getPolyWallSegments(dtPolyRef polyRef, dtQueryFilter filter,
											         float[] segmentVerts, dtPolyRef[] segmentRefs, ref int segmentCount,
											         int maxSegments)
        {
	        Debug.Assert(m_nav != null);
	
	        segmentCount = 0;
	
	        dtMeshTile tile = null;
	        dtPoly poly = null;
	        if (dtStatusFailed(m_nav.getTileAndPolyByRef(polyRef, ref tile, ref poly)))
		        return DT_FAILURE | DT_INVALID_PARAM;
	
	        int n = 0;
	        const int MAX_INTERVAL = 16;
	        dtSegInterval[] ints = new dtSegInterval[MAX_INTERVAL];
            dtcsArrayItemsCreate(ints);
	        int nints;
	
	        bool storePortals = segmentRefs != null;
	
	        dtStatus status = DT_SUCCESS;
	
	        for (int i = 0, j = (int)poly.vertCount-1; i < (int)poly.vertCount; j = i++) {
                // Skip non-solid edges.
                nints = 0;
                if ((poly.neis[j] & DT_EXT_LINK) != 0) {
                    // Tile border.
                    for (uint k = poly.firstLink; k != DT_NULL_LINK; k = tile.links[k].next) {
                        dtLink link = tile.links[k];
                        if (link.edge == j) {
                            if (link.polyRef != 0) {
                                dtMeshTile neiTile = null;
                                dtPoly neiPoly = null;
                                m_nav.getTileAndPolyByRefUnsafe(link.polyRef, ref neiTile, ref neiPoly);
                                if (filter.passFilter(link.polyRef, neiTile, neiPoly)) {
                                    insertInterval(ints, ref nints, MAX_INTERVAL, link.bmin, link.bmax, link.polyRef);
                                }
                            }
                        }
                    }
                } else {
                    // Internal edge
                    dtPolyRef neiRef = 0;
                    if (poly.neis[j] != 0) {
                        uint idx = (uint)(poly.neis[j] - 1);
                        neiRef = m_nav.getPolyRefBase(tile) | idx;
                        if (!filter.passFilter(neiRef, tile, tile.polys[idx]))
                            neiRef = 0;
                    }

                    // If the edge leads to another polygon and portals are not stored, skip.
                    if (neiRef != 0 && !storePortals)
                        continue;

                    if (n < maxSegments) {
                        //const float* vj = &tile.verts[poly.verts[j]*3];
                        //const float* vi = &tile.verts[poly.verts[i]*3];
                        //float* seg = &segmentVerts[n*6];
                        int vjStart = poly.verts[j] * 3;
                        int viStart = poly.verts[i] * 3;
                        int segStart = n * 6;
                        dtVcopy(segmentVerts, segStart, tile.verts, vjStart);
                        dtVcopy(segmentVerts, segStart + 3, tile.verts, viStart);
                        if (segmentRefs != null)
                            segmentRefs[n] = neiRef;
                        n++;
                    } else {
                        status |= DT_BUFFER_TOO_SMALL;
                    }

                    continue;
                }

                // Add sentinels
                insertInterval(ints, ref nints, MAX_INTERVAL, -1, 0, 0);
                insertInterval(ints, ref nints, MAX_INTERVAL, 255, 256, 0);

                // Store segments.
                //const float* vj = &tile.verts[poly.verts[j]*3];
                //const float* vi = &tile.verts[poly.verts[i]*3];
                int vjStart2 = poly.verts[j] * 3;
                int viStart2 = poly.verts[i] * 3;
                for (int k = 1; k < nints; ++k) {
                    // Portal segment.
                    if (storePortals && ints[k].polyRef != 0) {
                        float tmin = ints[k].tmin / 255.0f;
                        float tmax = ints[k].tmax / 255.0f;
                        if (n < maxSegments) {
                            //float* seg = &segmentVerts[n*6];
                            int segStart = n * 6;
                            dtVlerp(segmentVerts, segStart, tile.verts, vjStart2, tile.verts, viStart2, tmin);
                            dtVlerp(segmentVerts, segStart + 3, tile.verts, vjStart2, tile.verts, viStart2, tmax);
                            if (segmentRefs != null)
                                segmentRefs[n] = ints[k].polyRef;
                            n++;
                        } else {
                            status |= DT_BUFFER_TOO_SMALL;
                        }
                    }

                    // Wall segment.
                    int imin = ints[k - 1].tmax;
                    int imax = ints[k].tmin;
                    if (imin != imax) {
                        float tmin = imin / 255.0f;
                        float tmax = imax / 255.0f;
                        if (n < maxSegments) {
                            //float* seg = &segmentVerts[n*6];
                            int segStart = n * 6;
                            dtVlerp(segmentVerts, segStart, tile.verts, vjStart2, tile.verts, viStart2, tmin);
                            dtVlerp(segmentVerts, segStart + 3, tile.verts, vjStart2, tile.verts, viStart2, tmax);
                            if (segmentRefs != null)
                                segmentRefs[n] = 0;
                            n++;
                        } else {
                            status |= DT_BUFFER_TOO_SMALL;
                        }
                    }
                }
            }
	
	        segmentCount = n;
	
	        return status;
        }
예제 #2
0
        static void insertInterval(dtSegInterval[] ints, ref int nints, int maxInts,
						           short tmin, short tmax, dtPolyRef polyRef)
        {
	        if (nints+1 > maxInts) 
                return;
	        // Find insertion point.
	        int idx = 0;
	        while (idx < nints)
	        {
		        if (tmax <= ints[idx].tmin)
			        break;
		        idx++;
	        }
	        // Move current results.
	        if (nints-idx != 0){
		        //memmove(ints+idx+1, ints+idx, sizeof(dtSegInterval)*(nints-idx));
                for (int i=0;i<(nints-idx);++i){
                    ints[idx+1+i] = ints[idx+i];
                }
            }
	        // Store
	        ints[idx].polyRef = polyRef;
	        ints[idx].tmin = tmin;
	        ints[idx].tmax = tmax;
	        nints++;
        }