Пример #1
0
        private void HandleClear()
        {
            // Abort any in-progress builds.
            Context.AbortAllReqests("User requested.");

            TileBuildData tdata = Context.Build.BuildData;

            int w = tdata.Width;
            int d = tdata.Depth;

            bool needsBaking =
                (tdata.NeedsBakingCount() == 0) ? false : true;

            for (int tx = 0; tx < w; tx++)
            {
                for (int tz = 0; tz < d; tz++)
                {
                    if (needsBaking)
                    {
                        tdata.ClearUnbaked(tx, tz);
                    }
                    else
                    {
                        tdata.Reset(tx, tz);
                    }
                }
            }
        }
Пример #2
0
        private void OnGUIStatusGrid(float areaHeight)
        {
            TileBuildData tdata = Context.Build.BuildData;

            for (int tx = 0; tx < tdata.Width; tx++)
            {
                for (int tz = 0; tz < tdata.Depth; tz++)
                {
                    Vector3 origin = new Vector3(tx * GridCellSize, areaHeight - tz * GridCellSize);

                    mCellVerts[0] = origin;

                    mCellVerts[1]    = origin;
                    mCellVerts[1].x += GridCellSize;

                    mCellVerts[2]    = origin;
                    mCellVerts[2].x += GridCellSize;
                    mCellVerts[2].y -= GridCellSize;

                    mCellVerts[3]    = origin;
                    mCellVerts[3].y -= GridCellSize;

                    Color c = ToColor(tdata.GetState(tx, tz));

                    Handles.DrawSolidRectangleWithOutline(mCellVerts, c, Color.black);
                }
            }

            OnGUISelection(areaHeight);
        }
Пример #3
0
        private void HandleBake()
        {
            const string Category = "Bake To Target";

            NavmeshBuild  build = Context.Build; // Caller checks for null.
            TileBuildData tdata = build.BuildData;

            // Double check.
            if (tdata.BakeableCount() == 0)
            {
                Debug.LogWarning(Category + ": No tiles were produced.  (All tiles empty?)", build);
                return;
            }

            if (Context.TaskCount > 0)
            {
                Debug.LogWarning(Category + ": There are in-progress background builds."
                                 + " The tiles associated with these builds will not be baked."
                                 + " In-progress builds: " + Context.TaskCount
                                 , build);
            }

            NavmeshParams nconfig;

            NavmeshTileData[] tiles;

            bool success = tdata.GetMeshBuildData(build.TileSetDefinition.BoundsMin
                                                  , build.TileSetDefinition.TileWorldSize
                                                  , out nconfig, out tiles);

            if (!success)
            {
                Logger.PostError("Bake to target: Error creating navigation mesh from build data."
                                 , Context.Build);
                return;
            }

            NavStatus status =
                build.BuildTarget.Load(nconfig, tiles, NMBEditorUtil.GetConfig(build));

            if ((status & NavStatus.Failure) == 0)
            {
                build.BuildData.SetAsBaked();
                EditorUtility.SetDirty((Object)build.BuildTarget);
            }
            else
            {
                Logger.PostError("Bake to target: Target reported failure."
                                 , (Object)Context.Build.BuildTarget);
            }
        }
Пример #4
0
        private void HandleBuildRequest(bool forceAll)
        {
            TileSelection sel = Context.Selection;

            int w;
            int d;
            int ix = 0;
            int iz = 0;

            int priority;

            if (!forceAll && sel.Validate())
            {
                TileZone zone = sel.Zone;

                w = zone.xmax + 1;
                d = zone.zmax + 1;

                ix = zone.xmin;
                iz = zone.zmin;

                priority = BuildTaskProcessor.MediumPriority;
            }
            else
            {
                TileBuildData tdata = Context.Build.BuildData;

                w = tdata.Width;
                d = tdata.Depth;

                priority = BuildTaskProcessor.LowPriority;
            }

            // Note: The iteration order appears odd, but it makes for better
            // progress visualizations.  Filling downward.
            for (int tz = d - 1; tz >= iz; tz--)
            {
                for (int tx = ix; tx < w; tx++)
                {
                    if (!Context.QueueTask(tx, tz, priority--, Logger))
                    {
                        Logger.PostError(string.Format("Build task failed: ({0},{1})", tx, tz)
                                         , Context.Build);
                    }
                }
            }
        }
Пример #5
0
        public static bool OnGUIStandardButtons(ControlContext context
                                                , DebugViewContext debugContext
                                                , bool resetAllowed)
        {
            NavmeshBuild build = context.Build;

            if (!build)
            {
                return(false);
            }

            TileBuildData tdata = build.BuildData;

            GUILayout.FlexibleSpace();

            // Note: It is assumed that you should't get any debug display options unless
            // you can reset the build.  So they are inside this condition.
            if (resetAllowed)
            {
                if (build.BuildState == NavmeshBuildState.Buildable || build.HasInputData)
                {
                    // One or more debug display options are allowed.
                    GUILayout.Label("Show");
                }

                // Always call these.
                debugContext.OnGUIMeshDisplayOptions();
                debugContext.OnGUIDebugExtras();

                GUILayout.Space(MarginSize);

                GUIStyle style = (tdata != null && tdata.NeedsBakingCount() == 0)
                    ? ControlUtil.HighlightedButton : GUI.skin.button;

                return(OnGUIResetButton(context, debugContext, style));
            }

            return(false);
        }
Пример #6
0
        protected override void OnGUIButtons()
        {
            DebugContext.SetViews(ViewOption.Mesh);

            NavmeshBuild build = Context.Build;

            if (!build)
            {
                // Build deleted.
                return;
            }

            TileBuildData  tdata  = Context.Build.BuildData;
            TileBuildState bstate = tdata.GetState(0, 0);

            bool canBake =
                (bstate == TileBuildState.Built || bstate == TileBuildState.Baked);

            bool isBuilding = (Context.TaskCount > 0);

            ControlUtil.BeginButtonArea(Context.ButtonArea);

            EditorGUIUtility.LookLikeControls(75);

            bool guiEnabled = GUI.enabled;

            GUI.enabled = !isBuilding;

            GUIStyle style = (canBake || isBuilding)
                ? GUI.skin.button : ControlUtil.HighlightedButton;

            if (GUILayout.Button("Build", style))
            {
                mProgress = 0;

                mLastTime = EditorApplication.timeSinceStartup;

                if (!Context.QueueTask(0, 0, BuildTaskProcessor.LowPriority, Logger))
                {
                    Logger.PostError("Build task failed.", Context.Build);
                }
            }

            GUI.enabled = !isBuilding && canBake;

            style = GUI.enabled
                ? ControlUtil.HighlightedButton : GUI.skin.button;

            if (GUILayout.Button("Bake", style))
            {
                HandleBake();
            }

            GUILayout.Space(ControlUtil.MarginSize);

            GUI.enabled = isBuilding;

            if (GUILayout.Button("Abort Build"))
            {
                Context.AbortAllReqests("User requested.");
            }

            GUI.enabled = guiEnabled;

            if (OnGUIStandardButtons())
            {
                // Special case.  Build was discarded.
                ControlUtil.EndButtonArea();
                return;
            }

            ControlUtil.OnGUIStandardButtons(Context, DebugContext, true);

            ControlUtil.EndButtonArea();
        }
Пример #7
0
        private void HandleWorkingNavmesh(TileSelection selection)
        {
            NavmeshBuild  build = selection.Build;
            TileBuildData tdata = build.BuildData;

            if (mDebugObject == null)
            {
                Navmesh navmesh = null;

                if (tdata.BakeableCount() == 0)
                {
                    // Nothing to display.
                    return;
                }

                bool success = true;

                TileSetDefinition tdef = build.TileSetDefinition;

                NavmeshParams     nconfig;
                NavmeshTileData[] tiles;

                if (tdef == null)
                {
                    tiles = new NavmeshTileData[1] {
                        tdata.GetTileData(0, 0)
                    };
                    nconfig = NavUtil.DeriveConfig(tiles[0]);
                }
                else
                {
                    TileZone zone;

                    if (selection.HasSelection)
                    {
                        zone = selection.Zone;
                    }
                    else
                    {
                        zone = new TileZone(0, 0, tdef.Width - 1, tdef.Depth - 1);
                    }

                    success = tdata.GetMeshBuildData(tdef.BoundsMin.ToUnityVector3(), tdef.TileWorldSize, zone
                                                     , out nconfig, out tiles);
                }

                NavStatus status = NavStatus.Sucess;

                if (success)
                {
                    status = Navmesh.Create(nconfig, out navmesh);

                    if ((status & NavStatus.Failure) == 0)
                    {
                        foreach (NavmeshTileData tile in tiles)
                        {
                            uint trash;
                            status = navmesh.AddTile(tile, Navmesh.NullTile, out trash);

                            if ((status & NavStatus.Sucess) == 0)
                            {
                                navmesh = null;
                                break;
                            }
                        }
                    }
                }

                if ((status & NavStatus.Sucess) == 0)
                {
                    Show = MeshDebugOption.None;                      // Use property.
                    Debug.LogError("Mesh Debug View: Error creating working navigation mesh: "
                                   + status + ". Disabled display.", build);
                }
                else
                {
                    mDebugObject = navmesh;
                }
            }

            if (mDebugObject != null)
            {
                Navmesh nm = ( Navmesh )mDebugObject;
                NavDebug.Draw(nm, NavmeshSceneDraw.Instance.ColorByArea);
            }
        }
Пример #8
0
        public void OnRenderObject(NavmeshBuild build, TileSelection selection)
        {
            if (!build)
            {
                return;
            }

            TileBuildData tdata = build.BuildData;

            if (!mEnabled ||
                mShow == MeshDebugOption.None ||
                tdata == null ||                  // This restriction is appropriate.
                build != selection.Build)                      // Important error check.
            {
                return;
            }

            INavmeshData target = build.BuildTarget;

            if (target != null && target.HasNavmesh && NavmeshSceneDraw.Instance.IsShown(target))
            {
                // Don't overdraw the target mesh's display.  It has priority.
                return;
            }

            if (tdata.Version != mLastVersion)
            {
                // Build data has changed.  Clear debug object.
                mLastVersion = tdata.Version;
                mDebugObject = null;
            }

            int tx   = 0;
            int tz   = 0;
            int size = 0;

            if (tdata.IsTiled)
            {
                tx   = selection.SelectedX;
                tz   = selection.SelectedZ;
                size = selection.ZoneSize;
            }

            if (mLastX != tx || mLastZ != tz || mLastSize != size)
            {
                // Change in selection.  Clear debug object.
                mLastX       = tx;
                mLastZ       = tz;
                mLastSize    = size;
                mDebugObject = null;
                // Debug.Log("Clear debug on selection change.");
            }

            if (mShow == MeshDebugOption.WorkingMesh)
            {
                HandleWorkingNavmesh(selection);
                return;
            }
            else if (tdata.IsTiled && !selection.Validate())
            {
                // The mesh is tiled with no valid selection.
                // Can't display any of the other meshes.
                mLastX    = -1;
                mLastZ    = -1;
                mLastSize = -1;
                return;
            }

            // Can only display a single tile for all other display options.
            // Choose the tile to display.

            switch (mShow)
            {
            case MeshDebugOption.PolyMesh:

                HandlePolyMesh(build, tx, tz);
                break;

            case MeshDebugOption.Detailmesh:

                HandleDetailMesh(build, tx, tz);
                break;

            case MeshDebugOption.InputGeometry:

                if (build.TileSetDefinition != null)
                {
                    HandleInputGeom(build, tx, tz);
                }
                break;
            }
        }
Пример #9
0
        private void ManageTileRequests()
        {
            TileBuildData tdata = mContext.Build.BuildData;

            mLogger.ResetLog();

            // Due to concurrency with the input build, this method
            // does not log things via the context.

            List <TileBuildTask> requests = mContext.TileTasks;

            for (int i = requests.Count - 1; i >= 0; i--)
            {
                TileBuildTask item = requests[i];

                if (item.IsFinished)
                {
                    requests.RemoveAt(i);

                    NavmeshBuild build = mContext.Build;

                    if (!build)
                    {
                        // Asset was deleted.
                        continue;
                    }

                    string tileText = string.Format("({0},{1})", item.TileX, item.TileZ);

                    switch (item.TaskState)
                    {
                    case BuildTaskState.Aborted:

                        mLogger.Log(item.Messages);
                        mLogger.PostError("Tile build failed: " + tileText, build);

                        tdata.SetAsFailed(item.TileX, item.TileZ);

                        break;

                    case BuildTaskState.Complete:

                        TileBuildAssets r = item.Result;

                        string msg;

                        if (r.NoResult)
                        {
                            msg = "Tile build complete. Tile is empty: " + tileText;
                            tdata.SetAsEmpty(r.TileX, r.TileZ);
                        }
                        else
                        {
                            msg = "Tile build complete: " + tileText;
                            tdata.SetWorkingData(r.TileX, r.TileZ, r.Tile, r.PolyCount);
                        }

                        mLogger.PostTrace(msg, item.Messages, build);

                        break;
                    }
                }
            }
        }
Пример #10
0
        private void ManageNMGenRequests()
        {
            mLogger.ResetLog();

            TileBuildData tdata = mContext.Build.BuildData;

            // Due to concurrency with the input build, this method
            // does not log things via the context.

            List <NMGenTask> requests = mContext.NMGenTasks;

            for (int i = requests.Count - 1; i >= 0; i--)
            {
                NMGenTask item = requests[i];

                if (item.IsFinished)
                {
                    requests.RemoveAt(i);

                    NavmeshBuild build = mContext.Build;

                    if (!build)
                    {
                        // Asset was deleted.
                        continue;
                    }

                    string tileText = string.Format("({0},{1})", item.TileX, item.TileZ);

                    switch (item.TaskState)
                    {
                    case BuildTaskState.Aborted:

                        mLogger.Log(item.Messages);
                        mLogger.PostError("Tile build failed: " + tileText, build);

                        tdata.SetAsFailed(item.TileX, item.TileZ);

                        break;

                    case BuildTaskState.Complete:

                        NMGenAssets r = item.Result;

                        if (r.NoResult)
                        {
                            mLogger.PostTrace("NMGen build complete. Tile is empty: " + tileText
                                              , item.Messages, build);

                            tdata.SetAsEmpty(r.TileX, r.TileZ);
                        }
                        else
                        {
                            tdata.SetWorkingData(r.TileX, r.TileZ, r.PolyMesh, r.DetailMesh);

                            mLogger.PostTrace("NMGen build complete: " + tileText
                                              , item.Messages, build);

                            mContext.QueueTask(mLogger, r.TileX, r.TileZ
                                               , r.PolyMesh, r.DetailMesh
                                               , (build.Config.BuildFlags & NMGenBuildFlag.BVTreeEnabled) != 0
                                               , item.Priority);
                        }

                        break;
                    }
                }
                else if (item.TaskState == BuildTaskState.InProgress &&
                         tdata.GetState(item.TileX, item.TileZ) != TileBuildState.InProgress)
                {
                    // Transition to the in-progress state.
                    tdata.SetAsInProgress(item.TileX, item.TileZ);
                }
            }
        }
Пример #11
0
        protected override void OnGUIMain()
        {
            if (mBlackLabel == null)
            {
                // Need to initialize shared style.
                mBlackLabel = new GUIStyle(GUI.skin.label);
                mBlackLabel.normal.textColor = Color.black;
                mBlackLabel.fontStyle        = FontStyle.Bold;
            }

            TileSelection selection = Context.Selection;

            selection.Validate();

            TileBuildData tdata = Context.Build.BuildData;

            if (tdata == null)
            {
                return;
            }

            Rect mainArea = Context.MainArea;

            // The box and shift makes it look better.
            GUI.Box(mainArea, "");
            mainArea.x += MarginSize;
            mainArea.y += MarginSize;

            // Draw the status grid.

            // Note: View is expanded by one grid size in order to minimize
            // grid/slider overlap.
            Rect view
                = new Rect(0, 0, tdata.Width * GridCellSize + GridCellSize
                           , tdata.Depth * GridCellSize + GridCellSize);

            mScrollPos = GUI.BeginScrollView(mainArea, mScrollPos, view);

            OnGUIStatusGrid(view.height - GridCellSize);

            GUI.EndScrollView();

            OnGUIMainStandard();

            if (IsBaseBusy)
            {
                return;
            }

            // Handle the mouse, including click selection.

            Event   evt      = Event.current;
            Vector2 mousePos = evt.mousePosition;

            if (mainArea.Contains(mousePos))
            {
                Vector2 gridPos = mousePos;

                gridPos.x -= mainArea.xMin - mScrollPos.x;
                gridPos.y -= mainArea.yMin - mScrollPos.y;

                int x = Mathf.FloorToInt(gridPos.x / GridCellSize);
                // For the depth, we need to invert the y-axis.
                int z = tdata.Depth - Mathf.FloorToInt(gridPos.y / GridCellSize) - 1;

                if (x < tdata.Width && z >= 0 && z < tdata.Depth)
                {
                    GUI.Label(new Rect(mousePos.x - 20, mousePos.y - 20, 120, 25)
                              , "(" + x + "," + z + "): " + tdata.GetState(x, z)
                              , mBlackLabel);

                    mMouseX = x;
                    mMouseZ = z;

                    if (evt.type == EventType.MouseDown && evt.button == 0)
                    {
                        if (selection.SelectedX == mMouseX && selection.SelectedZ == mMouseZ)
                        {
                            // Clicked on same tile. Deselect.
                            selection.ClearSelection();
                        }
                        else
                        {
                            selection.SetSelection(mMouseX, mMouseZ);
                        }
                    }
                }
                else
                {
                    mMouseX = TileSelection.NoSelection;
                    mMouseZ = TileSelection.NoSelection;
                }
            }
            else
            {
                mMouseX = TileSelection.NoSelection;
                mMouseZ = TileSelection.NoSelection;
            }
        }
Пример #12
0
        protected override void OnGUIButtons()
        {
            DebugContext.SetViews(ViewOption.Grid | ViewOption.Selection | ViewOption.Mesh);

            NavmeshBuild build = Context.Build;

            if (!build)
            {
                return;
            }

            TileBuildData tdata = build.BuildData;

            if (tdata == null)
            {
                return;
            }

            TileSelection selection = Context.Selection;

            bool hasSelection  = selection.Validate();
            bool needBaking    = (tdata.NeedsBakingCount() > 0);
            int  activeCount   = Context.TaskCount;
            int  bakeableCount = tdata.BakeableCount();

            bool origGUIEnabled = GUI.enabled;

            bool guiEnabled = !IsBaseBusy;

            GUI.enabled = guiEnabled;

            ControlUtil.BeginButtonArea(Context.ButtonArea);

            if (GUILayout.Button("Build All"))
            {
                HandleBuildRequest(true);
            }

            GUI.enabled = guiEnabled && hasSelection;

            if (GUILayout.Button("Build Zone"))
            {
                HandleBuildRequest(false);
            }

            ////////////////////////////////////////////////////////////////////
            GUILayout.Space(MarginSize);

            // Only disable baking if there is nothing at all that can be baked.
            GUI.enabled = guiEnabled && activeCount == 0 && (bakeableCount > 0);

            GUIStyle style = (bakeableCount > 0 && activeCount == 0)
                ? ControlUtil.HighlightedButton : GUI.skin.button;

            if (GUILayout.Button("Bake All", style))
            {
                HandleBake();
            }

            ////////////////////////////////////////////////////////////////////
            GUILayout.Space(MarginSize);

            // Note: Technically only the last condition is needed.  But checking the
            // other conditions first saves processing time.
            GUI.enabled = guiEnabled && activeCount == 0 &&
                          tdata.GetStateCount(TileBuildState.NotBuilt) < tdata.Width * tdata.Depth;

            if (GUILayout.Button((needBaking ? "Revert Unbaked" : "Clear All")))
            {
                HandleClear();
            }

            GUI.enabled = guiEnabled && (activeCount != 0);

            if (GUILayout.Button("Abort Builds"))
            {
                Context.AbortAllReqests("User requested.");
            }

            ////////////////////////////////////////////////////////////////////
            GUILayout.Space(ControlUtil.MarginSize);

            GUI.enabled = guiEnabled;
            if (OnGUIStandardButtons())
            {
                // Special case.  Build was discarded.
                ControlUtil.EndButtonArea();
                return;
            }

            ///////////////////////////////////////////////////////////////////
            GUILayout.Space(MarginSize);

            GUI.enabled = guiEnabled && hasSelection;

            EditorGUIUtility.LookLikeControls(100);
            selection.ZoneSize = EditorGUILayout.IntField("Zone Size", selection.ZoneSize);
            EditorGUIUtility.LookLikeControls();

            GUI.enabled = guiEnabled;

            ////////////////////////////////////////////////////////////////////
            GUILayout.Space(MarginSize);

            GUILayout.Label("Bakeable Tiles: " + bakeableCount);

            ControlUtil.OnGUIStandardButtons(Context, DebugContext, true);

            ControlUtil.EndButtonArea();

            GUI.enabled = origGUIEnabled;
        }
Пример #13
0
        private void OnGUISelection(float areaHeight)
        {
            Vector3 origin;
            int     xSize = GridCellSize;
            int     ySize = GridCellSize;

            TileSelection selection = Context.Selection;

            if (selection.Validate())
            {
                // Draw the tile marker.
                origin = new Vector3(selection.SelectedX * GridCellSize
                                     , areaHeight - selection.SelectedZ * GridCellSize);

                mCellVerts[0] = origin;

                mCellVerts[1]    = origin;
                mCellVerts[1].x += GridCellSize;

                mCellVerts[2]    = origin;
                mCellVerts[2].x += GridCellSize;
                mCellVerts[2].y -= GridCellSize;

                mCellVerts[3]    = origin;
                mCellVerts[3].y -= GridCellSize;

                Handles.DrawSolidRectangleWithOutline(mCellVerts
                                                      , Color.clear
                                                      , new Color(0.93f, 0.58f, 0.11f)); // Orange.

                TileZone zone = selection.Zone;

                origin =
                    new Vector3(zone.xmin * GridCellSize, areaHeight - zone.zmin * GridCellSize);

                xSize = zone.Width * GridCellSize;
                ySize = zone.Depth * GridCellSize;
            }
            else
            {
                origin = new Vector3(0, areaHeight);

                TileBuildData tdata = Context.Build.BuildData;

                xSize = tdata.Width * GridCellSize;
                ySize = tdata.Depth * GridCellSize;
            }

            mCellVerts[0] = origin;

            mCellVerts[1]    = origin;
            mCellVerts[1].x += xSize;

            mCellVerts[2]    = origin;
            mCellVerts[2].x += xSize;
            mCellVerts[2].y -= ySize;

            mCellVerts[3]    = origin;
            mCellVerts[3].y -= ySize;

            Handles.DrawSolidRectangleWithOutline(mCellVerts
                                                  , Color.clear
                                                  , ControlUtil.SelectionColor);
        }
Пример #14
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);
        }
Пример #15
0
        private bool BuildSingleTile()
        {
            TileBuildData tdata  = mBuild.BuildData;
            NMGenConfig   config = mBuild.Config;
            InputGeometry geom   = mBuild.InputGeom;

            mContext.ResetLog();

            /*
             * Design note:
             *
             * Not using the build task since it doesn't provide enough progress
             * feedback for a single tile.
             *
             */

            // Create the NMGen builder.

            IncrementalBuilder builder = IncrementalBuilder.Create(config.GetConfig()
                                                                   , config.ResultOptions
                                                                   , geom
                                                                   , mBuild.NMGenProcessors);

            if (builder == null)
            {
                mContext.PostError("Unexpected failure creating NMGen builder.", mBuild);
                tdata.SetAsFailed(0, 0);
                return(false);
            }
            else if (builder.IsFinished)
            {
                if (builder.State == NMGenState.NoResult)
                {
                    mContext.PostError("NMGen build did not produce a result. (Early exit.)"
                                       , builder.GetMessages(), mBuild);
                    tdata.SetAsFailed(0, 0);
                    return(false);
                }
                else
                {
                    mContext.PostError("Unexpected NMGen builder completion."
                                       , builder.GetMessages(), mBuild);
                    tdata.SetAsFailed(0, 0);
                    return(false);
                }
            }

            mBuild.BuildData.SetAsInProgress(0, 0);

            // Run the NMGen builder.

            while (!builder.IsFinished)
            {
                if (EditorUtility.DisplayCancelableProgressBar("Build Single Tile Mesh"
                                                               , IncrementalBuilder.ToLabel(builder.State)
                                                               , IncrementalBuilder.ToProgress(builder.State)))
                {
                    return(false);
                }

                builder.Build();
            }

            // Handle NMGen failures.

            mContext.Log(builder.GetMessages());   // Single tile build.  So go ahead an record.

            switch (builder.State)
            {
            case NMGenState.Aborted:

                mContext.PostError("NMGen build failed.", mBuild);
                tdata.SetAsFailed(0, 0);
                return(false);

            case NMGenState.NoResult:

                mContext.PostError("NMGen build did not produce a result.", mBuild);
                tdata.SetAsFailed(0, 0);
                return(false);
            }

            mContext.Log(string.Format("Completed NMGen build: {0} polygons."
                                       , builder.Result.PolyMesh.PolyCount)
                         , mBuild);

            // Build the tile.

            NMGenAssets result = builder.Result;

            if (result.DetailMesh == null)
            {
                Debug.LogError("result.DetailMesh ==null!");
            }

            NavmeshTileBuildData tbd = org.critterai.nmbuild.NMBuild.GetBuildData(
                mContext, 0, 0
                , result.PolyMesh.GetData(false), result.DetailMesh.GetData(false)
                , mBuild.Connections
                , (config.BuildFlags & NMGenBuildFlag.BVTreeEnabled) != 0);

            if (tbd == null)
            {
                // No need to log the error.  The above method takes care of that.
                tdata.SetAsFailed(0, 0);
                return(false);
            }

            NavmeshTileData td = NavmeshTileData.Create(tbd);

            if (td.Size == 0)
            {
                mContext.PostError(
                    "Could not create {0} object. Cause unknown." + typeof(NavmeshTileData)
                    , mBuild);
                tdata.SetAsFailed(0, 0);
                return(false);
            }

            // Finalize the tile.

            tdata.SetWorkingData(0, 0, result.PolyMesh, result.DetailMesh);
            tdata.SetWorkingData(0, 0, td, tbd.PolyCount);

            mContext.PostTrace("Completed single tile build.", mBuild);

            return(true);
        }
Пример #16
0
        private bool BuildMultiTiled()
        {
            TileSetDefinition tdef  = mBuild.TileSetDefinition;
            TileBuildData     tdata = mBuild.BuildData;

            mContext.ResetLog();

            int total = tdef.Width * tdef.Depth;

            string msg = string.Format("Multi-tile build: {0} tiles ({1}x{2})"
                                       , total, tdef.Width, tdef.Depth);

            mContext.Log(msg, mBuild);

            int count = 0; // For the progress bar.

            for (int tx = 0; tx < tdef.Width; tx++)
            {
                for (int tz = 0; tz < tdef.Depth; tz++)
                {
                    count++;

                    string tileText = string.Format("({0},{1})", tx, tz);

                    if (EditorUtility.DisplayCancelableProgressBar("Multi-tiled Build & Bake"
                                                                   , string.Format("Tile: {0}  ({1} of {2})", tileText, count, total)
                                                                   , (float)count / total))
                    {
                        return(false);
                    }

                    // Create the NMGen builder.

                    IncrementalBuilder builder = IncrementalBuilder.Create(tx, tz
                                                                           , mBuild.Config.ResultOptions
                                                                           , mBuild.TileSetDefinition
                                                                           , mBuild.NMGenProcessors);

                    if (builder == null)
                    {
                        mContext.PostError(
                            "Unexpected failure creating NMGen builder: Tile: " + tileText
                            , mBuild);
                        tdata.SetAsFailed(tx, tz);
                        return(false);
                    }

                    mBuild.BuildData.SetAsInProgress(tx, tz);

                    // Create and run the build task.

                    NMGenTask ntask = NMGenTask.Create(builder, 0);

                    ntask.Run();

                    if (ntask.TaskState == BuildTaskState.Aborted)
                    {
                        mContext.PostError("NMGen build task failed: Tile: " + tileText
                                           , ntask.Messages, mBuild);
                        tdata.SetAsFailed(tx, tz);
                        return(false);
                    }

                    NMGenAssets nr = ntask.Result;

                    if (nr.NoResult)
                    {
                        mContext.PostTrace("NMGen complete. Empty tile: " + tileText
                                           , builder.GetMessages()
                                           , mBuild);
                        tdata.SetAsEmpty(tx, tz);
                        continue;
                    }

                    msg = string.Format("NMGen complete. Tile {0} has {1} polygons."
                                        , tileText, nr.PolyMesh.PolyCount);

                    mContext.PostTrace(msg, builder.GetMessages(), mBuild);

                    TileBuildTask ttask = TileBuildTask.Create(tx, tz
                                                               , nr.PolyMesh.GetData(false), nr.DetailMesh.GetData(false)
                                                               , mBuild.Connections
                                                               , (mBuild.Config.BuildFlags & NMGenBuildFlag.BVTreeEnabled) != 0
                                                               , false, 0);

                    ttask.Run();

                    if (ttask.TaskState == BuildTaskState.Aborted)
                    {
                        mContext.PostError("Tile build task failed: Tile: " + tileText
                                           , ttask.Messages
                                           , mBuild);
                        tdata.SetAsFailed(tx, tz);
                        return(false);
                    }

                    TileBuildAssets tr = ttask.Result;

                    tdata.SetWorkingData(tx, tz, nr.PolyMesh, nr.DetailMesh);
                    tdata.SetWorkingData(tx, tz, tr.Tile, tr.PolyCount);
                }
            }

            int bakeable = tdata.BakeableCount();

            if (bakeable == 0)
            {
                mContext.PostError("Build did not produce any usuable tiles. (All tiles empty?)"
                                   , mBuild);
                return(false);
            }

            msg = string.Format("Tile build complete. {0} tiles produced. {1} empty tiles."
                                , bakeable, tdata.GetStateCount(TileBuildState.Empty));

            mContext.PostTrace(msg, mBuild);

            return(true);
        }
Пример #17
0
        public static void OnGUIPrimary(NavmeshBuild build
                                        , NMGenConfig config
                                        , bool includeSlope)
        {
            if (!build)
            {
                return;
            }

            bool guiEnabled = GUI.enabled;

            EditorGUIUtility.LookLikeControls(155);

            float xz = config.XZCellSize;
            float y  = config.YCellSize;
            float a  = xz * xz;
            float effective;

            //////////////////////////////////////////////////////////////

            GUILayout.Label("Agent Settings");
            GUILayout.Space(MarginSize);

            TileBuildData tdata = build.BuildData;

            GUI.enabled = guiEnabled && (tdata == null);

            effective = (float)Mathf.Ceil(config.WalkableHeight / y) * y;

            config.WalkableHeight = EditorGUILayout.FloatField(
                NMGenConfig.HeightLabel + Effective(effective)
                , config.WalkableHeight);


            effective           = (float)Mathf.Floor(config.WalkableStep / y) * y;
            config.WalkableStep = EditorGUILayout.FloatField(
                NMGenConfig.StepLabel + Effective(effective)
                , config.WalkableStep);

            effective             = (float)Mathf.Ceil(config.WalkableRadius / xz) * xz;
            config.WalkableRadius = EditorGUILayout.FloatField(
                NMGenConfig.RadiusLabel + Effective(effective)
                , config.WalkableRadius);

            GUI.enabled = guiEnabled;

            if (includeSlope)
            {
                config.WalkableSlope = EditorGUILayout.FloatField(
                    NMGenConfig.SlopeLabel
                    , config.WalkableSlope);
            }

            /////////////////////////////////////////////////////////////////

            GUILayout.Space(2 * MarginSize);
            GUILayout.Label("Resolution and Tile Settings");
            GUILayout.Space(MarginSize);

            GUI.enabled = guiEnabled && (tdata == null);

            config.XZCellSize = EditorGUILayout.FloatField(
                NMGenConfig.XZSizeLabel
                , config.XZCellSize);

            config.YCellSize = EditorGUILayout.FloatField(
                NMGenConfig.YSizeLabel
                , config.YCellSize);

            config.TileSize = EditorGUILayout.IntField(
                NMGenConfig.TileSizeLabel
                + " (" + config.TileSize * config.XZCellSize + ")"
                , config.TileSize);


            config.BorderSize = EditorGUILayout.IntField(
                NMGenConfig.HFBorderLabel
                , config.BorderSize);

            GUI.enabled = guiEnabled;

            int   derBorderSize = NMGenConfig.DeriveBorderSize(config);
            float derXZ         = NMGenConfig.DeriveXZCellSize(config);
            float derY          = NMGenConfig.DeriveYCellSize(config);

            if ((config.TileSize == 0 && config.BorderSize != derBorderSize) ||
                config.BorderSize < derBorderSize ||
                config.XZCellSize > derXZ ||
                config.YCellSize > derY)
            {
                GUILayout.Space(MarginSize);

                System.Text.StringBuilder sb = new System.Text.StringBuilder();

                sb.AppendLine("Recommendations:");

                if (config.XZCellSize > derXZ)
                {
                    sb.AppendLine(NMGenConfig.XZSizeLabel + " of " + derXZ + " or less.");
                }

                if (config.YCellSize > derY)
                {
                    sb.AppendLine(NMGenConfig.YSizeLabel + " of " + derY + " or less.");
                }

                if (config.TileSize == 0 && config.BorderSize != derBorderSize)
                {
                    sb.AppendLine("Border Size of " + derBorderSize + ".");
                }
                else if (config.BorderSize < derBorderSize)
                {
                    sb.AppendLine("Border Size of " + derBorderSize + " or higher.");
                }

                GUILayout.Box(sb.ToString().Trim(), EditorUtil.HelpStyle, GUILayout.ExpandWidth(true));
            }

            if (build.HasInputData)
            {
                InputGeometry geom = build.InputGeom;

                Vector3 bmin = geom.BoundsMin;
                Vector3 bmax = geom.BoundsMax;

                float w = bmax.x - bmin.x;
                float d = bmax.z - bmin.z;

                GUILayout.Space(MarginSize);

                int tw = Mathf.CeilToInt(w / xz);
                int td = Mathf.CeilToInt(d / xz);
                GUILayout.Label(string.Format("Cells: {0:N0} ({1:N0} x {2:N0})"
                                              , tw * td, tw, td));

                if (config.TileSize > 0)
                {
                    tw = Mathf.Max(1, Mathf.CeilToInt((float)tw / config.TileSize));
                    td = Mathf.Max(1, Mathf.CeilToInt((float)td / config.TileSize));
                }
                else
                {
                    tw = 1;
                    td = 1;
                }
                GUILayout.Label(string.Format("Tiles: {0:N0} ({1:N0} x {2:N0})"
                                              , tw * td, tw, td));
            }

            /////////////////////////////////////////////////////////////////

            GUILayout.Space(2 * MarginSize);
            GUILayout.Label("Miscellaneous Settings");
            GUILayout.Space(MarginSize);

            config.DetailSampleDistance = EditorGUILayout.FloatField(
                NMGenConfig.DetailSampleLabel
                , config.DetailSampleDistance);

            config.DetailMaxDeviation = EditorGUILayout.FloatField(
                NMGenConfig.DetailDevLabel
                , config.DetailMaxDeviation);

            effective            = Mathf.Ceil(config.MinRegionArea / a) * a;
            config.MinRegionArea = EditorGUILayout.FloatField(
                NMGenConfig.IslandRegionLabel + Effective(effective)
                , config.MinRegionArea);
        }