From d888e57c76c7927ff79014919ea72bb950b8b403 Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Thu, 21 Apr 2016 21:00:58 +0000
Subject: [PATCH] Added, Draw Lines mode: additional guidelines and
 horizontal/vertical line lengths can now be displayed for currently drawn
 line using "Show guidelines" top menu button. Changed, Draw Lines mode: line
 angles are now shown only when "Show guidelines" mode is enabled. Fixed, Draw
 Lines mode: in some cases "Snap to cardinal directions" mode was snapping
 only to diagonals. Fixed, Draw Lines mode: snap to geometry behaved
 incorrectly when "Snap to cardinal directions" mode was enabled. Changed,
 Things mode: dynamic light shape is now drawn using highlight color when a
 dynamic light thing is highlighted. Added more sanity checks to MODELDEFS
 parser.

---
 .../Core/GZBuilder/GZDoom/ModeldefParser.cs   |  19 +-
 .../GZBuilder/GZDoom/ModeldefStructure.cs     |  16 +-
 Source/Core/Geometry/Line2D.cs                |  42 +++-
 Source/Core/Geometry/Tools.cs                 |  86 --------
 .../Plugins/BuilderModes/BuilderModes.csproj  |   3 +
 .../BuilderModes/ClassicModes/BridgeMode.cs   |   2 +-
 .../ClassicModes/DrawGeometryMode.cs          | 201 ++++++++++++++----
 .../BuilderModes/ClassicModes/DrawGridMode.cs |   4 +-
 .../BuilderModes/ClassicModes/LinedefsMode.cs |   6 +-
 .../BuilderModes/ClassicModes/SectorsMode.cs  |   4 +-
 .../BuilderModes/ClassicModes/ThingsMode.cs   | 100 ++++++++-
 .../BuilderModes/ClassicModes/VerticesMode.cs |   2 +-
 .../DrawLineOptionsPanel.Designer.cs          |  20 +-
 .../Interface/DrawLineOptionsPanel.cs         |   9 +
 .../Properties/Resources.Designer.cs          |   7 +
 .../BuilderModes/Properties/Resources.resx    |  25 ++-
 .../BuilderModes/Resources/Guidelines.png     | Bin 0 -> 1101 bytes
 Source/Plugins/NodesViewer/NodesViewerMode.cs |   4 +-
 18 files changed, 389 insertions(+), 161 deletions(-)
 create mode 100644 Source/Plugins/BuilderModes/Resources/Guidelines.png

diff --git a/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs b/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
index 3e70094b0..aa954256e 100644
--- a/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
+++ b/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
@@ -109,6 +109,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
 								// Add models
 								foreach(var fs in mds.Frames[targetsprite])
 								{
+									// Sanity checks
+									if(string.IsNullOrEmpty(mds.ModelNames[fs.ModelIndex]))
+									{
+										LogWarning("Model definition \"" + classname + "\", frame \"" + fs.SpriteName + " " + fs.FrameName + "\" references undefiend model index " + fs.ModelIndex);
+										continue;
+									}
+									
 									// Texture name will be empty when skin path is embedded in the model
 									string texturename = (!string.IsNullOrEmpty(mds.TextureNames[fs.ModelIndex]) ? mds.TextureNames[fs.ModelIndex].ToLowerInvariant() : string.Empty);
 
@@ -118,8 +125,16 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
 									md.FrameIndices.Add(fs.FrameIndex);
 								}
 
-								// Add to collection
-								entries[classname] = md;
+								// More sanity checks...
+								if(md.ModelNames.Count == 0)
+								{
+									LogWarning("Model definition \"" + classname + "\" has no defined models");
+								}
+								else
+								{
+									// Add to collection
+									entries[classname] = md;
+								}
 							}
 						}
 					}
diff --git a/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs b/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
index 52428707d..d232f88dc 100644
--- a/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
+++ b/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
@@ -335,12 +335,18 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
 						parser.SkipWhitespace(true);
 						int fimodelindnex;
 						token = parser.ReadToken();
-						if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out fimodelindnex) || fimodelindnex < 0)
+						if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out fimodelindnex))
 						{
 							// Not numeric!
 							parser.ReportError("Expected model index, but got \"" + token + "\"");
 							return false;
 						}
+						if(fimodelindnex < 0 || fimodelindnex > MAX_MODELS - 1)
+						{
+							// Out of bounds
+							parser.ReportError("Model index must be in [0.." + (MAX_MODELS - 1) + "] range");
+							return false;
+						}
 
 						// Frame number
 						parser.SkipWhitespace(true);
@@ -407,12 +413,18 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom
 						parser.SkipWhitespace(true);
 						int modelindnex;
 						token = parser.ReadToken();
-						if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out modelindnex) || modelindnex < 0)
+						if(!int.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out modelindnex))
 						{
 							// Not numeric!
 							parser.ReportError("Expected model index, but got \"" + token + "\"");
 							return false;
 						}
+						if(modelindnex < 0 || modelindnex > MAX_MODELS - 1)
+						{
+							// Out of bounds
+							parser.ReportError("Model index must be in [0.." + (MAX_MODELS - 1) + "] range");
+							return false;
+						}
 
 						// Frame name
 						parser.SkipWhitespace(true);
diff --git a/Source/Core/Geometry/Line2D.cs b/Source/Core/Geometry/Line2D.cs
index 934dad6e9..5a8f6e0c6 100644
--- a/Source/Core/Geometry/Line2D.cs
+++ b/Source/Core/Geometry/Line2D.cs
@@ -107,11 +107,35 @@ namespace CodeImp.DoomBuilder.Geometry
 		public static bool GetIntersection(Vector2D v1, Vector2D v2, float x3, float y3, float x4, float y4, out float u_ray)
 		{
 			float u_line;
-			return GetIntersection(v1, v2, x3, y3, x4, y4, out u_ray, out u_line);
+			return GetIntersection(v1, v2, x3, y3, x4, y4, out u_ray, out u_line, true);
+		}
+
+		//mxd. This tests if the line intersects with the given line coordinates
+		public static bool GetIntersection(Vector2D v1, Vector2D v2, float x3, float y3, float x4, float y4, out float u_ray, bool bounded)
+		{
+			float u_line;
+			return GetIntersection(v1, v2, x3, y3, x4, y4, out u_ray, out u_line, bounded);
+		}
+
+		//mxd. Gets intersection point between given lines
+		public static Vector2D GetIntersectionPoint(Line2D line1, Line2D line2, bool bounded)
+		{
+			float u_ray, u_line;
+			if(GetIntersection(line1.v1, line1.v2, line2.v1.x, line2.v1.y, line2.v2.x, line2.v2.y, out u_ray, out u_line, bounded))
+				return GetCoordinatesAt(line2.v1, line2.v2, u_ray);
+
+			// No dice...
+			return new Vector2D(float.NaN, float.NaN);
 		}
 
 		// This tests if the line intersects with the given line coordinates
 		public static bool GetIntersection(Vector2D v1, Vector2D v2, float x3, float y3, float x4, float y4, out float u_ray, out float u_line)
+		{
+			return GetIntersection(v1, v2, x3, y3, x4, y4, out u_ray, out u_line, true);
+		}
+
+		// This tests if the line intersects with the given line coordinates
+		public static bool GetIntersection(Vector2D v1, Vector2D v2, float x3, float y3, float x4, float y4, out float u_ray, out float u_line, bool bounded)
 		{
 			// Calculate divider
 			float div = (y4 - y3) * (v2.x - v1.x) - (x4 - x3) * (v2.y - v1.y);
@@ -126,7 +150,7 @@ namespace CodeImp.DoomBuilder.Geometry
 				u_ray = ((v2.x - v1.x) * (v1.y - y3) - (v2.y - v1.y) * (v1.x - x3)) / div;
 
 				// Return if intersecting
-				if(u_ray < 0.0f || u_ray > 1.0f || u_line < 0.0f || u_line > 1.0f) return false; //mxd
+				if(bounded && (u_ray < 0.0f || u_ray > 1.0f || u_line < 0.0f || u_line > 1.0f)) return false; //mxd
 				return true;
 			}
 
@@ -229,7 +253,12 @@ namespace CodeImp.DoomBuilder.Geometry
 
 		public bool GetIntersection(float x3, float y3, float x4, float y4, out float u_ray)
 		{
-			return Line2D.GetIntersection(v1, v2, x3, y3, x4, y4, out u_ray);
+			return Line2D.GetIntersection(v1, v2, x3, y3, x4, y4, out u_ray, true);
+		}
+
+		public bool GetIntersection(float x3, float y3, float x4, float y4, out float u_ray, bool bounded)
+		{
+			return Line2D.GetIntersection(v1, v2, x3, y3, x4, y4, out u_ray, bounded);
 		}
 
 		public bool GetIntersection(float x3, float y3, float x4, float y4, out float u_ray, out float u_line)
@@ -244,7 +273,12 @@ namespace CodeImp.DoomBuilder.Geometry
 
 		public bool GetIntersection(Line2D ray, out float u_ray)
 		{
-			return Line2D.GetIntersection(v1, v2, ray.v1.x, ray.v1.y, ray.v2.x, ray.v2.y, out u_ray);
+			return Line2D.GetIntersection(v1, v2, ray.v1.x, ray.v1.y, ray.v2.x, ray.v2.y, out u_ray, true);
+		}
+
+		public bool GetIntersection(Line2D ray, out float u_ray, bool bounded)
+		{
+			return Line2D.GetIntersection(v1, v2, ray.v1.x, ray.v1.y, ray.v2.x, ray.v2.y, out u_ray, bounded);
 		}
 
 		public bool GetIntersection(Line2D ray, out float u_ray, out float u_line)
diff --git a/Source/Core/Geometry/Tools.cs b/Source/Core/Geometry/Tools.cs
index bf3b151e6..727542fa9 100644
--- a/Source/Core/Geometry/Tools.cs
+++ b/Source/Core/Geometry/Tools.cs
@@ -2155,92 +2155,6 @@ namespace CodeImp.DoomBuilder.Geometry
 			return (int)t.Position.z;
 		}
 
-		public static List<Line3D> GetDynamicLightShapes()
-		{
-			List<Line3D> circles = new List<Line3D>();
-			const int linealpha = 128;
-			foreach(Thing t in General.Map.Map.Things)
-			{
-				int lightid = Array.IndexOf(GZBuilder.GZGeneral.GZ_LIGHTS, t.Type);
-				if(lightid == -1) continue;
-
-				// TODO: this basically duplicates VisualThing.UpdateLight()...
-				// Determine light radiii
-				int primaryradius;
-				int secondaryradius = 0;
-
-				if(lightid < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[2]) //if it's gzdoom light
-				{
-					int n;
-					if(lightid < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[0]) n = 0;
-					else if(lightid < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[1]) n = 10;
-					else n = 20;
-					DynamicLightType lightType = (DynamicLightType)(t.Type - 9800 - n);
-
-					if(lightType == DynamicLightType.SECTOR)
-					{
-						if(t.Sector == null) t.DetermineSector();
-						int scaler = (t.Sector != null ? t.Sector.Brightness / 4 : 2);
-						primaryradius = (int)Math.Round((t.Args[3] * scaler) * General.Settings.GZDynamicLightRadius);
-					}
-					else
-					{
-						primaryradius = (int)Math.Round((t.Args[3] * 2) * General.Settings.GZDynamicLightRadius); //works... that.. way in GZDoom
-						if(lightType > 0)
-							secondaryradius = (int)Math.Round((t.Args[4] * 2) * General.Settings.GZDynamicLightRadius);
-					}
-				}
-				else //it's one of vavoom lights
-				{
-					primaryradius = (int)Math.Round((t.Args[0] * 8) * General.Settings.GZDynamicLightRadius);
-				}
-
-				// Check radii...
-				if(primaryradius < 1 && secondaryradius < 1) continue;
-
-				// Determine light color
-				PixelColor color;
-				switch(t.Type)
-				{
-					case 1502: // Vavoom light
-						color = new PixelColor(linealpha, 255, 255, 255);
-						break;
-
-					case 1503: // Vavoom colored light
-						color = new PixelColor(linealpha, (byte)t.Args[1], (byte)t.Args[2], (byte)t.Args[3]);
-						break;
-
-					default:
-						color = new PixelColor(linealpha, (byte)t.Args[0], (byte)t.Args[1], (byte)t.Args[2]);
-						break;
-				}
-
-				// Add lines if visible
-				const int numsides = 24;
-				if(primaryradius > 0) circles.AddRange(MakeCircleLines(t.Position, color, primaryradius, numsides));
-				if(secondaryradius > 0) circles.AddRange(MakeCircleLines(t.Position, color, secondaryradius, numsides));
-			}
-
-			// Done
-			return circles;
-		}
-
-		private static IEnumerable<Line3D> MakeCircleLines(Vector2D pos, PixelColor color, float radius, int numsides)
-		{
-			List<Line3D> result = new List<Line3D>(numsides);
-			Vector2D start = new Vector2D(pos.x, pos.y + radius);
-			float anglestep = Angle2D.PI2 / numsides;
-			
-			for(int i = 1; i < numsides + 1; i++)
-			{
-				Vector2D end = pos + new Vector2D((float)Math.Sin(anglestep * i) * radius, (float)Math.Cos(anglestep * i) * radius);
-				result.Add(new Line3D(start, end, color, false));
-				start = end;
-			}
-
-			return result;
-		} 
-
 		#endregion
 
 		#region ================== Linedefs (mxd)
diff --git a/Source/Plugins/BuilderModes/BuilderModes.csproj b/Source/Plugins/BuilderModes/BuilderModes.csproj
index 2afdcfb64..7558bb976 100644
--- a/Source/Plugins/BuilderModes/BuilderModes.csproj
+++ b/Source/Plugins/BuilderModes/BuilderModes.csproj
@@ -610,6 +610,9 @@
   <ItemGroup>
     <None Include="Resources\Repeat.png" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="Resources\Guidelines.png" />
+  </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
diff --git a/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs b/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
index d42c8cfe4..b223c482c 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
@@ -196,7 +196,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.ClassicModes
 				{
 					List<DrawnVertex> points = new List<DrawnVertex>();
 					for(int p = 0; p < shapes[i][c].Length; p++)
-						points.Add(DrawGeometryMode.GetCurrentPosition(shapes[i][c][p], true, false, false, renderer, points));
+						points.Add(DrawGeometryMode.GetCurrentPosition(shapes[i][c][p], true, false, false, false, renderer, points));
 					shapesRow.Add(points);
 				}
 				drawShapes.Add(shapesRow);
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
index 00ccb9fea..dcd482b08 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
@@ -23,6 +23,7 @@ using System.Windows.Forms;
 using CodeImp.DoomBuilder.Actions;
 using CodeImp.DoomBuilder.Editing;
 using CodeImp.DoomBuilder.Geometry;
+using CodeImp.DoomBuilder.GZBuilder.Geometry;
 using CodeImp.DoomBuilder.Map;
 using CodeImp.DoomBuilder.Rendering;
 using CodeImp.DoomBuilder.Windows;
@@ -54,20 +55,20 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Drawing points
 		protected List<DrawnVertex> points;
 		protected List<LineLengthLabel> labels;
-
-		// Keep track of view changes (never used. mxd)
-		//protected float lastoffsetx;
-		//protected float lastoffsety;
-		//protected float lastscale;
+		private LineLengthLabel[] guidelabels; //mxd
 
 		// Options
 		protected bool snaptogrid;		// SHIFT to toggle
 		protected bool snaptonearest;	// CTRL to enable
 		protected bool snaptocardinaldirection; //mxd. ALT-SHIFT to enable
-		protected static bool usefourcardinaldirections;
+		protected bool usefourcardinaldirections;
 		protected bool continuousdrawing; //mxd. Restart after finishing drawing?
 		protected bool autoclosedrawing;  //mxd. Finish drawing when new points and existing geometry form a closed shape
 		protected bool drawingautoclosed; //mxd
+		private bool showguidelines; //mxd
+
+		//mxd. Map area bounds
+		private Line2D top, bottom, left, right;
 
 		//mxd. Labels display style
 		protected bool labelshowangle = true;
@@ -109,8 +110,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(!isdisposed)
 			{
 				// Clean up
-				if(labels != null)
-					foreach(LineLengthLabel l in labels) l.Dispose();
+				if(labels != null) foreach(LineLengthLabel l in labels) l.Dispose();
+				if(guidelabels != null) foreach(LineLengthLabel l in guidelabels) l.Dispose();
 				
 				// Done
 				base.Dispose();
@@ -154,9 +155,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				// Update labels for already drawn lines
 				for(int i = 0; i < labels.Count - 1; i++)
+				{
+					labels[i].ShowAngle = showguidelines;
 					labels[i].Move(points[i].pos, points[i + 1].pos);
+				}
 
 				// Update label for active line
+				labels[labels.Count - 1].ShowAngle = showguidelines;
 				labels[labels.Count - 1].Move(points[points.Count - 1].pos, curp.pos);
 			}
 
@@ -167,6 +172,64 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				PixelColor color;
 				if(points.Count > 0)
 				{
+					//mxd
+					bool renderguidelabels = false;
+					if(showguidelines)
+					{
+						Vector2D prevp = points[points.Count - 1].pos;
+						if(curp.pos.x != prevp.x && curp.pos.y != prevp.y)
+						{
+							renderguidelabels = true;
+							
+							Vector2D tr = new Vector2D(Math.Max(curp.pos.x, prevp.x), Math.Max(curp.pos.y, prevp.y));
+							Vector2D bl = new Vector2D(Math.Min(curp.pos.x, prevp.x), Math.Min(curp.pos.y, prevp.y));
+							
+							// Create guidelines
+							PixelColor c = General.Colors.InfoLine.WithAlpha(80);
+							Line3D[] lines = new Line3D[5];
+							lines[0] = new Line3D(new Vector2D(tr.x, General.Map.Config.TopBoundary), new Vector2D(tr.x, General.Map.Config.BottomBoundary), c, false);
+							lines[1] = new Line3D(new Vector2D(bl.x, General.Map.Config.TopBoundary), new Vector2D(bl.x, General.Map.Config.BottomBoundary), c, false);
+							lines[2] = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, tr.y), new Vector2D(General.Map.Config.RightBoundary, tr.y), c, false);
+							lines[3] = new Line3D(new Vector2D(General.Map.Config.LeftBoundary, bl.y), new Vector2D(General.Map.Config.RightBoundary, bl.y), c, false);
+
+							// Create current line extent. Make sure v1 is to the left of v2
+							Line2D current = (curp.pos.x < prevp.x ? new Line2D(curp.pos, prevp) : new Line2D(prevp, curp.pos));
+							
+							Vector2D extentstart, extentend;
+							if(current.v1.y < current.v2.y) // Start is lower
+							{
+								// Start point can hit left or bottom boundaries
+								extentstart = Line2D.GetIntersectionPoint(left, current, false);
+								if(extentstart.y < General.Map.Config.BottomBoundary) extentstart = Line2D.GetIntersectionPoint(bottom, current, false);
+
+								// End point can hit right or top boundaries
+								extentend = Line2D.GetIntersectionPoint(right, current, false);
+								if(extentend.y > General.Map.Config.TopBoundary) extentend = Line2D.GetIntersectionPoint(top, current, false);
+							}
+							else // Start is higher
+							{
+								// Start point can hit left or top boundaries
+								extentstart = Line2D.GetIntersectionPoint(left, current, false);
+								if(extentstart.y > General.Map.Config.TopBoundary) extentstart = Line2D.GetIntersectionPoint(top, current, false);
+
+								// End point can hit right or bottom boundaries
+								extentend = Line2D.GetIntersectionPoint(right, current, false);
+								if(extentend.y < General.Map.Config.BottomBoundary) extentend = Line2D.GetIntersectionPoint(bottom, current, false);
+							}
+
+							lines[4] = new Line3D(extentstart, extentend, c, false);
+
+							// Render them
+							renderer.RenderArrows(lines);
+
+							// Update horiz/vert length labels
+							guidelabels[0].Move(tr, new Vector2D(tr.x, bl.y));
+							guidelabels[1].Move(new Vector2D(bl.x, tr.y), tr);
+							guidelabels[2].Move(new Vector2D(tr.x, bl.y), bl);
+							guidelabels[3].Move(bl, new Vector2D(bl.x, tr.y));
+						}
+					}
+					
 					// Render lines
 					DrawnVertex lastp = points[0];
 					for(int i = 1; i < points.Count; i++)
@@ -197,6 +260,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						// Render vertex
 						renderer.RenderRectangleFilled(new RectangleF(points[i].pos.x - vsize, points[i].pos.y - vsize, vsize * 2.0f, vsize * 2.0f), color, true);
 					}
+
+					//mxd. Render guide labels?
+					if(renderguidelabels)
+					{
+						foreach(LineLengthLabel l in guidelabels) renderer.RenderText(l.TextLabel);
+					}
 				}
 
 				// Determine point color
@@ -226,14 +295,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		}
 		
 		// This returns the aligned and snapped draw position
-		public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, bool snaptocardinal, IRenderer2D renderer, List<DrawnVertex> points)
+		public static DrawnVertex GetCurrentPosition(Vector2D mousemappos, bool snaptonearest, bool snaptogrid, bool snaptocardinal, bool usefourcardinaldirections, IRenderer2D renderer, List<DrawnVertex> points)
 		{
 			DrawnVertex p = new DrawnVertex();
 			p.stitch = true; //mxd. Setting these to false seems to be a good way to create invalid geometry...
 			p.stitchline = true; //mxd
 
 			//mxd. If snap to cardinal directions is enabled and we have points, modify mouse position
-			Vector2D vm;
+			Vector2D vm, gridoffset;
 			if(snaptocardinal && points.Count > 0)
 			{
 				Vector2D offset = mousemappos - points[points.Count - 1].pos;
@@ -246,10 +315,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 				offset = new Vector2D(0, -offset.GetLength()).GetRotated(angle);
 				vm = points[points.Count - 1].pos + offset;
+
+				//mxd. We need to be snapped relative to initial position
+				Vector2D prev = points[points.Count - 1].pos;
+				gridoffset = prev - General.Map.Grid.SnappedToGrid(prev);
 			}
 			else
 			{
 				vm = mousemappos;
+				gridoffset = new Vector2D();
 			}
 			
 			float vrange = BuilderPlug.Me.StitchRange / renderer.Scale;
@@ -260,31 +334,60 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				// Go for all drawn points
 				foreach(DrawnVertex v in points)
 				{
-					if(Vector2D.DistanceSq(mousemappos, v.pos) < (vrange * vrange))
+					if(Vector2D.DistanceSq(vm, v.pos) < (vrange * vrange))
 					{
 						p.pos = v.pos;
-						//p.stitch = true;
-						//p.stitchline = true;
 						return p;
 					}
 				}
 
 				// Try the nearest vertex
-				Vertex nv = General.Map.Map.NearestVertexSquareRange(mousemappos, vrange);
+				Vertex nv = General.Map.Map.NearestVertexSquareRange(vm, vrange);
 				if(nv != null)
 				{
-					p.pos = nv.Position;
-					//p.stitch = true;
-					//p.stitchline = true;
-					return p;
+					//mxd. Line angle must stay the same
+					if(snaptocardinal) //mxd
+					{
+						Line2D ourline = new Line2D(points[points.Count - 1].pos, vm);
+						if(Math.Round(ourline.GetSideOfLine(nv.Position), 1) == 0)
+						{
+							p.pos = nv.Position;
+							return p;
+						}
+					}
+					else
+					{
+						p.pos = nv.Position;
+						return p;
+					}
 				}
 
-				// Try the nearest linedef
-				Linedef nl = General.Map.Map.NearestLinedefRange(mousemappos, BuilderPlug.Me.StitchRange / renderer.Scale);
+				// Try the nearest linedef. mxd. We'll need much bigger stitch distance when snapping to cardinal directions
+				Linedef nl = General.Map.Map.NearestLinedefRange(vm, BuilderPlug.Me.StitchRange / renderer.Scale);
 				if(nl != null)
 				{
+					//mxd. Line angle must stay the same
+					if(snaptocardinal)
+					{
+						Line2D ourline = new Line2D(points[points.Count - 1].pos, vm);
+						Line2D nearestline = new Line2D(nl.Start.Position, nl.End.Position);
+						Vector2D intersection = Line2D.GetIntersectionPoint(nearestline, ourline, false);
+						if(!float.IsNaN(intersection.x))
+						{
+							// Intersection is on nearestline?
+							float u = Line2D.GetNearestOnLine(nearestline.v1, nearestline.v2, intersection);
+
+							if(u < 0f || u > 1f){}
+							else
+							{
+								p.pos = new Vector2D((float)Math.Round(intersection.x, General.Map.FormatInterface.VertexDecimals), 
+													 (float)Math.Round(intersection.y, General.Map.FormatInterface.VertexDecimals));
+								return p;
+							}
+						}
+					}
 					// Snap to grid?
-					if(snaptogrid)
+					else if(snaptogrid)
 					{
 						// Get grid intersection coordinates
 						List<Vector2D> coords = nl.GetGridIntersections();
@@ -295,7 +398,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						Vector2D found_coord = new Vector2D();
 						foreach(Vector2D v in coords)
 						{
-							Vector2D delta = mousemappos - v;
+							Vector2D delta = vm - v;
 							if(delta.GetLengthSq() < found_distance)
 							{
 								found_distance = delta.GetLengthSq();
@@ -308,17 +411,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						{
 							// Align to the closest grid intersection
 							p.pos = found_coord;
-							//p.stitch = true;
-							//p.stitchline = true;
 							return p;
 						}
 					}
 					else
 					{
 						// Aligned to line
-						p.pos = nl.NearestOnLine(mousemappos);
-						//p.stitch = true;
-						//p.stitchline = true;
+						p.pos = nl.NearestOnLine(vm);
 						return p;
 					}
 				}
@@ -328,11 +427,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				// Always snap to the first drawn vertex so that the user can finish a complete sector without stitching
 				if(points.Count > 0)
 				{
-					if(Vector2D.DistanceSq(mousemappos, points[0].pos) < (vrange * vrange))
+					if(Vector2D.DistanceSq(vm, points[0].pos) < (vrange * vrange))
 					{
 						p.pos = points[0].pos;
-						//p.stitch = true;
-						//p.stitchline = false;
 						return p;
 					}
 				}
@@ -374,31 +471,26 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					vm = points[points.Count - 1].pos;
 				else
 					vm = dline.GetCoordinatesAt(u);
-
 			}
 
-
 			// Snap to grid?
 			if(snaptogrid)
 			{
 				// Aligned to grid
-				p.pos = General.Map.Grid.SnappedToGrid(vm);
+				p.pos = General.Map.Grid.SnappedToGrid(vm - gridoffset) + gridoffset;
 
 				// special handling 
 				if(p.pos.x > General.Map.Config.RightBoundary) p.pos.x = General.Map.Config.RightBoundary;
 				if(p.pos.y < General.Map.Config.BottomBoundary) p.pos.y = General.Map.Config.BottomBoundary;
-				//p.stitch = snaptonearest;
-				//p.stitchline = snaptonearest;
+
 				return p;
 			}
 			else
 			{
 				// Normal position
-				vm.x = (float)Math.Round(vm.x); //mxd
-				vm.y = (float)Math.Round(vm.y); //mxd
-				p.pos = vm;
-				//p.stitch = snaptonearest;
-				//p.stitchline = snaptonearest;
+				p.pos.x = (float)Math.Round(vm.x); //mxd
+				p.pos.y = (float)Math.Round(vm.y); //mxd
+
 				return p;
 			}
 		}
@@ -406,7 +498,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This gets the aligned and snapped draw position
 		protected DrawnVertex GetCurrentPosition()
 		{
-			return GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, snaptocardinaldirection, renderer, points);
+			return GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, snaptocardinaldirection, usefourcardinaldirections, renderer, points);
 		}
 		
 		// This draws a point at a specific location
@@ -560,10 +652,29 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			panel = new DrawLineOptionsPanel();
 			panel.OnContinuousDrawingChanged += OnContinuousDrawingChanged;
 			panel.OnAutoCloseDrawingChanged += OnAutoCloseDrawingChanged;
+			panel.OnShowGuidelinesChanged += OnShowGuidelinesChanged;
 
 			// Needs to be set after adding the events...
 			panel.ContinuousDrawing = General.Settings.ReadPluginSetting("drawlinesmode.continuousdrawing", false);
 			panel.AutoCloseDrawing = General.Settings.ReadPluginSetting("drawlinesmode.autoclosedrawing", false);
+			panel.ShowGuidelines = General.Settings.ReadPluginSetting("drawlinesmode.showguidelines", false);
+
+			// Create guide labels
+			guidelabels = new LineLengthLabel[4];
+			for(int i = 0; i < guidelabels.Length; i++)
+			{
+				guidelabels[i] = new LineLengthLabel { ShowAngle = false, Color = General.Colors.InfoLine };
+			}
+
+			// Create map boudary lines
+			Vector2D btl = new Vector2D(General.Map.Config.LeftBoundary, General.Map.Config.TopBoundary);
+			Vector2D btr = new Vector2D(General.Map.Config.RightBoundary, General.Map.Config.TopBoundary);
+			Vector2D bbl = new Vector2D(General.Map.Config.LeftBoundary, General.Map.Config.BottomBoundary);
+			Vector2D bbr = new Vector2D(General.Map.Config.RightBoundary, General.Map.Config.BottomBoundary);
+			top = new Line2D(btl, btr);
+			right = new Line2D(btr, bbr);
+			bottom = new Line2D(bbl, bbr);
+			left = new Line2D(btl, bbl); 
 		}
 
 		protected virtual void AddInterface()
@@ -575,6 +686,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			General.Settings.WritePluginSetting("drawlinesmode.continuousdrawing", panel.ContinuousDrawing);
 			General.Settings.WritePluginSetting("drawlinesmode.autoclosedrawing", panel.AutoCloseDrawing);
+			General.Settings.WritePluginSetting("drawlinesmode.showguidelines", panel.ShowGuidelines);
 			panel.Unregister();
 		}
 
@@ -763,6 +875,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			autoclosedrawing = (bool)value;
 		}
+
+		//mxd
+		private void OnShowGuidelinesChanged(object value, EventArgs e)
+		{
+			showguidelines = (bool)value;
+			General.Interface.RedrawDisplay();
+		}
 		
 		#endregion
 		
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs
index f808f2893..2f99b7df6 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGridMode.cs
@@ -204,7 +204,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				// Handle the case when start point is not on current grid.
 				Vector2D gridoffset = General.Map.Grid.SnappedToGrid(points[0].pos) - points[0].pos;
-				curp = GetCurrentPosition(mousemappos + gridoffset, snaptonearest, snaptogrid, snaptocardinaldirection, renderer, points);
+				curp = GetCurrentPosition(mousemappos + gridoffset, snaptonearest, snaptogrid, snaptocardinaldirection, usefourcardinaldirections, renderer, points);
 				curp.pos -= gridoffset;
 			}
 			else
@@ -297,7 +297,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				// Handle the case when start point is not on current grid.
 				Vector2D gridoffset = General.Map.Grid.SnappedToGrid(points[0].pos) - points[0].pos;
-				newpoint = GetCurrentPosition(mousemappos + gridoffset, snaptonearest, snaptogrid, snaptocardinaldirection, renderer, new List<DrawnVertex> { points[0] });
+				newpoint = GetCurrentPosition(mousemappos + gridoffset, snaptonearest, snaptogrid, snaptocardinaldirection, usefourcardinaldirections, renderer, new List<DrawnVertex> { points[0] });
 				newpoint.pos -= gridoffset;
 				
 				// Create vertices for final shape.
diff --git a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
index 84797d779..4a5bd4ee0 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
@@ -742,7 +742,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				DrawGeometryMode drawmode = new DrawGeometryMode();
 				bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
 				bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
-				DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, renderer, new List<DrawnVertex>());
+				DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, false, renderer, new List<DrawnVertex>());
 
 				if(drawmode.DrawPointAt(v))
 					General.Editing.ChangeMode(drawmode);
@@ -868,7 +868,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				{
 					bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
 					bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
-					Vector2D v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, renderer, new List<DrawnVertex>()).pos;
+					Vector2D v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, false, renderer, new List<DrawnVertex>()).pos;
 
 					if(v != insertpreview)
 					{
@@ -1287,7 +1287,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
 				bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
-				DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, renderer, new List<DrawnVertex>());
+				DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, false, renderer, new List<DrawnVertex>());
 				drawmode.DrawPointAt(v);
 			}
 			General.Editing.ChangeMode(drawmode);
diff --git a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
index bcd37952b..3bddebb0a 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
@@ -904,7 +904,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				DrawGeometryMode drawmode = new DrawGeometryMode();
 				bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
 				bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
-				DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, renderer, new List<DrawnVertex>());
+				DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, false, renderer, new List<DrawnVertex>());
 				
 				if(drawmode.DrawPointAt(v))
 					General.Editing.ChangeMode(drawmode);
@@ -1517,7 +1517,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				bool snaptogrid = General.Interface.ShiftState ^ General.Interface.SnapToGrid;
 				bool snaptonearest = General.Interface.CtrlState ^ General.Interface.AutoMerge;
-				DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, renderer, new List<DrawnVertex>());
+				DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, false, renderer, new List<DrawnVertex>());
 				drawmode.DrawPointAt(v);
 			}
 			General.Editing.ChangeMode(drawmode);
diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
index 90e2b0e15..31fe04a17 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
@@ -246,7 +246,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 				//mxd. Dynamic light radii
 				if(!General.Map.DOOM && General.Settings.GZDrawLightsMode != LightRenderMode.NONE)
+				{
 					eventlines.AddRange(dynamiclightshapes);
+					if(highlighted != null) eventlines.AddRange(GetDynamicLightShapes(new List<Thing> { highlighted } ));
+				}
 
 				//mxd
 				if(eventlines.Count > 0) renderer.RenderArrows(eventlines);
@@ -993,9 +996,104 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			persistenteventlines = LinksCollector.GetThingLinks(General.Map.ThingsFilter.VisibleThings);
 
 			// Update light radii
-			dynamiclightshapes = Tools.GetDynamicLightShapes();
+			dynamiclightshapes = GetDynamicLightShapes(General.Map.Map.Things);
 		}
 
+		//mxd
+		private List<Line3D> GetDynamicLightShapes(IEnumerable<Thing> things)
+		{
+			List<Line3D> circles = new List<Line3D>();
+			const int linealpha = 128;
+			foreach(Thing t in things)
+			{
+				int lightid = Array.IndexOf(GZBuilder.GZGeneral.GZ_LIGHTS, t.Type);
+				if(lightid == -1) continue;
+
+				// TODO: this basically duplicates VisualThing.UpdateLight()...
+				// Determine light radiii
+				int primaryradius;
+				int secondaryradius = 0;
+
+				if(lightid < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[2]) //if it's gzdoom light
+				{
+					int n;
+					if(lightid < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[0]) n = 0;
+					else if(lightid < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[1]) n = 10;
+					else n = 20;
+					DynamicLightType lightType = (DynamicLightType)(t.Type - 9800 - n);
+
+					if(lightType == DynamicLightType.SECTOR)
+					{
+						if(t.Sector == null) t.DetermineSector();
+						int scaler = (t.Sector != null ? t.Sector.Brightness / 4 : 2);
+						primaryradius = (int)Math.Round((t.Args[3] * scaler) * General.Settings.GZDynamicLightRadius);
+					}
+					else
+					{
+						primaryradius = (int)Math.Round((t.Args[3] * 2) * General.Settings.GZDynamicLightRadius); //works... that.. way in GZDoom
+						if(lightType > 0)
+							secondaryradius = (int)Math.Round((t.Args[4] * 2) * General.Settings.GZDynamicLightRadius);
+					}
+				}
+				else //it's one of vavoom lights
+				{
+					primaryradius = (int)Math.Round((t.Args[0] * 8) * General.Settings.GZDynamicLightRadius);
+				}
+
+				// Check radii...
+				if(primaryradius < 1 && secondaryradius < 1) continue;
+
+				// Determine light color
+				PixelColor color;
+				if(t == highlighted)
+				{
+					color = General.Colors.Highlight.WithAlpha(linealpha);
+				}
+				else
+				{
+					switch(t.Type)
+					{
+						case 1502: // Vavoom light
+							color = new PixelColor(linealpha, 255, 255, 255);
+							break;
+
+						case 1503: // Vavoom colored light
+							color = new PixelColor(linealpha, (byte)t.Args[1], (byte)t.Args[2], (byte)t.Args[3]);
+							break;
+
+						default:
+							color = new PixelColor(linealpha, (byte)t.Args[0], (byte)t.Args[1], (byte)t.Args[2]);
+							break;
+					}
+				}
+
+				// Add lines if visible
+				const int numsides = 24;
+				if(primaryradius > 0) circles.AddRange(MakeCircleLines(t.Position, color, primaryradius, numsides));
+				if(secondaryradius > 0) circles.AddRange(MakeCircleLines(t.Position, color, secondaryradius, numsides));
+			}
+
+			// Done
+			return circles;
+		}
+
+		//mxd
+		private static IEnumerable<Line3D> MakeCircleLines(Vector2D pos, PixelColor color, float radius, int numsides)
+		{
+			List<Line3D> result = new List<Line3D>(numsides);
+			Vector2D start = new Vector2D(pos.x, pos.y + radius);
+			float anglestep = Angle2D.PI2 / numsides;
+
+			for(int i = 1; i < numsides + 1; i++)
+			{
+				Vector2D end = pos + new Vector2D((float)Math.Sin(anglestep * i) * radius, (float)Math.Cos(anglestep * i) * radius);
+				result.Add(new Line3D(start, end, color, false));
+				start = end;
+			}
+
+			return result;
+		} 
+
 		#endregion
 
 		#region ================== Actions
diff --git a/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs b/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
index f2d1d5902..6367caf4c 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
@@ -355,7 +355,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				{
 					// Start drawing mode
 					DrawGeometryMode drawmode = new DrawGeometryMode();
-					DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, renderer, new List<DrawnVertex>());
+					DrawnVertex v = DrawGeometryMode.GetCurrentPosition(mousemappos, snaptonearest, snaptogrid, false, false, renderer, new List<DrawnVertex>());
 
 					if(drawmode.DrawPointAt(v))
 						General.Editing.ChangeMode(drawmode);
diff --git a/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs
index 88f1ada0c..f441e347b 100644
--- a/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs
+++ b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.Designer.cs
@@ -31,6 +31,7 @@
 			this.toolStrip1 = new System.Windows.Forms.ToolStrip();
 			this.continuousdrawing = new System.Windows.Forms.ToolStripButton();
 			this.autoclosedrawing = new System.Windows.Forms.ToolStripButton();
+			this.showguidelines = new System.Windows.Forms.ToolStripButton();
 			this.toolStrip1.SuspendLayout();
 			this.SuspendLayout();
 			// 
@@ -38,10 +39,11 @@
 			// 
 			this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
             this.continuousdrawing,
-            this.autoclosedrawing});
+            this.autoclosedrawing,
+            this.showguidelines});
 			this.toolStrip1.Location = new System.Drawing.Point(0, 0);
 			this.toolStrip1.Name = "toolStrip1";
-			this.toolStrip1.Size = new System.Drawing.Size(406, 25);
+			this.toolStrip1.Size = new System.Drawing.Size(619, 25);
 			this.toolStrip1.TabIndex = 8;
 			this.toolStrip1.Text = "toolStrip1";
 			// 
@@ -66,13 +68,24 @@
 			this.autoclosedrawing.Text = "Auto-finish drawing";
 			this.autoclosedrawing.CheckedChanged += new System.EventHandler(this.autoclosedrawing_CheckedChanged);
 			// 
+			// showguidelines
+			// 
+			this.showguidelines.CheckOnClick = true;
+			this.showguidelines.Image = global::CodeImp.DoomBuilder.BuilderModes.Properties.Resources.Guidelines;
+			this.showguidelines.ImageTransparentColor = System.Drawing.Color.Magenta;
+			this.showguidelines.Margin = new System.Windows.Forms.Padding(2, 1, 0, 2);
+			this.showguidelines.Name = "showguidelines";
+			this.showguidelines.Size = new System.Drawing.Size(113, 22);
+			this.showguidelines.Text = "Show guidelines";
+			this.showguidelines.CheckedChanged += new System.EventHandler(this.showguidelines_CheckedChanged);
+			// 
 			// DrawLineOptionsPanel
 			// 
 			this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
 			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
 			this.Controls.Add(this.toolStrip1);
 			this.Name = "DrawLineOptionsPanel";
-			this.Size = new System.Drawing.Size(406, 60);
+			this.Size = new System.Drawing.Size(619, 60);
 			this.toolStrip1.ResumeLayout(false);
 			this.toolStrip1.PerformLayout();
 			this.ResumeLayout(false);
@@ -85,5 +98,6 @@
 		private System.Windows.Forms.ToolStrip toolStrip1;
 		private System.Windows.Forms.ToolStripButton continuousdrawing;
 		private System.Windows.Forms.ToolStripButton autoclosedrawing;
+		private System.Windows.Forms.ToolStripButton showguidelines;
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs
index 776e26e4c..178260b0c 100644
--- a/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs
+++ b/Source/Plugins/BuilderModes/Interface/DrawLineOptionsPanel.cs
@@ -7,9 +7,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
 	{
 		public event EventHandler OnContinuousDrawingChanged;
 		public event EventHandler OnAutoCloseDrawingChanged;
+		public event EventHandler OnShowGuidelinesChanged;
 
 		public bool ContinuousDrawing { get { return continuousdrawing.Checked; } set { continuousdrawing.Checked = value; } }
 		public bool AutoCloseDrawing { get { return autoclosedrawing.Checked; } set { autoclosedrawing.Checked = value; } }
+		public bool ShowGuidelines { get { return showguidelines.Checked; } set { showguidelines.Checked = value; } }
 		
 		public DrawLineOptionsPanel()
 		{
@@ -20,10 +22,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			General.Interface.AddButton(continuousdrawing);
 			General.Interface.AddButton(autoclosedrawing);
+			General.Interface.AddButton(showguidelines);
 		}
 
 		public void Unregister()
 		{
+			General.Interface.RemoveButton(showguidelines);
 			General.Interface.RemoveButton(autoclosedrawing);
 			General.Interface.RemoveButton(continuousdrawing);
 		}
@@ -37,5 +41,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			if(OnAutoCloseDrawingChanged != null) OnAutoCloseDrawingChanged(autoclosedrawing.Checked, EventArgs.Empty);
 		}
+
+		private void showguidelines_CheckedChanged(object sender, EventArgs e)
+		{
+			if(OnShowGuidelinesChanged != null) OnShowGuidelinesChanged(showguidelines.Checked, EventArgs.Empty);
+		}
 	}
 }
diff --git a/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs b/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs
index 3a36fac33..44d280041 100644
--- a/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs
+++ b/Source/Plugins/BuilderModes/Properties/Resources.Designer.cs
@@ -214,6 +214,13 @@ namespace CodeImp.DoomBuilder.BuilderModes.Properties {
             }
         }
         
+        internal static System.Drawing.Bitmap Guidelines {
+            get {
+                object obj = ResourceManager.GetObject("Guidelines", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
         internal static System.Drawing.Bitmap Hide {
             get {
                 object obj = ResourceManager.GetObject("Hide", resourceCulture);
diff --git a/Source/Plugins/BuilderModes/Properties/Resources.resx b/Source/Plugins/BuilderModes/Properties/Resources.resx
index 6992badfb..de4c6ed1d 100644
--- a/Source/Plugins/BuilderModes/Properties/Resources.resx
+++ b/Source/Plugins/BuilderModes/Properties/Resources.resx
@@ -139,8 +139,8 @@
   <data name="ViewSelectionEffects" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\ViewSelectionEffects.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="Flip" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\Flip.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  <data name="Repeat" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Repeat.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
   <data name="HideAll" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\HideAll.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
@@ -196,6 +196,9 @@
   <data name="ThingPointAtCursor" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\ThingPointAtCursor.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="PlaceThings" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\PlaceThings.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
   <data name="Text" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Text.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
@@ -226,20 +229,20 @@
   <data name="Show2" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Show2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="Folder" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\Folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
-  </data>
   <data name="ColorPick" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\ColorPick.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="Repeat" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\Repeat.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  <data name="NewSector2" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\NewSector2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
+  <data name="Flip" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Flip.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
   <data name="FlipSelectionH" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\FlipSelectionH.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="PlaceThings" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\PlaceThings.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  <data name="Folder" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Folder.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
   <data name="Angle" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Angle.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
@@ -259,7 +262,7 @@
   <data name="Show3" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>..\Resources\Show3.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
-  <data name="NewSector2" type="System.Resources.ResXFileRef, System.Windows.Forms">
-    <value>..\Resources\NewSector2.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  <data name="Guidelines" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Guidelines.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
 </root>
\ No newline at end of file
diff --git a/Source/Plugins/BuilderModes/Resources/Guidelines.png b/Source/Plugins/BuilderModes/Resources/Guidelines.png
new file mode 100644
index 0000000000000000000000000000000000000000..bae95463b40efd34175d208233187b132da16558
GIT binary patch
literal 1101
zcmaJ=OK1~87~cA}*rJH|K<v2j;K5{HP0}olHOZzn(A1a)8xhp)?zCCj-C1|1W>XJh
z>jSkSik|c$DpG1yJcuY-@F0qMQ9RTKC<rPD9<-pPT4!TZJs1~eXXfYszW?>j;Z)1U
zs>&6W6h&1fnxr(@7rJZS9P+REGAWa7IgV#>E9$^`*@9F=MePtIbh#6zp{y2mJ%sfX
zHFJ%Y$>MCXSyYhjlU*O5qniXxQS}XuDJxwNgLc@d8DaYK?GYMiYM5^GC)uPKgE_6K
z*MhCREg7Y^O9`oT!+KEfh=f3gSO$*XZP=m{ri;8HIlE?t21OU#6{deDl})BV3|SEP
zeF3k+27(|M@^SuPur|03@GR$NSb-5(FE5C-tXRu~sgEYnEVV;SON~>p$Sq9gFg8Vo
z$>;OFyx>DtC&Pt8A%^7{p7#<DuU#;(?05~^Q(};ytyr3gHDmynQEo>)I82jFf0v+}
z)3k;?)h5y~#*s~i^RaG8CC6m)|E{_|?QP>U{FCoLiS10mgiIRRsK-*s;5s~RC{v7C
zP{zp0Ak<yzVk(C)vUA7;u~@NdpiMJWl(&nBWKv8RHkJ(qCZsS;IDDF>iV=a2`y+my
z4Mu_-7Y{^*Xta*lA_B`xAue9RN=WI^p@B<S^$%7ki*?1In<TOXEp0bc8!e=RV$q^j
zJ{Ptu-xO9Yp9@zO%aCLkceH<vx@02yagWo&C6{UGLxbquBEqI#-q}JP#YjSmWSkeT
zS|3&3V;43@m2KDNts46<dVX?p(T_P-`{?X|E)Fiv9=TZ6Yst$3$6t?rYTWbr`M_4-
z*}nhinZ_sEZf0}CXy3=7Q&fNC<IiW~C#kms2l|9Z++fA6l(3|3eDcBu&-Eq4++$Ff
zefi<0H`TRg4+W~5Rv)~7tZr@~mGX>kUW3~A4h6rzo>lYU(uo}vg|+9JGv;YH@viFZ
z#LC5bCS^vhdzl7x>D}>TqkW;=fs-xY`p0H0pa$kUV_%=Xzu`XcM7%}165ZMN3u&=#
A_5c6?

literal 0
HcmV?d00001

diff --git a/Source/Plugins/NodesViewer/NodesViewerMode.cs b/Source/Plugins/NodesViewer/NodesViewerMode.cs
index 507c7a944..195562b2c 100644
--- a/Source/Plugins/NodesViewer/NodesViewerMode.cs
+++ b/Source/Plugins/NodesViewer/NodesViewerMode.cs
@@ -529,7 +529,7 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
 					{
 						// Split line with plane and insert the vertex
 						float u;
-						Line2D.GetIntersection(split.pos, split.pos + split.delta, prev.x, prev.y, cur.x, cur.y, out u);
+						Line2D.GetIntersection(split.pos, split.pos + split.delta, prev.x, prev.y, cur.x, cur.y, out u, false);
 						Vector2D newv = prev + (cur - prev) * u;
 						newp.Add(newv);
 					}
@@ -543,7 +543,7 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
 					{
 						// Split line with plane and insert the vertex
 						float u;
-						Line2D.GetIntersection(split.pos, split.pos + split.delta, prev.x, prev.y, cur.x, cur.y, out u);
+						Line2D.GetIntersection(split.pos, split.pos + split.delta, prev.x, prev.y, cur.x, cur.y, out u, false);
 						Vector2D newv = prev + (cur - prev) * u;
 						newp.Add(newv);
 					}
-- 
GitLab