Пример #1
0
        public Status GetPolyArea(long refId, ref short resultArea)
        {
            long salt, it, ip;

            if (refId == 0)
            {
                return(Status.Failure);
            }

            DecodePolyId(refId, out salt, out it, out ip);
            if (it >= _maxTiles)
            {
                return(Status.Failure | Status.InvalidParam);
            }
            if (_tiles[it].Salt != salt || _tiles[it].Header == null)
            {
                return(Status.Failure | Status.InvalidParam);
            }
            MeshTile tile = _tiles[it];

            if (ip >= _tiles[it].Header.PolyCount)
            {
                return(Status.Failure | Status.InvalidParam);
            }

            Poly poly = tile.Polys[ip];

            resultArea = poly.Area;

            return(Status.Success);
        }
Пример #2
0
        public Status RestoreTileState(MeshTile tile, TileState tileState)
        {
            if (tileState.Magic != Helper.NavMeshMagic)
            {
                return(Status.Failure | Status.WrongMagic);
            }
            if (tileState.Version != Helper.NavMeshVersion)
            {
                return(Status.Failure | Status.WrongVersion);
            }
            if (tileState.Ref != GetTileRef(tile))
            {
                return(Status.Failure | Status.InvalidParam);
            }

            for (int i = 0; i < tile.Header.PolyCount; i++)
            {
                Poly      p = tile.Polys[i];
                PolyState s = tileState.PolyStates[i];
                p.Flags = s.Flags;
                p.Area  = s.Area;
            }

            return(Status.Success);
        }
Пример #3
0
        public Status SetPolyFlags(long refId, int flags)
        {
            long salt, it, ip;

            if (refId == 0)
            {
                return(Status.Failure);
            }

            DecodePolyId(refId, out salt, out it, out ip);
            if (it >= _maxTiles)
            {
                return(Status.Failure | Status.InvalidParam);
            }
            if (_tiles[it].Salt != salt || _tiles[it].Header == null)
            {
                return(Status.Failure | Status.InvalidParam);
            }
            MeshTile tile = _tiles[it];

            if (ip >= _tiles[it].Header.PolyCount)
            {
                return(Status.Failure | Status.InvalidParam);
            }

            Poly poly = tile.Polys[ip];

            poly.Flags = flags;
            return(Status.Success);
        }
Пример #4
0
 public float GetCost(float pax, float pay, float paz, float pbx, float pby, float pbz,
                      long prevRef, MeshTile prevTile, Poly prevPoly,
                      long curRef, MeshTile curTile, Poly curPoly,
                      long nextRef, MeshTile nextTile, Poly nextPoly)
 {
     return(Helper.VDist(pax, pay, paz, pbx, pby, pbz) * _areaCost[curPoly.Area]);
 }
Пример #5
0
        public Status GetTileAndPolyByRef(long refid, ref MeshTile tile, ref Poly poly)
        {
            if (refid == 0)
            {
                return(Status.Failure);
            }
            long salt, it, ip;

            DecodePolyId(refid, out salt, out it, out ip);
            if (it >= _maxTiles)
            {
                return(Status.Failure | Status.InvalidParam);
            }
            if (_tiles[it].Salt != salt || _tiles[it].Header == null)
            {
                return(Status.Failure | Status.InvalidParam);
            }
            if (ip >= _tiles[it].Header.PolyCount)
            {
                return(Status.Failure | Status.InvalidParam);
            }
            tile = _tiles[it];
            poly = _tiles[it].Polys[ip];
            return(Status.Success);
        }
Пример #6
0
        public void GetTileAndPolyByRefUnsafe(long refId, out MeshTile tile, out Poly poly)
        {
            long salt, it, ip;

            DecodePolyId(refId, out salt, out it, out ip);
            tile = _tiles[it];
            poly = _tiles[it].Polys[ip];
        }
Пример #7
0
        private void BaseOffMeshLinks(MeshTile tile)
        {
            if (tile == null)
            {
                return;
            }
            long baseId = GetPolyRefBase(tile);

            for (int i = 0; i < tile.Header.OffMeshConCount; i++)
            {
                OffMeshConnection con = tile.OffMeshCons[i];
                Poly poly             = tile.Polys[con.Poly];

                float[] ext       = { con.Rad, tile.Header.WalkableClimb, con.Rad };
                int     p         = 0;
                float[] nearestPt = new float[3];
                long    refId     = FindNearestPolyInTile(tile, con.Pos[p + 0], con.Pos[p + 1], con.Pos[p + 2], ext[0], ext[1],
                                                          ext[2], ref nearestPt);
                if (refId <= 0)
                {
                    continue;
                }
                if (((nearestPt[0] - con.Pos[p + 0]) * (nearestPt[0] - con.Pos[p + 0])) +
                    ((nearestPt[2] - con.Pos[p + 2]) * (nearestPt[2] - con.Pos[p + 2])) > (con.Rad * con.Rad))
                {
                    continue;
                }

                int v = poly.Verts[0] * 3;
                Array.Copy(nearestPt, 0, tile.Verts, v, 3);

                long idx = AllocLink(tile);
                if (idx != NullLink)
                {
                    Link link = tile.Links[idx];
                    link.Ref       = refId;
                    link.Edge      = 0;
                    link.Side      = 0xff;
                    link.BMin      = link.BMax = 0;
                    link.Next      = poly.FirstLink;
                    poly.FirstLink = idx;
                }

                long tidx = AllocLink(tile);
                if (tidx != NullLink)
                {
                    int  landPolyIdx = (int)DecodePolyIdPoly(refId);
                    Poly landPoly    = tile.Polys[landPolyIdx];
                    Link link        = tile.Links[tidx];
                    link.Ref           = baseId | con.Poly;
                    link.Edge          = 0xff;
                    link.Side          = 0xff;
                    link.BMin          = link.BMax = 0;
                    link.Next          = landPoly.FirstLink;
                    landPoly.FirstLink = tidx;
                }
            }
        }
Пример #8
0
        private int FindConnectingPolys(float vax, float vay, float vaz, float vbx, float vby, float vbz, MeshTile tile,
                                        int side, ref long[] con, ref float[] conarea, int maxcon)
        {
            if (tile == null)
            {
                return(0);
            }
            float[] amin = new float[2], amax = new float[2];
            Helper.CalcSlabEndPoints(vax, vay, vaz, vbx, vby, vbz, ref amin, ref amax, side);
            float apos = Helper.GetSlabCoord(vax, vay, vaz, side);

            float[] bmin   = new float[2], bmax = new float[2];
            int     m      = NavMeshBuilder.ExtLink | side;
            int     n      = 0;
            long    baseId = GetPolyRefBase(tile);

            for (int i = 0; i < tile.Header.PolyCount; i++)
            {
                Poly poly = tile.Polys[i];
                int  nv   = poly.VertCount;
                for (int j = 0; j < nv; j++)
                {
                    if (poly.Neis[j] != m)
                    {
                        continue;
                    }

                    int   vc   = poly.Verts[j] * 3;
                    int   vd   = poly.Verts[(j + 1) % nv] * 3;
                    float bpos = Helper.GetSlabCoord(tile.Verts[vc + 0], tile.Verts[vc + 1], tile.Verts[vc + 2], side);

                    if (Math.Abs(apos - bpos) > 0.01f)
                    {
                        continue;
                    }

                    Helper.CalcSlabEndPoints(tile.Verts[vc + 0], tile.Verts[vc + 1], tile.Verts[vc + 2], tile.Verts[vd + 0], tile.Verts[vd + 1], tile.Verts[vd + 2], ref bmin, ref bmax, side);

                    if (!Helper.OverlapSlabs(amin, amax, bmin, bmax, 0.01f, tile.Header.WalkableClimb))
                    {
                        continue;
                    }

                    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]             = baseId | i;
                        n++;
                    }
                    break;
                }
            }
            return(n);
        }
Пример #9
0
        public Status GetOffMeshConnectionPolyEndPoints(long prevRef, long polyRef, ref float[] startPos, ref float[] endPos)
        {
            long salt, it, ip;

            if (polyRef == 0)
            {
                return(Status.Failure);
            }

            DecodePolyId(polyRef, out salt, out it, out ip);
            if (it >= _maxTiles)
            {
                return(Status.Failure | Status.InvalidParam);
            }
            if (_tiles[it].Salt != salt || _tiles[it].Header == null)
            {
                return(Status.Failure | Status.InvalidParam);
            }
            MeshTile tile = _tiles[it];

            if (ip >= _tiles[it].Header.PolyCount)
            {
                return(Status.Failure | Status.InvalidParam);
            }

            Poly poly = tile.Polys[ip];

            if (poly.Type != NavMeshBuilder.PolyTypeOffMeshConnection)
            {
                return(Status.Failure);
            }

            int idx0 = 0, idx1 = 1;

            for (long i = poly.FirstLink; i != NullLink; i = tile.Links[i].Next)
            {
                if (tile.Links[i].Edge == 0)
                {
                    if (tile.Links[i].Ref != prevRef)
                    {
                        idx0 = 1;
                        idx1 = 0;
                    }
                    break;
                }
            }

            Array.Copy(tile.Verts, poly.Verts[idx0] * 3, startPos, 0, 3);
            Array.Copy(tile.Verts, poly.Verts[idx1] * 3, endPos, 0, 3);

            return(Status.Success);
        }
Пример #10
0
        public Status StoreTileState(MeshTile tile, out TileState tileState)
        {
            tileState            = new TileState();
            tileState.Magic      = Helper.NavMeshMagic;
            tileState.Version    = Helper.NavMeshVersion;
            tileState.Ref        = GetTileRef(tile);
            tileState.PolyStates = new PolyState[tile.Header.PolyCount];
            for (int i = 0; i < tile.Header.PolyCount; i++)
            {
                Poly p = tile.Polys[i];
                tileState.PolyStates[i]       = new PolyState();
                tileState.PolyStates[i].Flags = p.Flags;
                tileState.PolyStates[i].Area  = p.Area;
            }

            return(Status.Success);
        }
Пример #11
0
        private void ConnectIntLinks(MeshTile tile)
        {
            if (tile == null)
            {
                return;
            }
            long baseId = GetPolyRefBase(tile);

            for (int i = 0; i < tile.Header.PolyCount; i++)
            {
                Poly poly = tile.Polys[i];
                poly.FirstLink = NullLink;

                if (poly.Type == NavMeshBuilder.PolyTypeOffMeshConnection)
                {
                    continue;
                }

                for (int j = poly.VertCount - 1; j >= 0; j--)
                {
                    if (poly.Neis[j] == 0 || (poly.Neis[j] & NavMeshBuilder.ExtLink) != 0)
                    {
                        continue;
                    }

                    long idx = AllocLink(tile);
                    if (idx != NullLink)
                    {
                        Link link = tile.Links[idx];
                        link.Ref  = baseId | (poly.Neis[j] - 1);
                        link.Edge = (short)j;
                        link.Side = 0xff;
                        link.BMin = link.BMax = 0;

                        link.Next      = poly.FirstLink;
                        poly.FirstLink = idx;
                    }
                }
            }
        }
Пример #12
0
        private void UnconnectExtLinks(ref MeshTile tile, ref MeshTile target)
        {
            if (tile == null || target == null)
            {
                return;
            }

            long targetNum = DecodePolyIdTile(GetTileRef(target));

            for (int i = 0; i < tile.Header.PolyCount; i++)
            {
                Poly poly = tile.Polys[i];
                long j    = poly.FirstLink;
                long pj   = NullLink;
                while (j != NullLink)
                {
                    if (tile.Links[j].Side != 0xff && DecodePolyIdTile(tile.Links[j].Ref) == targetNum)
                    {
                        long nj = tile.Links[j].Next;
                        if (pj == NullLink)
                        {
                            poly.FirstLink = nj;
                        }
                        else
                        {
                            tile.Links[pj].Next = nj;
                        }
                        FreeLink(ref tile, j);
                        j = nj;
                    }
                    else
                    {
                        pj = j;
                        j  = tile.Links[j].Next;
                    }
                }
            }
        }
Пример #13
0
        public OffMeshConnection GetOffMeshConnectionByRef(long refId)
        {
            long salt, it, ip;

            if (refId == 0)
            {
                return(null);
            }

            DecodePolyId(refId, out salt, out it, out ip);
            if (it >= _maxTiles)
            {
                return(null);
            }
            if (_tiles[it].Salt != salt || _tiles[it].Header == null)
            {
                return(null);
            }
            MeshTile tile = _tiles[it];

            if (ip >= _tiles[it].Header.PolyCount)
            {
                return(null);
            }

            Poly poly = tile.Polys[ip];

            if (poly.Type != NavMeshBuilder.PolyTypeOffMeshConnection)
            {
                return(null);
            }

            long idx = ip - tile.Header.OffMeshBase;

            return(tile.OffMeshCons[idx]);
        }
Пример #14
0
        public NavMeshBuilder(NavMeshCreateParams param)
        {
            if (param.Nvp > VertsPerPoly)
            {
                throw new ArgumentException("Too many Verts per Poly for NavMeshBuilder");
            }
            if (param.VertCount >= 0xffff)
            {
                throw new ArgumentException("Too many total verticies for NavMeshBuilder");
            }
            if (param.VertCount == 0 || param.Verts == null)
            {
                throw new ArgumentException("No vertices, cannot generate nav mesh");
            }
            if (param.PolyCount == 0 || param.Polys == null)
            {
                throw new ArgumentException("No Polygons, cannot generate nav mesh");
            }

            int nvp = param.Nvp;

            short[] offMeshConClass       = new short[0];
            int     storedOffMeshConCount = 0;
            int     offMeshConLinkCount   = 0;

            if (param.OffMeshConCount > 0)
            {
                offMeshConClass = new short[param.OffMeshConCount * 2];

                float hmin = float.MaxValue;
                float hmax = float.MinValue;

                if (param.DetailVerts != null && param.DetailVertsCount > 0)
                {
                    for (int i = 0; i < param.DetailVertsCount; i++)
                    {
                        int h = i * 3 + 1;
                        hmin = Math.Min(hmin, param.DetailVerts[h]);
                        hmax = Math.Max(hmax, param.DetailVerts[h]);
                    }
                }
                else
                {
                    for (int i = 0; i < param.VertCount; i++)
                    {
                        int   iv = i * 3;
                        float h  = param.BMin[1] + param.Verts[iv + 1] * param.Ch;
                        hmin = Math.Min(hmin, h);
                        hmax = Math.Max(hmax, h);
                    }
                }
                hmin -= param.WalkableClimb;
                hmax += param.WalkableClimb;
                float[] bmin = new float[3], bmax = new float[3];
                Array.Copy(param.BMin, bmin, 3);
                Array.Copy(param.BMax, bmax, 3);

                bmin[1] = hmin;
                bmax[1] = hmax;

                for (int i = 0; i < param.OffMeshConCount; i++)
                {
                    int p0 = (i * 2 + 0) * 3;
                    int p1 = (i * 2 + 1) * 3;
                    offMeshConClass[i * 2 + 0] = ClassifyOffMeshPoint(param.OffMeshConVerts[p0 + 0],
                                                                      param.OffMeshConVerts[p0 + 1],
                                                                      param.OffMeshConVerts[p0 + 2], bmin, bmax);
                    offMeshConClass[i * 2 + 1] = ClassifyOffMeshPoint(param.OffMeshConVerts[p1 + 0],
                                                                      param.OffMeshConVerts[p1 + 1],
                                                                      param.OffMeshConVerts[p1 + 2], bmin, bmax);

                    if (offMeshConClass[i * 2 + 0] == 0xff)
                    {
                        if (param.OffMeshConVerts[p0 + 1] < bmin[1] || param.OffMeshConVerts[p0 + 1] > bmax[1])
                        {
                            offMeshConClass[i * 2 + 0] = 0;
                        }
                    }

                    if (offMeshConClass[i * 2 + 0] == 0xff)
                    {
                        offMeshConLinkCount++;
                    }
                    if (offMeshConClass[i * 2 + 1] == 0xff)
                    {
                        offMeshConLinkCount++;
                    }

                    if (offMeshConClass[i * 2 + 0] == 0xff)
                    {
                        storedOffMeshConCount++;
                    }
                }
            }

            int totPolyCount = param.PolyCount + storedOffMeshConCount;
            int totVertCount = param.VertCount + storedOffMeshConCount * 2;

            int edgeCount   = 0;
            int portalCount = 0;

            for (int i = 0; i < param.PolyCount; i++)
            {
                int p = i * 2 * nvp;
                for (int j = 0; j < nvp; j++)
                {
                    if (param.Polys[p + j] == PolyMesh.MeshNullIdx)
                    {
                        break;
                    }
                    edgeCount++;

                    if ((param.Polys[p + nvp + j] & 0x8000) != 0)
                    {
                        int dir = param.Polys[p + nvp + j] & 0xf;
                        if (dir != 0xf)
                        {
                            portalCount++;
                        }
                    }
                }
            }

            int maxLinkCount = edgeCount + portalCount * 2 + offMeshConLinkCount * 2;

            int uniqueDetailVertCount = 0;
            int detailTryCount        = 0;

            if (param.DetailMeshes != null)
            {
                detailTryCount = param.DetailTriCount;
                for (int i = 0; i < param.PolyCount; i++)
                {
                    int p   = i * nvp * 2;
                    int ndv = (int)param.DetailMeshes[i * 4 + 1];
                    int nv  = 0;
                    for (int j = 0; j < nvp; j++)
                    {
                        if (param.Polys[p + j] == PolyMesh.MeshNullIdx)
                        {
                            break;
                        }
                        nv++;
                    }
                    ndv -= nv;
                    uniqueDetailVertCount += ndv;
                }
            }
            else
            {
                uniqueDetailVertCount = 0;
                detailTryCount        = 0;
                for (int i = 0; i < param.PolyCount; i++)
                {
                    int p  = i * nvp * 2;
                    int nv = 0;
                    for (int j = 0; j < nvp; j++)
                    {
                        if (param.Polys[p + j] == PolyMesh.MeshNullIdx)
                        {
                            break;
                        }
                        nv++;
                    }
                    detailTryCount += nv - 2;
                }
            }

            // Initialize the header and all nav data.
            Header = new MeshHeader
            {
                Magic           = Helper.NavMeshMagic,
                Version         = Helper.NavMeshVersion,
                X               = param.TileX,
                Y               = param.TileY,
                Layer           = param.TileLayer,
                UserId          = param.UserId,
                PolyCount       = totPolyCount,
                VertCount       = totVertCount,
                MaxLinkCount    = maxLinkCount,
                DetailMeshCount = param.PolyCount,
                DetailVertCount = uniqueDetailVertCount,
                DetailTriCount  = detailTryCount,
                BVQuantFactor   = 1.0f / param.Cs,
                OffMeshBase     = param.PolyCount,
                WalkableHeight  = param.WalkableHeight,
                WalkableRadius  = param.WalkableRadius,
                WalkableClimb   = param.WalkableClimb,
                OffMeshConCount = storedOffMeshConCount,
                BVNodeCount     = param.BuildBvTree ? param.PolyCount * 2 : 0,
                BMin            = new float[3],
                BMax            = new float[3]
            };
            Array.Copy(param.BMin, Header.BMin, 3);
            Array.Copy(param.BMax, Header.BMax, 3);

            NavVerts = new float[totVertCount * 3];
            NavPolys = new Poly[totPolyCount];
            for (int i = 0; i < totPolyCount; i++)
            {
                NavPolys[i] = new Poly();
            }
            NavLinks = new Link[maxLinkCount];
            for (int i = 0; i < maxLinkCount; i++)
            {
                NavLinks[i] = new Link();
            }
            NavDMeshes = new PolyDetail[param.PolyCount];
            for (int i = 0; i < param.PolyCount; i++)
            {
                NavDMeshes[i] = new PolyDetail();
            }
            NavDVerts = new float[3 * uniqueDetailVertCount];
            NavDTris  = new short[4 * detailTryCount];
            NavBvTree = param.BuildBvTree ? new BVNode[param.PolyCount * 2] : new BVNode[0];
            if (param.BuildBvTree)
            {
                for (int i = 0; i < param.PolyCount * 2; i++)
                {
                    NavBvTree[i] = new BVNode();
                }
            }
            OffMeshCons = new OffMeshConnection[storedOffMeshConCount];
            for (int i = 0; i < storedOffMeshConCount; i++)
            {
                OffMeshCons[i] = new OffMeshConnection();
            }


            int offMeshVertsBase = param.VertCount;
            int offMeshPolyBase  = param.PolyCount;

            // store vertices
            // Mesh
            for (int i = 0; i < param.VertCount; i++)
            {
                int iv = i * 3;
                int v  = i * 3;
                NavVerts[v + 0] = param.BMin[0] + param.Verts[iv + 0] * param.Cs;
                NavVerts[v + 1] = param.BMin[1] + param.Verts[iv + 1] * param.Ch;
                NavVerts[v + 2] = param.BMin[2] + param.Verts[iv + 2] * param.Cs;
            }
            // off-link
            int n = 0;

            for (int i = 0; i < param.OffMeshConCount; i++)
            {
                if (offMeshConClass[i * 2 + 0] == 0xff)
                {
                    int linkv = i * 2 * 3;
                    int v     = (offMeshVertsBase + n * 2) * 3;
                    Array.Copy(param.OffMeshConVerts, linkv, NavVerts, v, 3);
                    Array.Copy(param.OffMeshConVerts, linkv + 3, NavVerts, v + 3, 3);
                    n++;
                }
            }

            // store polygons
            // mesh
            int src = 0;

            for (int i = 0; i < param.PolyCount; i++)
            {
                Poly p = NavPolys[i];
                p.VertCount = 0;
                p.Flags     = param.PolyFlags[i];
                p.Area      = param.PolyAreas[i];
                p.Type      = PolyTypeGround;
                for (int j = 0; j < nvp; j++)
                {
                    if (param.Polys[src + j] == PolyMesh.MeshNullIdx)
                    {
                        break;
                    }
                    p.Verts[j] = param.Polys[src + j];
                    if ((param.Polys[src + nvp + j] & 0x8000) != 0)
                    {
                        int dir = param.Polys[src + nvp + j] & 0xf;
                        if (dir == 0xf)
                        {
                            p.Neis[j] = 0;
                        }
                        else if (dir == 0)
                        {
                            p.Neis[j] = ExtLink | 4;
                        }
                        else if (dir == 1)
                        {
                            p.Neis[j] = ExtLink | 2;
                        }
                        else if (dir == 2)
                        {
                            p.Neis[j] = ExtLink | 0;
                        }
                        else if (dir == 3)
                        {
                            p.Neis[j] = ExtLink | 6;
                        }
                    }
                    else
                    {
                        p.Neis[j] = param.Polys[src + nvp + j] + 1;
                    }
                    p.VertCount++;
                }
                src += nvp * 2;
            }
            // off mesh
            n = 0;
            for (int i = 0; i < param.OffMeshConCount; i++)
            {
                if (offMeshConClass[i * 2 + 0] == 0xff)
                {
                    Poly p = NavPolys[offMeshPolyBase + n];
                    p.VertCount = 2;
                    p.Verts[0]  = (offMeshVertsBase + n * 2 + 0);
                    p.Verts[1]  = (offMeshVertsBase + n * 2 + 1);
                    p.Flags     = param.OffMeshConFlags[i];
                    p.Area      = (short)param.OffMeshConAreas[i];
                    p.Type      = PolyTypeOffMeshConnection;
                    n++;
                }
            }

            // Store detail meshes and verts
            if (param.DetailMeshes != null)
            {
                int vbase = 0;
                for (int i = 0; i < param.PolyCount; i++)
                {
                    PolyDetail dtl = NavDMeshes[i];
                    int        vb  = (int)param.DetailMeshes[i * 4 + 0];
                    int        ndv = (int)param.DetailMeshes[i * 4 + 1];
                    int        nv  = NavPolys[i].VertCount;
                    dtl.VertBase  = vbase;
                    dtl.VertCount = (short)(ndv - nv);
                    dtl.TriBase   = param.DetailMeshes[i * 4 + 2];
                    dtl.TriCount  = (short)param.DetailMeshes[i * 4 + 3];
                    if (ndv - nv > 0)
                    {
                        Array.Copy(param.DetailVerts, (vb + nv) * 3, NavDVerts, vbase * 3, (ndv - nv) * 3);
                        vbase += (short)(ndv - nv);
                    }
                }
                Array.Copy(param.DetailTris, NavDTris, param.DetailTriCount * 4);
            }
            else
            {
                // Create dummy detail mesh
                int tbase = 0;
                for (int i = 0; i < param.PolyCount; i++)
                {
                    PolyDetail dtl = NavDMeshes[i];
                    int        nv  = NavPolys[i].VertCount;
                    dtl.VertBase  = 0;
                    dtl.VertCount = 0;
                    dtl.TriBase   = tbase;
                    dtl.TriCount  = (short)(nv - 2);
                    for (int j = 2; j < nv; j++)
                    {
                        int t = tbase * 4;
                        NavDTris[t + 0] = 0;
                        NavDTris[t + 1] = (short)(j - 1);
                        NavDTris[t + 2] = (short)j;
                        NavDTris[t + 3] = (1 << 2);
                        if (j == 2)
                        {
                            NavDTris[t + 3] |= (1 << 0);
                        }
                        if (j == nv - 1)
                        {
                            NavDTris[t + 3] |= (1 << 4);
                        }
                        tbase++;
                    }
                }
            }

            // Store and create BVTree
            if (param.BuildBvTree)
            {
                CreateBVTree(param.Verts, param.VertCount, param.Polys, param.PolyCount, nvp, param.Cs, param.Ch, param.PolyCount * 2);
            }

            // store off-mesh connections
            n = 0;
            for (int i = 0; i < param.OffMeshConCount; i++)
            {
                if (offMeshConClass[i * 2 + 0] == 0xff)
                {
                    OffMeshConnection con = OffMeshCons[n];
                    con.Poly = offMeshPolyBase + n;
                    int endPts = i * 2 * 3;
                    Array.Copy(param.OffMeshConVerts, endPts, con.Pos, 0, 3);
                    Array.Copy(param.OffMeshConVerts, endPts + 3, con.Pos, 3, 3);
                    con.Rad   = param.OffMeshConRad[i];
                    con.Flags = param.OffMeshConDir[i] > 0 ? OffMeshConBiDir : (short)0;
                    con.Side  = offMeshConClass[i * 2 + 1];
                    if (param.OffMeshConUserId != null)
                    {
                        con.UserId = param.OffMeshConUserId[i];
                    }
                    n++;
                }
            }
        }
Пример #15
0
 public bool PassFilter(long refId, MeshTile tile, Poly poly)
 {
     return((poly.Flags & IncludeFlags) != 0 && (poly.Flags & ExcludeFlags) == 0);
 }
Пример #16
0
        private void ConnectExtOffMeshLinks(ref MeshTile tile, ref MeshTile target, int side)
        {
            if (tile == null)
            {
                return;
            }

            short oppositeSide = (side == -1) ? (short)0xff : (short)Helper.OppositeTile(side);

            for (int i = 0; i < target.Header.OffMeshConCount; i++)
            {
                OffMeshConnection targetCon = target.OffMeshCons[i];
                if (targetCon.Side != oppositeSide)
                {
                    continue;
                }

                Poly targetPoly = target.Polys[targetCon.Poly];
                if (targetPoly.FirstLink == NullLink)
                {
                    continue;
                }

                float[] ext = { targetCon.Rad, target.Header.WalkableClimb, targetCon.Rad };

                int     p         = 3;
                float[] nearestPt = new float[3];
                long    refId     = FindNearestPolyInTile(tile, targetCon.Pos[p + 0], targetCon.Pos[p + 1], targetCon.Pos[p + 2],
                                                          ext[0], ext[1], ext[2], ref nearestPt);
                if (refId <= 0)
                {
                    continue;
                }

                if (((nearestPt[0] - targetCon.Pos[p + 0]) * (nearestPt[0] - targetCon.Pos[p + 0])) + ((nearestPt[2] - targetCon.Pos[p + 2]) * (nearestPt[2] - targetCon.Pos[p + 2])) > (targetCon.Rad * targetCon.Rad))
                {
                    continue;
                }

                int v = targetPoly.Verts[1] * 3;
                Array.Copy(nearestPt, 0, target.Verts, v, 3);

                long idx = AllocLink(target);
                if (idx != NullLink)
                {
                    Link link = target.Links[idx];
                    link.Ref  = refId;
                    link.Edge = 1;
                    link.Side = oppositeSide;
                    link.BMin = link.BMax = 0;

                    link.Next            = targetPoly.FirstLink;
                    targetPoly.FirstLink = idx;
                }

                if ((targetCon.Flags & NavMeshBuilder.OffMeshConBiDir) != 0)
                {
                    long tidx = AllocLink(tile);
                    if (tidx != NullLink)
                    {
                        int  landPolyIdx = (int)DecodePolyIdPoly(refId);
                        Poly landPoly    = tile.Polys[landPolyIdx];
                        Link link        = tile.Links[tidx];
                        link.Ref           = GetPolyRefBase(target) | (targetCon.Poly);
                        link.Edge          = 0xff;
                        link.Side          = side == -1 ? (short)0xff : (short)side;
                        link.BMin          = link.BMax = 0;
                        link.Next          = landPoly.FirstLink;
                        landPoly.FirstLink = tidx;
                    }
                }
            }
        }
Пример #17
0
        private int QueryPolygonsInTile(MeshTile tile, float qminx, float qminy, float qminz, float qmaxx, float qmaxy,
                                        float qmaxz, ref long[] polys, int maxPolys)
        {
            if (tile.BVTree != null)
            {
                int     node  = 0;
                int     end   = tile.Header.BVNodeCount;
                float[] tbmin = tile.Header.BMin;
                float[] tbmax = tile.Header.BMax;
                float   qfac  = tile.Header.BVQuantFactor;

                int[] bmin = new int[3], bmax = new int[3];

                float minx = Math.Min(tbmax[0], Math.Max(qminx, tbmin[0])) - tbmin[0];
                float miny = Math.Min(tbmax[1], Math.Max(qminy, tbmin[1])) - tbmin[1];
                float minz = Math.Min(tbmax[2], Math.Max(qminz, tbmin[2])) - tbmin[2];
                float maxx = Math.Min(tbmax[0], Math.Max(qmaxx, tbmin[0])) - tbmin[0];
                float maxy = Math.Min(tbmax[1], Math.Max(qmaxy, tbmin[1])) - tbmin[1];
                float maxz = Math.Min(tbmax[2], Math.Max(qmaxz, tbmin[2])) - tbmin[2];

                bmin[0] = (int)(qfac * minx) & 0xfffe;
                bmin[1] = (int)(qfac * miny) & 0xfffe;
                bmin[2] = (int)(qfac * minz) & 0xfffe;
                bmax[0] = (int)(qfac * maxx + 1) | 1;
                bmax[1] = (int)(qfac * maxy + 1) | 1;
                bmax[2] = (int)(qfac * maxz + 1) | 1;

                long baseId = GetPolyRefBase(tile);
                int  n      = 0;
                while (node < end)
                {
                    bool overlap    = Helper.OverlapQuantBounds(bmin, bmax, tile.BVTree[node].BMin, tile.BVTree[node].BMax);
                    bool isLeafNode = tile.BVTree[node].I >= 0;

                    if (isLeafNode && overlap)
                    {
                        if (n < maxPolys)
                        {
                            polys[n++] = baseId | tile.BVTree[node].I;
                        }
                    }

                    if (overlap || isLeafNode)
                    {
                        node++;
                    }
                    else
                    {
                        int escapeIndex = -tile.BVTree[node].I;
                        node += escapeIndex;
                    }
                }
                return(n);
            }
            else
            {
                float[] bmin   = new float[3], bmax = new float[3];
                int     n      = 0;
                long    baseId = GetPolyRefBase(tile);
                for (int i = 0; i < tile.Header.PolyCount; i++)
                {
                    Poly p = tile.Polys[i];
                    if (p.Type == NavMeshBuilder.PolyTypeOffMeshConnection)
                    {
                        continue;
                    }

                    int v = p.Verts[0 * 3];
                    Array.Copy(tile.Verts, v, bmin, 0, 3);
                    Array.Copy(tile.Verts, v, bmax, 0, 3);
                    for (int j = 1; j < p.VertCount; j++)
                    {
                        v = p.Verts[j] * 3;
                        Helper.VMin(ref bmin, tile.Verts[v + 0], tile.Verts[v + 1], tile.Verts[v + 2]);
                        Helper.VMax(ref bmax, tile.Verts[v + 0], tile.Verts[v + 1], tile.Verts[v + 2]);
                    }
                    if (Helper.OverlapBounds(qminx, qminy, qminz, qmaxx, qmaxy, qmaxz, bmin[0], bmin[1], bmin[2],
                                             bmax[0], bmax[1], bmax[2]))
                    {
                        if (n < maxPolys)
                        {
                            polys[n++] = baseId | i;
                        }
                    }
                }
                return(n);
            }
        }
Пример #18
0
        private void ClosestPointOnPolyInTile(MeshTile tile, long ip, float posx, float posy, float posz, ref float[] closestPt)
        {
            Poly poly = tile.Polys[ip];

            if (poly.Type == NavMeshBuilder.PolyTypeOffMeshConnection)
            {
                int   v0 = poly.Verts[0] * 3;
                int   v1 = poly.Verts[1] * 3;
                float d0 = Helper.VDist(posx, posy, posz, tile.Verts[v0 + 0], tile.Verts[v0 + 1], tile.Verts[v0 + 2]);
                float d1 = Helper.VDist(posx, posy, posz, tile.Verts[v1 + 0], tile.Verts[v1 + 1], tile.Verts[v1 + 2]);
                float u  = d0 / (d0 + d1);
                Helper.VLerp(ref closestPt, tile.Verts[v0 + 0], tile.Verts[v0 + 1], tile.Verts[v0 + 2], tile.Verts[v1 + 0], tile.Verts[v1 + 1], tile.Verts[v1 + 2], u);
                return;
            }

            PolyDetail pd = tile.DetailMeshes[ip];

            float[] verts = new float[NavMeshBuilder.VertsPerPoly * 3];
            float[] edged = new float[NavMeshBuilder.VertsPerPoly];
            float[] edget = new float[NavMeshBuilder.VertsPerPoly];
            int     nv    = poly.VertCount;

            for (int i = 0; i < nv; i++)
            {
                Array.Copy(tile.Verts, poly.Verts[i] * 3, verts, i * 3, 3);
            }

            closestPt[0] = posx;
            closestPt[1] = posy;
            closestPt[2] = posz;

            if (!Helper.DistancePtPolyEdgesSqr(posx, posy, posz, verts, nv, ref edged, ref edget))
            {
                float dmin = float.MaxValue;
                int   imin = -1;
                for (int i = 0; i < nv; i++)
                {
                    if (edged[i] < dmin)
                    {
                        dmin = edged[i];
                        imin = i;
                    }
                }
                int va = imin * 3;
                int vb = ((imin + 1) % nv) * 3;
                Helper.VLerp(ref closestPt, verts[va + 0], verts[va + 1], verts[va + 2], verts[vb + 0], verts[vb + 1], verts[vb + 2], edget[imin]);
            }

            for (int j = 0; j < pd.TriCount; j++)
            {
                int     t = (int)(pd.TriBase + j) * 4;
                float[] v = new float[9];
                for (int k = 0; k < 3; k++)
                {
                    if (tile.DetailTris[t + k] < poly.VertCount)
                    {
                        Array.Copy(tile.Verts, poly.Verts[tile.DetailTris[t + k]] * 3, v, k * 3, 3);
                        //v[k] = tile.Verts[poly.Verts[tile.DetailTris[t + k]]*3];
                    }
                    else
                    {
                        Array.Copy(tile.DetailVerts, (pd.VertBase + (tile.DetailTris[t + k] - poly.VertCount)) * 3, v, k * 3, 3);
                        //v[k] = tile.DetailVerts[(pd.VertBase + (tile.DetailTris[t + k] - poly.VertCount))*3];
                    }
                }
                float h = 0;
                if (Helper.ClosestHeightPointTriangle(posx, posy, posz, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], ref h))
                {
                    closestPt[1] = h;
                    break;
                }
            }
        }
Пример #19
0
        private void ConnectExtLinks(ref MeshTile tile, ref MeshTile target, int side)
        {
            if (tile == null)
            {
                return;
            }

            for (int i = 0; i < tile.Header.PolyCount; i++)
            {
                Poly poly = tile.Polys[i];

                int nv = poly.VertCount;
                for (int j = 0; j < nv; j++)
                {
                    if ((poly.Neis[j] & NavMeshBuilder.ExtLink) == 0)
                    {
                        continue;
                    }

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

                    int     va   = poly.Verts[j] * 3;
                    int     vb   = poly.Verts[(j + 1) % nv] * 3;
                    long[]  nei  = new long[4];
                    float[] neia = new float[4 * 2];
                    int     nnei = FindConnectingPolys(tile.Verts[va + 0], tile.Verts[va + 1], tile.Verts[va + 2],
                                                       tile.Verts[vb + 0], tile.Verts[vb + 1], tile.Verts[vb + 2], target,
                                                       Helper.OppositeTile(dir), ref nei, ref neia, 4);
                    for (int k = 0; k < nnei; k++)
                    {
                        long idx = AllocLink(tile);
                        if (idx != NullLink)
                        {
                            Link link = tile.Links[idx];
                            link.Ref  = nei[k];
                            link.Edge = (short)j;
                            link.Side = (short)dir;

                            link.Next      = poly.FirstLink;
                            poly.FirstLink = idx;

                            if (dir == 0 || dir == 4)
                            {
                                float tmin = (neia[k * 2 + 0] - tile.Verts[va + 2]) /
                                             (tile.Verts[vb + 2] - tile.Verts[va + 2]);
                                float tmax = (neia[k * 2 + 1] - tile.Verts[va + 2]) /
                                             (tile.Verts[vb + 2] - tile.Verts[va + 2]);
                                if (tmin > tmax)
                                {
                                    float temp = tmin;
                                    tmin = tmax;
                                    tmax = temp;
                                }
                                link.BMin = (short)(Math.Min(1.0f, Math.Max(tmin, 0.0f)) * 255.0f);
                                link.BMax = (short)(Math.Min(1.0f, Math.Max(tmax, 0.0f)) * 255.0f);
                            }
                            else if (dir == 2 || dir == 6)
                            {
                                float tmin = (neia[k * 2 + 0] - tile.Verts[va + 0]) /
                                             (tile.Verts[vb + 0] - tile.Verts[va + 0]);
                                float tmax = (neia[k * 2 + 1] - tile.Verts[va + 0]) /
                                             (tile.Verts[vb + 0] - tile.Verts[va + 0]);
                                if (tmin > tmax)
                                {
                                    float temp = tmin;
                                    tmin = tmax;
                                    tmax = temp;
                                }
                                link.BMin = (short)(Math.Min(1.0f, Math.Max(tmin, 0.0f)) * 255.0f);
                                link.BMax = (short)(Math.Min(1.0f, Math.Max(tmax, 0.0f)) * 255.0f);
                            }
                        }
                    }
                }
            }
        }