private void BuildContours()
        {
            ContourSet cset = ContourSet.Build(mBuildContext
                                               , mBuildContext.CompactField
                                               , mConfig.EdgeMaxDeviation
                                               , mConfig.MaxEdgeLength
                                               , mConfig.ContourOptions);

            if (cset == null)
            {
                FinalizeAbort("Aborted at contour set build.");
                return;
            }

            if (cset.Count < 1)
            {
                FinalizeNoResult("Completed after contour build. No useable contours generated.");
                return;
            }

            mBuildContext.Contours = cset;

            if (PostProcess() && PostContoursCheck() && PostCompactFieldCheck())
            {
                mBuildContext.Log("Built contour set. Contour count: " + cset.Count, this);
                mState = NMGenState.PolyMeshBuild;
            }
        }
        /// <summary>
        /// Returns human friendly text for the specified state.
        /// </summary>
        /// <param name="state">The state.</param>
        /// <returns>Human friendly text.</returns>
        public static string ToLabel(NMGenState state)
        {
            switch (state)
            {
            case NMGenState.Aborted:
                return("Aborted.");

            case NMGenState.CompactFieldBuild:
                return("Building compact heightfield.");

            case NMGenState.Complete:
                return("Complete");

            case NMGenState.ContourBuild:
                return("Building contours.");

            case NMGenState.DetailMeshBuild:
                return("Building detail mesh.");

            case NMGenState.HeightfieldBuild:
                return("Building heightfield.");

            case NMGenState.PolyMeshBuild:
                return("Building polygon mesh.");

            case NMGenState.RegionBuild:
                return("Building regions.");

            case NMGenState.NoResult:
                return("No result.");
            }
            return("Unhandled state: " + state);
        }
        private void FinalizeComplete()
        {
            if ((mResultOptions & NMGenAssetFlag.Heightfield) == 0 && mBuildContext.Heightfield != null)
            {
                mBuildContext.Heightfield.RequestDisposal();
                mBuildContext.Heightfield = null;
            }

            if ((mResultOptions & NMGenAssetFlag.CompactField) == 0 && mBuildContext.CompactField != null)
            {
                mBuildContext.CompactField.RequestDisposal();
                mBuildContext.CompactField = null;
            }

            if ((mResultOptions & NMGenAssetFlag.ContourSet) == 0 && mBuildContext.Contours != null)
            {
                mBuildContext.Contours.RequestDisposal();
                mBuildContext.Contours = null;
            }

            // Polymesh is always kept.

            if ((mResultOptions & NMGenAssetFlag.DetailMesh) == 0 && mBuildContext.DetailMesh != null)
            {
                mBuildContext.DetailMesh.RequestDisposal();
                mBuildContext.DetailMesh = null;
            }

            mBuildContext.Log("Build Complete. Result: " + mResultOptions, this);
            mState = NMGenState.Complete;
        }
Exemple #4
0
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The flags will be applied during the <see cref="NMGenState.PolyMeshBuild"/>
        /// state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.PolyMeshBuild)
            {
                return(true);
            }

            PolyMesh     mesh = context.PolyMesh;
            PolyMeshData data = mesh.GetData(false);

            if (data.polyCount == 0)
            {
                return(true);
            }

            bool applied = false;

            for (int i = 0; i < mAreas.Length; i++)
            {
                byte   area  = mAreas[i];
                ushort flags = mFlags[i];

                int marked = 0;

                for (int iPoly = 0; iPoly < data.polyCount; iPoly++)
                {
                    if (data.areas[iPoly] == area)
                    {
                        data.flags[iPoly] |= flags;
                        marked++;
                    }
                }

                if (marked > 0)
                {
                    string msg = string.Format(
                        "{0} : Added '0x{1:X}' flag(s) to {2} poylgons assigned to area {3}."
                        , Name, flags, marked, area);

                    context.Log(msg, this);

                    applied = true;
                }
            }

            if (applied)
            {
                mesh.Load(data);
            }
            else
            {
                context.Log(Name + ": No flags applied.", this);
            }

            return(true);
        }
Exemple #5
0
 /// <summary>
 /// Runs all the processors in order of priority.  (Ascending)
 /// </summary>
 /// <remarks>
 /// <para>
 /// A return value of false indicates the build should be aborted.
 /// </para>
 /// </remarks>
 /// <param name="state">The current state of the build.</param>
 /// <param name="context">The build context.</param>
 /// <returns>False if the build should abort.</returns>
 public bool Process(NMGenContext context, NMGenState state)
 {
     foreach (INMGenProcessor p in mProcessors)
     {
         if (!p.ProcessBuild(context, state))
         {
             return(false);
         }
     }
     return(true);
 }
        /// <summary>
        /// Performs a single build step.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The result state will represent either a finished state or the build step that
        /// will be performed during the next call to the method.
        /// </para>
        /// </remarks>
        /// <returns>The state at the end of the build step.</returns>
        public NMGenState Build()
        {
            switch (mState)
            {
            case NMGenState.Initialized:

                mBuildContext.Log("Build: " + mTileText, this);

                mProcessors.LogProcessors(mBuildContext);

                mState = NMGenState.HeightfieldBuild;

                break;

            case NMGenState.HeightfieldBuild:

                //UnityEngine.Debug.Log("hfb");
                BuildHeightfield();
                break;

            case NMGenState.CompactFieldBuild:

                //UnityEngine.Debug.Log("cfb");
                BuildCompactField();
                break;

            case NMGenState.RegionBuild:

                //UnityEngine.Debug.Log("rb");
                BuildRegions();
                break;

            case NMGenState.ContourBuild:

                //UnityEngine.Debug.Log("cb");
                BuildContours();
                break;

            case NMGenState.PolyMeshBuild:

                BuildPolyMesh();
                break;

            case NMGenState.DetailMeshBuild:

                BuildDetailMesh();
                break;
            }
            return(mState);
        }
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The flags will be applied during the <see cref="NMGenState.PolyMeshBuild"/>
        /// state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.PolyMeshBuild)
                return true;

            PolyMesh mesh = context.PolyMesh;
            PolyMeshData data = mesh.GetData(false);

            if (data.polyCount == 0)
                return true;

            bool applied = false;

            for (int i = 0; i < mAreas.Length; i++)
            {
                byte area = mAreas[i];
                ushort flags = mFlags[i];

                int marked = 0;

                for (int iPoly = 0; iPoly < data.polyCount; iPoly++)
                {
                    if (data.areas[iPoly] == area)
                    {
                        data.flags[iPoly] |= flags;
                        marked++;
                    }
                }

                if (marked > 0)
                {
                    string msg = string.Format(
                        "{0} : Added '0x{1:X}' flag(s) to {2} poylgons assigned to area {3}."
                        , Name, flags, marked, area);

                    context.Log(msg, this);

                    applied = true;
                }
            }

            if (applied)
                mesh.Load(data);
            else
                context.Log(Name + ": No flags applied.", this);

            return true;
        }
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Will be applied during the <see cref="NMGenState.HeightfieldBuild"/> state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.HeightfieldBuild)
                return true;

            if (context.Heightfield.MarkLowObstaclesWalkable(context
                , context.Config.WalkableStep))
            {
                context.Log(Name + ": Marked low obstacles as walklable.", this);
                return true;
            }

            context.Log(Name + ": Mark low obstacles failed.", this);
            return false;

        }
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Will be applied during the <see cref="NMGenState.HeightfieldBuild"/> state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {

            if (state != NMGenState.HeightfieldBuild)
                return true;

            if (context.Heightfield.MarkLowHeightSpansNotWalkable(context
                , context.Config.WalkableHeight))
            {
                context.Log(Name + ": Marked low height spans as not walklable.", this);
                return true;
            }

            context.Log(Name + ": Mark low height spans failed.", this);
            return false;
        }
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The area will be applied during the <see cref="NMGenState.CompactFieldBuild"/> state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.CompactFieldBuild)
                return true;

            if (context.CompactField.MarkBoxArea(context, mBoundsMin, mBoundsMax, Area))
            {
                context.Log(string.Format("{0} : Marked box area: Area: {1}, Priority: {2}"
                    , Name, Area, Priority)
                    , this);
                return true;
            }

            context.Log(Name + ": Failed to mark box area.", this);
            return false;
        }
        private void BuildCompactField()
        {
            Heightfield hf = mBuildContext.Heightfield;

            CompactHeightfield chf = CompactHeightfield.Build(mBuildContext
                                                              , hf
                                                              , mConfig.WalkableHeight
                                                              , mConfig.WalkableStep);

            if (CanDispose(NMGenAssetFlag.Heightfield))
            {
                hf.RequestDisposal();
                mBuildContext.Heightfield = null;
            }

            if (chf == null)
            {
                FinalizeAbort("Aborted at compact heightfield build.");
                return;
            }

            if (chf.SpanCount < 1)
            {
                FinalizeNoResult("Complete at compact heightfield build. No spans.");
                return;
            }

            mBuildContext.CompactField = chf;

            // Note: Post process is done before eroding the walkable area
            // so that the processors can stamp additional obstructions into
            // the heightfield.
            if (PostProcess() && PostCompactFieldCheck())
            {
                if (mConfig.WalkableRadius > 0)
                {
                    chf = mBuildContext.CompactField;
                    chf.ErodeWalkableArea(mBuildContext, mConfig.WalkableRadius);
                    mBuildContext.Log("Eroded walkable area by radius: " + mConfig.walkableRadius
                                      , this);
                }

                mBuildContext.Log("Built compact heightfield. Spans: " + chf.SpanCount, this);

                mState = NMGenState.RegionBuild;
            }
        }
Exemple #12
0
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Will be applied during the <see cref="NMGenState.HeightfieldBuild"/> state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.HeightfieldBuild)
            {
                return(true);
            }

            if (context.Heightfield.MarkLowObstaclesWalkable(context
                                                             , context.Config.WalkableStep))
            {
                context.Log(Name + ": Marked low obstacles as walklable.", this);
                return(true);
            }

            context.Log(Name + ": Mark low obstacles failed.", this);
            return(false);
        }
        private void BuildRegions()
        {
            CompactHeightfield chf = mBuildContext.CompactField;

            chf.BuildDistanceField(mBuildContext);
            mBuildContext.Log("Built distance field. Max Distance: " + chf.MaxDistance, this);

            if (mConfig.UseMonotone)
            {
                if (!chf.BuildRegionsMonotone(mBuildContext
                                              , mConfig.BorderSize
                                              , mConfig.MinRegionArea
                                              , mConfig.MergeRegionArea))
                {
                    FinalizeAbort("Monotone region generation failed.");
                    return;
                }
            }
            else
            {
                if (!chf.BuildRegions(mBuildContext
                                      , mConfig.BorderSize
                                      , mConfig.MinRegionArea
                                      , mConfig.MergeRegionArea))
                {
                    FinalizeAbort("Region generation failed.");
                    return;
                }
            }

            if (PostProcess() && PostCompactFieldCheck())
            {
                if (chf.MaxRegion < 2)
                {
                    // Null region counts as a region.  So expect
                    // at least 2.
                    FinalizeNoResult("Completed after region build. No useable regions formed.");
                    return;
                }

                mBuildContext.Log("Generated regions. Region Count: " + chf.MaxRegion, this);

                // Success.
                mState = NMGenState.ContourBuild;
            }
        }
Exemple #14
0
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// Will be applied during the <see cref="NMGenState.HeightfieldBuild"/> state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.HeightfieldBuild)
            {
                return(true);
            }

            if (context.Heightfield.MarkLowHeightSpansNotWalkable(context
                                                                  , context.Config.WalkableHeight))
            {
                context.Log(Name + ": Marked low height spans as not walklable.", this);
                return(true);
            }

            context.Log(Name + ": Mark low height spans failed.", this);
            return(false);
        }
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The area will be applied during the <see cref="NMGenState.CompactFieldBuild"/>
        /// state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.CompactFieldBuild)
                return true;

            if (context.CompactField.MarkConvexPolyArea(context, verts, ymin, ymax, Area))
            {
                context.Log(string.Format(
                    "{0}: Marked convex polygon area: Area: {1}, Priority: {2}"
                    , Name, Area, Priority)
                    , this);

                return true;
            }

            context.Log(Name + ": Failed to mark convex polygon area.", this);
            return false;
        }
Exemple #16
0
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The area will be applied during the <see cref="NMGenState.CompactFieldBuild"/> state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.CompactFieldBuild)
            {
                return(true);
            }

            if (context.CompactField.MarkBoxArea(context, mBoundsMin, mBoundsMax, Area))
            {
                context.Log(string.Format("{0} : Marked box area: Area: {1}, Priority: {2}"
                                          , Name, Area, Priority)
                            , this);
                return(true);
            }

            context.Log(Name + ": Failed to mark box area.", this);
            return(false);
        }
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The area will be applied during the <see cref="NMGenState.CompactFieldBuild"/>
        /// state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.CompactFieldBuild)
                return true;

            if (context.CompactField.MarkCylinderArea(context
                , mCenterBase, mRadius, mHeight
                , Area))
            {
                context.Log(string.Format("{0} : Marked box area: Area: {1}, Priority: {2}"
                    , Name, Area, Priority)
                    , this);
                return true;
            }

            context.Log(Name + ": Failed to mark cylinder area.", this);
            return false;
        }
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The flags will be applied during the <see cref="NMGenState.PolyMeshBuild"/> state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>True</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.PolyMeshBuild)
                return true;

            PolyMeshData data = context.PolyMesh.GetData(false);

            for (int i = 0; i < data.flags.Length; i++)
            {
                data.flags[i] |= mFlags;
            }

            context.PolyMesh.Load(data);
            context.Log(string.Format("{0}: Applied flag(s) to all polys. Flag(s): 0x{1:X}"
                , Name, mFlags)
                , this);

            return true;
        }
        private IncrementalBuilder(NMGenTileParams tileConfig
                                   , NMGenParams config
                                   , NMGenAssetFlag resultOptions
                                   , InputGeometry source
                                   , ProcessorSet processors)
        {
            mConfig     = config;
            mTileConfig = tileConfig;

            mGeometry      = source;
            mProcessors    = processors;
            mResultOptions = resultOptions;

            mBuildContext = new NMGenContext(tileConfig.TileX, tileConfig.TileZ, mConfig.Clone());

            mTileText = string.Format("({0},{1})", tileConfig.TileX, tileConfig.TileZ);

            mState = NMGenState.Initialized;
        }
Exemple #20
0
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The area will be applied during the <see cref="NMGenState.CompactFieldBuild"/>
        /// state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.CompactFieldBuild)
            {
                return(true);
            }

            if (context.CompactField.MarkConvexPolyArea(context, verts, ymin, ymax, Area))
            {
                context.Log(string.Format(
                                "{0}: Marked convex polygon area: Area: {1}, Priority: {2}"
                                , Name, Area, Priority)
                            , this);

                return(true);
            }

            context.Log(Name + ": Failed to mark convex polygon area.", this);
            return(false);
        }
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The area will be applied during the <see cref="NMGenState.CompactFieldBuild"/>
        /// state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>False on error, otherwise true.</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.CompactFieldBuild)
            {
                return(true);
            }

            if (context.CompactField.MarkCylinderArea(context
                                                      , mCenterBase, mRadius, mHeight
                                                      , Area))
            {
                context.Log(string.Format("{0} : Marked box area: Area: {1}, Priority: {2}"
                                          , Name, Area, Priority)
                            , this);
                return(true);
            }

            context.Log(Name + ": Failed to mark cylinder area.", this);
            return(false);
        }
Exemple #22
0
        /// <summary>
        /// Process the build context.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The flags will be applied during the <see cref="NMGenState.PolyMeshBuild"/> state.
        /// </para>
        /// </remarks>
        /// <param name="state">The current build state.</param>
        /// <param name="context">The context to process.</param>
        /// <returns>True</returns>
        public override bool ProcessBuild(NMGenContext context, NMGenState state)
        {
            if (state != NMGenState.PolyMeshBuild)
            {
                return(true);
            }

            PolyMeshData data = context.PolyMesh.GetData(false);

            for (int i = 0; i < data.flags.Length; i++)
            {
                data.flags[i] |= mFlags;
            }

            context.PolyMesh.Load(data);
            context.Log(string.Format("{0}: Applied flag(s) to all polys. Flag(s): 0x{1:X}"
                                      , Name, mFlags)
                        , this);

            return(true);
        }
        /// <summary>
        /// Returns a progress value associated with the specified state.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The value will be between 0 and 1.0, suitable for providing build progress feedback.
        /// </para>
        /// </remarks>
        /// <param name="state">The state.</param>
        /// <returns>A progress value for the state.</returns>
        public static float ToProgress(NMGenState state)
        {
            const float inc = 1 / 6f;

            switch (state)
            {
            case NMGenState.Initialized:
                return(0);

            case NMGenState.HeightfieldBuild:
                return(inc * 1);

            case NMGenState.CompactFieldBuild:
                return(inc * 2);

            case NMGenState.RegionBuild:
                return(inc * 3);

            case NMGenState.ContourBuild:
                return(inc * 4);

            case NMGenState.PolyMeshBuild:
                return(inc * 5);

            case NMGenState.DetailMeshBuild:
                return(inc * 6);

            case NMGenState.Complete:
                return(1);

            case NMGenState.Aborted:
                return(1);

            case NMGenState.NoResult:
                return(1);
            }
            return(1);
        }
        private void BuildHeightfield()
        {
            int width;
            int depth;

            NMGen.DeriveSizeOfCellGrid(mTileConfig.BoundsMin
                                       , mTileConfig.BoundsMax
                                       , mConfig.XZCellSize
                                       , out width
                                       , out depth);

            Heightfield hf = Heightfield.Create(width, depth
                                                , mTileConfig.BoundsMin, mTileConfig.BoundsMax
                                                , mConfig.XZCellSize, mConfig.YCellSize);


            hf.AddTriangles(mBuildContext
                            , mGeometry.Mesh
                            , mTileConfig.boundsMin
                            , mTileConfig.boundsMax
                            , mConfig.WalkableStep); // Merge for any spans less than step.


            if (hf.GetSpanCount() < 1)
            {
                FinalizeNoResult("Complete at heightfield build. No spans.");
                return;
            }


            mBuildContext.Heightfield = hf;

            if (PostProcess() && PostHeightfieldCheck())
            {
                mBuildContext.Log("Voxelized triangles. Span count: " + hf.GetSpanCount(), this);
                mState = NMGenState.CompactFieldBuild;
            }
        }
        private void BuildPolyMesh()
        {
            ContourSet cset = mBuildContext.Contours;

            PolyMesh polyMesh = PolyMesh.Build(mBuildContext
                                               , cset
                                               , mConfig.MaxVertsPerPoly
                                               , mConfig.WalkableHeight
                                               , mConfig.WalkableRadius
                                               , mConfig.WalkableStep);

            if (CanDispose(NMGenAssetFlag.ContourSet))
            {
                cset.RequestDisposal();
                mBuildContext.Contours = null;
            }

            if (polyMesh == null)
            {
                FinalizeAbort("Aborted at poly mesh build.");
                return;
            }

            if (polyMesh.PolyCount < 1)
            {
                FinalizeNoResult("Aborted after poly mesh build. No polygons generated.");
                return;
            }

            mBuildContext.PolyMesh = polyMesh;

            if (PostProcess() & PostPolyMeshCheck() & PostCompactFieldCheck())
            {
                mBuildContext.Log("Built poly mesh. PolyCount: " + polyMesh.PolyCount, this);
                mState = NMGenState.DetailMeshBuild;
            }
        }
Exemple #26
0
 /// <summary>
 /// Process the build context.
 /// </summary>
 /// <param name="state">The current build state.</param>
 /// <param name="context">The context to process.</param>
 /// <returns>False if the build should abort.  Otherwise true.</returns>
 public abstract bool ProcessBuild(NMGenContext context, NMGenState state);
 /// <summary>
 /// Runs all the processors in order of priority.  (Ascending)
 /// </summary>
 /// <remarks>
 /// <para>
 /// A return value of false indicates the build should be aborted.
 /// </para>
 /// </remarks>
 /// <param name="state">The current state of the build.</param>
 /// <param name="context">The build context.</param>
 /// <returns>False if the build should abort.</returns>
 public bool Process(NMGenContext context, NMGenState state)
 {
     foreach (INMGenProcessor p in mProcessors)
     {
         if (!p.ProcessBuild(context, state))
             return false;
     }
     return true;
 }
 private void FinalizeAbort(string message)
 {
     mBuildContext.Log(message, this);
     DisposeAssets();
     mState = NMGenState.Aborted;
 }
 private void FinalizeNoResult(string message)
 {
     mBuildContext.Log(message, this);
     DisposeAssets();
     mState = NMGenState.NoResult;
 }
Exemple #30
0
 /// <summary>
 /// Process the build context.
 /// </summary>
 /// <param name="state">The current build state.</param>
 /// <param name="context">The context to process.</param>
 /// <returns>False if the build should abort.  Otherwise true.</returns>
 public abstract bool ProcessBuild(NMGenContext context, NMGenState state);
        private IncrementalBuilder(NMGenTileParams tileConfig
            , NMGenParams config
            , NMGenAssetFlag resultOptions
            , InputGeometry source
            , ProcessorSet processors)
        {
            mConfig = config;
            mTileConfig = tileConfig;

            mGeometry = source;
            mProcessors = processors;
            mResultOptions = resultOptions;

            mBuildContext = new NMGenContext(tileConfig.TileX, tileConfig.TileZ, mConfig.Clone());

            mTileText = string.Format("({0},{1})", tileConfig.TileX, tileConfig.TileZ);

            mState = NMGenState.Initialized;
        }
        /// <summary>
        /// Performs a single build step.
        /// </summary>
        /// <remarks>
        /// <para>
        /// The result state will represent either a finished state or the build step that 
        /// will be performed during the next call to the method.
        /// </para>
        /// </remarks>
        /// <returns>The state at the end of the build step.</returns>
        public NMGenState Build()
        {
            switch (mState)
            {
                case NMGenState.Initialized:

                    mBuildContext.Log("Build: " + mTileText, this);

                    mProcessors.LogProcessors(mBuildContext);

                    mState = NMGenState.HeightfieldBuild;

                    break;

                case NMGenState.HeightfieldBuild:

                    //UnityEngine.Debug.Log("hfb");
                    BuildHeightfield();
                    break;

                case NMGenState.CompactFieldBuild:

                    //UnityEngine.Debug.Log("cfb");
                    BuildCompactField();
                    break;

                case NMGenState.RegionBuild:

                    //UnityEngine.Debug.Log("rb");
                    BuildRegions();
                    break;

                case NMGenState.ContourBuild:

                    //UnityEngine.Debug.Log("cb");
                    BuildContours();
                    break;

                case NMGenState.PolyMeshBuild:

                    BuildPolyMesh();
                    break;

                case NMGenState.DetailMeshBuild:

                    BuildDetailMesh();
                    break;
            }
            return mState;
        }
        private void FinalizeComplete()
        {
            if ((mResultOptions & NMGenAssetFlag.Heightfield) == 0 && mBuildContext.Heightfield != null)
            {
                mBuildContext.Heightfield.RequestDisposal();
                mBuildContext.Heightfield = null;
            }

            if ((mResultOptions & NMGenAssetFlag.CompactField) == 0 && mBuildContext.CompactField != null)
            {
                mBuildContext.CompactField.RequestDisposal();
                mBuildContext.CompactField = null;
            }

            if ((mResultOptions & NMGenAssetFlag.ContourSet) == 0 && mBuildContext.Contours != null)
            {
                mBuildContext.Contours.RequestDisposal();
                mBuildContext.Contours = null;
            }

            // Polymesh is always kept.

            if ((mResultOptions & NMGenAssetFlag.DetailMesh) == 0 && mBuildContext.DetailMesh != null)
            {
                mBuildContext.DetailMesh.RequestDisposal();
                mBuildContext.DetailMesh = null;
            }

            mBuildContext.Log("Build Complete. Result: " + mResultOptions, this);
            mState = NMGenState.Complete;
        }
 private void FinalizeAbort(string message)
 {
     mBuildContext.Log(message, this);
     DisposeAssets();
     mState = NMGenState.Aborted;
 }
        private void BuildRegions()
        {
            CompactHeightfield chf = mBuildContext.CompactField;

            chf.BuildDistanceField(mBuildContext);
            mBuildContext.Log("Built distance field. Max Distance: " + chf.MaxDistance, this);

            if (mConfig.UseMonotone)
            {
                if (!chf.BuildRegionsMonotone(mBuildContext
                    , mConfig.BorderSize
                    , mConfig.MinRegionArea
                    , mConfig.MergeRegionArea))
                {
                    FinalizeAbort("Monotone region generation failed.");
                    return;
                }
            }
            else
            {
                if (!chf.BuildRegions(mBuildContext
                    , mConfig.BorderSize
                    , mConfig.MinRegionArea
                    , mConfig.MergeRegionArea))
                {
                    FinalizeAbort("Region generation failed.");
                    return;
                }
            }

            if (PostProcess() && PostCompactFieldCheck())
            {
                if (chf.MaxRegion < 2)
                {
                    // Null region counts as a region.  So expect
                    // at least 2.
                    FinalizeNoResult("Completed after region build. No useable regions formed.");
                    return;
                }

                mBuildContext.Log("Generated regions. Region Count: " + chf.MaxRegion, this);

                // Success.
                mState = NMGenState.ContourBuild;
            }
        }
        private void BuildPolyMesh()
        {
            ContourSet cset = mBuildContext.Contours;

            PolyMesh polyMesh = PolyMesh.Build(mBuildContext
                , cset
                , mConfig.MaxVertsPerPoly
                , mConfig.WalkableHeight
                , mConfig.WalkableRadius
                , mConfig.WalkableStep);

            if (CanDispose(NMGenAssetFlag.ContourSet))
            {
                cset.RequestDisposal();
                mBuildContext.Contours = null;
            }

            if (polyMesh == null)
            {
                FinalizeAbort("Aborted at poly mesh build.");
                return;
            }

            if (polyMesh.PolyCount < 1)
            {
                FinalizeNoResult("Aborted after poly mesh build. No polygons generated.");
                return;
            }

            mBuildContext.PolyMesh = polyMesh;

            if (PostProcess() & PostPolyMeshCheck() & PostCompactFieldCheck())
            {
                mBuildContext.Log("Built poly mesh. PolyCount: " + polyMesh.PolyCount, this);
                mState = NMGenState.DetailMeshBuild;
            }
        }
        private void BuildHeightfield()
        {
            int width;
            int depth;

            NMGen.DeriveSizeOfCellGrid(mTileConfig.BoundsMin
                , mTileConfig.BoundsMax
                , mConfig.XZCellSize
                , out width
                , out depth);

            Heightfield hf = Heightfield.Create(width, depth
                , mTileConfig.BoundsMin, mTileConfig.BoundsMax
                , mConfig.XZCellSize, mConfig.YCellSize);

            hf.AddTriangles(mBuildContext
                , mGeometry.Mesh
                , mTileConfig.boundsMin
                , mTileConfig.boundsMax
                , mConfig.WalkableStep);  // Merge for any spans less than step.

            if (hf.GetSpanCount() < 1)
            {
                FinalizeNoResult("Complete at heightfield build. No spans.");
                return;
            }

            mBuildContext.Heightfield = hf;

            if (PostProcess() && PostHeightfieldCheck())
            {
                mBuildContext.Log("Voxelized triangles. Span count: " + hf.GetSpanCount(), this);
                mState = NMGenState.CompactFieldBuild;
            }
        }
 /// <summary>
 /// Returns human friendly text for the specified state.
 /// </summary>
 /// <param name="state">The state.</param>
 /// <returns>Human friendly text.</returns>
 public static string ToLabel(NMGenState state)
 {
     switch (state)
     {
         case NMGenState.Aborted:
             return "Aborted.";
         case NMGenState.CompactFieldBuild:
             return "Building compact heightfield.";
         case NMGenState.Complete:
             return "Complete";
         case NMGenState.ContourBuild:
             return "Building contours.";
         case NMGenState.DetailMeshBuild:
             return "Building detail mesh.";
         case NMGenState.HeightfieldBuild:
             return "Building heightfield.";
         case NMGenState.PolyMeshBuild:
             return "Building polygon mesh.";
         case NMGenState.RegionBuild:
             return "Building regions.";
         case NMGenState.NoResult:
             return "No result.";
     }
     return "Unhandled state: " + state;
 }
        private void BuildCompactField()
        {
            Heightfield hf = mBuildContext.Heightfield;

            CompactHeightfield chf = CompactHeightfield.Build(mBuildContext
                , hf
                , mConfig.WalkableHeight
                , mConfig.WalkableStep);

            if (CanDispose(NMGenAssetFlag.Heightfield))
            {
                hf.RequestDisposal();
                mBuildContext.Heightfield = null;
            }

            if (chf == null)
            {
                FinalizeAbort("Aborted at compact heightfield build.");
                return;
            }

            if (chf.SpanCount < 1)
            {
                FinalizeNoResult("Complete at compact heightfield build. No spans.");
                return;
            }

            mBuildContext.CompactField = chf;

            // Note: Post process is done before eroding the walkable area
            // so that the processors can stamp additional obstructions into
            // the heightfield.
            if (PostProcess() && PostCompactFieldCheck())
            {
                if (mConfig.WalkableRadius > 0)
                {
                    chf = mBuildContext.CompactField;
                    chf.ErodeWalkableArea(mBuildContext, mConfig.WalkableRadius);
                    mBuildContext.Log("Eroded walkable area by radius: " + mConfig.walkableRadius
                        , this);
                }

                mBuildContext.Log("Built compact heightfield. Spans: " + chf.SpanCount, this);

                mState = NMGenState.RegionBuild;
            }
        }
 private void FinalizeNoResult(string message)
 {
     mBuildContext.Log(message, this);
     DisposeAssets();
     mState = NMGenState.NoResult;
 }
        private void BuildContours()
        {
            ContourSet cset = ContourSet.Build(mBuildContext
                , mBuildContext.CompactField
                , mConfig.EdgeMaxDeviation
                , mConfig.MaxEdgeLength
                , mConfig.ContourOptions);

            if (cset == null)
            {
                FinalizeAbort("Aborted at contour set build.");
                return;
            }

            if (cset.Count < 1)
            {
                FinalizeNoResult("Completed after contour build. No useable contours generated.");
                return;
            }

            mBuildContext.Contours = cset;

            if (PostProcess() && PostContoursCheck() && PostCompactFieldCheck())
            {
                mBuildContext.Log("Built contour set. Contour count: " + cset.Count, this);
                mState = NMGenState.PolyMeshBuild;
            }
        }
 /// <summary>
 /// Returns a progress value associated with the specified state. 
 /// </summary>
 /// <remarks>
 /// <para>
 /// The value will be between 0 and 1.0, suitable for providing build progress feedback.
 /// </para>
 /// </remarks>
 /// <param name="state">The state.</param>
 /// <returns>A progress value for the state.</returns>
 public static float ToProgress(NMGenState state)
 {
     const float inc = 1 / 6f;
     switch (state)
     {
         case NMGenState.Initialized:
             return 0;
         case NMGenState.HeightfieldBuild:
             return inc * 1;
         case NMGenState.CompactFieldBuild:
             return inc * 2;
         case NMGenState.RegionBuild:
             return inc * 3;
         case NMGenState.ContourBuild:
             return inc * 4;
         case NMGenState.PolyMeshBuild:
             return inc * 5;
         case NMGenState.DetailMeshBuild:
             return inc * 6;
         case NMGenState.Complete:
             return 1;
         case NMGenState.Aborted:
             return 1;
         case NMGenState.NoResult:
             return 1;
     }
     return 1;
 }