Example #1
0
        public Boundary(BoundarySide side, GraphicsDevice graphics)
        {
            this.graphics = graphics;
            this.side     = side;

            switch (side)
            {
            case BoundarySide.Left:
                box = new Rectangle((Game1.gameWidth / 2) - (Tetrimino.tileSize * 5) - boundaryWidth, (Game1.gameHeight - Tetrimino.tileSize * 25), boundaryWidth, Tetrimino.tileSize * 21);
                break;

            case BoundarySide.Right:
                box = new Rectangle((Game1.gameWidth / 2) + (Tetrimino.tileSize * 5), (Game1.gameHeight - Tetrimino.tileSize * 25), boundaryWidth, Tetrimino.tileSize * 21);
                break;

            case BoundarySide.Bottom:
                box = new Rectangle((Game1.gameWidth / 2) - (Tetrimino.tileSize * 5) - boundaryWidth, (Game1.gameHeight - Tetrimino.tileSize * 4), Tetrimino.tileSize * 10 + boundaryWidth * 2, boundaryWidth);
                break;

            case BoundarySide.Top:
                box = new Rectangle((Game1.gameWidth / 2) - (Tetrimino.tileSize * 5) - boundaryWidth, (Game1.gameHeight - Tetrimino.tileSize * 24 - 2), Tetrimino.tileSize * 10 + boundaryWidth * 2, 2);
                break;
            }

            texture = new Texture2D(graphics, box.Width, box.Height);
            Color[] color = new Color[box.Width * box.Height];
            for (int i = 0; i < color.Length; i++)
            {
                color[i] = new Color(0, 0, 0);
            }
            texture.SetData(color);
        }
Example #2
0
        /// <summary>
        /// Search for neighbor polygons in the tile.
        /// </summary>
        /// <param name="va">Vertex A</param>
        /// <param name="vb">Vertex B</param>
        /// <param name="side">Polygon edge</param>
        /// <param name="con">Resulting Connection polygon</param>
        /// <param name="conarea">Resulting Connection area</param>
        public void FindConnectingPolys(Vector3 va, Vector3 vb, BoundarySide side, List <NavPolyId> con, List <float> conarea)
        {
            Vector2 amin, amax;

            CalcSlabEndPoints(va, vb, out amin, out amax, side);
            float apos = GetSlabCoord(va, side);

            //Remove links pointing to 'side' and compact the links array
            Vector2 bmin, bmax;

            //Iterate through all the tile's polygons
            for (int i = 0; i < PolyCount; i++)
            {
                int numPolyVerts = Polys[i].VertCount;

                //Iterate through all the vertices
                for (int j = 0; j < numPolyVerts; j++)
                {
                    //Skip edges which do not point to the right side
                    if (Polys[i].Neis[j] != (Link.External | (int)side))
                    {
                        continue;
                    }

                    //Grab two adjacent vertices
                    Vector3 vc   = Verts[Polys[i].Verts[j]];
                    Vector3 vd   = Verts[Polys[i].Verts[(j + 1) % numPolyVerts]];
                    float   bpos = GetSlabCoord(vc, side);

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

                    //Check if the segments touch
                    CalcSlabEndPoints(vc, vd, out bmin, out bmax, side);

                    //Skip if slabs don't overlap
                    if (!OverlapSlabs(amin, amax, bmin, bmax, 0.01f, WalkableClimb))
                    {
                        continue;
                    }

                    //Add return value
                    if (con.Count < con.Capacity)
                    {
                        conarea.Add(Math.Max(amin.X, bmin.X));
                        conarea.Add(Math.Min(amax.X, bmax.X));

                        NavPolyId id;
                        idManager.SetPolyIndex(ref baseRef, i, out id);
                        con.Add(id);
                    }

                    break;
                }
            }
        }
Example #3
0
        /// <summary>
        /// Gets the side in the exact opposite direction as a specified side.
        /// </summary>
        /// <remarks>
        /// The value <see cref="BoundarySide.Internal"/> will always return <see cref="BoundarySide.Internal"/>.
        /// </remarks>
        /// <param name="side">A side.</param>
        /// <returns>The opposite side.</returns>
        public static BoundarySide GetOpposite(this BoundarySide side)
        {
            if (side == BoundarySide.Internal)
            {
                return(BoundarySide.Internal);
            }

            return((BoundarySide)((int)(side + 4) % 8));
        }
Example #4
0
        public static string ToStringEx(this BoundarySide side)
        {
            switch (side)
            {
            case BoundarySide.Low: return("Low");

            case BoundarySide.High: return("High");

            case BoundarySide.All: return("ALL");

            default: return("");
            }
        }
Example #5
0
        /// <summary>
        /// Return the proper slab coordinate value depending on the 'side' value.
        /// </summary>
        /// <param name="va">Vertex A</param>
        /// <param name="side">The side</param>
        /// <returns>Slab coordinate value</returns>
        public float GetSlabCoord(Vector3 va, BoundarySide side)
        {
            if (side == BoundarySide.PlusX || side == BoundarySide.MinusX)
            {
                return(va.X);
            }
            else if (side == BoundarySide.PlusZ || side == BoundarySide.MinusZ)
            {
                return(va.Z);
            }

            return(0);
        }
Example #6
0
        /// <summary>
        /// Gets the neighboring tile at that position
        /// </summary>
        /// <param name="x">The x-coordinate</param>
        /// <param name="y">The y-coordinate</param>
        /// <param name="side">The side value</param>
        /// <param name="tiles">An array of MeshTiles</param>
        /// <returns>The number of tiles satisfying the condition</returns>
        public IEnumerable <MeshTile> GetNeighborTilesAt(int x, int y, BoundarySide side)
        {
            int nx = x, ny = y;

            switch (side)
            {
            case BoundarySide.PlusX:
                nx++;
                break;

            case BoundarySide.PlusXPlusZ:
                nx++;
                ny++;
                break;

            case BoundarySide.PlusZ:
                ny++;
                break;

            case BoundarySide.MinusXPlusZ:
                nx--;
                ny++;
                break;

            case BoundarySide.MinusX:
                nx--;
                break;

            case BoundarySide.MinusXMinusZ:
                nx--;
                ny--;
                break;

            case BoundarySide.MinusZ:
                ny--;
                break;

            case BoundarySide.PlusXMinusZ:
                nx++;
                ny--;
                break;
            }

            return(GetTilesAt(nx, ny));
        }
Example #7
0
        /// <summary>
        /// Gets the neighboring tile at that position
        /// </summary>
        /// <param name="x">The x-coordinate</param>
        /// <param name="y">The y-coordinate</param>
        /// <param name="side">The side value</param>
        /// <param name="tiles">An array of MeshTiles</param>
        /// <returns>The number of tiles satisfying the condition</returns>
        public int GetNeighbourTilesAt(int x, int y, BoundarySide side, MeshTile[] tiles)
        {
            int nx = x, ny = y;

            switch (side)
            {
            case BoundarySide.PlusX:
                nx++;
                break;

            case BoundarySide.PlusXPlusZ:
                nx++;
                ny++;
                break;

            case BoundarySide.PlusZ:
                ny++;
                break;

            case BoundarySide.MinusXPlusZ:
                nx--;
                ny++;
                break;

            case BoundarySide.MinusX:
                nx--;
                break;

            case BoundarySide.MinusXMinusZ:
                nx--;
                ny--;
                break;

            case BoundarySide.MinusZ:
                ny--;
                break;

            case BoundarySide.PlusXMinusZ:
                nx++;
                ny--;
                break;
            }

            return(GetTilesAt(nx, ny, tiles));
        }
Example #8
0
        /// <summary>
        /// Search for neighbor polygons in the tile.
        /// </summary>
        /// <param name="va">Vertex A</param>
        /// <param name="vb">Vertex B</param>
        /// <param name="tile">Current tile</param>
        /// <param name="side">Polygon edge</param>
        /// <param name="con">Resulting Connection polygon</param>
        /// <param name="conarea">Resulting Connection area</param>
        public void FindConnectingPolys(Vector3 va, Vector3 vb, MeshTile tile, BoundarySide side, List<int> con, List<float> conarea)
        {
            if (tile == null)
                return;

            Vector2 amin = Vector2.Zero;
            Vector2 amax = Vector2.Zero;
            CalcSlabEndPoints(va, vb, amin, amax, side);
            float apos = GetSlabCoord(va, side);

            //Remove links pointing to 'side' and compact the links array
            Vector2 bmin = Vector2.Zero;
            Vector2 bmax = Vector2.Zero;

            int polyBase = GetPolyRefBase(tile);

            //Iterate through all the tile's polygons
            for (int i = 0; i < tile.Header.PolyCount; i++)
            {
                int numPolyVerts = tile.Polys[i].VertCount;

                //Iterate through all the vertices
                for (int j = 0; j < numPolyVerts; j++)
                {
                    //Skip edges which do not point to the right side
                    if (tile.Polys[i].Neis[j] != (Link.External | (int)side))
                        continue;

                    //Grab two adjacent vertices
                    Vector3 vc = tile.Verts[tile.Polys[i].Verts[j]];
                    Vector3 vd = tile.Verts[tile.Polys[i].Verts[(j + 1) % numPolyVerts]];
                    float bpos = GetSlabCoord(vc, side);

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

                    //Check if the segments touch
                    CalcSlabEndPoints(vc, vd, bmin, bmax, side);

                    //Skip if slabs don't overlap
                    if (!OverlapSlabs(amin, amax, bmin, bmax, 0.01f, tile.Header.WalkableClimb))
                        continue;

                    //Add return value
                    if (con.Count < con.Capacity)
                    {
                        conarea.Add(Math.Max(amin.X, bmin.X));
                        conarea.Add(Math.Min(amax.X, bmax.X));
                        con.Add(GetReference(polyBase, i));
                    }

                    break;
                }
            }
        }
Example #9
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<int> nei = new List<int>(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);
                            }
                        }
                    }
                }
            }
        }
Example #10
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;
                    }
                }
            }
        }
Example #11
0
		/// <summary>
		/// Initializes a new instance of the <see cref="NavMeshBuilder" /> class.
		/// Add all the PolyMesh and PolyMeshDetail attributes to the Navigation Mesh.
		/// Then, add Off-Mesh connection support.
		/// </summary>
		/// <param name="polyMesh">The PolyMesh</param>
		/// <param name="polyMeshDetail">The PolyMeshDetail</param>
		/// <param name="offMeshCons">Offmesh connection data</param>
		/// <param name="settings">The settings used to build.</param>
		public NavMeshBuilder(PolyMesh polyMesh, PolyMeshDetail polyMeshDetail, OffMeshConnection[] offMeshCons, NavMeshGenerationSettings settings)
		{
			if (settings.VertsPerPoly > PathfindingCommon.VERTS_PER_POLYGON)
				throw new InvalidOperationException("The number of vertices per polygon is above SharpNav's limit");
			if (polyMesh.VertCount == 0)
				throw new InvalidOperationException("The provided PolyMesh has no vertices.");
			if (polyMesh.PolyCount == 0)
				throw new InvalidOperationException("The provided PolyMesh has not polys.");

			int nvp = settings.VertsPerPoly;

			//classify off-mesh connection points
			BoundarySide[] offMeshSides = new BoundarySide[offMeshCons.Length * 2];
			int storedOffMeshConCount = 0;
			int offMeshConLinkCount = 0;

			if (offMeshCons.Length > 0)
			{
				//find height bounds
				float hmin = float.MaxValue;
				float hmax = -float.MaxValue;

				if (polyMeshDetail != null)
				{
					for (int i = 0; i < polyMeshDetail.VertCount; i++)
					{
						float h = polyMeshDetail.Verts[i].Y;
						hmin = Math.Min(hmin, h);
						hmax = Math.Max(hmax, h);
					}
				}
				else
				{
					for (int i = 0; i < polyMesh.VertCount; i++)
					{
						PolyVertex iv = polyMesh.Verts[i];
						float h = polyMesh.Bounds.Min.Y + iv.Y * settings.CellHeight;
						hmin = Math.Min(hmin, h);
						hmax = Math.Max(hmax, h);
					}
				}

				hmin -= settings.MaxClimb;
				hmax += settings.MaxClimb;
				BBox3 bounds = polyMesh.Bounds;
				bounds.Min.Y = hmin;
				bounds.Max.Y = hmax;

				for (int i = 0; i < offMeshCons.Length; i++)
				{
					Vector3 p0 = offMeshCons[i].Pos0;
					Vector3 p1 = offMeshCons[i].Pos1;

					offMeshSides[i * 2 + 0] = BoundarySideExtensions.FromPoint(p0, bounds);
					offMeshSides[i * 2 + 1] = BoundarySideExtensions.FromPoint(p1, bounds);

					//off-mesh start position isn't touching mesh
					if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
					{
						if (p0.Y < bounds.Min.Y || p0.Y > bounds.Max.Y)
							offMeshSides[i * 2 + 0] = 0;
					}

					//count number of links to allocate
					if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
						offMeshConLinkCount++;
					if (offMeshSides[i * 2 + 1] == BoundarySide.Internal)
						offMeshConLinkCount++;

					if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
						storedOffMeshConCount++;
				}
			}

			//off-mesh connections stored as polygons, adjust values
			int totPolyCount = polyMesh.PolyCount + storedOffMeshConCount;
			int totVertCount = polyMesh.VertCount + storedOffMeshConCount * 2;

			//find portal edges
			int edgeCount = 0;
			int portalCount = 0;
			for (int i = 0; i < polyMesh.PolyCount; i++)
			{
				PolyMesh.Polygon p = polyMesh.Polys[i];
				for (int j = 0; j < nvp; j++)
				{
					if (p.Vertices[j] == PolyMesh.NullId)
						break;

					edgeCount++;
					
					if (PolyMesh.IsBoundaryEdge(p.NeighborEdges[j]))
					{
						int dir = p.NeighborEdges[j] % 16;
						if (dir != 15)
							portalCount++;
					}
				}
			}

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

			//find unique detail vertices
			int uniqueDetailVertCount = 0;
			int detailTriCount = 0;
			if (polyMeshDetail != null)
			{
				detailTriCount = polyMeshDetail.TrisCount;
				for (int i = 0; i < polyMesh.PolyCount; i++)
				{
					int numDetailVerts = polyMeshDetail.Meshes[i].VertexCount;
					int numPolyVerts = polyMesh.Polys[i].VertexCount;
					uniqueDetailVertCount += numDetailVerts - numPolyVerts;
				}
			}
			else
			{
				uniqueDetailVertCount = 0;
				detailTriCount = 0;
				for (int i = 0; i < polyMesh.PolyCount; i++)
				{
					int numPolyVerts = polyMesh.Polys[i].VertexCount;
					uniqueDetailVertCount += numPolyVerts - 2;
				}
			}

			//allocate data
			header = new PathfindingCommon.NavMeshInfo();
			navVerts = new Vector3[totVertCount];
			navPolys = new Poly[totPolyCount];
			navDMeshes = new PolyMeshDetail.MeshData[polyMesh.PolyCount];
			navDVerts = new Vector3[uniqueDetailVertCount];
			navDTris = new PolyMeshDetail.TriangleData[detailTriCount];
			offMeshConnections = new OffMeshConnection[storedOffMeshConCount];

			//store header
			//HACK TiledNavMesh should figure out the X/Y/layer instead of the user maybe?
			header.X = 0;
			header.Y = 0;
			header.Layer = 0;
			header.PolyCount = totPolyCount;
			header.VertCount = totVertCount;
			header.MaxLinkCount = maxLinkCount;
			header.Bounds = polyMesh.Bounds;
			header.DetailMeshCount = polyMesh.PolyCount;
			header.DetailVertCount = uniqueDetailVertCount;
			header.DetailTriCount = detailTriCount;
			header.OffMeshBase = polyMesh.PolyCount;
			header.WalkableHeight = settings.AgentHeight;
			header.WalkableRadius = settings.AgentRadius;
			header.WalkableClimb = settings.MaxClimb;
			header.OffMeshConCount = storedOffMeshConCount;
			header.BvNodeCount = settings.BuildBoundingVolumeTree ? polyMesh.PolyCount * 2 : 0;
			header.BvQuantFactor = 1f / settings.CellSize;

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

			//store vertices
			for (int i = 0; i < polyMesh.VertCount; i++)
			{
				PolyVertex iv = polyMesh.Verts[i];
				navVerts[i].X = polyMesh.Bounds.Min.X + iv.X * settings.CellSize;
				navVerts[i].Y = polyMesh.Bounds.Min.Y + iv.Y * settings.CellHeight;
				navVerts[i].Z = polyMesh.Bounds.Min.Z + iv.Z * settings.CellSize;
			}

			//off-mesh link vertices
			int n = 0;
			for (int i = 0; i < offMeshCons.Length; i++)
			{
				//only store connections which start from this tile
				if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
				{
					navVerts[offMeshVertsBase + (n * 2 + 0)] = offMeshCons[i].Pos0;
					navVerts[offMeshVertsBase + (n * 2 + 1)] = offMeshCons[i].Pos1;
					n++;
				}
			}

			//store polygons
			for (int i = 0; i < polyMesh.PolyCount; i++)
			{
				navPolys[i] = new Poly();
				navPolys[i].VertCount = 0;
				navPolys[i].Tag = polyMesh.Polys[i].Tag;
				navPolys[i].Area = polyMesh.Polys[i].Area;
				navPolys[i].PolyType = PolygonType.Ground;
				navPolys[i].Verts = new int[nvp];
				navPolys[i].Neis = new int[nvp];
				for (int j = 0; j < nvp; j++)
				{
					if (polyMesh.Polys[i].Vertices[j] == PolyMesh.NullId)
						break;

					navPolys[i].Verts[j] = polyMesh.Polys[i].Vertices[j];
					if (PolyMesh.IsBoundaryEdge(polyMesh.Polys[i].NeighborEdges[j]))
					{
						//border or portal edge
						int dir = polyMesh.Polys[i].NeighborEdges[j] % 16;
						if (dir == 0xf) //border
							navPolys[i].Neis[j] = 0;
						else if (dir == 0) //portal x-
							navPolys[i].Neis[j] = Link.External | 4;
						else if (dir == 1) //portal z+
							navPolys[i].Neis[j] = Link.External | 2;
						else if (dir == 2) //portal x+
							navPolys[i].Neis[j] = Link.External | 0;
						else if (dir == 3) //portal z-
							navPolys[i].Neis[j] = Link.External | 6;
					}
					else
					{
						//normal connection
						navPolys[i].Neis[j] = polyMesh.Polys[i].NeighborEdges[j] + 1;
					}

					navPolys[i].VertCount++;
				}
			}

			//off-mesh connection vertices
			n = 0;
			for (int i = 0; i < offMeshCons.Length; i++)
			{
				//only store connections which start from this tile
				if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
				{
					navPolys[offMeshPolyBase + n].VertCount = 2;
					navPolys[offMeshPolyBase + n].Verts = new int[nvp];
					navPolys[offMeshPolyBase + n].Verts[0] = offMeshVertsBase + (n * 2 + 0);
					navPolys[offMeshPolyBase + n].Verts[1] = offMeshVertsBase + (n * 2 + 1);
					navPolys[offMeshPolyBase + n].Tag = offMeshCons[i].Flags;
					navPolys[offMeshPolyBase + n].Area = polyMesh.Polys[offMeshCons[i].Poly].Area; //HACK is this correct?
					navPolys[offMeshPolyBase + n].PolyType = PolygonType.OffMeshConnection;
					n++;
				}
			}
			
			//store detail meshes and vertices
			if (polyMeshDetail != null)
			{
				int vbase = 0;
				List<Vector3> storedDetailVerts = new List<Vector3>();
				for (int i = 0; i < polyMesh.PolyCount; i++)
				{
					int vb = polyMeshDetail.Meshes[i].VertexIndex;
					int numDetailVerts = polyMeshDetail.Meshes[i].VertexCount;
					int numPolyVerts = navPolys[i].VertCount;
					navDMeshes[i].VertexIndex = vbase;
					navDMeshes[i].VertexCount = numDetailVerts - numPolyVerts;
					navDMeshes[i].TriangleIndex = polyMeshDetail.Meshes[i].TriangleIndex;
					navDMeshes[i].TriangleCount = polyMeshDetail.Meshes[i].TriangleCount;
					
					//Copy detail vertices 
					//first 'nv' verts are equal to nav poly verts
					//the rest are detail verts
					for (int j = 0; j < navDMeshes[i].VertexCount; j++)
					{
						storedDetailVerts.Add(polyMeshDetail.Verts[vb + numPolyVerts + j]);
					}

					vbase += numDetailVerts - numPolyVerts;
				}

				navDVerts = storedDetailVerts.ToArray();

				//store triangles
				for (int j = 0; j < polyMeshDetail.TrisCount; j++)
					navDTris[j] = polyMeshDetail.Tris[j];
			}
			else
			{
				//create dummy detail mesh by triangulating polys
				int tbase = 0;
				for (int i = 0; i < polyMesh.PolyCount; i++)
				{
					int numPolyVerts = navPolys[i].VertCount;
					navDMeshes[i].VertexIndex = 0;
					navDMeshes[i].VertexCount = 0;
					navDMeshes[i].TriangleIndex = tbase;
					navDMeshes[i].TriangleCount = numPolyVerts - 2;

					//triangulate polygon
					for (int j = 2; j < numPolyVerts; j++)
					{
						navDTris[tbase].VertexHash0 = 0;
						navDTris[tbase].VertexHash1 = j - 1;
						navDTris[tbase].VertexHash2 = j;

						//bit for each edge that belongs to the poly boundary
						navDTris[tbase].Flags = 1 << 2;
						if (j == 2) 
							navDTris[tbase].Flags |= 1 << 0;
						if (j == numPolyVerts - 1)
							navDTris[tbase].Flags |= 1 << 4;
						
						tbase++;
					}
				}
			}
			
			//store and create BV tree
			if (settings.BuildBoundingVolumeTree)
			{
				//build tree
				navBvTree = new BVTree(polyMesh.Verts, polyMesh.Polys, nvp, settings.CellSize, settings.CellHeight);
			}

			//store off-mesh connections
			n = 0;
			for (int i = 0; i < offMeshConnections.Length; i++)
			{
				//only store connections which start from this tile
				if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
				{
					offMeshConnections[n].Poly = offMeshPolyBase + n;

					//copy connection end points
					offMeshConnections[n].Pos0 = offMeshCons[i].Pos0;
					offMeshConnections[n].Pos1 = offMeshCons[i].Pos1;

					offMeshConnections[n].Radius = offMeshCons[i].Radius;
					offMeshConnections[n].Flags = offMeshCons[i].Flags;
					offMeshConnections[n].Side = offMeshSides[i * 2 + 1];
					offMeshConnections[n].Tag = offMeshCons[i].Tag;

					n++;
				}
			}
		}
Example #12
0
        /// <summary>
        /// Find the slab endpoints based off of the 'side' value.
        /// </summary>
        /// <param name="va">Vertex A</param>
        /// <param name="vb">Vertex B</param>
        /// <param name="bmin">Minimum bounds</param>
        /// <param name="bmax">Maximum bounds</param>
        /// <param name="side">The side</param>
        public void CalcSlabEndPoints(Vector3 va, Vector3 vb, Vector2 bmin, Vector2 bmax, BoundarySide side)
        {
            if (side == BoundarySide.PlusX || side == BoundarySide.MinusX)
            {
                if (va.Z < vb.Z)
                {
                    bmin.X = va.Z;
                    bmin.Y = va.Y;

                    bmax.X = vb.Z;
                    bmax.Y = vb.Y;
                }
                else
                {
                    bmin.X = vb.Z;
                    bmin.Y = vb.Y;

                    bmax.X = va.Z;
                    bmax.Y = va.Y;
                }
            }
            else if (side == BoundarySide.PlusZ || side == BoundarySide.MinusZ)
            {
                if (va.X < vb.X)
                {
                    bmin.X = va.X;
                    bmin.Y = va.Y;

                    bmax.X = vb.X;
                    bmax.Y = vb.Y;
                }
                else
                {
                    bmin.X = vb.X;
                    bmin.Y = vb.Y;

                    bmax.X = va.X;
                    bmax.Y = va.Y;
                }
            }
        }
Example #13
0
        /// <summary>
        /// Find the slab endpoints based off of the 'side' value.
        /// </summary>
        /// <param name="va">Vertex A</param>
        /// <param name="vb">Vertex B</param>
        /// <param name="bmin">Minimum bounds</param>
        /// <param name="bmax">Maximum bounds</param>
        /// <param name="side">The side</param>
        public void CalcSlabEndPoints(Vector3 va, Vector3 vb, Vector2 bmin, Vector2 bmax, BoundarySide side)
        {
            if (side == BoundarySide.PlusX || side == BoundarySide.MinusX)
            {
                if (va.Z < vb.Z)
                {
                    bmin.X = va.Z;
                    bmin.Y = va.Y;

                    bmax.X = vb.Z;
                    bmax.Y = vb.Y;
                }
                else
                {
                    bmin.X = vb.Z;
                    bmin.Y = vb.Y;

                    bmax.X = va.Z;
                    bmax.Y = va.Y;
                }
            }
            else if (side == BoundarySide.PlusZ || side == BoundarySide.MinusZ)
            {
                if (va.X < vb.X)
                {
                    bmin.X = va.X;
                    bmin.Y = va.Y;

                    bmax.X = vb.X;
                    bmax.Y = vb.Y;
                }
                else
                {
                    bmin.X = vb.X;
                    bmin.Y = vb.Y;

                    bmax.X = va.X;
                    bmax.Y = va.Y;
                }
            }
        }
Example #14
0
		public IEnumerable<MeshTile> GetNeighborTilesAt(Vector2i location, BoundarySide side)
		{
			return GetNeighborTilesAt(location.X, location.Y, side);
		}
Example #15
0
 public IEnumerable <MeshTile> GetNeighborTilesAt(Vector2i location, BoundarySide side)
 {
     return(GetNeighborTilesAt(location.X, location.Y, side));
 }
Example #16
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;
                    }
                }
            }
        }
Example #17
0
        /// <summary>
        /// Initializes a new instance of the <see cref="NavMeshBuilder" /> class.
        /// Add all the PolyMesh and PolyMeshDetail attributes to the Navigation Mesh.
        /// Then, add Off-Mesh connection support.
        /// </summary>
        /// <param name="polyMesh">The PolyMesh</param>
        /// <param name="polyMeshDetail">The PolyMeshDetail</param>
        /// <param name="offMeshCons">Offmesh connection data</param>
        /// <param name="settings">The settings used to build.</param>
        public NavMeshBuilder(PolyMesh polyMesh, PolyMeshDetail polyMeshDetail, OffMeshConnection[] offMeshCons, NavMeshGenerationSettings settings)
        {
            if (settings.VertsPerPoly > PathfindingCommon.VERTS_PER_POLYGON)
            {
                throw new InvalidOperationException("The number of vertices per polygon is above SharpNav's limit");
            }
            if (polyMesh.VertCount == 0)
            {
                throw new InvalidOperationException("The provided PolyMesh has no vertices.");
            }
            if (polyMesh.PolyCount == 0)
            {
                throw new InvalidOperationException("The provided PolyMesh has not polys.");
            }

            int nvp = settings.VertsPerPoly;

            //classify off-mesh connection points
            BoundarySide[] offMeshSides          = new BoundarySide[offMeshCons.Length * 2];
            int            storedOffMeshConCount = 0;
            int            offMeshConLinkCount   = 0;

            if (offMeshCons.Length > 0)
            {
                //find height bounds
                float hmin = float.MaxValue;
                float hmax = -float.MaxValue;

                if (polyMeshDetail != null)
                {
                    for (int i = 0; i < polyMeshDetail.VertCount; i++)
                    {
                        float h = polyMeshDetail.Verts[i].Y;
                        hmin = Math.Min(hmin, h);
                        hmax = Math.Max(hmax, h);
                    }
                }
                else
                {
                    for (int i = 0; i < polyMesh.VertCount; i++)
                    {
                        PolyVertex iv = polyMesh.Verts[i];
                        float      h  = polyMesh.Bounds.Min.Y + iv.Y * settings.CellHeight;
                        hmin = Math.Min(hmin, h);
                        hmax = Math.Max(hmax, h);
                    }
                }

                hmin -= settings.MaxClimb;
                hmax += settings.MaxClimb;
                BBox3 bounds = polyMesh.Bounds;
                bounds.Min.Y = hmin;
                bounds.Max.Y = hmax;

                for (int i = 0; i < offMeshCons.Length; i++)
                {
                    Vector3 p0 = offMeshCons[i].Pos0;
                    Vector3 p1 = offMeshCons[i].Pos1;

                    offMeshSides[i * 2 + 0] = BoundarySideExtensions.FromPoint(p0, bounds);
                    offMeshSides[i * 2 + 1] = BoundarySideExtensions.FromPoint(p1, bounds);

                    //off-mesh start position isn't touching mesh
                    if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                    {
                        if (p0.Y < bounds.Min.Y || p0.Y > bounds.Max.Y)
                        {
                            offMeshSides[i * 2 + 0] = 0;
                        }
                    }

                    //count number of links to allocate
                    if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                    {
                        offMeshConLinkCount++;
                    }
                    if (offMeshSides[i * 2 + 1] == BoundarySide.Internal)
                    {
                        offMeshConLinkCount++;
                    }

                    if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                    {
                        storedOffMeshConCount++;
                    }
                }
            }

            //off-mesh connections stored as polygons, adjust values
            int totPolyCount = polyMesh.PolyCount + storedOffMeshConCount;
            int totVertCount = polyMesh.VertCount + storedOffMeshConCount * 2;

            //find portal edges
            int edgeCount   = 0;
            int portalCount = 0;

            for (int i = 0; i < polyMesh.PolyCount; i++)
            {
                PolyMesh.Polygon p = polyMesh.Polys[i];
                for (int j = 0; j < nvp; j++)
                {
                    if (p.Vertices[j] == PolyMesh.NullId)
                    {
                        break;
                    }

                    edgeCount++;

                    if (PolyMesh.IsBoundaryEdge(p.NeighborEdges[j]))
                    {
                        int dir = p.NeighborEdges[j] % 16;
                        if (dir != 15)
                        {
                            portalCount++;
                        }
                    }
                }
            }

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

            //find unique detail vertices
            int uniqueDetailVertCount = 0;
            int detailTriCount        = 0;

            if (polyMeshDetail != null)
            {
                detailTriCount = polyMeshDetail.TrisCount;
                for (int i = 0; i < polyMesh.PolyCount; i++)
                {
                    int numDetailVerts = polyMeshDetail.Meshes[i].VertexCount;
                    int numPolyVerts   = polyMesh.Polys[i].VertexCount;
                    uniqueDetailVertCount += numDetailVerts - numPolyVerts;
                }
            }
            else
            {
                uniqueDetailVertCount = 0;
                detailTriCount        = 0;
                for (int i = 0; i < polyMesh.PolyCount; i++)
                {
                    int numPolyVerts = polyMesh.Polys[i].VertexCount;
                    uniqueDetailVertCount += numPolyVerts - 2;
                }
            }

            //allocate data
            header             = new PathfindingCommon.NavMeshInfo();
            navVerts           = new Vector3[totVertCount];
            navPolys           = new Poly[totPolyCount];
            navDMeshes         = new PolyMeshDetail.MeshData[polyMesh.PolyCount];
            navDVerts          = new Vector3[uniqueDetailVertCount];
            navDTris           = new PolyMeshDetail.TriangleData[detailTriCount];
            offMeshConnections = new OffMeshConnection[storedOffMeshConCount];

            //store header
            //HACK TiledNavMesh should figure out the X/Y/layer instead of the user maybe?
            header.X               = 0;
            header.Y               = 0;
            header.Layer           = 0;
            header.PolyCount       = totPolyCount;
            header.VertCount       = totVertCount;
            header.MaxLinkCount    = maxLinkCount;
            header.Bounds          = polyMesh.Bounds;
            header.DetailMeshCount = polyMesh.PolyCount;
            header.DetailVertCount = uniqueDetailVertCount;
            header.DetailTriCount  = detailTriCount;
            header.OffMeshBase     = polyMesh.PolyCount;
            header.WalkableHeight  = settings.AgentHeight;
            header.WalkableRadius  = settings.AgentRadius;
            header.WalkableClimb   = settings.MaxClimb;
            header.OffMeshConCount = storedOffMeshConCount;
            header.BvNodeCount     = settings.BuildBoundingVolumeTree ? polyMesh.PolyCount * 2 : 0;
            header.BvQuantFactor   = 1f / settings.CellSize;

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

            //store vertices
            for (int i = 0; i < polyMesh.VertCount; i++)
            {
                PolyVertex iv = polyMesh.Verts[i];
                navVerts[i].X = polyMesh.Bounds.Min.X + iv.X * settings.CellSize;
                navVerts[i].Y = polyMesh.Bounds.Min.Y + iv.Y * settings.CellHeight;
                navVerts[i].Z = polyMesh.Bounds.Min.Z + iv.Z * settings.CellSize;
            }

            //off-mesh link vertices
            int n = 0;

            for (int i = 0; i < offMeshCons.Length; i++)
            {
                //only store connections which start from this tile
                if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                {
                    navVerts[offMeshVertsBase + (n * 2 + 0)] = offMeshCons[i].Pos0;
                    navVerts[offMeshVertsBase + (n * 2 + 1)] = offMeshCons[i].Pos1;
                    n++;
                }
            }

            //store polygons
            for (int i = 0; i < polyMesh.PolyCount; i++)
            {
                navPolys[i]           = new Poly();
                navPolys[i].VertCount = 0;
                navPolys[i].Tag       = polyMesh.Polys[i].Tag;
                navPolys[i].Area      = polyMesh.Polys[i].Area;
                navPolys[i].PolyType  = PolygonType.Ground;
                navPolys[i].Verts     = new int[nvp];
                navPolys[i].Neis      = new int[nvp];
                for (int j = 0; j < nvp; j++)
                {
                    if (polyMesh.Polys[i].Vertices[j] == PolyMesh.NullId)
                    {
                        break;
                    }

                    navPolys[i].Verts[j] = polyMesh.Polys[i].Vertices[j];
                    if (PolyMesh.IsBoundaryEdge(polyMesh.Polys[i].NeighborEdges[j]))
                    {
                        //border or portal edge
                        int dir = polyMesh.Polys[i].NeighborEdges[j] % 16;
                        if (dir == 0xf)                         //border
                        {
                            navPolys[i].Neis[j] = 0;
                        }
                        else if (dir == 0)                         //portal x-
                        {
                            navPolys[i].Neis[j] = Link.External | 4;
                        }
                        else if (dir == 1)                         //portal z+
                        {
                            navPolys[i].Neis[j] = Link.External | 2;
                        }
                        else if (dir == 2)                         //portal x+
                        {
                            navPolys[i].Neis[j] = Link.External | 0;
                        }
                        else if (dir == 3)                         //portal z-
                        {
                            navPolys[i].Neis[j] = Link.External | 6;
                        }
                    }
                    else
                    {
                        //normal connection
                        navPolys[i].Neis[j] = polyMesh.Polys[i].NeighborEdges[j] + 1;
                    }

                    navPolys[i].VertCount++;
                }
            }

            //off-mesh connection vertices
            n = 0;
            for (int i = 0; i < offMeshCons.Length; i++)
            {
                //only store connections which start from this tile
                if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                {
                    navPolys[offMeshPolyBase + n].VertCount = 2;
                    navPolys[offMeshPolyBase + n].Verts     = new int[nvp];
                    navPolys[offMeshPolyBase + n].Verts[0]  = offMeshVertsBase + (n * 2 + 0);
                    navPolys[offMeshPolyBase + n].Verts[1]  = offMeshVertsBase + (n * 2 + 1);
                    navPolys[offMeshPolyBase + n].Tag       = offMeshCons[i].Flags;
                    navPolys[offMeshPolyBase + n].Area      = polyMesh.Polys[offMeshCons[i].Poly].Area;                //HACK is this correct?
                    navPolys[offMeshPolyBase + n].PolyType  = PolygonType.OffMeshConnection;
                    n++;
                }
            }

            //store detail meshes and vertices
            if (polyMeshDetail != null)
            {
                int            vbase             = 0;
                List <Vector3> storedDetailVerts = new List <Vector3>();
                for (int i = 0; i < polyMesh.PolyCount; i++)
                {
                    int vb             = polyMeshDetail.Meshes[i].VertexIndex;
                    int numDetailVerts = polyMeshDetail.Meshes[i].VertexCount;
                    int numPolyVerts   = navPolys[i].VertCount;
                    navDMeshes[i].VertexIndex   = vbase;
                    navDMeshes[i].VertexCount   = numDetailVerts - numPolyVerts;
                    navDMeshes[i].TriangleIndex = polyMeshDetail.Meshes[i].TriangleIndex;
                    navDMeshes[i].TriangleCount = polyMeshDetail.Meshes[i].TriangleCount;

                    //Copy detail vertices
                    //first 'nv' verts are equal to nav poly verts
                    //the rest are detail verts
                    for (int j = 0; j < navDMeshes[i].VertexCount; j++)
                    {
                        storedDetailVerts.Add(polyMeshDetail.Verts[vb + numPolyVerts + j]);
                    }

                    vbase += numDetailVerts - numPolyVerts;
                }

                navDVerts = storedDetailVerts.ToArray();

                //store triangles
                for (int j = 0; j < polyMeshDetail.TrisCount; j++)
                {
                    navDTris[j] = polyMeshDetail.Tris[j];
                }
            }
            else
            {
                //create dummy detail mesh by triangulating polys
                int tbase = 0;
                for (int i = 0; i < polyMesh.PolyCount; i++)
                {
                    int numPolyVerts = navPolys[i].VertCount;
                    navDMeshes[i].VertexIndex   = 0;
                    navDMeshes[i].VertexCount   = 0;
                    navDMeshes[i].TriangleIndex = tbase;
                    navDMeshes[i].TriangleCount = numPolyVerts - 2;

                    //triangulate polygon
                    for (int j = 2; j < numPolyVerts; j++)
                    {
                        navDTris[tbase].VertexHash0 = 0;
                        navDTris[tbase].VertexHash1 = j - 1;
                        navDTris[tbase].VertexHash2 = j;

                        //bit for each edge that belongs to the poly boundary
                        navDTris[tbase].Flags = 1 << 2;
                        if (j == 2)
                        {
                            navDTris[tbase].Flags |= 1 << 0;
                        }
                        if (j == numPolyVerts - 1)
                        {
                            navDTris[tbase].Flags |= 1 << 4;
                        }

                        tbase++;
                    }
                }
            }

            //store and create BV tree
            if (settings.BuildBoundingVolumeTree)
            {
                //build tree
                navBvTree = new BVTree(polyMesh.Verts, polyMesh.Polys, nvp, settings.CellSize, settings.CellHeight);
            }

            //store off-mesh connections
            n = 0;
            for (int i = 0; i < offMeshConnections.Length; i++)
            {
                //only store connections which start from this tile
                if (offMeshSides[i * 2 + 0] == BoundarySide.Internal)
                {
                    offMeshConnections[n].Poly = offMeshPolyBase + n;

                    //copy connection end points
                    offMeshConnections[n].Pos0 = offMeshCons[i].Pos0;
                    offMeshConnections[n].Pos1 = offMeshCons[i].Pos1;

                    offMeshConnections[n].Radius = offMeshCons[i].Radius;
                    offMeshConnections[n].Flags  = offMeshCons[i].Flags;
                    offMeshConnections[n].Side   = offMeshSides[i * 2 + 1];
                    offMeshConnections[n].Tag    = offMeshCons[i].Tag;

                    n++;
                }
            }
        }
Example #18
0
        /// <summary>
        /// Gets the neighboring tile at that position
        /// </summary>
        /// <param name="x">The x-coordinate</param>
        /// <param name="y">The y-coordinate</param>
        /// <param name="side">The side value</param>
        /// <param name="tiles">An array of MeshTiles</param>
        /// <returns>The number of tiles satisfying the condition</returns>
        public int GetNeighbourTilesAt(int x, int y, BoundarySide side, MeshTile[] tiles)
        {
            int nx = x, ny = y;
            switch (side)
            {
                case BoundarySide.PlusX:
                    nx++;
                    break;

                case BoundarySide.PlusXPlusZ:
                    nx++;
                    ny++;
                    break;

                case BoundarySide.PlusZ:
                    ny++;
                    break;

                case BoundarySide.MinusXPlusZ:
                    nx--;
                    ny++;
                    break;

                case BoundarySide.MinusX:
                    nx--;
                    break;

                case BoundarySide.MinusXMinusZ:
                    nx--;
                    ny--;
                    break;

                case BoundarySide.MinusZ:
                    ny--;
                    break;

                case BoundarySide.PlusXMinusZ:
                    nx++;
                    ny--;
                    break;
            }

            return GetTilesAt(nx, ny, tiles);
        }
Example #19
0
		/// <summary>
		/// Gets the neighboring tile at that position
		/// </summary>
		/// <param name="x">The x-coordinate</param>
		/// <param name="y">The y-coordinate</param>
		/// <param name="side">The side value</param>
		/// <param name="tiles">An array of MeshTiles</param>
		/// <returns>The number of tiles satisfying the condition</returns>
		public IEnumerable<MeshTile> GetNeighborTilesAt(int x, int y, BoundarySide side)
		{
			int nx = x, ny = y;
			switch (side)
			{
				case BoundarySide.PlusX:
					nx++;
					break;

				case BoundarySide.PlusXPlusZ:
					nx++;
					ny++;
					break;

				case BoundarySide.PlusZ:
					ny++;
					break;

				case BoundarySide.MinusXPlusZ:
					nx--;
					ny++;
					break;

				case BoundarySide.MinusX:
					nx--;
					break;

				case BoundarySide.MinusXMinusZ:
					nx--;
					ny--;
					break;

				case BoundarySide.MinusZ:
					ny--;
					break;

				case BoundarySide.PlusXMinusZ:
					nx++;
					ny--;
					break;
			}

			return GetTilesAt(nx, ny);
		}
Example #20
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);
                        }
                    }
                }
            }
        }
Example #21
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);
                }
            }
        }
Example #22
0
        /// <summary>
        /// Return the proper slab coordinate value depending on the 'side' value.
        /// </summary>
        /// <param name="va">Vertex A</param>
        /// <param name="side">The side</param>
        /// <returns>Slab coordinate value</returns>
        public float GetSlabCoord(Vector3 va, BoundarySide side)
        {
            if (side == BoundarySide.PlusX || side == BoundarySide.MinusX)
                return va.X;
            else if (side == BoundarySide.PlusZ || side == BoundarySide.MinusZ)
                return va.Z;

            return 0;
        }
Example #23
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);
        }
Example #24
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);
                            }
                        }
                    }
                }
            }
        }
Example #25
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);
        }