Ejemplo n.º 1
0
        /// <summary>
        /// Allocate links for each of the tile's polygons' vertices
        /// </summary>
        /// <param name="tile">A tile contains a set of polygons, which are linked to each other</param>
        public void ConnectIntLinks(ref MeshTile tile)
        {
            if (tile == null)
            {
                return;
            }

            PolyId polyBase = GetPolyRefBase(tile);

            //Iterate through all the polygons
            for (int i = 0; i < tile.Header.PolyCount; i++)
            {
                //The polygon links will end in a null link
                tile.Polys[i].FirstLink = Link.Null;

                //Avoid Off-Mesh Connection polygons
                if (tile.Polys[i].PolyType == PolygonType.OffMeshConnection)
                {
                    continue;
                }

                //Build edge links
                for (int j = tile.Polys[i].VertCount - 1; j >= 0; j--)
                {
                    //Skip hard and non-internal edges
                    if (tile.Polys[i].Neis[j] == 0 || IsExternalLink(tile.Polys[i].Neis[j]))
                    {
                        continue;
                    }

                    //Allocate a new link if possible
                    int idx = AllocLink(tile);

                    //Allocation of link should be successful
                    if (IsLinkAllocated(idx))
                    {
                        //Initialize a new link
                        PolyId id;
                        PolyId.SetPolyIndex(ref polyBase, tile.Polys[i].Neis[j] - 1, out id);
                        tile.Links[idx].Reference = id;
                        tile.Links[idx].Edge      = j;
                        tile.Links[idx].Side      = BoundarySide.Internal;
                        tile.Links[idx].BMin      = tile.Links[idx].BMax = 0;

                        //Add to polygon's links list
                        tile.Links[idx].Next    = tile.Polys[i].FirstLink;
                        tile.Polys[i].FirstLink = idx;
                    }
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Find all the polygons within a certain bounding box.
        /// </summary>
        /// <param name="tile">Current tile</param>
        /// <param name="qbounds">The bounds</param>
        /// <param name="polys">List of polygons</param>
        /// <returns>Number of polygons found</returns>
        public int QueryPolygonsInTile(MeshTile tile, BBox3 qbounds, List <PolyId> polys)
        {
            if (tile.BVTree.Count != 0)
            {
                int     node  = 0;
                int     end   = tile.Header.BvNodeCount;
                Vector3 tbmin = tile.Header.Bounds.Min;
                Vector3 tbmax = tile.Header.Bounds.Max;

                //Clamp query box to world box
                Vector3    qbmin = qbounds.Min;
                Vector3    qbmax = qbounds.Max;
                PolyBounds b;
                float      bminx = MathHelper.Clamp(qbmin.X, tbmin.X, tbmax.X) - tbmin.X;
                float      bminy = MathHelper.Clamp(qbmin.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
                float      bminz = MathHelper.Clamp(qbmin.Z, tbmin.Z, tbmax.Z) - tbmin.Z;
                float      bmaxx = MathHelper.Clamp(qbmax.X, tbmin.X, tbmax.X) - tbmin.X;
                float      bmaxy = MathHelper.Clamp(qbmax.Y, tbmin.Y, tbmax.Y) - tbmin.Y;
                float      bmaxz = MathHelper.Clamp(qbmax.Z, tbmin.Z, tbmax.Z) - tbmin.Z;

                const int MinMask = unchecked ((int)0xfffffffe);

                b.Min.X = (int)(bminx * tile.Header.BvQuantFactor) & MinMask;
                b.Min.Y = (int)(bminy * tile.Header.BvQuantFactor) & MinMask;
                b.Min.Z = (int)(bminz * tile.Header.BvQuantFactor) & MinMask;
                b.Max.X = (int)(bmaxx * tile.Header.BvQuantFactor + 1) | 1;
                b.Max.Y = (int)(bmaxy * tile.Header.BvQuantFactor + 1) | 1;
                b.Max.Z = (int)(bmaxz * tile.Header.BvQuantFactor + 1) | 1;

                //traverse tree
                PolyId polyBase = GetPolyRefBase(tile);

                while (node < end)
                {
                    BVTree.Node bvNode     = tile.BVTree[node];
                    bool        overlap    = PolyBounds.Overlapping(ref b, ref bvNode.Bounds);
                    bool        isLeafNode = bvNode.Index >= 0;

                    if (isLeafNode && overlap)
                    {
                        if (polys.Count < polys.Capacity)
                        {
                            PolyId polyRef;
                            PolyId.SetPolyIndex(ref polyBase, bvNode.Index, out polyRef);
                            polys.Add(polyRef);
                        }
                    }

                    if (overlap || isLeafNode)
                    {
                        node++;
                    }
                    else
                    {
                        int escapeIndex = -bvNode.Index;
                        node += escapeIndex;
                    }
                }

                return(polys.Count);
            }
            else
            {
                BBox3  b;
                PolyId polyBase = GetPolyRefBase(tile);

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

                    //don't return off-mesh connection polygons
                    if (poly.PolyType == PolygonType.OffMeshConnection)
                    {
                        continue;
                    }

                    //calculate polygon bounds
                    b.Max = b.Min = tile.Verts[poly.Verts[0]];
                    for (int j = 1; j < poly.VertCount; j++)
                    {
                        Vector3 v = tile.Verts[poly.Verts[j]];
                        Vector3Extensions.ComponentMin(ref b.Min, ref v, out b.Min);
                        Vector3Extensions.ComponentMax(ref b.Max, ref v, out b.Max);
                    }

                    if (BBox3.Overlapping(ref qbounds, ref b))
                    {
                        if (polys.Count < polys.Capacity)
                        {
                            PolyId polyRef;
                            PolyId.SetPolyIndex(ref polyBase, i, out polyRef);
                            polys.Add(polyRef);
                        }
                    }
                }

                return(polys.Count);
            }
        }
Ejemplo n.º 3
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 <PolyId> 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;

            PolyId 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));

                        PolyId id;
                        PolyId.SetPolyIndex(ref polyBase, i, out id);
                        con.Add(id);
                    }

                    break;
                }
            }
        }
Ejemplo n.º 4
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;
                    }
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Begin creating off-mesh links between the tile polygons.
        /// </summary>
        /// <param name="tile">Current Tile</param>
        public void BaseOffMeshLinks(ref MeshTile tile)
        {
            if (tile == null)
            {
                return;
            }

            PolyId polyBase = GetPolyRefBase(tile);

            //Base off-mesh connection start points
            for (int i = 0; i < tile.Header.OffMeshConCount; i++)
            {
                int con  = i;
                int poly = tile.OffMeshConnections[con].Poly;

                Vector3 extents = new Vector3(tile.OffMeshConnections[con].Radius, tile.Header.WalkableClimb, tile.OffMeshConnections[con].Radius);

                //Find polygon to connect to
                Vector3 p         = tile.OffMeshConnections[con].Pos0;
                Vector3 nearestPt = new Vector3();
                PolyId  reference = FindNearestPolyInTile(tile, p, extents, ref nearestPt);
                if (reference == PolyId.Null)
                {
                    continue;
                }

                //Do extra checks
                if ((nearestPt.X - p.X) * (nearestPt.X - p.X) + (nearestPt.Z - p.Z) * (nearestPt.Z - p.Z) >
                    tile.OffMeshConnections[con].Radius * tile.OffMeshConnections[con].Radius)
                {
                    continue;
                }

                //Make sure location is on current mesh
                tile.Verts[tile.Polys[poly].Verts[0]] = nearestPt;

                //Link off-mesh connection to target poly
                int idx = AllocLink(tile);
                if (IsLinkAllocated(idx))
                {
                    //Initialize a new link
                    tile.Links[idx].Reference = reference;
                    tile.Links[idx].Edge      = 0;
                    tile.Links[idx].Side      = BoundarySide.Internal;
                    tile.Links[idx].BMin      = tile.Links[idx].BMax = 0;

                    //Add to polygon's links list
                    tile.Links[idx].Next       = tile.Polys[poly].FirstLink;
                    tile.Polys[poly].FirstLink = idx;
                }

                //Start end-point always conects back to off-mesh connection
                int tidx = AllocLink(tile);
                if (IsLinkAllocated(tidx))
                {
                    //Initialize a new link
                    int    landPolyIdx = reference.DecodePolyIndex(polyBits);
                    PolyId id;
                    PolyId.SetPolyIndex(ref polyBase, tile.OffMeshConnections[con].Poly, out id);
                    tile.Links[idx].Reference = id;
                    tile.Links[idx].Edge      = 0xff;
                    tile.Links[idx].Side      = BoundarySide.Internal;
                    tile.Links[idx].BMin      = tile.Links[idx].BMax = 0;

                    //Add to polygon's links list
                    tile.Links[idx].Next = tile.Polys[landPolyIdx].FirstLink;
                    tile.Polys[landPolyIdx].FirstLink = tidx;
                }
            }
        }