/src/Mooege/Core/GS/Map/Debug/DebugNavMesh.cs
C# | 347 lines | 263 code | 62 blank | 22 comment | 44 complexity | 64929fb2947935440bc83475f3666e67 MD5 | raw file
- /*
- * Copyright (C) 2011 mooege project
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- using System.Drawing;
- using System.Linq;
- using System.Threading.Tasks;
- using System.Windows;
- using Mooege.Common.Helpers.Concurrency;
- using Mooege.Core.GS.Actors;
- using Mooege.Core.GS.Players;
- namespace Mooege.Core.GS.Map.Debug
- {
- public class DebugNavMesh
- {
- public World World { get; private set; }
- public Player Player { get; private set; }
- public Rect Bounds { get { return World.QuadTree.RootNode.Bounds; } }
- public ConcurrentList<Scene> MasterScenes { get; private set; }
- public ConcurrentList<Scene> SubScenes { get; private set; }
- public ConcurrentList<Rect> UnWalkableCells { get; private set; }
- public ConcurrentList<Rect> WalkableCells { get; private set; }
- public ConcurrentList<Player> Players { get; private set; }
- public ConcurrentList<Monster> Monsters { get; private set; }
- public ConcurrentList<NPC> NPCs { get; private set; }
- public bool DrawMasterScenes;
- public bool DrawSubScenes;
- public bool DrawWalkableCells;
- public bool DrawUnwalkableCells;
- public bool DrawMonsters;
- public bool DrawNPCs;
- public bool DrawPlayers;
- public bool PrintSceneLabels;
- public bool FillCells;
- public bool DrawPlayerProximityCircle;
- public bool DrawPlayerProximityRectangle;
- private readonly Pen _masterScenePen = new Pen(Color.Black, 1.0f);
- private readonly Pen _subScenePen = new Pen(Color.DarkGray, 1.0f);
- private readonly Brush _unwalkableBrush = Brushes.Red;
- private readonly Pen _unwalkablePen = new Pen(Color.Red, 1.0f);
- private readonly Brush _walkableBrush = Brushes.Blue;
- private readonly Pen _walkablePen = new Pen(Color.Blue, 1.0f);
- private readonly Pen _playerProximityPen = new Pen(Brushes.DarkViolet, 2.0f);
- private readonly Font _sceneFont = new Font("Verdana", 7);
- public DebugNavMesh(World world, Player player = null)
- {
- this.World = world;
- this.Player = player;
- this._subScenePen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot;
- this.MasterScenes = new ConcurrentList<Scene>();
- this.SubScenes = new ConcurrentList<Scene>();
- this.UnWalkableCells = new ConcurrentList<Rect>();
- this.WalkableCells = new ConcurrentList<Rect>();
- this.Players = new ConcurrentList<Player>();
- this.Monsters = new ConcurrentList<Monster>();
- this.NPCs = new ConcurrentList<NPC>();
- }
- #region update
- public void Update(bool processObjectsInAllTheWorld)
- {
- this.MasterScenes.Clear();
- this.SubScenes.Clear();
- this.WalkableCells.Clear();
- this.UnWalkableCells.Clear();
- this.Players.Clear();
- this.Monsters.Clear();
- this.NPCs.Clear();
- var scenes = (processObjectsInAllTheWorld || this.Player == null)
- ? World.QuadTree.Query<Scene>(World.QuadTree.RootNode.Bounds)
- : this.Player.GetScenesInRegion();
- Parallel.ForEach(scenes, scene =>
- {
- if (scene.Parent == null)
- this.MasterScenes.Add(scene);
- else
- this.SubScenes.Add(scene);
- this.AnalyzeScene(scene);
- });
- var actors = (processObjectsInAllTheWorld || this.Player == null)
- ? World.QuadTree.Query<Actor>(World.QuadTree.RootNode.Bounds)
- : this.Player.GetActorsInRange();
- Parallel.ForEach(actors, actor =>
- {
- if (actor is Player)
- this.Players.Add(actor as Player);
- else if (actor is NPC)
- this.NPCs.Add(actor as NPC);
- else if (actor is Monster)
- this.Monsters.Add(actor as Monster);
- });
- }
- private void AnalyzeScene(Scene scene)
- {
- Parallel.ForEach(scene.NavZone.NavCells, cell =>
- {
- float x = scene.Position.X + cell.Min.X;
- float y = scene.Position.Y + cell.Min.Y;
- float sizex = cell.Max.X - cell.Min.X;
- float sizey = cell.Max.Y - cell.Min.Y;
- var rect = new Rect(x, y, sizex, sizey);
- // TODO: Feature request: Also allow drawing of NavCellFlags.NOSpawn, NavCellFlags.LevelAreaBit0, NavCellFlags.LevelAreaBit1 cells. /raist.
- if ((cell.Flags & Mooege.Common.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk) != Mooege.Common.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk)
- UnWalkableCells.Add(rect);
- else
- WalkableCells.Add(rect);
- });
- }
- #endregion
- #region drawing
- public Bitmap Draw()
- {
- // As quad-tree always has 4 quad-nodes beneath the root node, the quad node's area will be far larger then actual area covered by scenes.
- // We don't want to draw a bitmap that's as large as quad-tree's area, as it'll be consuming so much memory.
- // So instead find the rightMostScene and bottomMostScene and limit the drawed bitmaps size according. /raist.
- // TODO: We can even limit to leftMostScene and topMostScene because player-proximity rendering mode will be also containing large empty areas. /raist.
- Scene rightMostScene = null;
- Scene bottomMostScene = null;
- foreach (var scene in this.MasterScenes)
- {
- if (rightMostScene == null)
- rightMostScene = scene;
- if (bottomMostScene == null)
- bottomMostScene = scene;
- if (scene.Bounds.X + scene.Bounds.Width > rightMostScene.Bounds.X + rightMostScene.Bounds.Width)
- rightMostScene = scene;
- if (scene.Bounds.Y + scene.Bounds.Height > bottomMostScene.Bounds.Y + bottomMostScene.Bounds.Height)
- bottomMostScene = scene;
- }
- if (rightMostScene == null || bottomMostScene == null)
- return null;
- var maxX = (int) (rightMostScene.Bounds.X + rightMostScene.Bounds.Width) + 1;
- var maxY = (int)(bottomMostScene.Bounds.Y + bottomMostScene.Bounds.Height) + 1;
- var bitmap = new Bitmap(maxX, maxY, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
- using (var graphics = Graphics.FromImage(bitmap))
- {
- graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
- graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
- graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
- graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
- graphics.FillRectangle(Brushes.LightGray, 0, 0, bitmap.Width, bitmap.Height);
- this.DrawShapes(graphics);
- if (this.PrintSceneLabels)
- this.DrawLabels(graphics);
- graphics.Save();
- }
- return bitmap;
- }
- private void DrawShapes(Graphics graphics)
- {
- if (this.DrawMasterScenes)
- {
- foreach (var scene in this.MasterScenes)
- {
- this.DrawScene(graphics, scene);
- }
- }
- if (this.DrawSubScenes)
- {
- foreach (var scene in this.SubScenes)
- {
- this.DrawScene(graphics, scene);
- }
- }
- if (this.DrawWalkableCells)
- this.DrawWalkables(graphics);
- if (this.DrawUnwalkableCells)
- this.DrawUnwalkables(graphics);
- if (this.DrawMonsters)
- {
- foreach (var monster in this.Monsters)
- {
- this.DrawActor(monster, graphics, Brushes.Green, 7);
- }
- }
- if (this.DrawNPCs)
- {
- foreach (var npc in this.NPCs)
- {
- this.DrawActor(npc, graphics, Brushes.Orange, 7);
- }
- }
- if (this.DrawPlayers)
- {
- foreach (var player in this.Players)
- {
- this.DrawActor(player, graphics, Brushes.DarkViolet, 7);
- }
- }
- if(this.DrawPlayerProximityCircle)
- this.DrawProximityCircle(graphics);
- if(this.DrawPlayerProximityRectangle)
- this.DrawProximityRectangle(graphics);
- }
- private void DrawScene(Graphics graphics, Scene scene)
- {
- var rect = new Rectangle((int)scene.Bounds.Left, (int)scene.Bounds.Top, (int)scene.Bounds.Width, (int)scene.Bounds.Height);
- graphics.DrawRectangle(scene.Parent == null ? _masterScenePen : _subScenePen, rect);
- }
- private void DrawWalkables(Graphics graphics)
- {
- foreach (var cell in this.WalkableCells)
- {
- var rect = new Rectangle(new System.Drawing.Point((int)cell.Left, (int)cell.Top), new System.Drawing.Size((int)cell.Width, (int)cell.Height));
-
- if (this.FillCells)
- graphics.FillRectangle(_walkableBrush, rect);
- else
- graphics.DrawRectangle(_walkablePen, rect);
- }
- }
- private void DrawUnwalkables(Graphics graphics)
- {
- foreach (var cell in this.UnWalkableCells)
- {
- var rect = new Rectangle(new System.Drawing.Point((int)cell.Left, (int)cell.Top), new System.Drawing.Size((int)cell.Width, (int)cell.Height));
-
- if (this.FillCells)
- graphics.FillRectangle(_unwalkableBrush, rect);
- else
- graphics.DrawRectangle(_unwalkablePen, rect);
- }
- }
- private void DrawActor(Actor actor, Graphics graphics, Brush brush, int radius)
- {
- var rect = new Rectangle((int)actor.Bounds.X, (int)actor.Bounds.Y, (int)actor.Bounds.Width + radius, (int)actor.Bounds.Height + radius);
- graphics.FillEllipse(brush, rect);
- }
- private void DrawProximityCircle(Graphics graphics)
- {
- if (this.Player == null)
- return;
- var rect = new RectangleF(this.Player.Position.X - Actor.DefaultQueryProximityRadius,
- this.Player.Position.Y - Actor.DefaultQueryProximityRadius,
- Actor.DefaultQueryProximityRadius * 2,
- Actor.DefaultQueryProximityRadius * 2);
- graphics.DrawEllipse(this._playerProximityPen, rect);
- }
- private void DrawProximityRectangle(Graphics graphics)
- {
- if (this.Player == null)
- return;
- graphics.DrawRectangle(this._playerProximityPen,
- this.Player.Position.X - Actor.DefaultQueryProximityLenght/2,
- this.Player.Position.Y - Actor.DefaultQueryProximityLenght/2,
- Actor.DefaultQueryProximityLenght,
- Actor.DefaultQueryProximityLenght);
- }
- private void DrawLabels(Graphics graphics)
- {
- if (this.DrawMasterScenes)
- {
- foreach (var scene in this.MasterScenes)
- {
- this.DrawSceneLabel(graphics, scene);
- }
- }
- if (this.DrawSubScenes)
- {
- foreach (var scene in this.SubScenes)
- {
- this.DrawSceneLabel(graphics, scene);
- }
- }
- }
- private void DrawSceneLabel(Graphics graphics, Scene scene)
- {
- var stringRectangle = new RectangleF((float)scene.Bounds.Left, (float)scene.Bounds.Top, (float)scene.Bounds.Width, (float)scene.Bounds.Height);
- var drawFormat = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
- if (!string.IsNullOrEmpty(scene.SceneSNO.Name))
- graphics.DrawString(scene.SceneSNO.Name, _sceneFont, scene.Parent == null ? Brushes.Black : Brushes.Gray, stringRectangle, drawFormat);
- }
- #endregion
- }
- }