コード例 #1
0
void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side)
{
    if (!tile) return;

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

        // Create new links.
        unsigned short m = DT_EXT_LINK | (unsigned short)side;
        const int nv = 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;

            // Create new links
            const float* va = &tile->verts[poly->verts[j]*3];
            const float* vb = &tile->verts[poly->verts[(j+1) % nv]*3];
            dtPolyRef nei[4];
            float neia[4*2];
            int nnei = findConnectingPolys(va,vb, target, dtOppositeTile(side), nei,neia,4);
            for (int k = 0; k < nnei; ++k)
            {
                unsigned int idx = allocLink(tile);
                if (idx != DT_NULL_LINK)
                {
                    dtLink* link = &tile->links[idx];
                    link->ref = nei[k];
                    link->edge = (unsigned char)j;
                    link->side = (unsigned char)side;

                    link->next = poly->firstLink;
                    poly->firstLink = idx;

                    // Compress portal limits to a byte value.
                    if (side == 0 || side == 4)
                    {
                        float tmin = (neia[k*2+0]-va[2]) / (vb[2]-va[2]);
                        float tmax = (neia[k*2+1]-va[2]) / (vb[2]-va[2]);
                        if (tmin > tmax)
                            dtSwap(tmin,tmax);
                        link->bmin = (unsigned char)(dtClamp(tmin, 0.0f, 1.0f)*255.0f);
                        link->bmax = (unsigned char)(dtClamp(tmax, 0.0f, 1.0f)*255.0f);
                    }
                    else if (side == 2 || side == 6)
                    {
                        float tmin = (neia[k*2+0]-va[0]) / (vb[0]-va[0]);
                        float tmax = (neia[k*2+1]-va[0]) / (vb[0]-va[0]);
                        if (tmin > tmax)
                            dtSwap(tmin,tmax);
                        link->bmin = (unsigned char)(dtClamp(tmin, 0.0f, 1.0f)*255.0f);
                        link->bmax = (unsigned char)(dtClamp(tmax, 0.0f, 1.0f)*255.0f);
                    }
                }
            }
        }
    }
}
コード例 #2
0
dtStatus dtBuildTileCacheDistanceField(dtTileCacheAlloc* alloc, dtTileCacheLayer& layer, dtTileCacheDistanceField& dfield)
{
    dtAssert(alloc);

    const int w = (int)layer.header->width;
    const int h = (int)layer.header->height;

    dfield.data = (unsigned short*)alloc->alloc(w*h*sizeof(unsigned short));
    if (!dfield.data)
    {
        return DT_FAILURE | DT_OUT_OF_MEMORY;
    }

    dtTileCacheDistanceField tmpField;
    tmpField.data = (unsigned short*)alloc->alloc(w*h*sizeof(unsigned short));
    if (!tmpField.data)
    {
        return DT_FAILURE | DT_OUT_OF_MEMORY;
    }

    calculateDistanceField(layer, dfield.data, dfield.maxDist);
    if (boxBlur(layer, 1, dfield.data, tmpField.data) != dfield.data)
    {
        dtSwap(dfield.data, tmpField.data);
    }

    alloc->free(tmpField.data);
    return DT_SUCCESS;
}
コード例 #3
0
ファイル: CrowdTool.cpp プロジェクト: 0jpq0/server
static bool isectSegAABB(const float* sp, const float* sq,
						 const float* amin, const float* amax,
						 float& tmin, float& tmax)
{
	static const float EPS = 1e-6f;
	
	float d[3];
	dtVsub(d, sq, sp);
	tmin = 0;  // set to -FLT_MAX to get first hit on line
	tmax = FLT_MAX;		// set to max distance ray can travel (for segment)
	
	// For all three slabs
	for (int i = 0; i < 3; i++)
	{
		if (fabsf(d[i]) < EPS)
		{
			// Ray is parallel to slab. No hit if origin not within slab
			if (sp[i] < amin[i] || sp[i] > amax[i])
				return false;
		}
		else
		{
			// Compute intersection t value of ray with near and far plane of slab
			const float ood = 1.0f / d[i];
			float t1 = (amin[i] - sp[i]) * ood;
			float t2 = (amax[i] - sp[i]) * ood;
			// Make t1 be intersection with near plane, t2 with far plane
			if (t1 > t2) dtSwap(t1, t2);
			// Compute the intersection of slab intersections intervals
			if (t1 > tmin) tmin = t1;
			if (t2 < tmax) tmax = t2;
			// Exit with no collision as soon as slab intersection becomes empty
			if (tmin > tmax) return false;
		}
	}
	
	return true;
}
コード例 #4
0
dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc,
                                 const int minRegionArea, const int mergeRegionArea,
                                 dtTileCacheLayer& layer, dtTileCacheDistanceField dfield)
{
    dtAssert(alloc);

    const int w = (int)layer.header->width;
    const int h = (int)layer.header->height;
    const int size = w*h;

    dtFixedArray<unsigned short> buf(alloc, size*4);
    if (!buf)
    {
        return DT_FAILURE | DT_OUT_OF_MEMORY;
    }

    dtIntArray stack(1024);
    dtIntArray visited(1024);

    unsigned short* srcReg = buf;
    unsigned short* srcDist = buf+size;
    unsigned short* dstReg = buf+size*2;
    unsigned short* dstDist = buf+size*3;

    memset(srcReg, 0, sizeof(unsigned short)*size);
    memset(srcDist, 0, sizeof(unsigned short)*size);

    unsigned short regionId = 1;
    unsigned short level = (dfield.maxDist+1) & ~1;

    // TODO: Figure better formula, expandIters defines how much the
    // watershed "overflows" and simplifies the regions. Tying it to
    // agent radius was usually good indication how greedy it could be.
    //	const int expandIters = 4 + walkableRadius * 2;
    const int expandIters = 8;

    while (level > 0)
    {
        level = level >= 2 ? level-2 : 0;

        // Expand current regions until no empty connected cells found.
        if (expandRegions(expandIters, level, layer, dfield, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
        {
            dtSwap(srcReg, dstReg);
            dtSwap(srcDist, dstDist);
        }

        // Mark new regions with IDs.
        for (int y = 0; y < h; ++y)
        {
            for (int x = 0; x < w; ++x)
            {
                const int i=x+y*w;
                if (dfield.data[i] < level || srcReg[i] != 0 || layer.areas[i] == DT_TILECACHE_NULL_AREA)
                    continue;
                if (floodRegion(x, y, i, level, regionId, layer, dfield, srcReg, srcDist, stack))
                    regionId++;
            }
        }
    }

    // Expand current regions until no empty connected cells found.
    if (expandRegions(expandIters*8, 0, layer, dfield, srcReg, srcDist, dstReg, dstDist, stack) != srcReg)
    {
        dtSwap(srcReg, dstReg);
        dtSwap(srcDist, dstDist);
    }

    dtStatus status = filterSmallRegions(alloc, layer, minRegionArea, mergeRegionArea, regionId, srcReg);
    if (dtStatusFailed(status))
    {
        return status;
    }

    // Write the result out.
    memcpy(layer.regs, srcReg, sizeof(unsigned short)*size);
    layer.regCount = regionId;

    return DT_SUCCESS;
}
コード例 #5
0
static unsigned short* expandRegions(int maxIter, unsigned short level,
                                     dtTileCacheLayer& layer, dtTileCacheDistanceField& dfield,
                                     unsigned short* srcReg, unsigned short* srcDist,
                                     unsigned short* dstReg, unsigned short* dstDist,
                                     dtIntArray& stack)
{
    const int w = (int)layer.header->width;
    const int h = (int)layer.header->height;

    // Find cells revealed by the raised level.
    stack.resize(0);
    for (int y = 0; y < h; ++y)
    {
        for (int x = 0; x < w; ++x)
        {
            const int i = x+y*w;
            if (dfield.data[i] >= level && srcReg[i] == 0 && layer.areas[i] != DT_TILECACHE_NULL_AREA)
            {
                stack.push(x);
                stack.push(y);
                stack.push(i);
            }
        }
    }

    int iter = 0;
    while (stack.size() > 0)
    {
        int failed = 0;

        memcpy(dstReg, srcReg, sizeof(unsigned short)*w*h);
        memcpy(dstDist, srcDist, sizeof(unsigned short)*w*h);

        for (int j = 0; j < stack.size(); j += 3)
        {
            int x = stack[j+0];
            int y = stack[j+1];
            int i = stack[j+2];
            if (i < 0)
            {
                failed++;
                continue;
            }

            unsigned short r = srcReg[i];
            unsigned short d2 = 0xffff;
            const unsigned char area = layer.areas[i];
            for (int dir = 0; dir < 4; ++dir)
            {
                const int ax = x + getDirOffsetX(dir);
                const int ay = y + getDirOffsetY(dir);
                const int ai = ax+ay*w;
                if (ax >= 0 && ax < w && ay >= 0 && ay < h && isConnected(layer, i, dir))
                {
                    if (layer.areas[ai] != area) continue;
                    if (srcReg[ai] > 0)
                    {
                        if ((int)srcDist[ai]+2 < (int)d2)
                        {
                            r = srcReg[ai];
                            d2 = srcDist[ai]+2;
                        }
                    }
                }
            }
            if (r)
            {
                stack[j+2] = -1; // mark as used
                dstReg[i] = r;
                dstDist[i] = d2;
            }
            else
            {
                failed++;
            }
        }

        // rcSwap source and dest.
        dtSwap(srcReg, dstReg);
        dtSwap(srcDist, dstDist);

        if (failed*3 == stack.size())
            break;

        if (level > 0)
        {
            ++iter;
            if (iter >= maxIter)
                break;
        }
    }

    return srcReg;
}