Example #1
0
        public bool QueueTask(BuildContext context
            , int tx, int tz
            , PolyMesh polyMesh, PolyMeshDetail detailMesh
            , bool bvTreeEnabled
            , int priority)
        {
            TileBuildTask task = TileBuildTask.Create(tx, tz
                , polyMesh.GetData(false)
                , (detailMesh == null ? null : detailMesh.GetData(true))
                , Build.Connections
                , bvTreeEnabled
                , true
                , priority);

            if (!mTaskProcessor.QueueTask(task))
            {
                context.LogError("Task processor rejected task.", this);
                return false;
            }

            mTileTasks.Add(task);

            return true;
        }
Example #2
0
 /// <summary>
 /// Erodes the walkable area within the heightfield by the specified radius.
 /// </summary>
 /// <remarks>
 /// <para>
 /// Basically, any spans that are closer to a boundary or obstruction than the specified 
 /// radius are marked as unwalkable.
 /// </para>
 /// <para>
 /// This method is usually called immediately after the heightfield has been created.
 /// </para>
 /// </remarks>
 /// <param name="context">The context to use during the operation. </param>
 /// <param name="radius">The radius to apply. [Units: Spans]</param>
 /// <returns>True if the operation completed successfully.</returns>
 public bool ErodeWalkableArea(BuildContext context, int radius)
 {
     if (IsDisposed)
         return false;
     return CompactHeightfieldEx.nmcfErodeWalkableArea(context.root
         , radius
         , this);
 }
        /// <summary>
        /// Builds a detail mesh from the provided polygon mesh.
        /// </summary>
        /// <param name="context">The context to use for the operation.</param>
        /// <param name="polyMesh">The source polygon mesh.</param>
        /// <param name="field">The compact heightfield used to build the polygon mesh.</param>
        /// <param name="detailSampleDistance">
        /// The sample distance to use when sampling the surface height of the polygon mesh.
        /// </param>
        /// <param name="detailMaxDeviation">
        /// The maximum the surface of the detail mesh should deviate from the heightfield data.
        /// </param>
        /// <returns>A new detail mesh, or null on error.</returns>
        public static PolyMeshDetail Build(BuildContext context
            , PolyMesh polyMesh, CompactHeightfield field
            , float detailSampleDistance, float detailMaxDeviation)
        {
            if (context == null || polyMesh == null || polyMesh.IsDisposed
                || field == null || field.IsDisposed
                || detailSampleDistance < 0
                || detailMaxDeviation < 0)
            {
                return null;
            }

            PolyMeshDetail result = new PolyMeshDetail(AllocType.External);

            if (PolyMeshDetailEx.rcpdBuildPolyMeshDetail(context.root
                , ref polyMesh.root
                , field
                , detailSampleDistance
                , detailMaxDeviation
                , result))
            {
                return result;
            }

            return null;
        }
Example #4
0
        /// <summary>
        /// Builds a contour set from the region outlines in the provided <see cref="CompactHeightfield"/>.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The raw contours will match the region outlines exactly.  The edgeMaxDeviation 
        /// and maxEdgeLength parameters control how closely the simplified contours will match 
        /// the raw contours.
        /// </para>
        /// <para>
        /// Simplified contours are generated such that the vertices for portals between areas 
        /// match up.  (They are considered mandatory vertices.)
        /// </para>
        /// <para>
        /// Setting maxEdgeLength to zero will disabled the feature.
        /// </para>
        /// </remarks>
        /// <param name="context">The context to use for the build.</param>
        /// <param name="field">The field to use for the build.(Must have region data.)</param>
        /// <param name="edgeMaxDeviation">
        /// The maximum distance a simplified edge may deviate from the raw contour's vertices.
        /// [Limit: >= 0]
        /// </param>
        /// <param name="maxEdgeLength">
        /// The maximum allowed length of a simplified edge. [Limit: >= 0]
        /// </param>
        /// <param name="flags">The build flags.</param>
        /// <returns>The contour set, or null on failure.</returns>
        public static ContourSet Build(BuildContext context, CompactHeightfield field
            , float edgeMaxDeviation, int maxEdgeLength, ContourBuildFlags flags)
        {
            if (context == null || field == null || field.IsDisposed
                || edgeMaxDeviation < 0
                || maxEdgeLength < 0)
            {
                return null;
            }

            ContourSetEx root = new ContourSetEx();

            if (ContourSetEx.nmcsBuildSet(context.root, field
                , edgeMaxDeviation, maxEdgeLength
                , root
                , flags))
            {
                return new ContourSet(root);
            }

            return null;
        }
Example #5
0
 /// <summary>
 /// Builds the distance field for the heightfield.
 /// </summary>
 /// <remarks>
 /// <para>
 /// This method must be called before attempting to build region data.
 /// </para>
 /// <para>
 /// The distance data is avaiable via <see cref="MaxDistance"/> and 
 /// <see cref="GetDistanceData"/>.
 /// </para>
 /// </remarks>
 /// <param name="context">The context to use duing the operation.</param>
 /// <returns>True if the operation completed successfully.</returns>
 public bool BuildDistanceField(BuildContext context)
 {
     if (IsDisposed)
         return false;
     return CompactHeightfieldEx.nmcfBuildDistanceField(context.root, this);
 }
Example #6
0
        /// <summary>
        /// Creates a compact open heightfield from a solid heightfield.
        /// </summary>
        /// <param name="context">The context to use duing the operation.</param>
        /// <param name="sourceField">
        /// The solid heighfield to derive the compact heightfield from.
        /// </param>
        /// <param name="walkableHeight">
        /// The minimum floor to ceiling height that is still considered walkable. 
        /// [Limit: >= <see cref="NMGen.MinWalkableHeight"/>]
        /// </param>
        /// <param name="walkableStep">
        /// The maximum floor to floor step that is still considered walkable.</param>
        /// <returns>True if the operation completed successfully.</returns>
        public static CompactHeightfield Build(BuildContext context
            , Heightfield sourceField
            , int walkableHeight
            , int walkableStep)
        {
            if (context == null
                || sourceField == null || sourceField.IsDisposed
                || walkableHeight < NMGen.MinWalkableHeight
                || walkableStep < 0)
            {
                return null;
            }

            CompactHeightfield field = new CompactHeightfield();

            if (CompactHeightfieldEx.nmcfBuildField(context.root
                , walkableHeight
                , walkableStep
                , sourceField.root
                , field))
            {
                return field;
            }

            return null;
        }
Example #7
0
        /// <summary>
        /// Voxelizes the triangles in the provided mesh into the heightfield.
        /// </summary>
        /// <param name="context">The context to use for the operation</param>
        /// <param name="mesh">The triangle mesh.</param>
        /// <param name="areas">
        /// The ids of the areas the triangles belong to. 
        /// [Limit: &lt;= <see cref="NMGen.MaxArea"/>] [Size: >= mesh.triCount]
        /// </param>
        /// <param name="flagMergeThreshold">
        /// The distance where the walkable flag is favored over the non-walkable flag. 
        /// [Limit: >= 0] [Normal: 1]
        /// </param>
        /// <returns>True if the operation was successful.</returns>
        public bool AddTriangles(BuildContext context, TriangleMesh mesh, byte[] areas
            , int flagMergeThreshold)
        {
            if (IsDisposed)
                return false;

            return HeightfieldEx.nmhfRasterizeTriMesh(context.root
                , mesh.verts
                , mesh.vertCount
                , mesh.tris
                , areas
                , mesh.triCount
                , root
                , flagMergeThreshold);
        }
Example #8
0
 /// <summary>
 /// Applies the area to the all spans within the specified convex polygon.
 /// </summary>
 /// <remarks>
 /// <para>
 /// The y-values of the polygon vertices are ignored.  So the polygon is effectively 
 /// projected onto the xz-plane at yMin, then extruded to yMax.
 /// </para>
 /// <para>
 /// The method will return false if the polygon is completely outside of the heightfield.
 /// </para>
 /// </remarks>
 /// <param name="context">The context to use duing the operation.</param>
 /// <param name="verts">The vertices of the polygon [Length: vertCount]</param>
 /// <param name="yMin">The height of the base of the polygon.</param>
 /// <param name="yMax">The height of the top of the polygon.</param>
 /// <param name="area">The area to apply.</param>
 /// <returns>True if the operation completed successfully.</returns>
 public bool MarkConvexPolyArea(BuildContext context
     , Vector3[] verts, float yMin, float yMax
     , byte area)
 {
     if (IsDisposed)
         return false;
     return CompactHeightfieldEx.nmcfMarkConvexPolyArea(context.root
         , verts
         , verts.Length
         , yMin
         , yMax
         , area
         , this);
 }
Example #9
0
        /// <summary>
        /// Marks non-walkable spans as walkable if their maximum is within walkableStep of a 
        /// walkable neighbor.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Example of test: <c>Math.Abs(currentSpan.Max - neighborSpan.Max) &lt; walkableStep</c>
        /// </para>
        /// <para
        /// >Allows the formation of walkable regions that will flow over low lying objects such 
        /// as curbs, and up structures such as stairways.
        /// </para>
        /// </remarks>
        /// <param name="context">The context to use for the operation</param>
        /// <param name="walkableStep">
        /// The maximum allowed difference between span maximum's for the step to be considered 
        /// waklable. [Limit: > 0]
        /// </param>
        /// <returns>True if the operation was successful.</returns>
        public bool MarkLowObstaclesWalkable(BuildContext context, int walkableStep)
        {
            if (IsDisposed)
                return false;

            return HeightfieldEx.nmhfFilterLowHangingWalkableObstacles(context.root
                , walkableStep
                , root);
        }
Example #10
0
        /// <summary>
        /// Marks walkable spans as not walkable if the clearence above the span is less than the 
        /// specified height.
        /// </summary>
        /// <remarks>
        /// <para>
        /// For this method, the clearance above the span is the distance from the span's maximum 
        /// to the next higher span's minimum. (Same column.)
        /// </para>
        /// </remarks>
        /// <param name="context">The context to use for the operation</param>
        /// <param name="walkableHeight">
        /// The maximum allowed floor to ceiling height that is considered still walkable.
        /// [Limit: > <see cref="NMGen.MinWalkableHeight"/>]
        /// </param>
        /// <returns>True if the operation was successful.</returns>
        public bool MarkLowHeightSpansNotWalkable(BuildContext context, int walkableHeight)
        {
            if (IsDisposed)
                return false;

            return HeightfieldEx.nmhfFilterWalkableLowHeightSpans(context.root
                , walkableHeight
                , root);
        }
        /// <summary>
        /// Creates a standard <see cref="NavmeshTileBuildData"/> object from the provided
        /// parameters.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Errors will be logged to the build context.
        /// </para>
        /// </remarks>
        /// <param name="tx">The x-index of the tile.</param>
        /// <param name="tz">The z-index of the tile.</param>
        /// <param name="polyMesh">The polygon mesh data.</param>
        /// <param name="detailMesh">The detail mesh data. (Optional)</param>
        /// <param name="connections">The off-mesh connections. (Null allowed.)</param>
        /// <param name="bvTreeEnabled">True if bounding volumes should be generated.</param>
        /// <param name="context">The build context.</param>
        /// <returns>The tile build data, or null on error.</returns>
        public static NavmeshTileBuildData GetBuildData(BuildContext context
            , int tx, int tz
            , PolyMeshData polyMesh, PolyMeshDetailData detailMesh
            , ConnectionSet connections
            , bool bvTreeEnabled)
        {
            if (context == null)
                // Silent.
                return null;

            Vector3[] verts = null;
            float[] radii = null;
            byte[] dirs = null;
            byte[] areas = null;
            ushort[] flags = null;
            uint[] userIds = null;

            Vector3 bmin = polyMesh.boundsMin;
            Vector3 bmax = polyMesh.boundsMax;

            int connCount = (connections == null)
                ? 0
                : connections.GetConnections(bmin.x, bmin.z, bmax.x, bmax.z
                    , out verts, out radii, out dirs, out areas, out flags, out userIds);

            NavmeshTileBuildData result = new NavmeshTileBuildData(
                    polyMesh.vertCount
                    , polyMesh.polyCount
                    , polyMesh.maxVertsPerPoly
                    , (detailMesh == null ? 0 : detailMesh.vertCount)
                    , (detailMesh == null ? 0 : detailMesh.triCount)
                    , connCount);

            if (!result.LoadBase(tx, tz, 0, 0
                , polyMesh.boundsMin
                , polyMesh.boundsMax
                , polyMesh.xzCellSize
                , polyMesh.yCellSize
                , polyMesh.walkableHeight
                , polyMesh.walkableRadius
                , polyMesh.walkableStep
                , bvTreeEnabled))
            {
                context.LogError("Base data load failed. Bad configuration data or internal error."
                    , null);
                return null;
            }

            if (!result.LoadPolys(polyMesh.verts
                , polyMesh.vertCount
                , polyMesh.polys
                , polyMesh.flags
                , polyMesh.areas
                , polyMesh.polyCount))
            {
                context.LogError("Polygon load failed. Bad mesh data or internal error.", null);
                return null;
            }

            if (detailMesh != null)
            {
                if (!result.LoadDetail(detailMesh.verts
                    , detailMesh.vertCount
                    , detailMesh.tris
                    , detailMesh.triCount
                    , detailMesh.meshes
                    , detailMesh.meshCount))
                {
                    context.LogError("Detail load failed. Bad mesh data or internal error.", null);
                    return null;
                }
            }

            if (connCount > 0)
            {
                if (!result.LoadConns(verts, radii, dirs, areas, flags, userIds, connCount))
                {
                    context.LogError("Off-mesh connection load failed. Bad data or internal error."
                        , null);
                    return null;
                }
            }

            return result;
        }
Example #12
0
        /// <summary>
        /// Builds polygon mesh from the provided contours.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The values of the CellSize-based parameters will be converted to world units.
        /// </para>
        /// </remarks>
        /// <param name="context">The context to use for the operation.</param>
        /// <param name="contours">The contours to use to build the mesh.</param>
        /// <param name="maxVertsPerPoly">
        /// The maximum allowed vertices for a polygon. 
        /// [Limits: 3 &lt;= value &lt;= <see cref="NMGen.MaxAllowedVertsPerPoly"/>]
        /// </param>
        /// <param name="walkableHeight">
        /// The walkable height used to build the contour data. 
        /// [Limit: >= <see cref="NMGen.MinWalkableHeight"/>] [Units: YCellSize]
        /// </param>
        /// <param name="walkableRadius">
        /// The radius used to erode the walkable area covered by the contours. 
        /// [Limit: >= 0] [Units: XZCellSize]
        /// </param>
        /// <param name="walkableStep">
        /// The walkable step used to build
        /// the contour data. [Limit: >= 0] [Units: YCellSize]</param>
        /// <returns>The generated polygon mesh, or null if there were errors.</returns>
        public static PolyMesh Build(BuildContext context, ContourSet contours
            , int maxVertsPerPoly, int walkableHeight, int walkableRadius, int walkableStep)
        {
            if (context == null || contours == null)
                return null;

            PolyMesh result = new PolyMesh(AllocType.External);

            if (!PolyMeshEx.rcpmBuildFromContourSet(context.root
                , contours.root
                , maxVertsPerPoly
                , ref result.root
                , ref result.mMaxVerts))
            {
                return null;
            }

            result.mWalkableHeight = walkableHeight * contours.YCellSize;
            result.mWalkableRadius = walkableRadius * contours.XZCellSize;
            result.mWalkableStep = walkableStep * contours.YCellSize;
            
            return result;
        }
        /// <summary>
        /// Creates a builder.
        /// </summary>
        /// <remarks>
        /// <para>
        /// No validation is performed and the builder will use the parameters directly
        /// during the build.
        /// </para>
        /// <para>
        /// Builders created using this method are not guarenteed to produce a usable result.
        /// </para>
        /// <para>
        /// It is the responsibility of the caller to ensure thread safely if 
        /// <paramref name="isThreadSafe"/> is set to true.
        /// </para>
        /// <para>
        /// <b>Warning:</b> If walkable slope if greather than zero then the builder will
        /// apply <see cref="NMGen.ClearUnwalkableTriangles"/> directly to the areas parameter.
        /// </para>
        /// </remarks>
        /// <param name="mesh">The triangle mesh to use for the build.</param>
        /// <param name="areas">The triangle areas. (Null not permitted.)</param>
        /// <param name="walkableSlope">The walkable slope. 
        /// (See <see cref="NMGenParams.WalkableSlope"/>)</param>
        /// <param name="isThreadSafe">True if the builder can run safely on its own thread.</param>
        /// <returns>A builder, or null on error.</returns>
        public static InputGeometryBuilder UnsafeCreate(TriangleMesh mesh
            , byte[] areas
            , float walkableSlope
            , bool isThreadSafe)
        {
            if (mesh == null || areas == null || mesh.triCount < 0)
                return null;

            walkableSlope = System.Math.Min(NMGen.MaxAllowedSlope, walkableSlope);

            if (walkableSlope > 0)
            {
                BuildContext context = new BuildContext();
                if (!NMGen.ClearUnwalkableTriangles(context, mesh, walkableSlope, areas))
                    return null;
            }

            ChunkyTriMeshBuilder builder = ChunkyTriMeshBuilder.Create(mesh, areas, 32768);

            if (builder == null)
                return null;

            Vector3 bmin;
            Vector3 bmax;
            mesh.GetBounds(out bmin, out bmax);

            return new InputGeometryBuilder(builder, bmin, bmax, isThreadSafe);
        }
Example #14
0
 /// <summary>
 /// Applies a median filter to the walkable areas. (Removes noise.)
 /// </summary>
 /// <param name="context">The context to use duing the operation. </param>
 /// <returns>True if the operation completed successfully.</returns>
 public bool ApplyMedianFilter(BuildContext context)
 {
     if (IsDisposed)
         return false;
     return CompactHeightfieldEx.nmcfMedianFilterWalkableArea(context.root, this);
 }
Example #15
0
        /// <summary>
        /// Voxelizes the triangles from the provided <see cref="ChunkyTriMesh"/> into the 
        /// heightfield.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The chunks that are voxelized is controled by the bounds parameters.
        /// </para>
        /// </remarks>
        /// <param name="context">The build context.</param>
        /// <param name="mesh">The mesh.</param>
        /// <param name="boundsMin">The minimum bounds for the mesh query.</param>
        /// <param name="boundsMax">The maximum bounds for the mesh query.</param>
        /// <param name="flagMergeThreshold">
        /// The distance where the walkable flag is favored over the non-walkable flag. 
        /// [Limit: >= 0] [Normal: 1]
        /// </param>
        /// <returns>True if the operation was successful.</returns>
        public bool AddTriangles(BuildContext context, ChunkyTriMesh mesh
            , Vector3 boundsMin, Vector3 boundsMax
            , int flagMergeThreshold)
        {
            if (IsDisposed || mesh == null || mesh.IsDisposed)
                return false;

            List<ChunkyTriMeshNode> nodeList = new List<ChunkyTriMeshNode>();
            
            int triCount =  mesh.GetChunks(boundsMin.x, boundsMin.z
                , boundsMax.x, boundsMax.z
                , nodeList);

            if (triCount == 0)
                return true;

            return HeightfieldEx.nmhfRasterizeNodes(context.root
                , mesh.verts
                , mesh.tris
                , mesh.areas
                , nodeList.ToArray()
                , nodeList.Count
                , root
                , flagMergeThreshold);
        }
Example #16
0
        /// <summary>
        /// Applies the area to all spans within the specified bounding box. (AABB)
        /// </summary>
        /// <remarks>
        /// <para>
        /// The method will return false if the AABB is completely outside of the heightfield.
        /// </para>
        /// </remarks>
        /// <param name="context">The context to use duing the operation.</param>
        /// <param name="boundsMin">The minimum bounds of the AABB.</param>
        /// <param name="boundsMax">The maximum bounds of the AABB. </param>
        /// <param name="area">The area to apply.</param>
        /// <returns>True if the operation completed successfully.</returns>
        public bool MarkBoxArea(BuildContext context
            , Vector3 boundsMin, Vector3 boundsMax
            , byte area)
        {
            if (IsDisposed)
                return false;

            return CompactHeightfieldEx.nmcfMarkBoxArea(context.root
                , ref boundsMin
                , ref boundsMax
                , area
                , this);
        }
Example #17
0
        /// <summary>
        /// Voxelizes the provided triangles into the heightfield.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Unlike many other methods in the library, the arrays must be sized exactly to the 
        /// content.  If you need to pass buffers, use the method that takes a 
        /// <see cref="TriangleMesh"/> object.
        /// </para>
        /// </remarks>
        /// <param name="context">The context to use for the operation</param>
        /// <param name="verts">The vertices. [Length: >= vertCount] (No buffering allowed.)</param>
        /// <param name="tris">
        /// The triangles. [(vertAIndex, vertBIndex, vertCIndex) * triCount]
        /// </param>
        /// <param name="areas">
        /// The ids of the areas the triangles belong to. 
        /// [Limit: &lt;= <see cref="NMGen.MaxArea"/>] [Size: >= triCount]
        /// </param>
        /// <param name="flagMergeThreshold">
        /// The distance where the walkable flag is favored over the non-walkable flag. 
        /// [Limit: >= 0] [Normal: 1]
        /// </param>
        /// <returns>True if the operation was successful.</returns>
        public bool AddTriangles(BuildContext context
            , Vector3[] verts, ushort[] tris, byte[] areas
            , int flagMergeThreshold)
        {
            if (IsDisposed)
                return false;

            return HeightfieldEx.nmhfRasterizeTriMeshShort(context.root
                , verts
                , verts.Length / 3
                , tris
                , areas
                , tris.Length / 3
                , root
                , flagMergeThreshold);
        }
Example #18
0
 /// <summary>
 /// Applied the area to all spans within the specified cylinder.
 /// </summary>
 /// <remarks>
 /// <para>
 /// The method will return false if the cylinder is completely outside of the heightfield.
 /// </para>
 /// </remarks>
 /// <param name="context">The context to use duing the operation.</param>
 /// <param name="centerBase">The center of the base of the cylinder.</param>
 /// <param name="radius">The radius of the cylinder.</param>
 /// <param name="height">The height of the cylinder.</param>
 /// <param name="area">The area to apply.</param>
 /// <returns>True if the operation completed successfully.</returns>
 public bool MarkCylinderArea(BuildContext context
     , Vector3 centerBase, float radius, float height
     , byte area)
 {
     if (IsDisposed)
         return false;
     return CompactHeightfieldEx.nmcfMarkCylinderArea(context.root
         , ref centerBase
         , radius
         , height
         , area
         , this);
 }
Example #19
0
        /// <summary>
        /// Voxelizes the provided triangles into the heightfield.
        /// </summary>
        /// <param name="context">The context to use for the operation</param>
        /// <param name="verts">The triangles. [(vertA, vertB, vertC) * triCount]</param>
        /// <param name="areas">
        /// The ids of the areas the triangles belong to.
        /// [Limit: &lt;= <see cref="NMGen.MaxArea"/>] [Size: >= triCount]
        /// </param>
        /// <param name="triCount">The number of triangles in the vertex array.</param>
        /// <param name="flagMergeThreshold">
        /// The distance where the walkable flag is favored over the non-walkable flag. 
        /// [Limit: >= 0] [Normal: 1]
        /// </param>
        /// <returns>True if the operation was successful.</returns>
        public bool AddTriangles(BuildContext context
            , Vector3[] verts, byte[] areas, int triCount
            , int flagMergeThreshold)
        {
            if (IsDisposed)
                return false;

            return HeightfieldEx.nmhfRasterizeTriangles(context.root
                , verts, areas, triCount
                , root
                , flagMergeThreshold);
        }
Example #20
0
        /// <summary>
        /// Builds region data for the heightfield using simple monotone partitioning.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Non-null regions consist of connected, non-overlapping walkable spans that form a 
        /// single contour.
        /// </para>
        /// <para>
        /// The region data is available via <see cref="MaxRegion"/> and <see cref="GetSpanData"/>.
        /// </para>
        /// <para>
        /// If a region forms an area that is smaller than <paramref name="minRegionArea"/>, 
        /// all spans in the region is set to <see cref="NMGen.NullRegion"/>.
        /// </para>
        /// <para>
        /// Partitioning can result in smaller than necessary regions, especially 
        /// in diagonal corridors.  <paramref name="mergeRegionArea"/> helps reduce unecessarily 
        /// small regions.
        /// </para>
        /// </remarks>
        /// <param name="context">The context to use duing the operation.</param>
        /// <param name="borderSize">The AABB border size to apply.</param>
        /// <param name="minRegionArea">
        /// The minimum area allowed for unconnected (island) regions. [Units: Spans]
        /// </param>
        /// <param name="mergeRegionArea">
        /// The maximum region size that will be considered for merging with another region.
        /// [Units: Spans]
        /// </param>
        /// <returns>True if the operation completed successfully.</returns>
        public bool BuildRegionsMonotone(BuildContext context
            , int borderSize, int minRegionArea, int mergeRegionArea)
        {
            if (IsDisposed)
                return false;

            return CompactHeightfieldEx.nmcfBuildRegionsMonotone(context.root
                , this
                , borderSize
                , minRegionArea
                , mergeRegionArea);
        }
        /// <summary>
        /// Appends messages from the specified context to the current context.
        /// </summary>
        /// <param name="fromContext">The context to append the messages from.</param>
        public void AppendMessages(BuildContext fromContext)
        {
            if (fromContext == null || fromContext.MessageCount == 0)
                return;

            string[] msgs = fromContext.GetMessages();
            foreach (string msg in msgs)
            {
                BuildContextEx.nmbcLog(root, msg);
            }
        }
Example #22
0
        /// <summary>
        /// Set the area of all triangles with a slope below the specified value to 
        /// <see cref="MaxArea"/>.
        /// </summary>
        /// <param name="context">The context to use duing the operation.</param>
        /// <param name="mesh">The source mesh.</param>
        /// <param name="walkableSlope">The maximum walkable slope.</param>
        /// <param name="areas">
        /// The areas associated with each triangle. [Length: >= mesh.triCount] (In/Out)
        /// </param>
        /// <returns>True if the operation was successful.</returns>
        public static bool MarkWalkableTriangles(BuildContext context, TriangleMesh mesh
            , float walkableSlope
            , byte[] areas)
        {
            if (mesh == null
                || context == null
                || areas == null || areas.Length < mesh.triCount)
            {
                return false;
            }

            NMGenEx.nmgMarkWalkableTriangles(context.root
                , walkableSlope
                , mesh.verts
                , mesh.vertCount
                , mesh.tris
                , mesh.triCount
                , areas);

            return true;
        }
 /// <summary>
 /// Tests the operation of the context by adding up to 100 test messages.
 /// </summary>
 /// <remarks>
 /// <para>
 /// The only purpose of this method is to permit testing.</para>
 /// </remarks>
 /// <param name="context">The context to test.</param>
 /// <param name="count">The number of messages to add. (Limit &lt;100)</param>
 public static void LoadTestMessages(BuildContext context, int count)
 {
     if (context != null)
         BuildContextEx.nmgTestContext(context.root, Math.Min(100, count));
 }
Example #24
0
        /// <summary>
        /// Builds a layer set from the <see cref="CompactHeightfield"/>.
        /// </summary>
        /// <param name="context">The context to use duing the operation.</param>
        /// <param name="field">The source field.</param>
        /// <returns>The resulting layer set, or null on failure.</returns>
        public static HeightfieldLayerSet Build(BuildContext context, CompactHeightfield field)
        {
            if (context == null)
                return null;

            IntPtr ptr = IntPtr.Zero;
            
            int layerCount = HeightfieldLayserSetEx.nmlsBuildLayers(context.root
                , field
                , field.BorderSize
                , field.WalkableHeight
                , ref ptr);

            if (ptr == IntPtr.Zero)
                return null;

            return new HeightfieldLayerSet(ptr, layerCount);
        }
Example #25
0
        public bool QueueTask(int tx, int tz, int priority, BuildContext logger)
        {
            // Check for existing task and purge it.

            NavmeshBuild build = Build;

            if (!build)
                return false;

            TileBuildData tdata = build.BuildData;

            if (build.TileSetDefinition == null && (tx > 0 || tz > 0))
            {
                logger.LogError("Tile build requested, but no tile set found.", this);
                return false;
            }

            if (AbortRequest(tx, tz, "Overriden by new task."))
            {
                tdata.ClearUnbaked(tx, tz);

                logger.LogWarning(string.Format(
                    "Existing build task overridden by new task. ({0}, {1})"
                        , tx, tz), this);
            }

            IncrementalBuilder builder;
            NMGenConfig config = build.Config;

            if (build.TileSetDefinition == null)
            {
                InputGeometry geom = build.InputGeom;

                if (geom == null)
                {
                    logger.LogError("Input geometry not available.", this);
                    tdata.SetAsFailed(tx, tz);
                    return false;
                }

                builder = IncrementalBuilder.Create(config.GetConfig()
                    , config.ResultOptions
                    , geom
                    , build.NMGenProcessors);
            }
            else
            {
                builder = IncrementalBuilder.Create(tx, tz
                    , config.ResultOptions
                    , build.TileSetDefinition
                    , build.NMGenProcessors);
            }

            if (builder == null)
            {
                logger.LogError(string.Format("Tile set did not produce a builder. Tile: ({0},{1})"
                        , tx, tz)
                    , this);
                return false;
            }

            NMGenTask task = NMGenTask.Create(builder, priority);

            if (!mTaskProcessor.QueueTask(task))
            {
                logger.LogError(string.Format("Processor rejected task. Tile: ({0},{1})"
                        , tx, tz), this);
                return false;
            }
            
            mNMGenTasks.Add(task);
            tdata.SetAsQueued(tx, tz);

            return true;
        }