From 3eb05509afdef4370bc7054b04c693aefcdb7f40 Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Tue, 19 Apr 2016 20:40:42 +0000
Subject: [PATCH] Added, Visual mode: "Increase/Decrease Scale", "Reset Texture
 Offsets" and "Reset Local Texture Offsets" actions now work when used on 3d
 floor sides. Fixed: CVARINFO parser was unable to parse negative int/float
 values. Fixed: in some cases TextLabel text size was checked before it was
 calculated. Internal, Visual mode: reduced the number of unnecessary geometry
 updates when changing map geometry. Updated ZDoom_DECORATE.cfg (atan2 and
 VectorAngle).

---
 Build/Scripting/ZDoom_DECORATE.cfg            |  21 +-
 Source/Core/Rendering/TextLabel.cs            | 142 +++++----
 Source/Core/ZDoom/CvarInfoParser.cs           |   4 +-
 .../BuilderModes/ClassicModes/LinedefsMode.cs |   3 +-
 .../BuilderModes/ClassicModes/SectorsMode.cs  |   3 +-
 .../BuilderModes/ClassicModes/ThingsMode.cs   |   8 +-
 .../Plugins/BuilderModes/General/HintLabel.cs |   9 +-
 .../BuilderModes/General/LineLengthLabel.cs   |   2 +-
 .../VisualModes/BaseVisualGeometrySector.cs   |  88 ++----
 .../VisualModes/BaseVisualGeometrySidedef.cs  | 126 ++++----
 .../VisualModes/BaseVisualMode.cs             | 277 ++++++++----------
 .../VisualModes/BaseVisualSector.cs           |  25 +-
 .../VisualModes/BaseVisualThing.cs            |   2 +-
 .../VisualModes/EffectGlowingFlat.cs          |  36 +--
 .../VisualModes/EffectLineSlope.cs            |  10 +-
 .../BuilderModes/VisualModes/SectorData.cs    |  16 +-
 .../BuilderModes/VisualModes/VisualCeiling.cs |  67 +++--
 .../BuilderModes/VisualModes/VisualFloor.cs   |  35 +--
 .../VisualModes/VisualMiddle3D.cs             | 111 +++++--
 .../VisualModes/VisualMiddleBack.cs           | 163 ++---------
 .../VisualModes/VisualMiddleSingle.cs         |   4 +
 21 files changed, 523 insertions(+), 629 deletions(-)

diff --git a/Build/Scripting/ZDoom_DECORATE.cfg b/Build/Scripting/ZDoom_DECORATE.cfg
index 3497a3cfb..6ef76a582 100644
--- a/Build/Scripting/ZDoom_DECORATE.cfg
+++ b/Build/Scripting/ZDoom_DECORATE.cfg
@@ -386,6 +386,16 @@ keywords
 	A_SPosAttackUseAtkSound = "A_SPosAttackUseAtkSound";
 //Mathematical functions
 	abs = "abs(x)\nReturns the absolute value of x.";
+	exp = "exp(x)\nReturns the base-e exponential function of x, which is e raised to the power x.";
+	log = "log(x)\nReturns the natural logarithm of x - the opposite of exp."; 
+	log10 = "log10(x)\nReturns the common (base-10) logarithm of x.";
+	ceil = "ceil(x)\nRounds the number upward to the next closest integer.";
+	floor = "floor(x)\nRounds the number downward to the next closest integer.";
+	sqrt = "sqrt(x)\nReturns the square root of x.";
+	min = "min(x1, ...)\nGets the smallest value of all values listed.\nCan take any amount of numbers, and can solve both ints and floats.";
+	max = "max(x1, ...)\nGets the largest value of all values listed.\nCan take any amount of numbers, and can solve both ints and floats.";
+	clamp = "clamp(src, min, max)\nReturns src within the range of min and max inclusively. All parameters can be ints or floats.";	
+//Trigonometry functions
 	sin = "sin(x)\nTrigonometry function, x must be in degrees.";
 	cos = "cos(x)\nTrigonometry function, x must be in degrees.";
 	tan = "tan(x)\nTrigonometry function, x must be in degrees.";
@@ -395,15 +405,8 @@ keywords
 	sinh = "sinh(x)\nTrigonometry function, x must be in radians.";
 	cosh = "cosh(x)\nTrigonometry function, x must be in radians.";
 	tanh = "tanh(x)\nTrigonometry function, x must be in radians.";
-	exp = "exp(x)\nReturns the base-e exponential function of x, which is e raised to the power x.";
-	log = "log(x)\nReturns the natural logarithm of x - the opposite of exp."; 
-	log10 = "log10(x)\nReturns the common (base-10) logarithm of x.";
-	ceil = "ceil(x)\nRounds the number upward to the next closest integer.";
-	floor = "floor(x)\nRounds the number downward to the next closest integer.";
-	sqrt = "sqrt(x)\nReturns the square root of x.";
-	min = "min(x1, ...)\nGets the smallest value of all values listed.\nCan take any amount of numbers, and can solve both ints and floats.";
-	max = "max(x1, ...)\nGets the largest value of all values listed.\nCan take any amount of numbers, and can solve both ints and floats.";
-	clamp = "clamp(src, min, max)\nReturns src within the range of min and max inclusively. All parameters can be ints or floats.";
+	atan2 = "atan2(y, x)\nTrigonometry function, Returns an angle in degrees.";
+	VectorAngle = "VectorAngle(x, y)\nTrigonometry function."; 
 //Randum number functions
 	random = "int random[identifier](min, max)\nReturns a random integer value between min and max.";
 	random2 = "int random2[identifier](mask)\nReturns a random integer value between -mask and +mask.";
diff --git a/Source/Core/Rendering/TextLabel.cs b/Source/Core/Rendering/TextLabel.cs
index 4f157dcf3..f84f30b36 100644
--- a/Source/Core/Rendering/TextLabel.cs
+++ b/Source/Core/Rendering/TextLabel.cs
@@ -46,15 +46,20 @@ namespace CodeImp.DoomBuilder.Rendering
 		
 		// Text settings
 		private string text;
-		private RectangleF rect;
+		private Vector2D location; //mxd
 		private bool transformcoords;
 		private PixelColor color;
 		private PixelColor backcolor;
 		private TextAlignmentX alignx;
 		private TextAlignmentY aligny;
+		private bool drawbg; //mxd
+		
+		//mxd. Label image settings...
 		private SizeF textsize;
 		private Size texturesize;
-		private bool drawbg; //mxd
+		private RectangleF textrect;
+		private RectangleF bgrect;
+		private PointF textorigin;
 		
 		// This keeps track if changes were made
 		private bool updateneeded;
@@ -75,15 +80,9 @@ namespace CodeImp.DoomBuilder.Rendering
 		#region ================== Properties
 
 		// Properties
-		public RectangleF Rectangle { get { return rect; } set { rect = value; updateneeded = true; } }
-		public float Left { get { return rect.X; } set { rect.X = value; updateneeded = true; } }
-		public float Top { get { return rect.Y; } set { rect.Y = value; updateneeded = true; } }
-		public float Width { get { return rect.Width; } set { rect.Width = value; updateneeded = true; } }
-		public float Height { get { return rect.Height; } set { rect.Height = value; updateneeded = true; } }
-		public float Right { get { return rect.Right; } set { rect.Width = value - rect.X + 1f; updateneeded = true; } }
-		public float Bottom { get { return rect.Bottom; } set { rect.Height = value - rect.Y + 1f; updateneeded = true; } }
-		public string Text { get { return text; } set { if(text != value) { text = value; textureupdateneeded = true; } } }
-		public Font Font { get { return font; } set { font = value; textureupdateneeded = true; } } //mxd
+		public Vector2D Location { get { return location; } set { location = value; updateneeded = true; } } //mxd
+		public string Text { get { return text; } set { if(text != value) { text = value; textsize = Size.Empty; textureupdateneeded = true; } } }
+		public Font Font { get { return font; } set { font = value; textsize = Size.Empty; textureupdateneeded = true; } } //mxd
 		public bool TransformCoords { get { return transformcoords; } set { transformcoords = value; updateneeded = true; } }
 		public SizeF TextSize { get { if(textureupdateneeded) Update(General.Map.Renderer2D.TranslateX, General.Map.Renderer2D.TranslateY, General.Map.Renderer2D.Scale, -General.Map.Renderer2D.Scale); return textsize; } }
 		public TextAlignmentX AlignX { get { return alignx; } set { alignx = value; updateneeded = true; } }
@@ -108,12 +107,13 @@ namespace CodeImp.DoomBuilder.Rendering
 			// Initialize
 			this.text = "";
 			this.font = General.Settings.TextLabelFont; //mxd
-			this.rect = new RectangleF(0f, 0f, 1f, 1f);
+			this.location = new Vector2D(); //mxd
 			this.color = new PixelColor(255, 255, 255, 255);
 			this.backcolor = new PixelColor(128, 0, 0, 0);
 			this.alignx = TextAlignmentX.Center;
 			this.aligny = TextAlignmentY.Top;
-			this.textsize = new SizeF();
+			this.textsize = SizeF.Empty; //mxd
+			this.texturesize = Size.Empty; //mxd
 			this.updateneeded = true;
 			this.textureupdateneeded = true; //mxd
 			
@@ -166,25 +166,59 @@ namespace CodeImp.DoomBuilder.Rendering
 				if(text.Length > 0)
 				{
 					// Transform?
-					RectangleF absview;
-					if(transformcoords)
+					Vector2D abspos = (transformcoords ? location.GetTransformed(translatex, translatey, scalex, scaley) : location);
+
+					// Update text and texture sizes
+					if(textsize.IsEmpty || texturesize.IsEmpty)
 					{
-						// Calculate absolute coordinates
-						Vector2D lt = new Vector2D(rect.Left, rect.Top);
-						Vector2D rb = new Vector2D(rect.Right, rect.Bottom);
-						lt = lt.GetTransformed(translatex, translatey, scalex, scaley);
-						rb = rb.GetTransformed(translatex, translatey, scalex, scaley);
-						absview = new RectangleF((float)Math.Round(lt.x), (float)Math.Round(lt.y), rb.x - lt.x, rb.y - lt.y);
+						textorigin = new PointF(4, 3);
+						textrect = new RectangleF(textorigin, General.Interface.MeasureString(text, font));
+						textrect.Width = (float)Math.Round(textrect.Width);
+						textrect.Height = (float)Math.Round(textrect.Height);
+						bgrect = new RectangleF(0, 0, textrect.Width + textorigin.X * 2, textrect.Height + textorigin.Y * 2);
+
+						// Store calculated text size...
+						textsize = new SizeF(textrect.Width + textorigin.X * 2, textrect.Height + textorigin.Y * 2);
+
+						// Make PO2 image, for speed and giggles...
+						texturesize = new Size(General.NextPowerOf2((int)textsize.Width), General.NextPowerOf2((int)textsize.Height));
+
+						switch(alignx)
+						{
+							case TextAlignmentX.Center: bgrect.X = (texturesize.Width - bgrect.Width) / 2; break;
+							case TextAlignmentX.Right: bgrect.X = texturesize.Width - bgrect.Width; break;
+						}
+
+						switch(aligny)
+						{
+							case TextAlignmentY.Middle: bgrect.Y = (texturesize.Height - bgrect.Height) / 2; break;
+							case TextAlignmentY.Bottom: bgrect.Y = texturesize.Height - bgrect.Height; break;
+						}
+
+						textrect.X += bgrect.X;
+						textrect.Y += bgrect.Y;
 					}
-					else
+
+					// Align the text horizontally
+					float beginx = 0;
+					switch(alignx)
+					{
+						case TextAlignmentX.Left: beginx = abspos.x; break;
+						case TextAlignmentX.Center: beginx = abspos.x - texturesize.Width * 0.5f; break;
+						case TextAlignmentX.Right: beginx = abspos.x - texturesize.Width; break;
+					}
+
+					// Align the text vertically
+					float beginy = 0;
+					switch(aligny)
 					{
-						// Fixed coordinates
-						absview = rect;
+						case TextAlignmentY.Top: beginy = abspos.y; break;
+						case TextAlignmentY.Middle: beginy = abspos.y - texturesize.Height * 0.5f; break;
+						case TextAlignmentY.Bottom: beginy = abspos.y - texturesize.Height; break;
 					}
 
 					//mxd. Skip when not on screen...
-					RectangleF abssize = absview;
-					abssize.Inflate(textsize.Width / 2, textsize.Height / 2);
+					RectangleF abssize = new RectangleF(beginx, beginy, texturesize.Width, texturesize.Height);
 					Size windowsize = General.Map.Graphics.RenderTarget.ClientSize;
 					skiprendering = (abssize.Right < 0.1f) || (abssize.Left > windowsize.Width) || (abssize.Bottom < 0.1f) || (abssize.Top > windowsize.Height);
 					if(skiprendering) return;
@@ -200,8 +234,8 @@ namespace CodeImp.DoomBuilder.Rendering
 						}
 
 						// Create label image
-						Bitmap img = CreateLabelImage(text, font, alignx, aligny, color, backcolor, drawbg, out textsize);
-						texturesize = img.Size;
+						Bitmap img = CreateLabelImage(text, font, color, backcolor, drawbg, textrect, bgrect, texturesize, textorigin);
+						//texturesize = img.Size;
 
 						// Create texture
 						MemoryStream memstream = new MemoryStream((img.Size.Width * img.Size.Height * 4) + 4096);
@@ -213,24 +247,6 @@ namespace CodeImp.DoomBuilder.Rendering
 								Pool.Managed, General.Map.Graphics.PostFilter, General.Map.Graphics.MipGenerateFilter, 0);
 					}
 
-					// Align the text horizontally
-					float beginx = 0;
-					switch(alignx)
-					{
-						case TextAlignmentX.Left: beginx = absview.X; break;
-						case TextAlignmentX.Center: beginx = absview.X + (absview.Width - texturesize.Width) * 0.5f; break;
-						case TextAlignmentX.Right: beginx = absview.X + absview.Width - texturesize.Width; break;
-					}
-
-					// Align the text vertically
-					float beginy = 0;
-					switch(aligny)
-					{
-						case TextAlignmentY.Top: beginy = absview.Y; break;
-						case TextAlignmentY.Middle: beginy = absview.Y + (absview.Height - texturesize.Height) * 0.5f; break;
-						case TextAlignmentY.Bottom: beginy = absview.Y + absview.Height - texturesize.Height; break;
-					}
-
 					//mxd. Create the buffer
 					if(textbuffer == null || textbuffer.Disposed)
 					{
@@ -251,7 +267,8 @@ namespace CodeImp.DoomBuilder.Rendering
 				else
 				{
 					// No faces in polygon
-					textsize = new SizeF();
+					textsize = SizeF.Empty; //mxd
+					texturesize = Size.Empty; //mxd
 					skiprendering = true; //mxd
 				}
 
@@ -262,36 +279,9 @@ namespace CodeImp.DoomBuilder.Rendering
 		}
 
 		//mxd
-		private static Bitmap CreateLabelImage(string text, Font font, TextAlignmentX alignx, TextAlignmentY aligny, PixelColor color, PixelColor backcolor, bool drawbg, out SizeF textsize)
+		private static Bitmap CreateLabelImage(string text, Font font, PixelColor color, PixelColor backcolor, bool drawbg, RectangleF textrect, RectangleF bgrect, Size texturesize, PointF textorigin)
 		{
-			PointF textorigin = new PointF(4, 3);
-			RectangleF textrect = new RectangleF(textorigin, General.Interface.MeasureString(text, font));
-			textrect.Width = (float)Math.Round(textrect.Width);
-			textrect.Height = (float)Math.Round(textrect.Height);
-			RectangleF bgrect = new RectangleF(0, 0, textrect.Width + textorigin.X * 2, textrect.Height + textorigin.Y * 2);
-
-			// Store calculated text size...
-			textsize = new SizeF(bgrect.Width, bgrect.Height);
-
-			// Make PO2 image, for speed and giggles...
-			RectangleF po2rect = new RectangleF(0, 0, General.NextPowerOf2((int)bgrect.Width), General.NextPowerOf2((int)bgrect.Height));
-
-			switch(alignx)
-			{
-				case TextAlignmentX.Center: bgrect.X = (po2rect.Width - bgrect.Width) / 2; break;
-				case TextAlignmentX.Right:  bgrect.X = po2rect.Width - bgrect.Width; break;
-			}
-
-			switch(aligny)
-			{
-				case TextAlignmentY.Middle: bgrect.Y = (po2rect.Height - bgrect.Height) / 2; break;
-				case TextAlignmentY.Bottom: bgrect.Y = po2rect.Height - bgrect.Height; break;
-			}
-
-			textrect.X += bgrect.X;
-			textrect.Y += bgrect.Y;
-
-			Bitmap result = new Bitmap((int)po2rect.Width, (int)po2rect.Height);
+			Bitmap result = new Bitmap(texturesize.Width, texturesize.Height);
 			using(Graphics g = Graphics.FromImage(result))
 			{
 				g.SmoothingMode = SmoothingMode.HighQuality;
diff --git a/Source/Core/ZDoom/CvarInfoParser.cs b/Source/Core/ZDoom/CvarInfoParser.cs
index f0ad7c477..88f395b95 100644
--- a/Source/Core/ZDoom/CvarInfoParser.cs
+++ b/Source/Core/ZDoom/CvarInfoParser.cs
@@ -132,7 +132,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 			{
 				case "int":
 					int iv = 0;
-					if(!string.IsNullOrEmpty(value) && !int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out iv))
+					if(!string.IsNullOrEmpty(value) && !ReadSignedInt(value, ref iv))
 					{
 						ReportError("Cvar \"" + name + "\" has invalid integer value: \"" + value + "\"");
 						return false;
@@ -146,7 +146,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 
 				case "float":
 					float fv = 0f;
-					if(!string.IsNullOrEmpty(value) && !float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out fv))
+					if(!string.IsNullOrEmpty(value) && !ReadSignedFloat(value, ref fv))
 					{
 						ReportError("Cvar \"" + name + "\" has invalid decimal value: \"" + value + "\"");
 						return false;
diff --git a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
index 5f9d23f5e..84797d779 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
@@ -388,10 +388,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				TextLabel[] larr = new TextLabel[s.Labels.Count];
 				for(int i = 0; i < s.Labels.Count; i++)
 				{
-					Vector2D v = s.Labels[i].position;
 					TextLabel l = new TextLabel();
 					l.TransformCoords = true;
-					l.Rectangle = new RectangleF(v.x, v.y, 0.0f, 0.0f);
+					l.Location = s.Labels[i].position;
 					l.AlignX = TextAlignmentX.Center;
 					l.AlignY = TextAlignmentY.Middle;
 					l.Color = General.Colors.InfoLine;
diff --git a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
index fe826fcae..bcd37952b 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
@@ -153,10 +153,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				TextLabel[] labelarray = new TextLabel[s.Labels.Count];
 				for(int i = 0; i < s.Labels.Count; i++)
 				{
-					Vector2D v = s.Labels[i].position;
 					labelarray[i] = new TextLabel();
 					labelarray[i].TransformCoords = true;
-					labelarray[i].Rectangle = new RectangleF(v.x, v.y, 0.0f, 0.0f);
+					labelarray[i].Location = s.Labels[i].position;
 					labelarray[i].AlignX = TextAlignmentX.Center;
 					labelarray[i].AlignY = TextAlignmentY.Middle;
 					labelarray[i].Color = c;
diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
index ee9614437..90e2b0e15 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
@@ -929,10 +929,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				TextLabel[] larr = new TextLabel[s.Labels.Count];
 				for(int i = 0; i < s.Labels.Count; i++)
 				{
-					Vector2D v = s.Labels[i].position;
 					TextLabel l = new TextLabel();
 					l.TransformCoords = true;
-					l.Rectangle = new RectangleF(v.x, v.y, 0.0f, 0.0f);
+					l.Location = s.Labels[i].position;
 					l.AlignX = TextAlignmentX.Center;
 					l.AlignY = TextAlignmentY.Middle;
 					l.Color = General.Colors.InfoLine;
@@ -964,19 +963,18 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			labels = new Dictionary<Thing, TextLabel>(orderedselection.Count);
 			foreach(Thing thing in orderedselection)
 			{
-				Vector2D v = thing.Position;
 				TextLabel l = new TextLabel();
 				l.TransformCoords = true;
 
 				if(thing.FixedSize)
 				{
-					l.Rectangle = new RectangleF(v.x, v.y, 0f, 0f);
+					l.Location = thing.Position;
 					l.AlignX = TextAlignmentX.Center;
 					l.AlignY = TextAlignmentY.Middle;
 				}
 				else
 				{
-					l.Rectangle = new RectangleF(v.x - thing.Size + 1, v.y + thing.Size - 1, 0f, 0f);
+					l.Location = new Vector2D(thing.Position.x - thing.Size + 1, thing.Position.y + thing.Size - 1);
 					l.AlignX = TextAlignmentX.Left;
 					l.AlignY = TextAlignmentY.Top;
 				}
diff --git a/Source/Plugins/BuilderModes/General/HintLabel.cs b/Source/Plugins/BuilderModes/General/HintLabel.cs
index 4d945d421..b62ce6810 100644
--- a/Source/Plugins/BuilderModes/General/HintLabel.cs
+++ b/Source/Plugins/BuilderModes/General/HintLabel.cs
@@ -32,7 +32,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			bool endvisible = viewport.Contains(end.x, end.y);
 
 			// Get visile area
-			RectangleF labelrect;
 			if(!startvisible || !endvisible)
 			{
 				float minx = Math.Min(start.x, end.x);
@@ -42,16 +41,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				RectangleF labelarea = new RectangleF(minx, miny, maxx - minx, maxy - miny);
 				labelarea.Intersect(viewport);
 
-				labelrect = new RectangleF(labelarea.X + labelarea.Width * 0.5f, labelarea.Y + labelarea.Height * 0.5f, 0f, 0f);
+				label.Location = new Vector2D(labelarea.X + labelarea.Width * 0.5f, labelarea.Y + labelarea.Height * 0.5f);
 			}
 			else
 			{
 				Vector2D delta = end - start;
-				labelrect = new RectangleF(start.x + delta.x * 0.5f, start.y + delta.y * 0.5f, 0f, 0f);
-			}
 
-			// Apply changes
-			label.Rectangle = labelrect;
+				label.Location = new Vector2D(start.x + delta.x * 0.5f, start.y + delta.y * 0.5f);
+			}
 		}
 	}
 }
diff --git a/Source/Plugins/BuilderModes/General/LineLengthLabel.cs b/Source/Plugins/BuilderModes/General/LineLengthLabel.cs
index e499180e1..aca4c2fb6 100644
--- a/Source/Plugins/BuilderModes/General/LineLengthLabel.cs
+++ b/Source/Plugins/BuilderModes/General/LineLengthLabel.cs
@@ -204,7 +204,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 			// Apply changes
 			Vector2D delta = end - start;
-			label.Rectangle = new RectangleF(start.x + delta.x * 0.5f, start.y + delta.y * 0.5f, 0f, 0f);
+			label.Location = new Vector2D(start.x + delta.x * 0.5f, start.y + delta.y * 0.5f);
 		}
 		
 		#endregion
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
index af3c15c23..a03f405ca 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySector.cs
@@ -231,44 +231,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			return level.sector;
 		}
 
-		//mxd
-		protected void OnTextureChanged() 
-		{
-			// Effects may need updating...
-			mode.RebuildElementData();
-
-			// As well as sky render flag...
-			UpdateSkyRenderFlag();
-			
-			if(level.sector == this.Sector.Sector) 
-			{
-				this.Setup();
-
-				// 3D floors may need updating...
-				foreach(Sidedef s in level.sector.Sidedefs) 
-				{
-					if(s.Line.Action == 160 && s.Line.Front != null) 
-					{
-						int sectortag = ((General.Map.UDMF || (s.Line.Args[1] & 8) != 0) ? s.Line.Args[0] : s.Line.Args[0] + (s.Line.Args[4] << 8));
-						foreach(Sector sector in General.Map.Map.Sectors) 
-						{
-							if(sector.Tags.Contains(sectortag))
-							{
-								BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(sector);
-								vs.UpdateSectorGeometry(false);
-							}
-						}
-					}
-				}
-			}
-			// As well as this sector's geometry
-			else if(mode.VisualSectorExists(level.sector)) 
-			{
-				BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
-				vs.UpdateSectorGeometry(false);
-			}
-		}
-
 		//mxd
 		public virtual bool IsSelected() 
 		{
@@ -449,18 +411,29 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 			mode.CreateUndo(undodescription);
 			mode.SetActionResult(resultdescription);
-			Sector.Sector.Fields.BeforeFieldsChange();
+			level.sector.Fields.BeforeFieldsChange();
 
-			foreach(string key in keys) 
+			foreach(string key in keys)
 			{
-				if(Sector.Sector.Fields.ContainsKey(key)) 
+				if(level.sector.Fields.ContainsKey(key))
 				{
-					Sector.Sector.Fields.Remove(key);
-					Sector.Sector.UpdateNeeded = true;
+					level.sector.Fields.Remove(key);
+					level.sector.UpdateNeeded = true;
 				}
 			}
 
-			if(Sector.Sector.UpdateNeeded) Sector.UpdateSectorGeometry(false);
+			if(level.sector.UpdateNeeded)
+			{
+				if(level.sector != Sector.Sector && mode.VisualSectorExists(level.sector))
+				{
+					BaseVisualSector vs = (BaseVisualSector) mode.GetVisualSector(level.sector);
+					vs.UpdateSectorGeometry(false);
+				}
+				else
+				{
+					Sector.UpdateSectorGeometry(false);
+				}
+			}
 		}
 		
 		#endregion
@@ -576,7 +549,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(mode.VisualSectorExists(level.sector))
 			{
 				BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
-				vs.UpdateSectorGeometry(true);
+				vs.UpdateSectorGeometry(false);
 			}
 		}
 		
@@ -720,23 +693,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				mode.CreateUndo("Paste sector properties");
 				mode.SetActionResult("Pasted sector properties.");
 
-				//mxd. Glow effect may require SectorData update
-				bool oldfloortextureglows = (SectorProperties.CopySettings.FloorTexture && General.Map.Data.GlowingFlats.ContainsKey(level.sector.LongFloorTexture));
-				bool oldceiltextureglows = (SectorProperties.CopySettings.CeilingTexture && General.Map.Data.GlowingFlats.ContainsKey(level.sector.LongCeilTexture));
-
 				//mxd. Added "usecopysettings"
 				BuilderPlug.Me.CopiedSectorProps.Apply(level.sector, usecopysettings);
 
-				//mxd. Glow effect may require SectorData update
-				if(oldfloortextureglows || oldceiltextureglows
-					|| (SectorProperties.CopySettings.FloorTexture && General.Map.Data.GlowingFlats.ContainsKey(level.sector.LongFloorTexture))
-					|| (SectorProperties.CopySettings.CeilingTexture && General.Map.Data.GlowingFlats.ContainsKey(level.sector.LongCeilTexture)))
-				{
-					mode.RebuildElementData();
-					SectorData sd = mode.GetSectorData(level.sector);
-					sd.UpdateForced();
-				}
-
 				if(mode.VisualSectorExists(level.sector))
 				{
 					BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
@@ -766,7 +725,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			mode.CreateUndo("Change flat \"" + texture + "\"");
 			SetTexture(texture);
-			OnTextureChanged(); //mxd
+
+			// Update
+			if(mode.VisualSectorExists(level.sector))
+			{
+				BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
+				vs.UpdateSectorGeometry(false);
+			}
 		}
 		
 		// Copy texture
@@ -837,8 +802,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			} 
 			else 
 			{
-				//mxd. Need this to apply changes to 3d-floor even if control sector doesn't exist 
-				//as BaseVisualSector
+				//mxd. Need this to apply changes to 3d-floor even if control sector doesn't exist as BaseVisualSector
 				vs = mode.CreateBaseVisualSector(level.sector);
 			}
 
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs
index d6908c570..a6b966063 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualGeometrySidedef.cs
@@ -66,7 +66,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private bool performautoselection; //mxd
 
 		// Undo/redo
-		private int undoticket;
+		protected int undoticket;
 		
 		#endregion
 		
@@ -532,26 +532,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			return result;
 		}
 
-		//mxd
-		private void OnTextureChanged() 
-		{
-			//check for 3d floors
-			if(Sidedef.Line.Action == 160) 
-			{
-				int sectortag = ((General.Map.UDMF || (Sidedef.Line.Args[1] & 8) != 0) ? Sidedef.Line.Args[0] : Sidedef.Line.Args[0] + (Sidedef.Line.Args[4] << 8));
-				if(sectortag == 0) return;
-
-				foreach(Sector sector in General.Map.Map.Sectors) 
-				{
-					if(sector.Tags.Contains(sectortag))
-					{
-						BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(sector);
-						vs.UpdateSectorGeometry(true);
-					}
-				}
-			}
-		}
-
 		//mxd
 		public void SelectNeighbours(bool select, bool matchtexture, bool matchheight) 
 		{
@@ -594,7 +574,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		//mxd
 		private void SelectNeighbourSideParts(Sidedef side, Rectangle sourcerect, bool select, bool matchtexture, bool matchheight)
 		{
-			BaseVisualSector s = mode.GetVisualSector(side.Sector) as BaseVisualSector;
+			BaseVisualSector s = (BaseVisualSector)mode.GetVisualSector(side.Sector);
 			if(s != null)
 			{
 				VisualSidedefParts parts = s.GetSidedefParts(side);
@@ -778,7 +758,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 					// Update
 					VisualSector othersector = mode.GetVisualSector(Sidedef.Other.Sector);
-					if(othersector is BaseVisualSector) (othersector as BaseVisualSector).Changed = true;
+					if(othersector is BaseVisualSector) ((BaseVisualSector)othersector).Changed = true;
 				}
 			}
 		}
@@ -791,8 +771,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			mode.SetActionResult("Deleted a texture.");
 			SetTexture("-");
 
-			// Update
-			Sector.UpdateSectorGeometry(true);
+			//mxd. Update linked effects
+			SectorData sd = mode.GetSectorDataEx(Sector.Sector);
+			if(sd != null) sd.Reset(true);
 		}
 		
 		// Processing
@@ -871,12 +852,29 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			ResetTextureScale();
 
 			// And brightness
-			if(Sidedef.Fields.ContainsKey("light")) Sidedef.Fields.Remove("light");
-			if(Sidedef.Fields.ContainsKey("lightabsolute")) Sidedef.Fields.Remove("lightabsolute");
+			bool setupallparts = false;
+			if(Sidedef.Fields.ContainsKey("light"))
+			{
+				Sidedef.Fields.Remove("light");
+				setupallparts = true;
+			}
+			if(Sidedef.Fields.ContainsKey("lightabsolute"))
+			{
+				Sidedef.Fields.Remove("lightabsolute");
+				setupallparts = true;
+			}
 
-			// Update sidedef geometry
-			VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
-			parts.SetupAllParts();
+			if(setupallparts)
+			{
+				// Update all sidedef geometry
+				VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
+				parts.SetupAllParts();
+			}
+			else
+			{
+				// Update this part only
+				this.Setup();
+			}
 		}
 		
 		// Toggle upper-unpegged
@@ -1034,7 +1032,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 							// Update the parts for this sidedef!
 							if(mode.VisualSectorExists(sd.Sector))
 							{
-								BaseVisualSector vs = (mode.GetVisualSector(sd.Sector) as BaseVisualSector);
+								BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(sd.Sector);
 								VisualSidedefParts parts = vs.GetSidedefParts(sd);
 								parts.SetupAllParts();
 							}
@@ -1112,7 +1110,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			mode.CreateUndo("Change texture " + texture);
 			SetTexture(texture);
-			OnTextureChanged();//mxd
+			
+			//mxd. Update linked effects
+			SectorData sd = mode.GetSectorDataEx(Sector.Sector);
+			if(sd != null) sd.Reset(true);
 		}
 		
 		// Paste texture
@@ -1123,7 +1124,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				mode.CreateUndo("Paste texture \"" + BuilderPlug.Me.CopiedTexture + "\"");
 				mode.SetActionResult("Pasted texture \"" + BuilderPlug.Me.CopiedTexture + "\".");
 				SetTexture(BuilderPlug.Me.CopiedTexture);
-				OnTextureChanged(); //mxd
+
+				//mxd. Update linked effects
+				SectorData sd = mode.GetSectorDataEx(Sector.Sector);
+				if(sd != null) sd.Reset(true);
 			}
 		}
 		
@@ -1135,17 +1139,25 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				SetTextureOffsetX(BuilderPlug.Me.CopiedOffsets.X);
 				SetTextureOffsetY(BuilderPlug.Me.CopiedOffsets.Y);
+
+				// Update sidedef part geometry
+				this.Setup();
 			} 
 			else 
 			{
 				Sidedef.OffsetX = BuilderPlug.Me.CopiedOffsets.X;
 				Sidedef.OffsetY = BuilderPlug.Me.CopiedOffsets.Y;
+
+				// Update sidedef geometry
+				VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
+				parts.SetupAllParts();
 			}
+
+			//mxd. Update linked effects
+			SectorData sd = mode.GetSectorDataEx(Sector.Sector);
+			if(sd != null) sd.Reset(true);
+
 			mode.SetActionResult("Pasted texture offsets " + BuilderPlug.Me.CopiedOffsets.X + ", " + BuilderPlug.Me.CopiedOffsets.Y + ".");
-			
-			// Update sidedef geometry
-			VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
-			parts.SetupAllParts();
 		}
 		
 		// Copy texture
@@ -1262,9 +1274,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						updatelist.Add((BaseVisualSector)mode.GetVisualSector(l.Back.Sector));
 				}
 
+				//mxd. Always select front side for extrafloors
+				Linedef sourceline = GetControlLinedef();
+				Sidedef target = (sourceline != Sidedef.Line && sourceline.Front != null ? sourceline.Front : Sidedef);
+
 				General.Interface.OnEditFormValuesChanged += Interface_OnEditFormValuesChanged;
 				mode.StartRealtimeInterfaceUpdate(SelectionType.Linedefs);
-				DialogResult result = General.Interface.ShowEditLinedefs(linedefs, Sidedef.IsFront, !Sidedef.IsFront);
+				DialogResult result = General.Interface.ShowEditLinedefs(linedefs, target.IsFront, !target.IsFront);
 				mode.StopRealtimeInterfaceUpdate(SelectionType.Linedefs);
 				General.Interface.OnEditFormValuesChanged -= Interface_OnEditFormValuesChanged;
 
@@ -1393,18 +1409,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 				if(newlight == light) return;
 
-				//create undo
+				// Create undo
 				mode.CreateUndo("Change wall brightness", UndoGroup.SurfaceBrightnessChange, Sector.Sector.FixedIndex);
 				Sidedef.Fields.BeforeFieldsChange();
 
-				//apply changes
+				// Apply changes
 				UniFields.SetInteger(Sidedef.Fields, "light", newlight, (absolute ? int.MinValue : 0));
 				Tools.UpdateLightFogFlag(Sidedef);
 				mode.SetActionResult("Changed wall brightness to " + newlight + ".");
-				Sector.Sector.UpdateCache();
 
-				//rebuild sector
-				Sector.UpdateSectorGeometry(false);
+				// Update this part only
+				this.Setup();
 			}
 			else if(!Sector.Changed)
 			{
@@ -1431,7 +1446,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						if(mode.VisualThingExists(t))
 						{
 							// Update thing
-							BaseVisualThing vt = (mode.GetVisualThing(t) as BaseVisualThing);
+							BaseVisualThing vt = (BaseVisualThing)mode.GetVisualThing(t);
 							vt.Changed = true;
 						}
 					}
@@ -1452,6 +1467,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				MoveTextureOffset(new Point(-horizontal, -vertical));
 				Point p = GetTextureOffset();
 				mode.SetActionResult("Changed texture offsets to " + p.X + ", " + p.Y + ".");
+
+				// Update this part only
+				this.Setup();
 			} 
 			else 
 			{
@@ -1462,11 +1480,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				if(geometrytype != VisualGeometryType.WALL_MIDDLE && Texture != null) Sidedef.OffsetY %= Texture.Height;
 
 				mode.SetActionResult("Changed texture offsets to " + Sidedef.OffsetX + ", " + Sidedef.OffsetY + ".");
+
+				// Update all sidedef geometry
+				VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
+				parts.SetupAllParts();
 			}
-			
-			// Update sidedef geometry
-			VisualSidedefParts parts = Sector.GetSidedefParts(Sidedef);
-			parts.SetupAllParts();
+
+			//mxd. Update linked effects
+			SectorData sd = mode.GetSectorDataEx(Sector.Sector);
+			if(sd != null) sd.Reset(true);
 		}
 
 		//mxd
@@ -1488,7 +1510,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					break;
 
 				case VisualGeometryType.WALL_MIDDLE:
-				case VisualGeometryType.WALL_MIDDLE_3D:
 					keyX = "scalex_mid";
 					keyY = "scaley_mid";
 					break;
@@ -1523,8 +1544,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				UniFields.SetFloat(Sidedef.Fields, keyY, scaleY, 1.0f);
 			}
 
-			//update geometry
+			// Update geometry
 			Setup();
+
+			//mxd. Update linked effects
+			SectorData sd = mode.GetSectorDataEx(Sector.Sector);
+			if(sd != null) sd.Reset(true);
+
 			mode.SetActionResult("Wall scale changed to " + scaleX.ToString("F03", CultureInfo.InvariantCulture) + ", " + scaleY.ToString("F03", CultureInfo.InvariantCulture) + " (" + (int)Math.Round(Texture.Width / scaleX) + " x " + (int)Math.Round(Texture.Height / scaleY) + ").");
 		}
 
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
index 14162908b..e262b980c 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualMode.cs
@@ -282,7 +282,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Reset changed flags
 			foreach(KeyValuePair<Sector, VisualSector> vs in allsectors)
 			{
-				BaseVisualSector bvs = (vs.Value as BaseVisualSector);
+				BaseVisualSector bvs = (BaseVisualSector)vs.Value;
 				foreach(VisualFloor vf in bvs.ExtraFloors) vf.Changed = false;
 				foreach(VisualCeiling vc in bvs.ExtraCeilings) vc.Changed = false;
 				foreach(VisualFloor vf in bvs.ExtraBackFloors) vf.Changed = false; //mxd
@@ -343,7 +343,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				if(vs.Value != null)
 				{
-					BaseVisualSector bvs = vs.Value as BaseVisualSector;
+					BaseVisualSector bvs = (BaseVisualSector)vs.Value;
 					if((bvs.Floor != null) && bvs.Floor.Selected) selectedobjects.Add(bvs.Floor);
 					if((bvs.Ceiling != null) && bvs.Ceiling.Selected) selectedobjects.Add(bvs.Ceiling);
 					foreach(Sidedef sd in vs.Key.Sidedefs)
@@ -351,7 +351,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						List<VisualGeometry> sidedefgeos = bvs.GetSidedefGeometry(sd);
 						foreach(VisualGeometry sdg in sidedefgeos)
 						{
-							if(sdg.Selected) selectedobjects.Add((sdg as IVisualEventReceiver));
+							if(sdg.Selected) selectedobjects.Add((IVisualEventReceiver)sdg);
 						}
 					}
 				}
@@ -361,7 +361,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				if(vt.Value != null)
 				{
-					BaseVisualThing bvt = vt.Value as BaseVisualThing;
+					BaseVisualThing bvt = (BaseVisualThing)vt.Value;
 					if(bvt.Selected) selectedobjects.Add(bvt);
 				}
 			}
@@ -502,7 +502,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				if(vs.Value != null)
 				{
-					BaseVisualSector bvs = vs.Value as BaseVisualSector;
+					BaseVisualSector bvs = (BaseVisualSector)vs.Value;
 					if(bvs.Changed) bvs.Rebuild();
 				}
 			}
@@ -511,7 +511,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				if(vt.Value != null)
 				{
-					BaseVisualThing bvt = vt.Value as BaseVisualThing;
+					BaseVisualThing bvt = (BaseVisualThing)vt.Value;
 					if(bvt.Changed) bvt.Rebuild();
 				}
 			}
@@ -543,7 +543,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			Vector3D[] translatedcoords = TranslateCoordinates(coords, direction, absoluteposition);
 			for(int i = 0; i < visualthings.Count; i++) 
 			{
-				BaseVisualThing t = visualthings[i] as BaseVisualThing;
+				BaseVisualThing t = (BaseVisualThing)visualthings[i];
 				t.OnMove(translatedcoords[i]);
 			}
 
@@ -735,7 +735,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(!vertices.ContainsKey(v))
 				vertices.Add(v, new VisualVertexPair(new BaseVisualVertex(this, v, false), new BaseVisualVertex(this, v, true)));
 
-			return (floor ? vertices[v].FloorVertex as BaseVisualVertex : vertices[v].CeilingVertex as BaseVisualVertex);
+			return (floor ? (BaseVisualVertex)vertices[v].FloorVertex : (BaseVisualVertex)vertices[v].CeilingVertex);
 		}
 
 		//mxd
@@ -785,7 +785,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					// The visual sector associated is now outdated
 					if(VisualSectorExists(sectorsWithEffects[i])) 
 					{
-						BaseVisualSector vs = GetVisualSector(sectorsWithEffects[i]) as BaseVisualSector;
+						BaseVisualSector vs = (BaseVisualSector)GetVisualSector(sectorsWithEffects[i]);
 						vs.UpdateSectorGeometry(true);
 					}
 				}
@@ -853,13 +853,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						sd.AddEffectThingVertexSlope(slopeceilingthings, false);
 					}
 				}
-				
-				// ========== mxd. Glowing flats ==========
-				if(General.Map.Data.GlowingFlats.ContainsKey(s.LongFloorTexture) || General.Map.Data.GlowingFlats.ContainsKey(s.LongCeilTexture))
-				{
-					SectorData sd = GetSectorData(s);
-					sd.AddEffectGlowingFlat(s);
-				}
 			}
 			
 			// Find interesting linedefs (such as line slopes)
@@ -1077,7 +1070,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					}
 					else if(obj is VisualFloor || obj is VisualCeiling) 
 					{
-						VisualGeometry vg = obj as VisualGeometry;
+						VisualGeometry vg = (VisualGeometry)obj;
 						if(vg.Sector != null && vg.Sector.Sector != null && !selectedsectorindices.Contains(vg.Sector.Sector.Index))
 						{
 							selectedsectorindices.Add(vg.Sector.Sector.Index);
@@ -1087,7 +1080,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					else if(obj is VisualLower || obj is VisualUpper || obj is VisualMiddleDouble 
 						|| obj is VisualMiddleSingle || obj is VisualMiddle3D) 
 					{
-						VisualGeometry vg = obj as VisualGeometry;
+						VisualGeometry vg = (VisualGeometry)obj;
 						if(vg.Sidedef != null && !selectedlineindices.Contains(vg.Sidedef.Line.Index))
 						{
 							selectedlineindices.Add(vg.Sidedef.Line.Index);
@@ -1096,7 +1089,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					}
 					else if(obj is VisualVertex)
 					{
-						VisualVertex v = obj as VisualVertex;
+						VisualVertex v = (VisualVertex)obj;
 						if(!selectedvertexindices.Contains(v.Vertex.Index))
 						{
 							selectedvertexindices.Add(v.Vertex.Index);
@@ -1293,7 +1286,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				{
 					if(sd.Marked && VisualSectorExists(sd.Sector))
 					{
-						BaseVisualSector vs = GetVisualSector(sd.Sector) as BaseVisualSector;
+						BaseVisualSector vs = (BaseVisualSector)GetVisualSector(sd.Sector);
 						VisualSidedefParts parts = vs.GetSidedefParts(sd);
 						parts.SetupAllParts();
 					}
@@ -1304,23 +1297,26 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				{
 					if(s.Marked)
 					{
-						SectorData sd = GetSectorData(s);
-						sd.Reset(false); //mxd (changed Reset implementation)
-						
-						// UpdateSectorGeometry for associated sectors (sd.UpdateAlso) as well!
-						foreach(KeyValuePair<Sector, bool> us in sd.UpdateAlso)
+						SectorData sd = GetSectorDataEx(s);
+						if(sd != null)
 						{
-							if(VisualSectorExists(us.Key))
+							sd.Reset(false); //mxd (changed Reset implementation)
+
+							// UpdateSectorGeometry for associated sectors (sd.UpdateAlso) as well!
+							foreach(KeyValuePair<Sector, bool> us in sd.UpdateAlso)
 							{
-								BaseVisualSector vs = GetVisualSector(us.Key) as BaseVisualSector;
-								vs.UpdateSectorGeometry(us.Value);
+								if(VisualSectorExists(us.Key))
+								{
+									BaseVisualSector vs = (BaseVisualSector)GetVisualSector(us.Key);
+									vs.UpdateSectorGeometry(us.Value);
+								}
 							}
 						}
 						
 						// And update for this sector ofcourse
 						if(VisualSectorExists(s))
 						{
-							BaseVisualSector vs = GetVisualSector(s) as BaseVisualSector;
+							BaseVisualSector vs = (BaseVisualSector)GetVisualSector(s);
 							vs.UpdateSectorGeometry(false);
 						}
 					}
@@ -1336,7 +1332,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						if((vt.Value != null) && vt.Key.Marked)
 						{
 							if(vt.Key.IsDisposed) toremove.Add(vt.Key); //mxd. Disposed things will cause problems
-							else (vt.Value as BaseVisualThing).Rebuild();
+							else ((BaseVisualThing)vt.Value).Rebuild();
 						}
 					}
 
@@ -1423,13 +1419,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			base.OnUndoEnd();
 
 			//mxd. Effects may've become invalid
-			if(General.Settings.GZDoomRenderingEffects && sectordata != null && sectordata.Count > 0)
-				RebuildElementData();
+			if(sectordata != null && sectordata.Count > 0) RebuildElementData();
 
 			//mxd. As well as geometry...
 			foreach(KeyValuePair<Sector, VisualSector> group in visiblesectors)
 			{
-				BaseVisualSector vs = group.Value as BaseVisualSector;
+				BaseVisualSector vs = (BaseVisualSector)group.Value;
 				if(vs != null) vs.Rebuild();
 			}
 
@@ -1445,13 +1440,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			base.OnRedoEnd();
 
 			//mxd. Effects may've become invalid
-			if(sectordata != null && sectordata.Count > 0)
-				RebuildElementData();
+			if(sectordata != null && sectordata.Count > 0) RebuildElementData();
 
 			//mxd. As well as geometry...
 			foreach(KeyValuePair<Sector, VisualSector> group in visiblesectors) 
 			{
-				BaseVisualSector vs = group.Value as BaseVisualSector;
+				BaseVisualSector vs = (BaseVisualSector)group.Value;
 				if(vs != null) vs.Rebuild();
 			}
 
@@ -1466,7 +1460,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Reset changed flags
 			foreach(KeyValuePair<Sector, VisualSector> vs in allsectors) 
 			{
-				BaseVisualSector bvs = (vs.Value as BaseVisualSector);
+				BaseVisualSector bvs = (BaseVisualSector)vs.Value;
 				foreach(VisualFloor vf in bvs.ExtraFloors) vf.Changed = false;
 				foreach(VisualCeiling vc in bvs.ExtraCeilings) vc.Changed = false;
 				foreach(VisualFloor vf in bvs.ExtraBackFloors) vf.Changed = false;
@@ -1494,7 +1488,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					{
 						if(VisualSectorExists(s.Key)) 
 						{
-							BaseVisualSector vs = GetVisualSector(s.Key) as BaseVisualSector;
+							BaseVisualSector vs = (BaseVisualSector)GetVisualSector(s.Key);
 							vs.UpdateSectorGeometry(s.Value);
 						}
 					}
@@ -1535,35 +1529,33 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			//mxd. Because Upper/Middle/Lower textures offsets should be threated separately in UDMF
 			if(General.Map.UDMF)
 			{
-				Dictionary<BaseVisualGeometrySidedef, bool> donesides = new Dictionary<BaseVisualGeometrySidedef, bool>(selectedobjects.Count);
+				HashSet<BaseVisualGeometrySidedef> donesides = new HashSet<BaseVisualGeometrySidedef>();
 				foreach(IVisualEventReceiver i in objs) 
 				{
-					if(!(i is BaseVisualGeometrySidedef)) continue;
-					BaseVisualGeometrySidedef vs = i as BaseVisualGeometrySidedef; //mxd
-					if(!donesides.ContainsKey(vs)) 
+					BaseVisualGeometrySidedef vs = (BaseVisualGeometrySidedef)i; //mxd
+					if(!donesides.Contains(vs)) 
 					{
 						//mxd. added scaling by texture scale
 						if(vs.Texture.UsedInMap) //mxd. Otherwise it's MissingTexture3D and we probably don't want to drag that
 							vs.OnChangeTextureOffset((int)(dx / vs.Texture.Scale.x), (int)(dy / vs.Texture.Scale.y), false);
 
-						donesides.Add(vs, false);
+						donesides.Add(vs);
 					}
 				}
 			}
 			else
 			{
-				Dictionary<Sidedef, bool> donesides = new Dictionary<Sidedef, bool>(selectedobjects.Count);
+				HashSet<Sidedef> donesides = new HashSet<Sidedef>();
 				foreach(IVisualEventReceiver i in objs) 
 				{
-					if(!(i is BaseVisualGeometrySidedef)) continue;
-					BaseVisualGeometrySidedef vs = i as BaseVisualGeometrySidedef; //mxd
-					if(!donesides.ContainsKey(vs.Sidedef)) 
+					BaseVisualGeometrySidedef vs = (BaseVisualGeometrySidedef)i; //mxd
+					if(!donesides.Contains(vs.Sidedef)) 
 					{
 						//mxd. added scaling by texture scale
 						if(vs.Texture.UsedInMap) //mxd. Otherwise it's MissingTexture3D and we probably don't want to drag that
 							vs.OnChangeTextureOffset((int)(dx / vs.Texture.Scale.x), (int)(dy / vs.Texture.Scale.y), false);
 
-						donesides.Add(vs.Sidedef, false);
+						donesides.Add(vs.Sidedef);
 					}
 				}
 			}
@@ -1572,17 +1564,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Apply flat offsets
 		public void ApplyFlatOffsetChange(int dx, int dy)
 		{
-			Dictionary<Sector, int> donesectors = new Dictionary<Sector, int>(selectedobjects.Count);
+			HashSet<Sector> donesectors = new HashSet<Sector>();
 			List<IVisualEventReceiver> objs = GetSelectedObjects(true, false, false, false);
 			foreach(IVisualEventReceiver i in objs)
 			{
-				if(i is BaseVisualGeometrySector)
+				BaseVisualGeometrySector bvs = (BaseVisualGeometrySector)i;
+				if(bvs != null && !donesectors.Contains(bvs.Sector.Sector))
 				{
-					if(!donesectors.ContainsKey((i as BaseVisualGeometrySector).Sector.Sector))
-					{
-						i.OnChangeTextureOffset(dx, dy, false);
-						donesectors.Add((i as BaseVisualGeometrySector).Sector.Sector, 0);
-					}
+					bvs.OnChangeTextureOffset(dx, dy, false);
+					donesectors.Add(bvs.Sector.Sector);
 				}
 			}
 		}
@@ -1657,7 +1647,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		//mxd
 		internal List<IVisualEventReceiver> RemoveDuplicateSidedefs(List<IVisualEventReceiver> objs) 
 		{
-			Dictionary<Sidedef, bool> processed = new Dictionary<Sidedef, bool>();
+			HashSet<Sidedef> processed = new HashSet<Sidedef>();
 			List<IVisualEventReceiver> result = new List<IVisualEventReceiver>();
 
 			foreach(IVisualEventReceiver i in objs)
@@ -1665,9 +1655,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				BaseVisualGeometrySidedef sidedef = i as BaseVisualGeometrySidedef;
 				if(sidedef != null)
 				{
-					if (!processed.ContainsKey(sidedef.Sidedef))
+					if(!processed.Contains(sidedef.Sidedef))
 					{
-						processed.Add(sidedef.Sidedef, false);
+						processed.Add(sidedef.Sidedef);
 						result.Add(i);
 					}
 				}
@@ -1683,15 +1673,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This returns all selected sectors, no doubles
 		public List<Sector> GetSelectedSectors()
 		{
-			Dictionary<Sector, int> added = new Dictionary<Sector, int>();
+			HashSet<Sector> added = new HashSet<Sector>();
 			List<Sector> sectors = new List<Sector>();
 			foreach(IVisualEventReceiver i in selectedobjects)
 			{
 				BaseVisualGeometrySector sector = i as BaseVisualGeometrySector;
-				if(sector != null && !added.ContainsKey(sector.Level.sector))
+				if(sector != null && !added.Contains(sector.Level.sector))
 				{
 					sectors.Add(sector.Level.sector);
-					added.Add(sector.Level.sector, 0);
+					added.Add(sector.Level.sector);
 				}
 			}
 
@@ -1699,7 +1689,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if((selectedobjects.Count == 0) && (target.picked is BaseVisualGeometrySector))
 			{
 				Sector s = ((BaseVisualGeometrySector)target.picked).Level.sector;
-				if(!added.ContainsKey(s)) sectors.Add(s);
+				if(!added.Contains(s)) sectors.Add(s);
 			}
 			
 			return sectors;
@@ -1708,7 +1698,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This returns all selected linedefs, no doubles
 		public List<Linedef> GetSelectedLinedefs()
 		{
-			Dictionary<Linedef, int> added = new Dictionary<Linedef, int>();
+			HashSet<Linedef> added = new HashSet<Linedef>();
 			List<Linedef> linedefs = new List<Linedef>();
 			foreach(IVisualEventReceiver i in selectedobjects)
 			{
@@ -1716,10 +1706,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				if(sidedef != null)
 				{
 					Linedef l = sidedef.GetControlLinedef(); //mxd
-					if(!added.ContainsKey(l))
+					if(!added.Contains(l))
 					{
 						linedefs.Add(l);
-						added.Add(l, 0);
+						added.Add(l);
 					}
 				}
 			}
@@ -1728,7 +1718,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if((selectedobjects.Count == 0) && (target.picked is BaseVisualGeometrySidedef))
 			{
 				Linedef l = ((BaseVisualGeometrySidedef)target.picked).GetControlLinedef(); //mxd
-				if(!added.ContainsKey(l)) linedefs.Add(l);
+				if(!added.Contains(l)) linedefs.Add(l);
 			}
 
 			return linedefs;
@@ -1737,15 +1727,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This returns all selected sidedefs, no doubles
 		public List<Sidedef> GetSelectedSidedefs()
 		{
-			Dictionary<Sidedef, int> added = new Dictionary<Sidedef, int>();
+			HashSet<Sidedef> added = new HashSet<Sidedef>();
 			List<Sidedef> sidedefs = new List<Sidedef>();
 			foreach(IVisualEventReceiver i in selectedobjects)
 			{
 				BaseVisualGeometrySidedef sidedef = i as BaseVisualGeometrySidedef;
-				if(sidedef != null && !added.ContainsKey(sidedef.Sidedef))
+				if(sidedef != null && !added.Contains(sidedef.Sidedef))
 				{
 					sidedefs.Add(sidedef.Sidedef);
-					added.Add(sidedef.Sidedef, 0);
+					added.Add(sidedef.Sidedef);
 				}
 			}
 
@@ -1753,7 +1743,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if((selectedobjects.Count == 0) && (target.picked is BaseVisualGeometrySidedef))
 			{
 				Sidedef sd = ((BaseVisualGeometrySidedef)target.picked).Sidedef;
-				if(!added.ContainsKey(sd)) sidedefs.Add(sd);
+				if(!added.Contains(sd)) sidedefs.Add(sd);
 			}
 
 			return sidedefs;
@@ -1762,15 +1752,15 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This returns all selected things, no doubles
 		public List<Thing> GetSelectedThings()
 		{
-			Dictionary<Thing, int> added = new Dictionary<Thing, int>();
+			HashSet<Thing> added = new HashSet<Thing>();
 			List<Thing> things = new List<Thing>();
 			foreach(IVisualEventReceiver i in selectedobjects)
 			{
 				BaseVisualThing thing = i as BaseVisualThing;
-				if(thing != null && !added.ContainsKey(thing.Thing))
+				if(thing != null && !added.Contains(thing.Thing))
 				{
 					things.Add(thing.Thing);
-					added.Add(thing.Thing, 0);
+					added.Add(thing.Thing);
 				}
 			}
 
@@ -1778,7 +1768,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if((selectedobjects.Count == 0) && (target.picked is BaseVisualThing))
 			{
 				Thing t = ((BaseVisualThing)target.picked).Thing;
-				if(!added.ContainsKey(t)) things.Add(t);
+				if(!added.Contains(t)) things.Add(t);
 			}
 
 			return things;
@@ -1787,20 +1777,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		//mxd. This returns all selected vertices, no doubles
 		public List<Vertex> GetSelectedVertices() 
 		{
-			Dictionary<Vertex, int> added = new Dictionary<Vertex, int>();
+			HashSet<Vertex> added = new HashSet<Vertex>();
 			List<Vertex> verts = new List<Vertex>();
 
-			foreach(IVisualEventReceiver i in selectedobjects) 
+			foreach(IVisualEventReceiver i in selectedobjects)
 			{
-				if(i is BaseVisualVertex) 
+				BaseVisualVertex vertex = i as BaseVisualVertex;
+				if(vertex != null && !added.Contains(vertex.Vertex)) 
 				{
-					Vertex v = (i as BaseVisualVertex).Vertex;
-					
-					if(!added.ContainsKey(v)) 
-					{
-						verts.Add(v);
-						added.Add(v, 0);
-					}
+					verts.Add(vertex.Vertex);
+					added.Add(vertex.Vertex);
 				}
 			}
 
@@ -1808,7 +1794,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if((selectedobjects.Count == 0) && (target.picked is BaseVisualVertex)) 
 			{
 				Vertex v = ((BaseVisualVertex)target.picked).Vertex;
-				if(!added.ContainsKey(v)) verts.Add(v);
+				if(!added.Contains(v)) verts.Add(v);
 			}
 
 			return verts;
@@ -1821,7 +1807,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				if(singleselection || target.picked.Selected || targetonly)
 				{
-					return target.picked as IVisualEventReceiver;
+					return (IVisualEventReceiver)target.picked;
 				}
 
 				if(selectedobjects.Count > 0)
@@ -1829,7 +1815,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					return selectedobjects[0];
 				}
 
-				return target.picked as IVisualEventReceiver;
+				return (IVisualEventReceiver)target.picked;
 			}
 
 			return new NullVisualEventReceiver();
@@ -1907,7 +1893,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				if(vt.Value != null)
 				{
-					BaseVisualThing bvt = vt.Value as BaseVisualThing;
+					BaseVisualThing bvt = (BaseVisualThing)vt.Value;
 					bvt.Selected = false;
 				}
 			}
@@ -2023,20 +2009,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Get selection
 			if(selectedobjects.Count == 0)
 			{
-				IVisualEventReceiver i = (target.picked as IVisualEventReceiver);
-				if(i is VisualFloor) 
+				if(target.picked is VisualFloor) 
 				{
-					VisualFloor vf = i as VisualFloor;
+					VisualFloor vf = (VisualFloor)target.picked;
 					floors.Add(vf.Level.sector, vf);
 				} 
-				else if(i is VisualCeiling) 
+				else if(target.picked is VisualCeiling) 
 				{
-					VisualCeiling vc = i as VisualCeiling;
+					VisualCeiling vc = (VisualCeiling)target.picked;
 					ceilings.Add(vc.Level.sector, vc);
 				} 
-				else if(i is BaseVisualThing) 
+				else if(target.picked is BaseVisualThing) 
 				{
-					things.Add(i as BaseVisualThing);
+					things.Add((BaseVisualThing)target.picked);
 				}
 			} 
 			else 
@@ -2045,17 +2030,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				{
 					if(i is VisualFloor) 
 					{
-						VisualFloor vf = i as VisualFloor;
+						VisualFloor vf = (VisualFloor)i;
 						floors.Add(vf.Level.sector, vf);
 					} 
 					else if(i is VisualCeiling) 
 					{
-						VisualCeiling vc = i as VisualCeiling;
+						VisualCeiling vc = (VisualCeiling)i;
 						ceilings.Add(vc.Level.sector, vc);
 					} 
 					else if(i is BaseVisualThing) 
 					{
-						things.Add(i as BaseVisualThing);
+						things.Add((BaseVisualThing)i);
 					}
 				}
 			}
@@ -2221,23 +2206,22 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			List<BaseVisualThing> things = new List<BaseVisualThing>();
 			bool withinSelection = General.Interface.CtrlState;
 
-			//get selection
+			// Get selection
 			if(selectedobjects.Count == 0) 
 			{
-				IVisualEventReceiver i = (target.picked as IVisualEventReceiver);
-				if(i is VisualFloor) 
+				if(target.picked is VisualFloor) 
 				{
-					VisualFloor vf = i as VisualFloor;
+					VisualFloor vf = (VisualFloor)target.picked;
 					floors.Add(vf.Level.sector, vf);
 				} 
-				else if(i is VisualCeiling) 
+				else if(target.picked is VisualCeiling) 
 				{
-					VisualCeiling vc = i as VisualCeiling;
+					VisualCeiling vc = (VisualCeiling)target.picked;
 					ceilings.Add(vc.Level.sector, vc);
 				} 
-				else if(i is BaseVisualThing) 
+				else if(target.picked is BaseVisualThing) 
 				{
-					things.Add(i as BaseVisualThing);
+					things.Add((BaseVisualThing)target.picked);
 				}
 			}
 			else
@@ -2246,17 +2230,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				{
 					if(i is VisualFloor) 
 					{
-						VisualFloor vf = i as VisualFloor;
+						VisualFloor vf = (VisualFloor)i;
 						floors.Add(vf.Level.sector, vf);
 					} 
 					else if(i is VisualCeiling) 
 					{
-						VisualCeiling vc = i as VisualCeiling;
+						VisualCeiling vc = (VisualCeiling)i;
 						ceilings.Add(vc.Level.sector, vc);
 					} 
 					else if(i is BaseVisualThing) 
 					{
-						things.Add(i as BaseVisualThing);
+						things.Add((BaseVisualThing)i);
 					}
 				}
 			}
@@ -2427,7 +2411,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				return;
 			}
 
-			IVisualEventReceiver highlighted = (target.picked as IVisualEventReceiver);
+			IVisualEventReceiver highlighted = (IVisualEventReceiver)target.picked;
 
 			if(highlighted is BaseVisualThing) 
 			{
@@ -2439,7 +2423,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			int targetbrightness;
 			if(highlighted is VisualFloor) 
 			{
-				VisualFloor v = highlighted as VisualFloor;
+				VisualFloor v = (VisualFloor)highlighted;
 				targetbrightness = v.Level.sector.Fields.GetValue("lightfloor", 0);
 				if(!v.Level.sector.Fields.GetValue("lightfloorabsolute", false)) 
 				{
@@ -2448,7 +2432,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			} 
 			else if(highlighted is VisualCeiling) 
 			{
-				VisualCeiling v = highlighted as VisualCeiling;
+				VisualCeiling v = (VisualCeiling)highlighted;
 				targetbrightness = v.Level.sector.Fields.GetValue("lightceiling", 0);
 				if(!v.Level.sector.Fields.GetValue("lightceilingabsolute", false)) 
 				{
@@ -2457,7 +2441,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			} 
 			else if(highlighted is VisualUpper || highlighted is VisualMiddleSingle || highlighted is VisualMiddleDouble || highlighted is VisualLower) 
 			{
-				BaseVisualGeometrySidedef v = highlighted as BaseVisualGeometrySidedef;
+				BaseVisualGeometrySidedef v = (BaseVisualGeometrySidedef)highlighted;
 				targetbrightness = v.Sidedef.Fields.GetValue("light", 0);
 				if(!v.Sidedef.Fields.GetValue("lightabsolute", false)) 
 				{
@@ -2466,7 +2450,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			} 
 			else if(highlighted is VisualMiddle3D) 
 			{
-				VisualMiddle3D v = highlighted as VisualMiddle3D;
+				VisualMiddle3D v = (VisualMiddle3D)highlighted;
 				Sidedef sd = v.GetControlLinedef().Front;
 				if(sd == null) 
 				{
@@ -2497,7 +2481,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 				if(obj is VisualFloor) 
 				{
-					VisualFloor v = obj as VisualFloor;
+					VisualFloor v = (VisualFloor)obj;
 					v.Level.sector.Fields.BeforeFieldsChange();
 					v.Sector.Changed = true;
 
@@ -2514,7 +2498,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				} 
 				else if(obj is VisualCeiling) 
 				{
-					VisualCeiling v = obj as VisualCeiling;
+					VisualCeiling v = (VisualCeiling)obj;
 					v.Level.sector.Fields.BeforeFieldsChange();
 					v.Sector.Changed = true;
 					v.Sector.Sector.UpdateNeeded = true;
@@ -2532,7 +2516,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				} 
 				else if(obj is VisualUpper || obj is VisualMiddleSingle || obj is VisualMiddleDouble || obj is VisualLower) 
 				{
-					BaseVisualGeometrySidedef v = obj as BaseVisualGeometrySidedef;
+					BaseVisualGeometrySidedef v = (BaseVisualGeometrySidedef)obj;
 					v.Sidedef.Fields.BeforeFieldsChange();
 					v.Sector.Changed = true;
 
@@ -2727,7 +2711,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			renderer.SetCrosshairBusy(true);
 			General.Interface.RedrawDisplay();
 			GetTargetEventReceiver(false).OnSelectTexture();
-			RebuildElementData(); //mxd. Extrafloors or Glow effects may've been changed
 			renderer.SetCrosshairBusy(false);
 			PostAction();
 		}
@@ -2851,7 +2834,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			//align
 			foreach(IVisualEventReceiver i in objs) 
 			{
-				BaseVisualGeometrySidedef side = i as BaseVisualGeometrySidedef;
+				BaseVisualGeometrySidedef side = (BaseVisualGeometrySidedef)i;
 				
 				// Make sure the texture is loaded (we need the texture size)
 				if(!side.Texture.IsImageLoaded) side.Texture.LoadImage();
@@ -2867,7 +2850,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					// Update the parts for this sidedef!
 					if(VisualSectorExists(sd.Sector)) 
 					{
-						BaseVisualSector vs = (GetVisualSector(sd.Sector) as BaseVisualSector);
+						BaseVisualSector vs = (BaseVisualSector)GetVisualSector(sd.Sector);
 						VisualSidedefParts parts = vs.GetSidedefParts(sd);
 						parts.SetupAllParts();
 					}
@@ -2884,9 +2867,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Get selection
 			List<IVisualEventReceiver> objs = GetSelectedObjects(false, true, false, false);
 			List<BaseVisualGeometrySidedef> sides = new List<BaseVisualGeometrySidedef>();
-			foreach(IVisualEventReceiver side in objs) 
+			foreach(IVisualEventReceiver i in objs)
 			{
-				if(side is BaseVisualGeometrySidedef) sides.Add(side as BaseVisualGeometrySidedef);
+				BaseVisualGeometrySidedef side = (BaseVisualGeometrySidedef)i;
+				if(side != null) sides.Add(side);
 			}
 
 			if(sides.Count == 0)
@@ -3016,7 +3000,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				added = new HashSet<int>();
 				foreach(IVisualEventReceiver receiver in obj)
 				{
-					VisualGeometry vg = receiver as VisualGeometry;
+					VisualGeometry vg = (VisualGeometry)receiver;
 					if(vg != null && !added.Contains(vg.Sector.GetHashCode()))
 					{
 						selection.Add(receiver);
@@ -3035,7 +3019,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				added = new HashSet<int>();
 				foreach(IVisualEventReceiver receiver in obj)
 				{
-					VisualGeometry vg = receiver as VisualGeometry;
+					VisualGeometry vg = (VisualGeometry)receiver;
 					if(vg != null && !added.Contains(vg.Sidedef.Line.GetHashCode()))
 					{
 						selection.Add(receiver);
@@ -3054,7 +3038,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				added = new HashSet<int>();
 				foreach(IVisualEventReceiver receiver in obj)
 				{
-					VisualThing vt = receiver as VisualThing;
+					VisualThing vt = (VisualThing)receiver;
 					if(vt != null && !added.Contains(vt.Thing.GetHashCode()))
 					{
 						selection.Add(receiver);
@@ -3073,7 +3057,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				added = new HashSet<int>();
 				foreach(IVisualEventReceiver receiver in obj)
 				{
-					VisualVertex vv = receiver as VisualVertex;
+					VisualVertex vv = (VisualVertex)receiver;
 					if(vv != null && !added.Contains(vv.Vertex.GetHashCode()))
 					{
 						selection.Add(receiver);
@@ -3157,7 +3141,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			copybuffer.Clear();
 			foreach(IVisualEventReceiver i in objs) 
 			{
-				VisualThing vt = i as VisualThing;
+				VisualThing vt = (VisualThing)i;
 				if(vt != null) copybuffer.Add(new ThingCopyData(vt.Thing));
 			}
 			General.Interface.DisplayStatus(StatusType.Info, "Copied " + copybuffer.Count + " Things");
@@ -3177,7 +3161,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			List<IVisualEventReceiver> objs = GetSelectedObjects(false, false, true, false);
 			foreach(IVisualEventReceiver i in objs) 
 			{
-				BaseVisualThing thing = i as BaseVisualThing;
+				BaseVisualThing thing = (BaseVisualThing)i;
 				thing.Thing.Fields.BeforeFieldsChange();
 				thing.Thing.Dispose();
 				thing.Dispose();
@@ -3267,17 +3251,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				if(obj is BaseVisualThing) 
 				{
-					BaseVisualThing t = obj as BaseVisualThing;
+					BaseVisualThing t = (BaseVisualThing)obj;
 					t.SetAngle(General.ClampAngle(t.Thing.AngleDoom + increment));
 				}
 				else if(obj is VisualFloor) 
 				{
-					VisualFloor vf = obj as VisualFloor;
+					VisualFloor vf = (VisualFloor)obj;
 					vf.OnChangeTextureRotation(General.ClampAngle(vf.GetControlSector().Fields.GetValue("rotationfloor", 0.0f) + increment));
 				} 
 				else if(obj is VisualCeiling) 
 				{
-					VisualCeiling vc = obj as VisualCeiling;
+					VisualCeiling vc = (VisualCeiling)obj;
 					vc.OnChangeTextureRotation(General.ClampAngle(vc.GetControlSector().Fields.GetValue("rotationceiling", 0.0f) + increment));
 				}
 			}
@@ -3309,9 +3293,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 			foreach(IVisualEventReceiver obj in selection) 
 			{
-				if(!(obj is BaseVisualThing))  continue;
-				BaseVisualThing t = obj as BaseVisualThing;
-				t.SetPitch(General.ClampAngle(t.Thing.Pitch + increment));
+				BaseVisualThing t = (BaseVisualThing)obj;
+				if(t != null) t.SetPitch(General.ClampAngle(t.Thing.Pitch + increment));
 			}
 
 			PostAction();
@@ -3341,9 +3324,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 			foreach(IVisualEventReceiver obj in selection) 
 			{
-				if(!(obj is BaseVisualThing)) continue;
-				BaseVisualThing t = obj as BaseVisualThing;
-				t.SetRoll(General.ClampAngle(t.Thing.Roll + increment));
+				BaseVisualThing t = (BaseVisualThing)obj;
+				if(t != null) t.SetRoll(General.ClampAngle(t.Thing.Roll + increment));
 			}
 
 			PostAction();
@@ -3418,7 +3400,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			//apply changes to Visual Things
 			for(int i = 0; i < visualThings.Count; i++) 
 			{
-				BaseVisualThing t = visualThings[i] as BaseVisualThing;
+				BaseVisualThing t = (BaseVisualThing)visualThings[i];
 				t.Changed = true;
 
 				// Update what must be updated
@@ -3667,7 +3649,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				}
 
 				//add to update list
-				if(update) toUpdate.Add(vg.Sector as BaseVisualSector);
+				if(update) toUpdate.Add((BaseVisualSector)vg.Sector);
 			}
 
 			//update changed geometry
@@ -3846,13 +3828,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			List<BaseVisualGeometrySidedef> selectedVisualSides = new List<BaseVisualGeometrySidedef>();
 			if(checkSelectedSidedefParts && !singleselection) 
 			{
-				foreach(IVisualEventReceiver i in selectedobjects) 
+				foreach(IVisualEventReceiver i in selectedobjects)
 				{
-					if(i is BaseVisualGeometrySidedef) 
-					{
-						BaseVisualGeometrySidedef sd = i as BaseVisualGeometrySidedef;
-						if(!selectedVisualSides.Contains(sd)) selectedVisualSides.Add(sd);
-					}
+					BaseVisualGeometrySidedef side = (BaseVisualGeometrySidedef)i;
+					if(side != null && !selectedVisualSides.Contains(side)) selectedVisualSides.Add(side);
 				}
 			}
 			
@@ -4221,11 +4200,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		//mxd
 		private List<Sidedef> GetControlSides(Sidedef side, bool udmf) 
 		{
-			if(side.Other == null) return new List<Sidedef>() { side };
-			if(side.Other.Sector.Tag == 0) return new List<Sidedef>() { side };
+			if(side.Other == null) return new List<Sidedef> { side };
+			if(side.Other.Sector.Tag == 0) return new List<Sidedef> { side };
 
-			SectorData data = GetSectorData(side.Other.Sector);
-			if(data.ExtraFloors.Count == 0)	return new List<Sidedef>() { side };
+			SectorData data = GetSectorDataEx(side.Other.Sector);
+			if(data == null || data.ExtraFloors.Count == 0) return new List<Sidedef> { side };
 
 			List<Sidedef> sides = new List<Sidedef>();
 			foreach(Effect3DFloor ef in data.ExtraFloors)
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs
index 0147ecc2b..07430725a 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualSector.cs
@@ -124,16 +124,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			SectorData data = mode.GetSectorDataEx(this.Sector); //mxd
 			if(data != null) //mxd
 			{
-				data.Reset(includeneighbours);
+				data.Reset(false);
 
 				// Update sectors that rely on this sector
 				foreach(KeyValuePair<Sector, bool> s in data.UpdateAlso)
 				{
-					if(mode.VisualSectorExists(s.Key))
-					{
-						BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s.Key);
-						vs.Changed = true;
-					}
+					SectorData other = mode.GetSectorDataEx(s.Key);
+					if(other != null) other.Reset(s.Value);
 				}
 			}
 			
@@ -145,7 +142,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					if(mode.VisualThingExists(t))
 					{
 						// Update thing
-						BaseVisualThing vt = (mode.GetVisualThing(t) as BaseVisualThing);
+						BaseVisualThing vt = (BaseVisualThing)mode.GetVisualThing(t);
 						vt.Changed = true;
 					}
 				}
@@ -160,8 +157,16 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					{
 						if(mode.VisualSectorExists(sd.Other.Sector))
 						{
-							BaseVisualSector bvs = (BaseVisualSector)mode.GetVisualSector(sd.Other.Sector);
-							bvs.Changed = true;
+							SectorData other = mode.GetSectorDataEx(sd.Other.Sector);
+							if(other != null)
+							{
+								other.Reset(false);
+							}
+							else
+							{
+								BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(sd.Other.Sector);
+								vs.Changed = true;
+							}
 						}
 					}
 				}
@@ -189,7 +194,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					if(mode.VisualThingExists(t)) 
 					{
 						// Update thing
-						BaseVisualThing vt = (mode.GetVisualThing(t) as BaseVisualThing);
+						BaseVisualThing vt = (BaseVisualThing)mode.GetVisualThing(t);
 						vt.Rebuild();
 					}
 				}
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
index 35fd26df7..97e57b91a 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
@@ -707,7 +707,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				foreach(Thing t in things)
 				{
 					VisualThing vt = mode.GetVisualThing(t);
-					if(vt != null) updateList.Add(vt as BaseVisualThing);
+					if(vt != null) updateList.Add((BaseVisualThing)vt);
 				}
 
 				General.Interface.OnEditFormValuesChanged += Interface_OnEditFormValuesChanged;
diff --git a/Source/Plugins/BuilderModes/VisualModes/EffectGlowingFlat.cs b/Source/Plugins/BuilderModes/VisualModes/EffectGlowingFlat.cs
index 59557c21c..e00c56ba3 100644
--- a/Source/Plugins/BuilderModes/VisualModes/EffectGlowingFlat.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/EffectGlowingFlat.cs
@@ -1,45 +1,35 @@
-using CodeImp.DoomBuilder.Map;
-using CodeImp.DoomBuilder.Rendering;
+using CodeImp.DoomBuilder.Rendering;
 
 namespace CodeImp.DoomBuilder.BuilderModes
 {
-	internal class EffectGlowingFlat : SectorEffect
+	internal class EffectGlowingFlat
 	{
-		private readonly Sector sector;
+		private readonly SectorData data;
 
 		// Level planes
 		private SectorLevel ceillevel;
 		private SectorLevel floorlevel;
 		
 		// Constructor
-		public EffectGlowingFlat(SectorData data, Sector sourcesector) : base(data)
+		public EffectGlowingFlat(SectorData sourcedata)
 		{
-			sector = sourcesector;
-
-			// New effect added: This sector needs an update!
-			if(data.Mode.VisualSectorExists(data.Sector))
-			{
-				BaseVisualSector vs = (BaseVisualSector)data.Mode.GetVisualSector(data.Sector);
-				vs.UpdateSectorGeometry(false);
-			}
+			data = sourcedata;
 		}
 
-		public override void Update() 
+		public void Update() 
 		{
 			// Create ceiling glow effect?
-			if(General.Map.Data.GlowingFlats.ContainsKey(sector.LongCeilTexture))
+			if(General.Map.Data.GlowingFlats.ContainsKey(data.Sector.LongCeilTexture))
 			{
 				// Create ceiling level?
 				if(ceillevel == null)
 				{
-					ceillevel = new SectorLevel(data.Ceiling);
-					ceillevel.type = SectorLevelType.Glow;
-					ceillevel.disablelighting = true;
+					ceillevel = new SectorLevel(data.Ceiling) { type = SectorLevelType.Glow, disablelighting = true };
 					data.AddSectorLevel(ceillevel);
 				}
 
 				// Update ceiling level
-				data.CeilingGlow = General.Map.Data.GlowingFlats[sector.LongCeilTexture];
+				data.CeilingGlow = General.Map.Data.GlowingFlats[data.Sector.LongCeilTexture];
 				ceillevel.brightnessbelow = -1; // We need this plane for clipping only,
 				ceillevel.color = 0;            // so we need to reset all shading and coloring
 				ceillevel.plane = data.Ceiling.plane;
@@ -52,19 +42,17 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			}
 
 			// Create floor glow effect?
-			if(General.Map.Data.GlowingFlats.ContainsKey(sector.LongFloorTexture))
+			if(General.Map.Data.GlowingFlats.ContainsKey(data.Sector.LongFloorTexture))
 			{
 				// Create floor level?
 				if(floorlevel == null)
 				{
-					floorlevel = new SectorLevel(data.Floor);
-					floorlevel.type = SectorLevelType.Glow;
-					floorlevel.disablelighting = true;
+					floorlevel = new SectorLevel(data.Floor) { type = SectorLevelType.Glow, disablelighting = true };
 					data.AddSectorLevel(floorlevel);
 				}
 
 				// Update floor level
-				data.FloorGlow = General.Map.Data.GlowingFlats[sector.LongFloorTexture];
+				data.FloorGlow = General.Map.Data.GlowingFlats[data.Sector.LongFloorTexture];
 				floorlevel.plane = data.Floor.plane.GetInverted();
 				floorlevel.plane.Offset += data.FloorGlow.Height;
 
diff --git a/Source/Plugins/BuilderModes/VisualModes/EffectLineSlope.cs b/Source/Plugins/BuilderModes/VisualModes/EffectLineSlope.cs
index 1bc668521..187f8dec1 100644
--- a/Source/Plugins/BuilderModes/VisualModes/EffectLineSlope.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/EffectLineSlope.cs
@@ -43,6 +43,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					founddist = d;
 				}
 			}
+
+			if(foundv == null) return; //mxd
 			
 			// Align floor with back of line
 			if((l.Args[0] == 1) && (l.Front.Sector == data.Sector))
@@ -54,8 +56,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					data.Floor.plane = new Plane(v1, v2, v3, true);
 				else
 					data.Floor.plane = new Plane(v2, v1, v3, true);
-				SectorData sd = data.Mode.GetSectorData(l.Back.Sector);
-				sd.AddUpdateSector(data.Sector, true);
 			}
 			// Align floor with front of line
 			else if((l.Args[0] == 2) && (l.Back.Sector == data.Sector))
@@ -67,8 +67,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					data.Floor.plane = new Plane(v1, v2, v3, true);
 				else
 					data.Floor.plane = new Plane(v2, v1, v3, true);
-				SectorData sd = data.Mode.GetSectorData(l.Front.Sector);
-				sd.AddUpdateSector(data.Sector, true);
 			}
 			
 			// Align ceiling with back of line
@@ -81,8 +79,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					data.Ceiling.plane = new Plane(v1, v2, v3, false);
 				else
 					data.Ceiling.plane = new Plane(v2, v1, v3, false);
-				SectorData sd = data.Mode.GetSectorData(l.Back.Sector);
-				sd.AddUpdateSector(data.Sector, true);
 			}
 			// Align ceiling with front of line
 			else if((l.Args[1] == 2) && (l.Back.Sector == data.Sector))
@@ -94,8 +90,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					data.Ceiling.plane = new Plane(v1, v2, v3, false);
 				else
 					data.Ceiling.plane = new Plane(v2, v1, v3, false);
-				SectorData sd = data.Mode.GetSectorData(l.Front.Sector);
-				sd.AddUpdateSector(data.Sector, true);
 			}
 		}
 	}
diff --git a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs
index 07148ca63..97cbb7b52 100644
--- a/Source/Plugins/BuilderModes/VisualModes/SectorData.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/SectorData.cs
@@ -33,6 +33,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// Effects
 		private readonly List<SectorEffect> alleffects;
 		private readonly List<Effect3DFloor> extrafloors;
+		private readonly EffectGlowingFlat glowingflateffect; //mxd
 
 		internal GlowingFlatData CeilingGlow; //mxd
 		internal GlowingFlatData FloorGlow; //mxd
@@ -91,12 +92,13 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			this.floorbase = new SectorLevel(sector, SectorLevelType.Floor); //mxd
 			this.ceiling = new SectorLevel(sector, SectorLevelType.Ceiling);
 			this.ceilingbase = new SectorLevel(sector, SectorLevelType.Ceiling); //mxd
-			
-			BasicSetup();
+			this.glowingflateffect = new EffectGlowingFlat(this); //mxd
 			
 			// Add ceiling and floor
 			lightlevels.Add(floor);
 			lightlevels.Add(ceiling);
+
+			BasicSetup();
 		}
 		
 		#endregion
@@ -187,13 +189,6 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			EffectUDMFVertexOffset e = new EffectUDMFVertexOffset(this);
 			alleffects.Add(e);
 		}
-
-		//mxd.
-		public void AddEffectGlowingFlat(Sector sourcesector) 
-		{
-			EffectGlowingFlat e = new EffectGlowingFlat(this, sourcesector);
-			alleffects.Add(e);
-		}
 		
 		// This adds a sector for updating
 		public void AddUpdateSector(Sector s, bool includeneighbours)
@@ -319,6 +314,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			//mxd. We need sector brightness here, unaffected by custom ceiling brightness...
 			ceilingbase.brightnessbelow = sector.Brightness;
 			ceilingbase.color = PixelColor.FromInt(mode.CalculateBrightness(sector.Brightness)).WithAlpha(255).ToInt();
+
+			//mxd
+			glowingflateffect.Update();
 		}
 
 		//mxd
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs
index 2f156c5b8..1f89a50d8 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualCeiling.cs
@@ -93,9 +93,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					base.Texture = General.Map.Data.UnknownTexture3D;
 					setuponloadedtexture = s.LongCeilTexture;
 				} 
-				else 
+				else if(!base.Texture.IsImageLoaded)
 				{
-					if(!base.Texture.IsImageLoaded) setuponloadedtexture = s.LongCeilTexture;
+					setuponloadedtexture = s.LongCeilTexture;
 				}
 			} 
 			else 
@@ -113,20 +113,35 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 			// Determine brightness
 			int color = PixelColor.FromInt(level.color).WithAlpha((byte)General.Clamp(level.alpha, 0, 255)).ToInt();
-
-			//mxd. Top extrafloor level should calculate fogdensity
-			//from the brightness of the level above it
 			int targetbrightness;
 			if(extrafloor != null && !extrafloor.VavoomType && !level.disablelighting)
 			{
-				targetbrightness = 0;
-				SectorData sd = mode.GetSectorData(this.Sector.Sector);
-				for(int i = 0; i < sd.LightLevels.Count - 1; i++)
+				//mxd. Top extrafloor level should calculate fogdensity from the brightness of the level above it
+				if(!innerside)
 				{
-					if(sd.LightLevels[i] == level)
+					targetbrightness = 0;
+					SectorData sd = mode.GetSectorData(this.Sector.Sector);
+					for(int i = 0; i < sd.LightLevels.Count - 1; i++)
 					{
-						targetbrightness = sd.LightLevels[i + 1].brightnessbelow;
-						break;
+						if(sd.LightLevels[i] == level)
+						{
+							targetbrightness = sd.LightLevels[i + 1].brightnessbelow;
+							break;
+						}
+					}
+				}
+				//mxd. Inner extrafloor ceilings must be colored using control sector's color and brightness 
+				else
+				{
+					targetbrightness = level.brightnessbelow;
+					SectorData sd = mode.GetSectorData(this.Sector.Sector);
+					for(int i = 0; i < sd.LightLevels.Count; i++)
+					{
+						if(sd.LightLevels[i] == level)
+						{
+							if(i > 0) color = sd.LightLevels[i - 1].color;
+							break;
+						}
 					}
 				}
 			}
@@ -271,8 +286,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				UniFields.SetFloat(s.Fields, "yscaleceiling", scaleY, 1.0f);
 			}
 
-			//update geometry
-			OnTextureChanged();
+			// Update
+			if(mode.VisualSectorExists(level.sector))
+			{
+				BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
+				vs.UpdateSectorGeometry(false);
+			}
 
 			s.UpdateNeeded = true;
 			s.UpdateCache();
@@ -308,8 +327,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 				SetTexture(BuilderPlug.Me.CopiedFlat);
 
-				//mxd. 3D floors may need updating...
-				OnTextureChanged();
+				// Update
+				if(mode.VisualSectorExists(level.sector))
+				{
+					BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
+					vs.UpdateSectorGeometry(false);
+				}
 			}
 		}
 
@@ -512,20 +535,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This changes the texture
 		protected override void SetTexture(string texturename)
 		{
-			//mxd. Glow effect may require SectorData and geometry update
-			bool prevtextureglows = General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongCeilTexture);
-
 			// Set new texture
 			level.sector.SetCeilTexture(texturename);
-
-			//mxd. Glow effect may require SectorData and geometry update
-			if(prevtextureglows 
-				&& !General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongCeilTexture)
-				&& mode.VisualSectorExists(level.sector))
-			{
-				((BaseVisualSector)mode.GetVisualSector(level.sector)).Changed = true;
-			}
-			
 			General.Map.Data.UpdateUsedTextures();
 		}
 
@@ -553,7 +564,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				if(side.Other != null && side.Other.Sector != Sector.Sector && !neighbours.Contains(side.Other.Sector)) 
 				{
-					BaseVisualSector vs = mode.GetVisualSector(side.Other.Sector) as BaseVisualSector;
+					BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(side.Other.Sector);
 					if(vs == null) continue;
 
 					// When current ceiling is part of a 3d floor, it looks like a floor, so we need to select adjacent floors
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs
index 89e219068..ea4e4232a 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualFloor.cs
@@ -93,10 +93,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					base.Texture = General.Map.Data.UnknownTexture3D;
 					setuponloadedtexture = s.LongFloorTexture;
 				}
-				else
+				else if(!base.Texture.IsImageLoaded)
 				{
-					if(!base.Texture.IsImageLoaded)
-						setuponloadedtexture = s.LongFloorTexture;
+					setuponloadedtexture = s.LongFloorTexture;
 				}
 			}
 			else
@@ -259,8 +258,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				UniFields.SetFloat(s.Fields, "yscalefloor", scaleY, 1.0f);
 			}
 
-			//update geometry
-			OnTextureChanged();
+			// Update geometry
+			if(mode.VisualSectorExists(level.sector))
+			{
+				BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
+				vs.UpdateSectorGeometry(false);
+			}
 
 			s.UpdateNeeded = true;
 			s.UpdateCache();
@@ -296,8 +299,12 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				
 				SetTexture(BuilderPlug.Me.CopiedFlat);
 
-				//mxd. 3D floors may need updating...
-				OnTextureChanged();
+				// Update
+				if(mode.VisualSectorExists(level.sector))
+				{
+					BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
+					vs.UpdateSectorGeometry(false);
+				}
 			}
 		}
 
@@ -472,20 +479,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		// This changes the texture
 		protected override void SetTexture(string texturename)
 		{
-			//mxd. Glow effect may require SectorData and geometry update
-			bool prevtextureglows = General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongFloorTexture);
-			
 			// Set new texture
 			level.sector.SetFloorTexture(texturename);
-
-			//mxd. Glow effect may require SectorData and geometry update
-			if(prevtextureglows 
-				&& !General.Map.Data.GlowingFlats.ContainsKey(Sector.Sector.LongFloorTexture)
-				&& mode.VisualSectorExists(level.sector))
-			{
-				((BaseVisualSector)mode.GetVisualSector(level.sector)).Changed = true;
-			}
-
 			General.Map.Data.UpdateUsedTextures();
 		}
 
@@ -513,7 +508,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				if(side.Other != null && side.Other.Sector != Sector.Sector && !neighbours.Contains(side.Other.Sector))
 				{
-					BaseVisualSector vs = mode.GetVisualSector(side.Other.Sector) as BaseVisualSector;
+					BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(side.Other.Sector);
 					if(vs == null) continue;
 
 					// When current floor is part of a 3d floor, it looks like a ceiling, so we need to select adjacent ceilings
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs
index 089527faf..7a4cf6008 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddle3D.cs
@@ -19,6 +19,7 @@
 using System;
 using System.Collections.Generic;
 using System.Drawing;
+using System.Globalization;
 using CodeImp.DoomBuilder.Map;
 using CodeImp.DoomBuilder.Geometry;
 using CodeImp.DoomBuilder.Rendering;
@@ -30,7 +31,7 @@ using CodeImp.DoomBuilder.Data;
 
 namespace CodeImp.DoomBuilder.BuilderModes
 {
-	internal sealed class VisualMiddle3D : BaseVisualGeometrySidedef
+	internal class VisualMiddle3D : BaseVisualGeometrySidedef
 	{
 		#region ================== Constants
 
@@ -38,7 +39,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		
 		#region ================== Variables
 
-		private Effect3DFloor extrafloor;
+		protected Effect3DFloor extrafloor;
 		
 		#endregion
 		
@@ -99,36 +100,35 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			SectorData sd = mode.GetSectorData(Sidedef.Sector);
 			
 			//mxd. which texture we must use?
-			long textureLong = 0;
+			long texturelong = 0;
 			if((sourceside.Line.Args[2] & (int)Effect3DFloor.Flags.UseUpperTexture) != 0) 
 			{
 				if(Sidedef.LongHighTexture != MapSet.EmptyLongName)
-					textureLong = Sidedef.LongHighTexture;
+					texturelong = Sidedef.LongHighTexture;
 			} 
 			else if((sourceside.Line.Args[2] & (int)Effect3DFloor.Flags.UseLowerTexture) != 0) 
 			{
 				if(Sidedef.LongLowTexture != MapSet.EmptyLongName)
-					textureLong = Sidedef.LongLowTexture;
+					texturelong = Sidedef.LongLowTexture;
 			} 
 			else if(sourceside.LongMiddleTexture != MapSet.EmptyLongName) 
 			{
-				textureLong = sourceside.LongMiddleTexture;
+				texturelong = sourceside.LongMiddleTexture;
 			}
 
 			// Texture given?
-			if(textureLong != 0)
+			if(texturelong != 0)
 			{
 				// Load texture
-				base.Texture = General.Map.Data.GetTextureImage(textureLong);
+				base.Texture = General.Map.Data.GetTextureImage(texturelong);
 				if(base.Texture == null || base.Texture is UnknownImage)
 				{
 					base.Texture = General.Map.Data.UnknownTexture3D;
-					setuponloadedtexture = textureLong;
+					setuponloadedtexture = texturelong;
 				}
-				else
+				else if(!base.Texture.IsImageLoaded)
 				{
-					if(!base.Texture.IsImageLoaded)
-						setuponloadedtexture = textureLong;
+					setuponloadedtexture = texturelong;
 				}
 			}
 			else
@@ -379,14 +379,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				extrafloor.Linedef.Front.SetTextureMid(texturename);
 
 			General.Map.Data.UpdateUsedTextures();
-			this.Sector.Rebuild();
 
-			//mxd. Other sector also may require updating
-			SectorData sd = mode.GetSectorData(Sidedef.Other.Sector);
-			if(sd.ExtraFloors.Count > 0)
-				((BaseVisualSector)mode.GetVisualSector(Sidedef.Other.Sector)).Rebuild();
-
-			//mxd. As well as model sector
+			//mxd. Update model sector
 			mode.GetVisualSector(extrafloor.Linedef.Front.Sector).UpdateSectorGeometry(false);
 		}
 
@@ -407,8 +401,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			Sidedef.Fields.BeforeFieldsChange();
 			float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
 			float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
-			Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, oldx + xy.X);
-			Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, oldy + xy.Y);
+			float scalex = extrafloor.Linedef.Front.Fields.GetValue("scalex_mid", 1.0f); //mxd
+			float scaley = extrafloor.Linedef.Front.Fields.GetValue("scaley_mid", 1.0f); //mxd
+			Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldx, xy.X, scalex, Texture.Width)); //mxd
+			Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldy, xy.Y, scaley, Texture.Height)); //mxd
 		}
 
 		protected override Point GetTextureOffset()
@@ -430,7 +426,78 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(!General.Map.UDMF) return;
 			if(string.IsNullOrEmpty(extrafloor.Linedef.Front.MiddleTexture) || extrafloor.Linedef.Front.MiddleTexture == "-" || !Texture.IsImageLoaded) return;
 			FitTexture(options);
-			Setup();
+
+			// Update the model sector to update all 3d floors
+			mode.GetVisualSector(extrafloor.Linedef.Front.Sector).UpdateSectorGeometry(false);
+		}
+
+		//mxd. Only control sidedef scale is used by GZDoom
+		public override void OnChangeScale(int incrementX, int incrementY)
+		{
+			if(!General.Map.UDMF || !Texture.IsImageLoaded) return;
+
+			if((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
+				undoticket = mode.CreateUndo("Change wall scale");
+
+			Sidedef target = extrafloor.Linedef.Front;
+			if(target == null) return;
+
+			float scaleX = target.Fields.GetValue("scalex_mid", 1.0f);
+			float scaleY = target.Fields.GetValue("scaley_mid", 1.0f);
+
+			target.Fields.BeforeFieldsChange();
+
+			if(incrementX != 0)
+			{
+				float pix = (int)Math.Round(Texture.Width * scaleX) - incrementX;
+				float newscaleX = (float)Math.Round(pix / Texture.Width, 3);
+				scaleX = (newscaleX == 0 ? scaleX * -1 : newscaleX);
+				UniFields.SetFloat(target.Fields, "scalex_mid", scaleX, 1.0f);
+			}
+
+			if(incrementY != 0)
+			{
+				float pix = (int)Math.Round(Texture.Height * scaleY) - incrementY;
+				float newscaleY = (float)Math.Round(pix / Texture.Height, 3);
+				scaleY = (newscaleY == 0 ? scaleY * -1 : newscaleY);
+				UniFields.SetFloat(target.Fields, "scaley_mid", scaleY, 1.0f);
+			}
+			
+			// Update the model sector to update all 3d floors
+			mode.GetVisualSector(extrafloor.Linedef.Front.Sector).UpdateSectorGeometry(false);
+
+			// Display result
+			mode.SetActionResult("Wall scale changed to " + scaleX.ToString("F03", CultureInfo.InvariantCulture) + ", " + scaleY.ToString("F03", CultureInfo.InvariantCulture) + " (" + (int)Math.Round(Texture.Width / scaleX) + " x " + (int)Math.Round(Texture.Height / scaleY) + ").");
+		}
+
+		//mxd
+		protected override void ResetTextureScale()
+		{
+			Sidedef target = extrafloor.Linedef.Front;
+			target.Fields.BeforeFieldsChange();
+			if(target.Fields.ContainsKey("scalex_mid")) target.Fields.Remove("scalex_mid");
+			if(target.Fields.ContainsKey("scaley_mid")) target.Fields.Remove("scaley_mid");
+		}
+
+		//mxd
+		public override void OnResetTextureOffset()
+		{
+			base.OnResetTextureOffset();
+
+			// Update the model sector to update all 3d floors
+			mode.GetVisualSector(extrafloor.Linedef.Front.Sector).UpdateSectorGeometry(false);
+		}
+
+		//mxd
+		public override void OnResetLocalTextureOffset()
+		{
+			if(!General.Map.UDMF)
+			{
+				OnResetTextureOffset();
+				return;
+			}
+
+			base.OnResetLocalTextureOffset();
 
 			// Update the model sector to update all 3d floors
 			mode.GetVisualSector(extrafloor.Linedef.Front.Sector).UpdateSectorGeometry(false);
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleBack.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleBack.cs
index e76be5bfe..4ff02cae4 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleBack.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleBack.cs
@@ -1,12 +1,9 @@
 #region ================== Namespaces
 
-using System;
 using System.Collections.Generic;
-using System.Drawing;
 using CodeImp.DoomBuilder.Map;
 using CodeImp.DoomBuilder.Geometry;
 using CodeImp.DoomBuilder.Rendering;
-using CodeImp.DoomBuilder.Types;
 using CodeImp.DoomBuilder.VisualModes;
 using CodeImp.DoomBuilder.Data;
 
@@ -15,31 +12,16 @@ using CodeImp.DoomBuilder.Data;
 namespace CodeImp.DoomBuilder.BuilderModes
 {
 	//mxd. Used to render translucent 3D floor's inner sides
-	internal sealed class VisualMiddleBack : BaseVisualGeometrySidedef 
+	internal sealed class VisualMiddleBack : VisualMiddle3D 
 	{
-		#region ================== Variables
-
-		private Effect3DFloor extrafloor;
-
-		#endregion
-		
 		#region ================== Constructor / Setup
 		
 		// Constructor
-		public VisualMiddleBack(BaseVisualMode mode, VisualSector vs, Sidedef s)
-			: base(mode, vs, s)
-		{
-			//mxd
-			geometrytype = VisualGeometryType.WALL_MIDDLE;
-			partname = "mid";
-			
-			// We have no destructor
-			GC.SuppressFinalize(this);
-		}
+		public VisualMiddleBack(BaseVisualMode mode, VisualSector vs, Sidedef s) : base(mode, vs, s) { }
 		
 		// This builds the geometry. Returns false when no geometry created.
 		public override bool Setup() { return this.Setup(this.extrafloor); }
-		public bool Setup(Effect3DFloor extrafloor)
+		public new bool Setup(Effect3DFloor extrafloor)
 		{
 			Sidedef sourceside = extrafloor.Linedef.Front;
 			this.extrafloor = extrafloor;
@@ -77,35 +59,35 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			SectorData sd = mode.GetSectorData(Sidedef.Other.Sector);
 
 			//mxd. which texture we must use?
-			long longtexture = 0;
+			long texturelong = 0;
 			if((sourceside.Line.Args[2] & (int)Effect3DFloor.Flags.UseUpperTexture) != 0) 
 			{
-				if(Sidedef.Other.LongHighTexture != MapSet.EmptyLongName)
-					longtexture = Sidedef.Other.LongHighTexture;
+				if(Sidedef.LongHighTexture != MapSet.EmptyLongName)
+					texturelong = Sidedef.LongHighTexture;
 			} 
 			else if((sourceside.Line.Args[2] & (int)Effect3DFloor.Flags.UseLowerTexture) != 0) 
 			{
-				if(Sidedef.Other.LongLowTexture != MapSet.EmptyLongName)
-					longtexture = Sidedef.Other.LongLowTexture;
+				if(Sidedef.LongLowTexture != MapSet.EmptyLongName)
+					texturelong = Sidedef.LongLowTexture;
 			} 
-			else if((sourceside.LongMiddleTexture != MapSet.EmptyLongName)) 
+			else if(sourceside.LongMiddleTexture != MapSet.EmptyLongName) 
 			{
-				longtexture = sourceside.LongMiddleTexture;
+				texturelong = sourceside.LongMiddleTexture;
 			}
 
 			// Texture given?
-			if(longtexture != 0) 
+			if(texturelong != 0)
 			{
 				// Load texture
-				base.Texture = General.Map.Data.GetTextureImage(longtexture);
-				if(base.Texture == null || base.Texture is UnknownImage) 
+				base.Texture = General.Map.Data.GetTextureImage(texturelong);
+				if(base.Texture == null || base.Texture is UnknownImage)
 				{
 					base.Texture = General.Map.Data.UnknownTexture3D;
-					setuponloadedtexture = longtexture;
+					setuponloadedtexture = texturelong;
 				} 
 				else if(!base.Texture.IsImageLoaded) 
 				{
-					setuponloadedtexture = longtexture;
+					setuponloadedtexture = texturelong;
 				}
 			} 
 			else 
@@ -179,8 +161,8 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(((cl - fl) > 0.01f) || ((cr - fr) > 0.01f))
 			{
 				// Keep top and bottom planes for intersection testing
-				bottom = extrafloor.Ceiling.plane;
 				top = extrafloor.Floor.plane;
+				bottom = extrafloor.Ceiling.plane;
 				
 				// Create initial polygon, which is just a quad between floor and ceiling
 				WallPolygon poly = new WallPolygon();
@@ -189,7 +171,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				poly.Add(new Vector3D(vr.x, vr.y, cr));
 				poly.Add(new Vector3D(vr.x, vr.y, fr));
 				
-				// Determine initial color
+				// Determine initial color. Inside parts are shaded using control sector's brightness
 				int lightlevel;
 				PixelColor levelcolor; //mxd
 				if(((sourceside.Line.Args[2] & (int)Effect3DFloor.Flags.DisableLighting) != 0))
@@ -220,6 +202,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					// or when only our extrafloor is translucent
 					if(ef.ClipSidedefs == extrafloor.ClipSidedefs || ef.ClipSidedefs)
 					{
+						//TODO: [this crashed on me once when performing auto-align on myriad of textures on BoA C1M0]
+						if(ef.Floor == null || ef.Ceiling == null) ef.Update();
+						
 						int num = polygons.Count;
 						for(int pi = 0; pi < num; pi++)
 						{
@@ -281,113 +266,5 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		}
 		
 		#endregion
-		
-		#region ================== Methods
-
-		// Alpha based picking
-		public override bool PickAccurate(Vector3D from, Vector3D to, Vector3D dir, ref float u_ray)
-		{
-			if(!Texture.IsImageLoaded || (!Texture.IsTranslucent && !Texture.IsMasked)) return base.PickAccurate(from, to, dir, ref u_ray);
-
-			float u;
-			Sidedef sourceside = extrafloor.Linedef.Front;
-			new Line2D(from, to).GetIntersection(Sidedef.Line.Line, out u);
-			if(Sidedef != Sidedef.Line.Front) u = 1.0f - u;
-
-			// Some textures (e.g. HiResImage) may lie about their size, so use bitmap size instead
-			Bitmap image = Texture.GetBitmap();
-
-			// Determine texture scale...
-			Vector2D imgscale = new Vector2D((float)Texture.Width / image.Width, (float)Texture.Height / image.Height);
-			Vector2D texscale = (Texture is HiResImage) ? imgscale * Texture.Scale : Texture.Scale;
-
-			// Get correct offset to texture space...
-			float texoffsetx = Sidedef.OffsetX + sourceside.OffsetX + UniFields.GetFloat(Sidedef.Fields, "offsetx_mid") + UniFields.GetFloat(sourceside.Fields, "offsetx_mid");
-			int ox = (int)Math.Floor((u * Sidedef.Line.Length * UniFields.GetFloat(sourceside.Fields, "scalex_mid", 1.0f) / texscale.x + (texoffsetx / imgscale.x)) % image.Width);
-
-			float texoffsety = Sidedef.OffsetY + sourceside.OffsetY + UniFields.GetFloat(Sidedef.Fields, "offsety_mid") + UniFields.GetFloat(sourceside.Fields, "offsety_mid");
-			int oy = (int)Math.Ceiling(((pickintersect.z - sourceside.Sector.CeilHeight) * UniFields.GetFloat(sourceside.Fields, "scaley_mid", 1.0f) / texscale.y - (texoffsety / imgscale.y)) % image.Height);
-
-			// Make sure offsets are inside of texture dimensions...
-			if(ox < 0) ox += image.Width;
-			if(oy < 0) oy += image.Height;
-
-			// Check pixel alpha
-			Point pixelpos = new Point(General.Clamp(ox, 0, image.Width - 1), General.Clamp(image.Height - oy, 0, image.Height - 1));
-			return (image.GetPixel(pixelpos.X, pixelpos.Y).A > 0 && base.PickAccurate(@from, to, dir, ref u_ray));
-		}
-
-		// Return texture name
-		public override string GetTextureName() 
-		{
-			//mxd
-			if((extrafloor.Linedef.Args[2] & (int)Effect3DFloor.Flags.UseUpperTexture) != 0)
-				return Sidedef.HighTexture;
-			if((extrafloor.Linedef.Args[2] & (int)Effect3DFloor.Flags.UseLowerTexture) != 0)
-				return Sidedef.LowTexture;
-			return extrafloor.Linedef.Front.MiddleTexture;
-		}
-
-		// This changes the texture
-		protected override void SetTexture(string texturename) 
-		{
-			//mxd
-			if((extrafloor.Linedef.Args[2] & (int)Effect3DFloor.Flags.UseUpperTexture) != 0)
-				Sidedef.Other.SetTextureHigh(texturename);
-			if((extrafloor.Linedef.Args[2] & (int)Effect3DFloor.Flags.UseLowerTexture) != 0)
-				Sidedef.Other.SetTextureLow(texturename);
-			else
-				extrafloor.Linedef.Front.SetTextureMid(texturename);
-
-			General.Map.Data.UpdateUsedTextures();
-			this.Sector.Rebuild();
-
-			//mxd. Other sector also may require updating
-			((BaseVisualSector)mode.GetVisualSector(Sidedef.Other.Sector)).Rebuild();
-
-			//mxd. As well as model sector
-			mode.GetVisualSector(extrafloor.Linedef.Front.Sector).UpdateSectorGeometry(false);
-		}
-
-		protected override void SetTextureOffsetX(int x)
-		{
-			Sidedef.Fields.BeforeFieldsChange();
-			Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, (float)x);
-		}
-
-		protected override void SetTextureOffsetY(int y)
-		{
-			Sidedef.Fields.BeforeFieldsChange();
-			Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, (float)y);
-		}
-
-		protected override void MoveTextureOffset(Point xy)
-		{
-			Sidedef.Fields.BeforeFieldsChange();
-			float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
-			float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
-			float scalex = Sidedef.Fields.GetValue("scalex_mid", 1.0f);
-			float scaley = Sidedef.Fields.GetValue("scaley_mid", 1.0f);
-			Sidedef.Fields["offsetx_mid"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldx, xy.X, scalex, Texture != null ? Texture.Width : -1)); //mxd
-
-			//mxd. Don't clamp offsetY of clipped mid textures
-			bool dontClamp = (Texture == null || Sidedef.IsFlagSet("clipmidtex") || Sidedef.Line.IsFlagSet("clipmidtex"));
-			Sidedef.Fields["offsety_mid"] = new UniValue(UniversalType.Float, GetRoundedTextureOffset(oldy, xy.Y, scaley, dontClamp ? -1 : Texture.Height));
-		}
-
-		protected override Point GetTextureOffset()
-		{
-			float oldx = Sidedef.Fields.GetValue("offsetx_mid", 0.0f);
-			float oldy = Sidedef.Fields.GetValue("offsety_mid", 0.0f);
-			return new Point((int)oldx, (int)oldy);
-		}
-
-		//mxd
-		public override Linedef GetControlLinedef() 
-		{
-			return extrafloor.Linedef;
-		}
-
-		#endregion
 	}
 }
diff --git a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs
index f0f93c865..34d159575 100644
--- a/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/VisualMiddleSingle.cs
@@ -274,6 +274,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(string.IsNullOrEmpty(Sidedef.MiddleTexture) || Sidedef.MiddleTexture == "-" || !Texture.IsImageLoaded) return;
 			FitTexture(options);
 			Setup();
+
+			// Update linked effects
+			SectorData sd = mode.GetSectorDataEx(Sector.Sector);
+			if(sd != null) sd.Reset(true);
 		}
 		
 		#endregion
-- 
GitLab