PageRenderTime 74ms CodeModel.GetById 46ms app.highlight 24ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Mooege/Core/GS/Map/Debug/DebugNavMesh.cs

https://github.com/angerwin/d3sharp
C# | 347 lines | 263 code | 62 blank | 22 comment | 44 complexity | 64929fb2947935440bc83475f3666e67 MD5 | raw file
  1/*
  2 * Copyright (C) 2011 mooege project
  3 *
  4 * This program is free software; you can redistribute it and/or modify
  5 * it under the terms of the GNU General Public License as published by
  6 * the Free Software Foundation; either version 2 of the License, or
  7 * (at your option) any later version.
  8 *
  9 * This program is distributed in the hope that it will be useful,
 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 * GNU General Public License for more details.
 13 *
 14 * You should have received a copy of the GNU General Public License
 15 * along with this program; if not, write to the Free Software
 16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 17 */
 18
 19using System.Drawing;
 20using System.Linq;
 21using System.Threading.Tasks;
 22using System.Windows;
 23using Mooege.Common.Helpers.Concurrency;
 24using Mooege.Core.GS.Actors;
 25using Mooege.Core.GS.Players;
 26
 27namespace Mooege.Core.GS.Map.Debug
 28{
 29    public class DebugNavMesh
 30    {
 31        public World World { get; private set; }
 32        public Player Player { get; private set; }
 33        public Rect Bounds { get { return World.QuadTree.RootNode.Bounds; } }
 34
 35        public ConcurrentList<Scene> MasterScenes { get; private set; }
 36        public ConcurrentList<Scene> SubScenes { get; private set; }
 37        public ConcurrentList<Rect> UnWalkableCells { get; private set; }
 38        public ConcurrentList<Rect> WalkableCells { get; private set; }
 39        public ConcurrentList<Player> Players { get; private set; }
 40        public ConcurrentList<Monster> Monsters { get; private set; }
 41        public ConcurrentList<NPC> NPCs { get; private set; }
 42
 43        public bool DrawMasterScenes;
 44        public bool DrawSubScenes;
 45        public bool DrawWalkableCells;
 46        public bool DrawUnwalkableCells;
 47        public bool DrawMonsters;
 48        public bool DrawNPCs;
 49        public bool DrawPlayers;
 50        public bool PrintSceneLabels;
 51        public bool FillCells;
 52        public bool DrawPlayerProximityCircle;
 53        public bool DrawPlayerProximityRectangle;
 54
 55        private readonly Pen _masterScenePen = new Pen(Color.Black, 1.0f);
 56        private readonly Pen _subScenePen = new Pen(Color.DarkGray, 1.0f);
 57        private readonly Brush _unwalkableBrush = Brushes.Red;
 58        private readonly Pen _unwalkablePen = new Pen(Color.Red, 1.0f);
 59        private readonly Brush _walkableBrush = Brushes.Blue;
 60        private readonly Pen _walkablePen = new Pen(Color.Blue, 1.0f);
 61        private readonly Pen _playerProximityPen = new Pen(Brushes.DarkViolet, 2.0f);
 62        private readonly Font _sceneFont = new Font("Verdana", 7);        
 63
 64        public DebugNavMesh(World world, Player player = null)
 65        {
 66            this.World = world;
 67            this.Player = player;
 68
 69            this._subScenePen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot;
 70
 71            this.MasterScenes = new ConcurrentList<Scene>();
 72            this.SubScenes = new ConcurrentList<Scene>();
 73            this.UnWalkableCells = new ConcurrentList<Rect>();
 74            this.WalkableCells = new ConcurrentList<Rect>();
 75            this.Players = new ConcurrentList<Player>();
 76            this.Monsters = new ConcurrentList<Monster>();
 77            this.NPCs = new ConcurrentList<NPC>();           
 78        }
 79
 80        #region update
 81
 82        public void Update(bool processObjectsInAllTheWorld)
 83        {
 84            this.MasterScenes.Clear();
 85            this.SubScenes.Clear();
 86            this.WalkableCells.Clear();
 87            this.UnWalkableCells.Clear();
 88            this.Players.Clear();
 89            this.Monsters.Clear();
 90            this.NPCs.Clear();
 91
 92            var scenes = (processObjectsInAllTheWorld || this.Player == null)
 93                                        ? World.QuadTree.Query<Scene>(World.QuadTree.RootNode.Bounds)
 94                                        : this.Player.GetScenesInRegion();
 95
 96            Parallel.ForEach(scenes, scene =>
 97            {
 98                if (scene.Parent == null)
 99                    this.MasterScenes.Add(scene);
100                else
101                    this.SubScenes.Add(scene);
102
103                this.AnalyzeScene(scene);
104            });
105
106            var actors = (processObjectsInAllTheWorld || this.Player == null)
107                        ? World.QuadTree.Query<Actor>(World.QuadTree.RootNode.Bounds)
108                        : this.Player.GetActorsInRange();
109
110            Parallel.ForEach(actors, actor =>
111            {
112                if (actor is Player)
113                    this.Players.Add(actor as Player);
114                else if (actor is NPC)
115                    this.NPCs.Add(actor as NPC);
116                else if (actor is Monster)
117                    this.Monsters.Add(actor as Monster);
118            });
119        }
120
121        private void AnalyzeScene(Scene scene)
122        {
123            Parallel.ForEach(scene.NavZone.NavCells, cell =>
124            {
125                float x = scene.Position.X + cell.Min.X;
126                float y = scene.Position.Y + cell.Min.Y;
127
128                float sizex = cell.Max.X - cell.Min.X;
129                float sizey = cell.Max.Y - cell.Min.Y;
130
131                var rect = new Rect(x, y, sizex, sizey);
132
133                // TODO: Feature request: Also allow drawing of NavCellFlags.NOSpawn, NavCellFlags.LevelAreaBit0, NavCellFlags.LevelAreaBit1 cells. /raist.
134
135                if ((cell.Flags & Mooege.Common.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk) != Mooege.Common.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk)
136                    UnWalkableCells.Add(rect);
137                else
138                    WalkableCells.Add(rect);
139            });
140        }
141
142        #endregion
143
144        #region drawing 
145
146        public Bitmap Draw()
147        {
148            // 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.
149            // 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.
150            // So instead find the rightMostScene and bottomMostScene and limit the drawed bitmaps size according. /raist.
151            // TODO: We can even limit to leftMostScene and topMostScene because player-proximity rendering mode will be also containing large empty areas. /raist.
152
153            Scene rightMostScene = null;
154            Scene bottomMostScene = null;
155
156            foreach (var scene in this.MasterScenes)
157            {
158                if (rightMostScene == null)
159                    rightMostScene = scene;
160
161                if (bottomMostScene == null)
162                    bottomMostScene = scene;
163
164                if (scene.Bounds.X + scene.Bounds.Width > rightMostScene.Bounds.X + rightMostScene.Bounds.Width)
165                    rightMostScene = scene;
166
167                if (scene.Bounds.Y + scene.Bounds.Height > bottomMostScene.Bounds.Y + bottomMostScene.Bounds.Height)
168                    bottomMostScene = scene;
169            }
170
171            if (rightMostScene == null || bottomMostScene == null) 
172                return null;
173
174            var maxX = (int) (rightMostScene.Bounds.X + rightMostScene.Bounds.Width) + 1;
175            var maxY = (int)(bottomMostScene.Bounds.Y + bottomMostScene.Bounds.Height) + 1;
176
177            var bitmap = new Bitmap(maxX, maxY, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
178
179            using (var graphics = Graphics.FromImage(bitmap))
180            {
181                graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
182                graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
183                graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
184                graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
185
186                graphics.FillRectangle(Brushes.LightGray, 0, 0, bitmap.Width, bitmap.Height);
187
188                this.DrawShapes(graphics);
189
190                if (this.PrintSceneLabels)
191                    this.DrawLabels(graphics);
192
193                graphics.Save();
194            }
195
196            return bitmap;
197        }
198
199        private void DrawShapes(Graphics graphics)
200        {
201            if (this.DrawMasterScenes)
202            {
203                foreach (var scene in this.MasterScenes)
204                {
205                    this.DrawScene(graphics, scene);
206                }
207            }
208
209            if (this.DrawSubScenes)
210            {
211                foreach (var scene in this.SubScenes)
212                {
213                    this.DrawScene(graphics, scene);
214                }
215            }
216
217            if (this.DrawWalkableCells)
218                this.DrawWalkables(graphics);
219
220            if (this.DrawUnwalkableCells)
221                this.DrawUnwalkables(graphics);
222
223            if (this.DrawMonsters)
224            {
225                foreach (var monster in this.Monsters)
226                {
227                    this.DrawActor(monster, graphics, Brushes.Green, 7);
228                }
229            }
230
231            if (this.DrawNPCs)
232            {
233                foreach (var npc in this.NPCs)
234                {
235                    this.DrawActor(npc, graphics, Brushes.Orange, 7);
236                }
237            }
238
239            if (this.DrawPlayers)
240            {
241                foreach (var player in this.Players)
242                {
243                    this.DrawActor(player, graphics, Brushes.DarkViolet, 7);
244                }
245            }
246
247            if(this.DrawPlayerProximityCircle)
248                this.DrawProximityCircle(graphics);
249
250            if(this.DrawPlayerProximityRectangle)
251                this.DrawProximityRectangle(graphics);
252        }
253
254        private void DrawScene(Graphics graphics, Scene scene)
255        {
256            var rect = new Rectangle((int)scene.Bounds.Left, (int)scene.Bounds.Top, (int)scene.Bounds.Width, (int)scene.Bounds.Height);
257            graphics.DrawRectangle(scene.Parent == null ? _masterScenePen : _subScenePen, rect);
258        }
259
260        private void DrawWalkables(Graphics graphics)
261        {
262            foreach (var cell in this.WalkableCells)
263            {
264                var rect = new Rectangle(new System.Drawing.Point((int)cell.Left, (int)cell.Top), new System.Drawing.Size((int)cell.Width, (int)cell.Height));
265                
266                if (this.FillCells)
267                    graphics.FillRectangle(_walkableBrush, rect);
268                else
269                    graphics.DrawRectangle(_walkablePen, rect);
270            }
271        }
272
273        private void DrawUnwalkables(Graphics graphics)
274        {
275            foreach (var cell in this.UnWalkableCells)
276            {
277                var rect = new Rectangle(new System.Drawing.Point((int)cell.Left, (int)cell.Top), new System.Drawing.Size((int)cell.Width, (int)cell.Height));
278                
279                if (this.FillCells)
280                    graphics.FillRectangle(_unwalkableBrush, rect);
281                else
282                    graphics.DrawRectangle(_unwalkablePen, rect);
283            }
284        }
285
286        private void DrawActor(Actor actor, Graphics graphics, Brush brush, int radius)
287        {
288            var rect = new Rectangle((int)actor.Bounds.X, (int)actor.Bounds.Y, (int)actor.Bounds.Width + radius, (int)actor.Bounds.Height + radius);
289            graphics.FillEllipse(brush, rect);
290        }
291
292        private void DrawProximityCircle(Graphics graphics)
293        {
294            if (this.Player == null) 
295                return;
296
297            var rect = new RectangleF(this.Player.Position.X - Actor.DefaultQueryProximityRadius,
298                                      this.Player.Position.Y - Actor.DefaultQueryProximityRadius,
299                                      Actor.DefaultQueryProximityRadius * 2,
300                                      Actor.DefaultQueryProximityRadius * 2);
301
302            graphics.DrawEllipse(this._playerProximityPen, rect);
303        }
304
305        private void DrawProximityRectangle(Graphics graphics)
306        {
307            if (this.Player == null)
308                return;
309
310            graphics.DrawRectangle(this._playerProximityPen,
311                                   this.Player.Position.X - Actor.DefaultQueryProximityLenght/2,
312                                   this.Player.Position.Y - Actor.DefaultQueryProximityLenght/2,
313                                   Actor.DefaultQueryProximityLenght,
314                                   Actor.DefaultQueryProximityLenght);
315        }
316
317        private void DrawLabels(Graphics graphics)
318        {
319            if (this.DrawMasterScenes)
320            {
321                foreach (var scene in this.MasterScenes)
322                {
323                    this.DrawSceneLabel(graphics, scene);
324                }
325            }
326
327            if (this.DrawSubScenes)
328            {
329                foreach (var scene in this.SubScenes)
330                {
331                    this.DrawSceneLabel(graphics, scene);
332                }
333            }
334        }
335
336        private void DrawSceneLabel(Graphics graphics, Scene scene)
337        {
338            var stringRectangle = new RectangleF((float)scene.Bounds.Left, (float)scene.Bounds.Top, (float)scene.Bounds.Width, (float)scene.Bounds.Height);
339            var drawFormat = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
340
341            if (!string.IsNullOrEmpty(scene.SceneSNO.Name))
342                graphics.DrawString(scene.SceneSNO.Name, _sceneFont, scene.Parent == null ? Brushes.Black : Brushes.Gray, stringRectangle, drawFormat);
343        }
344
345        #endregion
346    }
347}