Пример #1
0
        /// <summary>
        /// Connect Off-Mesh links between polygons from two different tiles.
        /// </summary>
        /// <param name="tile">Current Tile</param>
        /// <param name="target">Target Tile</param>
        /// <param name="side">Polygon edge</param>
        public void ConnectExtOffMeshLinks(ref MeshTile tile, ref MeshTile target, BoundarySide side)
        {
            if (tile == null)
            {
                return;
            }

            //Connect off-mesh links, specifically links which land from target tile to this tile
            BoundarySide oppositeSide = side.GetOpposite();

            //Iterate through all the off-mesh connections of target tile
            for (int i = 0; i < target.Header.OffMeshConCount; i++)
            {
                OffMeshConnection targetCon = target.OffMeshConnections[i];
                if (targetCon.Side != oppositeSide)
                {
                    continue;
                }

                Poly targetPoly = target.Polys[targetCon.Poly];

                //Skip off-mesh connections which start location could not be connected at all
                if (!IsLinkAllocated(targetPoly.FirstLink))
                {
                    continue;
                }

                Vector3 extents = new Vector3(targetCon.Radius, target.Header.WalkableClimb, targetCon.Radius);

                //Find polygon to connect to
                Vector3 p         = targetCon.Pos1;
                Vector3 nearestPt = new Vector3();
                PolyId  reference = FindNearestPolyInTile(tile, p, extents, ref nearestPt);
                if (reference == PolyId.Null)
                {
                    continue;
                }

                //Further checks
                if ((nearestPt.X - p.X) * (nearestPt.X - p.X) + (nearestPt.Z - p.Z) * (nearestPt.Z - p.Z) >
                    (targetCon.Radius * targetCon.Radius))
                {
                    continue;
                }

                //Make sure the location is on the current mesh
                target.Verts[targetPoly.Verts[1]] = nearestPt;

                //Link off-mesh connection to target poly
                int idx = AllocLink(target);
                if (IsLinkAllocated(idx))
                {
                    target.Links[idx].Reference = reference;
                    target.Links[idx].Edge      = i;
                    target.Links[idx].Side      = oppositeSide;
                    target.Links[idx].BMin      = target.Links[idx].BMax = 0;

                    //add to linked list
                    target.Links[idx].Next    = target.Polys[i].FirstLink;
                    target.Polys[i].FirstLink = idx;
                }

                //link target poly to off-mesh connection
                if ((targetCon.Flags & OffMeshConnectionFlags.Bidirectional) != 0)
                {
                    int tidx = AllocLink(tile);
                    if (IsLinkAllocated(tidx))
                    {
                        int    landPolyIdx = reference.DecodePolyIndex(polyBits);
                        PolyId id;
                        id = GetPolyRefBase(target);
                        PolyId.SetPolyIndex(ref id, targetCon.Poly, out id);
                        tile.Links[tidx].Reference = id;
                        tile.Links[tidx].Edge      = 0xff;
                        tile.Links[tidx].Side      = side;
                        tile.Links[tidx].BMin      = tile.Links[tidx].BMax = 0;

                        //add to linked list
                        tile.Links[tidx].Next             = tile.Polys[landPolyIdx].FirstLink;
                        tile.Polys[landPolyIdx].FirstLink = tidx;
                    }
                }
            }
        }
Пример #2
0
        /// <summary>
        /// Connect Off-Mesh links between polygons from two different tiles.
        /// </summary>
        /// <param name="tile">Current Tile</param>
        /// <param name="target">Target Tile</param>
        /// <param name="side">Polygon edge</param>
        public void ConnectExtOffMeshLinks(ref MeshTile tile, ref MeshTile target, BoundarySide side)
        {
            if (tile == null)
                return;

            //Connect off-mesh links, specifically links which land from target tile to this tile
            BoundarySide oppositeSide = side.GetOpposite();

            //Iterate through all the off-mesh connections of target tile
            for (int i = 0; i < target.Header.OffMeshConCount; i++)
            {
                OffMeshConnection targetCon = target.OffMeshConnections[i];
                if (targetCon.Side != oppositeSide)
                    continue;

                Poly targetPoly = target.Polys[targetCon.Poly];

                //Skip off-mesh connections which start location could not be connected at all
                if (!IsLinkAllocated(targetPoly.FirstLink))
                    continue;

                Vector3 extents = new Vector3(targetCon.Radius, target.Header.WalkableClimb, targetCon.Radius);

                //Find polygon to connect to
                Vector3 p = targetCon.Pos1;
                Vector3 nearestPt = new Vector3();
                int reference = FindNearestPolyInTile(tile, p, extents, ref nearestPt);
                if (reference == 0)
                    continue;

                //Further checks
                if ((nearestPt.X - p.X) * (nearestPt.X - p.X) + (nearestPt.Z - p.Z) * (nearestPt.Z - p.Z) >
                    (targetCon.Radius * targetCon.Radius))
                    continue;

                //Make sure the location is on the current mesh
                target.Verts[targetPoly.Verts[1]] = nearestPt;

                //Link off-mesh connection to target poly
                int idx = AllocLink(target);
                if (IsLinkAllocated(idx))
                {
                    target.Links[idx].Reference = reference;
                    target.Links[idx].Edge = i;
                    target.Links[idx].Side = oppositeSide;
                    target.Links[idx].BMin = target.Links[idx].BMax = 0;

                    //add to linked list
                    target.Links[idx].Next = target.Polys[i].FirstLink;
                    target.Polys[i].FirstLink = idx;
                }

                //link target poly to off-mesh connection
                if ((targetCon.Flags & OffMeshConnectionFlags.Bidirectional) != 0)
                {
                    int tidx = AllocLink(tile);
                    if (IsLinkAllocated(tidx))
                    {
                        int landPolyIdx = DecodePolyIdPoly(reference);
                        tile.Links[tidx].Reference = GetReference(GetPolyRefBase(target), targetCon.Poly);
                        tile.Links[tidx].Edge = 0xff;
                        tile.Links[tidx].Side = side;
                        tile.Links[tidx].BMin = tile.Links[tidx].BMax = 0;

                        //add to linked list
                        tile.Links[tidx].Next = tile.Polys[landPolyIdx].FirstLink;
                        tile.Polys[landPolyIdx].FirstLink = tidx;
                    }
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Connect polygons from two different tiles.
        /// </summary>
        /// <param name="tile">Current Tile</param>
        /// <param name="target">Target Tile</param>
        /// <param name="side">Polygon edge</param>
        public void ConnectExtLinks(ref MeshTile tile, ref MeshTile target, BoundarySide side)
        {
            if (tile == null)
            {
                return;
            }

            //Connect border links
            for (int i = 0; i < tile.Header.PolyCount; i++)
            {
                int numPolyVerts = tile.Polys[i].VertCount;

                for (int j = 0; j < numPolyVerts; j++)
                {
                    //Skip non-portal edges
                    if ((tile.Polys[i].Neis[j] & Link.External) == 0)
                    {
                        continue;
                    }

                    BoundarySide dir = (BoundarySide)(tile.Polys[i].Neis[j] & 0xff);
                    if (side != BoundarySide.Internal && dir != side)
                    {
                        continue;
                    }

                    //Create new links
                    Vector3       va   = tile.Verts[tile.Polys[i].Verts[j]];
                    Vector3       vb   = tile.Verts[tile.Polys[i].Verts[(j + 1) % numPolyVerts]];
                    List <PolyId> nei  = new List <PolyId>(4);
                    List <float>  neia = new List <float>(4 * 2);
                    FindConnectingPolys(va, vb, target, dir.GetOpposite(), nei, neia);

                    //Iterate through neighbors
                    for (int k = 0; k < nei.Count; k++)
                    {
                        //Allocate a new link if possible
                        int idx = AllocLink(tile);

                        if (IsLinkAllocated(idx))
                        {
                            tile.Links[idx].Reference = nei[k];
                            tile.Links[idx].Edge      = j;
                            tile.Links[idx].Side      = dir;

                            tile.Links[idx].Next    = tile.Polys[i].FirstLink;
                            tile.Polys[i].FirstLink = idx;

                            //Compress portal limits to a value
                            if (dir == BoundarySide.PlusX || dir == BoundarySide.MinusX)
                            {
                                float tmin = (neia[k * 2 + 0] - va.Z) / (vb.Z - va.Z);
                                float tmax = (neia[k * 2 + 1] - va.Z) / (vb.Z - va.Z);

                                if (tmin > tmax)
                                {
                                    float temp = tmin;
                                    tmin = tmax;
                                    tmax = temp;
                                }

                                tile.Links[idx].BMin = (int)(MathHelper.Clamp(tmin, 0.0f, 1.0f) * 255.0f);
                                tile.Links[idx].BMax = (int)(MathHelper.Clamp(tmax, 0.0f, 1.0f) * 255.0f);
                            }
                            else if (dir == BoundarySide.PlusZ || dir == BoundarySide.MinusZ)
                            {
                                float tmin = (neia[k * 2 + 0] - va.X) / (vb.X - va.X);
                                float tmax = (neia[k * 2 + 1] - va.X) / (vb.X - va.X);

                                if (tmin > tmax)
                                {
                                    float temp = tmin;
                                    tmin = tmax;
                                    tmax = temp;
                                }

                                tile.Links[idx].BMin = (int)(MathHelper.Clamp(tmin, 0.0f, 1.0f) * 255.0f);
                                tile.Links[idx].BMax = (int)(MathHelper.Clamp(tmax, 0.0f, 1.0f) * 255.0f);
                            }
                        }
                    }
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Build a tile and link all the polygons togther, both internally and externally.
        /// Make sure to link off-mesh connections as well.
        /// </summary>
        /// <param name="data">Navigation Mesh data</param>
        /// <param name="lastRef">Last polygon reference</param>
        /// <param name="result">Last tile reference</param>
        public void AddTile(NavMeshBuilder data, PolyId lastRef, out PolyId result)
        {
            result = PolyId.Null;

            //make sure data is in right format
            PathfindingCommon.NavMeshInfo header = data.Header;

            //make sure location is free
            if (GetTileAt(header.X, header.Y, header.Layer) != null)
            {
                return;
            }

            //allocate a tile
            MeshTile tile = null;

            if (lastRef == PolyId.Null)
            {
                if (nextFree != null)
                {
                    tile      = nextFree;
                    nextFree  = tile.Next;
                    tile.Next = null;
                }
            }
            else
            {
                //try to relocate tile to specific index with the same salt
                int tileIndex = lastRef.DecodeTileIndex(polyBits, tileBits);
                if (tileIndex >= maxTiles)
                {
                    return;
                }

                //try to find specific tile id from free list
                MeshTile target = tiles[tileIndex];
                MeshTile prev   = null;
                tile = nextFree;
                while (tile != null && tile != target)
                {
                    prev = tile;
                    tile = tile.Next;
                }

                //couldn't find correct location
                if (tile != target)
                {
                    return;
                }

                //remove from freelist
                if (prev == null)
                {
                    nextFree = tile.Next;
                }
                else
                {
                    prev.Next = tile.Next;
                }

                //restore salt
                tile.Salt = lastRef.DecodeSalt(polyBits, tileBits, saltBits);
            }

            //make sure we could allocate a tile
            if (tile == null)
            {
                return;
            }

            //insert tile into position LookUp Table (lut)
            int h = ComputeTileHash(header.X, header.Y, tileLookupTableMask);

            tile.Next    = posLookup[h];
            posLookup[h] = tile;

            if (header.BvNodeCount == 0)
            {
                tile.BVTree = null;
            }

            //patch header
            tile.Verts              = data.NavVerts;
            tile.Polys              = data.NavPolys;
            tile.DetailMeshes       = data.NavDMeshes;
            tile.DetailVerts        = data.NavDVerts;
            tile.DetailTris         = data.NavDTris;
            tile.BVTree             = data.NavBvTree;
            tile.OffMeshConnections = data.OffMeshCons;

            //build links freelist
            tile.LinksFreeList = 0;
            tile.Links         = new Link[header.MaxLinkCount];
            for (int i = 0; i < header.MaxLinkCount; i++)
            {
                tile.Links[i] = new Link();
            }

            tile.Links[header.MaxLinkCount - 1].Next = Link.Null;
            for (int i = 0; i < header.MaxLinkCount - 1; i++)
            {
                tile.Links[i].Next = i + 1;
            }

            //init tile
            tile.Header = header;
            tile.Data   = data;

            ConnectIntLinks(ref tile);
            BaseOffMeshLinks(ref tile);

            //create connections with neighbor tiles
            MeshTile[] neis = new MeshTile[32];
            int        nneis;

            //connect with layers in current tile
            nneis = GetTilesAt(header.X, header.Y, neis);
            for (int j = 0; j < nneis; j++)
            {
                if (neis[j] != tile)
                {
                    ConnectExtLinks(ref tile, ref neis[j], BoundarySide.Internal);
                    ConnectExtLinks(ref neis[j], ref tile, BoundarySide.Internal);
                }

                ConnectExtOffMeshLinks(ref tile, ref neis[j], BoundarySide.Internal);
                ConnectExtOffMeshLinks(ref neis[j], ref tile, BoundarySide.Internal);
            }

            //connect with neighbour tiles
            for (int i = 0; i < 8; i++)
            {
                BoundarySide b  = (BoundarySide)i;
                BoundarySide bo = b.GetOpposite();
                nneis = GetNeighbourTilesAt(header.X, header.Y, b, neis);
                for (int j = 0; j < nneis; j++)
                {
                    ConnectExtLinks(ref tile, ref neis[j], b);
                    ConnectExtLinks(ref neis[j], ref tile, bo);
                    ConnectExtOffMeshLinks(ref tile, ref neis[j], b);
                    ConnectExtOffMeshLinks(ref neis[j], ref tile, bo);
                }
            }

            result = GetTileRef(tile);
        }
Пример #5
0
        /// <summary>
        /// Connect Off-Mesh links between polygons from two different tiles.
        /// </summary>
        /// <param name="target">Target Tile</param>
        /// <param name="side">Polygon edge</param>
        public void ConnectExtOffMeshLinks(NavTile target, BoundarySide side)
        {
            //Connect off-mesh links, specifically links which land from target tile to this tile
            BoundarySide oppositeSide = side.GetOpposite();

            //Iterate through all the off-mesh connections of target tile
            for (int i = 0; i < target.OffMeshConnectionCount; i++)
            {
                OffMeshConnection targetCon = target.OffMeshConnections[i];
                if (targetCon.Side != oppositeSide)
                {
                    continue;
                }

                NavPoly targetPoly = target.Polys[targetCon.Poly];

                //Skip off-mesh connections which start location could not be connected at all
                if (targetPoly.Links.Count == 0)
                {
                    continue;
                }

                Vector3 extents = new Vector3(targetCon.Radius, target.WalkableClimb, targetCon.Radius);

                //Find polygon to connect to
                Vector3   p         = targetCon.Pos1;
                Vector3   nearestPt = new Vector3();
                NavPolyId reference = FindNearestPoly(p, extents, ref nearestPt);
                if (reference == NavPolyId.Null)
                {
                    continue;
                }

                //Further checks
                if ((nearestPt.X - p.X) * (nearestPt.X - p.X) + (nearestPt.Z - p.Z) * (nearestPt.Z - p.Z) >
                    (targetCon.Radius * targetCon.Radius))
                {
                    continue;
                }

                //Make sure the location is on the current mesh
                target.Verts[targetPoly.Verts[1]] = nearestPt;

                //Link off-mesh connection to target poly
                Link link = new Link();
                link.Reference = reference;
                link.Edge      = i;
                link.Side      = oppositeSide;
                target.Polys[i].Links.Add(link);

                //link target poly to off-mesh connection
                if ((targetCon.Flags & OffMeshConnectionFlags.Bidirectional) != 0)
                {
                    int       landPolyIdx = idManager.DecodePolyIndex(ref reference);
                    NavPolyId id;
                    id = target.baseRef;
                    idManager.SetPolyIndex(ref id, targetCon.Poly, out id);

                    Link bidiLink = new Link();
                    bidiLink.Reference = id;
                    bidiLink.Edge      = 0xff;
                    bidiLink.Side      = side;
                    Polys[landPolyIdx].Links.Add(bidiLink);
                }
            }
        }
Пример #6
0
        /// <summary>
        /// Connect polygons from two different tiles.
        /// </summary>
        /// <param name="target">Target Tile</param>
        /// <param name="side">Polygon edge</param>
        public void ConnectExtLinks(NavTile target, BoundarySide side)
        {
            //Connect border links
            for (int i = 0; i < PolyCount; i++)
            {
                int numPolyVerts = Polys[i].VertCount;

                for (int j = 0; j < numPolyVerts; j++)
                {
                    //Skip non-portal edges
                    if ((Polys[i].Neis[j] & Link.External) == 0)
                    {
                        continue;
                    }

                    BoundarySide dir = (BoundarySide)(Polys[i].Neis[j] & 0xff);
                    if (side != BoundarySide.Internal && dir != side)
                    {
                        continue;
                    }

                    //Create new links
                    Vector3          va   = Verts[Polys[i].Verts[j]];
                    Vector3          vb   = Verts[Polys[i].Verts[(j + 1) % numPolyVerts]];
                    List <NavPolyId> nei  = new List <NavPolyId>(4);
                    List <float>     neia = new List <float>(4 * 2);
                    target.FindConnectingPolys(va, vb, dir.GetOpposite(), nei, neia);

                    //Iterate through neighbors
                    for (int k = 0; k < nei.Count; k++)
                    {
                        Link link = new Link();
                        link.Reference = nei[k];
                        link.Edge      = j;
                        link.Side      = dir;
                        Polys[i].Links.Add(link);

                        //Compress portal limits to a value
                        if (dir == BoundarySide.PlusX || dir == BoundarySide.MinusX)
                        {
                            float tmin = (neia[k * 2 + 0] - va.Z) / (vb.Z - va.Z);
                            float tmax = (neia[k * 2 + 1] - va.Z) / (vb.Z - va.Z);

                            if (tmin > tmax)
                            {
                                float temp = tmin;
                                tmin = tmax;
                                tmax = temp;
                            }

                            link.BMin = (int)(MathHelper.Clamp(tmin, 0.0f, 1.0f) * 255.0f);
                            link.BMax = (int)(MathHelper.Clamp(tmax, 0.0f, 1.0f) * 255.0f);
                        }
                        else if (dir == BoundarySide.PlusZ || dir == BoundarySide.MinusZ)
                        {
                            float tmin = (neia[k * 2 + 0] - va.X) / (vb.X - va.X);
                            float tmax = (neia[k * 2 + 1] - va.X) / (vb.X - va.X);

                            if (tmin > tmax)
                            {
                                float temp = tmin;
                                tmin = tmax;
                                tmax = temp;
                            }

                            link.BMin = (int)(MathHelper.Clamp(tmin, 0.0f, 1.0f) * 255.0f);
                            link.BMax = (int)(MathHelper.Clamp(tmax, 0.0f, 1.0f) * 255.0f);
                        }
                    }
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Build a tile and link all the polygons togther, both internally and externally.
        /// Make sure to link off-mesh connections as well.
        /// </summary>
        /// <param name="data">Navigation Mesh data</param>
        /// <param name="lastRef">Last polygon reference</param>
        /// <param name="result">Last tile reference</param>
        public PolyId AddTile(NavMeshBuilder data)
        {
            //make sure data is in right format
            PathfindingCommon.NavMeshInfo header = data.Header;

            //make sure location is free
            if (GetTileAt(header.X, header.Y, header.Layer) != null)
            {
                return(PolyId.Null);
            }

            PolyId   newTileId = GetNextTileRef();
            MeshTile tile      = new MeshTile(new Vector2i(header.X, header.Y), header.Layer, idManager, newTileId);

            tile.Salt = idManager.DecodeSalt(ref newTileId);

            if (header.BvNodeCount == 0)
            {
                tile.BVTree = null;
            }

            //patch header
            tile.Verts                  = data.NavVerts;
            tile.Polys                  = data.NavPolys;
            tile.PolyCount              = header.PolyCount;
            tile.DetailMeshes           = data.NavDMeshes;
            tile.DetailVerts            = data.NavDVerts;
            tile.DetailTris             = data.NavDTris;
            tile.BVTree                 = data.NavBvTree;
            tile.OffMeshConnections     = data.OffMeshCons;
            tile.OffMeshConnectionCount = header.OffMeshConCount;
            tile.BvQuantFactor          = header.BvQuantFactor;
            tile.BvNodeCount            = header.BvNodeCount;
            tile.Bounds                 = header.Bounds;
            tile.WalkableClimb          = header.WalkableClimb;

            //create connections within tile

            tile.ConnectIntLinks();
            tile.BaseOffMeshLinks();

            //create connections with neighbor tiles

            //connect with layers in current tile
            foreach (MeshTile layerTile in GetTilesAt(header.X, header.Y))
            {
                if (layerTile != tile)
                {
                    tile.ConnectExtLinks(layerTile, BoundarySide.Internal);
                    layerTile.ConnectExtLinks(tile, BoundarySide.Internal);
                }

                tile.ConnectExtOffMeshLinks(layerTile, BoundarySide.Internal);
                layerTile.ConnectExtOffMeshLinks(tile, BoundarySide.Internal);
            }

            //connect with neighbor tiles
            for (int i = 0; i < 8; i++)
            {
                BoundarySide b  = (BoundarySide)i;
                BoundarySide bo = b.GetOpposite();
                foreach (MeshTile neighborTile in GetNeighborTilesAt(header.X, header.Y, b))
                {
                    tile.ConnectExtLinks(neighborTile, b);
                    neighborTile.ConnectExtLinks(tile, bo);
                    tile.ConnectExtOffMeshLinks(neighborTile, b);
                    neighborTile.ConnectExtOffMeshLinks(tile, bo);
                }
            }

            AddTileAt(tile, GetNextTileRef());

            return(newTileId);
        }