From cf3d416967d453ad4c316de2b14172dbc4ee199f Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Mon, 29 Jul 2013 08:50:50 +0000
Subject: [PATCH] Renderer now works much faster in 2D modes. Textures now load
 up to 2x faster when "mix textures and flats" flag is set in game
 configuration. TEXTUREx/TEXTURES: texture will now be created if at least one
 of it's patches is loaded. Visual mode: fixed a crash when "Slope floor to
 here" (9500) or "Slope ceiling to here" (9501) things were not inside sector.
 Fixed: flats were not loaded form wads inside Directory and PK3/PK7
 resources. Sector Info Panel, Linedef Info Panel: texture size was shown for
 unknown textures.

---
 Source/Core/Builder.csproj                    |   3 +-
 Source/Core/Config/ResourceTextureSet.cs      |  18 +-
 Source/Core/Controls/FlatSelectorControl.cs   |   2 +-
 Source/Core/Controls/LinedefInfoPanel.cs      |   2 +-
 Source/Core/Controls/SectorInfoPanel.cs       |   2 +-
 .../Core/Controls/TextureSelectorControl.cs   |   2 +-
 Source/Core/Data/DataManager.cs               | 169 +++++-------
 Source/Core/Data/DirectoryReader.cs           |  16 +-
 Source/Core/Data/FileImage.cs                 |  64 +++--
 Source/Core/Data/HighResImage.cs              |  26 +-
 Source/Core/Data/ImageData.cs                 |   4 +-
 Source/Core/Data/PK3Reader.cs                 |  12 +-
 Source/Core/Data/PK3StructuredReader.cs       |  18 ++
 Source/Core/Data/TextureImage.cs              |  15 +-
 Source/Core/Editing/UndoManager.cs            |   6 +-
 .../Data/{GZDoomLight.cs => DynamicLight.cs}  |  13 +-
 .../Data/{ModelDefEntry.cs => ModelData.cs}   |  38 ++-
 Source/Core/GZBuilder/Data/ModelLoadState.cs  |  14 +
 Source/Core/GZBuilder/GZDoom/GldefsParser.cs  |  14 +-
 .../Core/GZBuilder/GZDoom/ModeldefParser.cs   |  18 +-
 .../GZBuilder/GZDoom/ModeldefStructure.cs     |   4 +-
 Source/Core/GZBuilder/GZGeneral.cs            |   2 +-
 Source/Core/GZBuilder/md3/ModelReader.cs      |  34 ++-
 Source/Core/General/MapManager.cs             |  44 ++--
 Source/Core/Map/Linedef.cs                    |   3 +-
 Source/Core/Map/MapSet.cs                     |  20 +-
 Source/Core/Map/Thing.cs                      |  31 ++-
 Source/Core/Rendering/IRenderer2D.cs          |   2 +-
 Source/Core/Rendering/Renderer2D.cs           | 244 ++++++++----------
 Source/Core/Rendering/Renderer3D.cs           |  31 ++-
 Source/Core/VisualModes/VisualThing.cs        |  69 ++---
 Source/Core/Windows/MainForm.cs               |   8 +-
 Source/Core/ZDoom/TexturesParser.cs           |   2 +-
 .../ClassicModes/BaseClassicMode.cs           |   4 +-
 .../BuilderModes/ClassicModes/BridgeMode.cs   |   1 +
 .../ClassicModes/BrightnessMode.cs            |   1 +
 .../ClassicModes/DragGeometryMode.cs          |   1 +
 .../ClassicModes/DrawGeometryMode.cs          |   1 +
 .../ClassicModes/EditSelectionMode.cs         |   2 +-
 .../ClassicModes/FlatAlignMode.cs             |   2 +-
 .../BuilderModes/ClassicModes/LinedefsMode.cs |  16 +-
 .../ClassicModes/MakeSectorMode.cs            |   1 +
 .../BuilderModes/ClassicModes/SectorsMode.cs  |  14 +-
 .../BuilderModes/ClassicModes/ThingsMode.cs   |  12 +-
 .../BuilderModes/ClassicModes/VerticesMode.cs |   4 +-
 .../BuilderModes/General/BuilderPlug.cs       |   2 +-
 .../VisualModes/BaseVisualThing.cs            |  16 +-
 Source/Plugins/TagExplorer/BuilderPlug.cs     |   7 +-
 48 files changed, 520 insertions(+), 514 deletions(-)
 rename Source/Core/GZBuilder/Data/{GZDoomLight.cs => DynamicLight.cs} (71%)
 rename Source/Core/GZBuilder/Data/{ModelDefEntry.cs => ModelData.cs} (50%)
 create mode 100644 Source/Core/GZBuilder/Data/ModelLoadState.cs

diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj
index 17a1d705e..c16056d72 100644
--- a/Source/Core/Builder.csproj
+++ b/Source/Core/Builder.csproj
@@ -754,7 +754,8 @@
     <Compile Include="GZBuilder\Data\LinedefColorPreset.cs" />
     <Compile Include="GZBuilder\Data\LinksCollector.cs" />
     <Compile Include="GZBuilder\Data\MapInfo.cs" />
-    <Compile Include="GZBuilder\Data\ModeldefEntry.cs" />
+    <Compile Include="GZBuilder\Data\ModelData.cs" />
+    <Compile Include="GZBuilder\Data\ModelLoadState.cs" />
     <Compile Include="GZBuilder\Data\ScriptItem.cs" />
     <Compile Include="GZBuilder\Data\ScriptType.cs" />
     <Compile Include="GZBuilder\Data\SharpCompressHelper.cs" />
diff --git a/Source/Core/Config/ResourceTextureSet.cs b/Source/Core/Config/ResourceTextureSet.cs
index ca3538402..6246b53b6 100644
--- a/Source/Core/Config/ResourceTextureSet.cs
+++ b/Source/Core/Config/ResourceTextureSet.cs
@@ -41,7 +41,7 @@ namespace CodeImp.DoomBuilder.Config
 		#region ================== Properties
 		
 		public ICollection<ImageData> Textures { get { return textures.Values; } }
-		public ICollection<ImageData> Flats { get { return flats.Values; } }
+		public ICollection<ImageData> Flats { get { return General.Map.Config.MixTexturesFlats ? textures.Values : flats.Values; } }
 		public DataLocation Location { get { return location; } }
 		
 		#endregion
@@ -86,28 +86,20 @@ namespace CodeImp.DoomBuilder.Config
 		// Check if this set has a flat
 		internal bool FlatExists(ImageData image)
 		{
+			if(General.Map.Config.MixTexturesFlats) return textures.ContainsKey(image.LongName); //mxd
 			return flats.ContainsKey(image.LongName);
 		}
 
 		// Mix the textures and flats
 		internal void MixTexturesAndFlats()
 		{
-			// Make a copy of the flats only
-			Dictionary<long, ImageData> flatsonly = new Dictionary<long, ImageData>(flats);
-			
-			// Add textures to flats
-			foreach(KeyValuePair<long, ImageData> t in textures)
-			{
-				if(!flats.ContainsKey(t.Key))
-					flats.Add(t.Key, t.Value);
-			}
-			
 			// Add flats to textures
-			foreach(KeyValuePair<long, ImageData> f in flatsonly)
-			{
+			foreach(KeyValuePair<long, ImageData> f in flats) {
 				if(!textures.ContainsKey(f.Key))
 					textures.Add(f.Key, f.Value);
 			}
+
+			flats.Clear(); //mxd
 		}
 		
 		#endregion
diff --git a/Source/Core/Controls/FlatSelectorControl.cs b/Source/Core/Controls/FlatSelectorControl.cs
index 71decdc67..0821d8471 100644
--- a/Source/Core/Controls/FlatSelectorControl.cs
+++ b/Source/Core/Controls/FlatSelectorControl.cs
@@ -50,7 +50,7 @@ namespace CodeImp.DoomBuilder.Controls
 			{
 				ImageData texture = General.Map.Data.GetFlatImage(imagename); //mxd
 
-				if(string.IsNullOrEmpty(texture.FullName)) DisplayImageSize(0, 0); //mxd
+				if(string.IsNullOrEmpty(texture.FullName) || texture is UnknownImage) DisplayImageSize(0, 0); //mxd
 				else DisplayImageSize(texture.ScaledWidth, texture.ScaledHeight); //mxd
 				
 				// Set the image
diff --git a/Source/Core/Controls/LinedefInfoPanel.cs b/Source/Core/Controls/LinedefInfoPanel.cs
index 1eebf6fd1..150706e62 100644
--- a/Source/Core/Controls/LinedefInfoPanel.cs
+++ b/Source/Core/Controls/LinedefInfoPanel.cs
@@ -445,7 +445,7 @@ namespace CodeImp.DoomBuilder.Controls
 			{
 				//mxd
 				ImageData texture = General.Map.Data.GetTextureImage(name);
-				if(General.Settings.ShowTextureSizes && texture.ImageState == ImageLoadState.Ready) {
+				if(General.Settings.ShowTextureSizes && texture.ImageState == ImageLoadState.Ready && !(texture is UnknownImage)) {
 					label.Visible = true;
 					label.Text = texture.ScaledWidth + "x" + texture.ScaledHeight;
 				} else {
diff --git a/Source/Core/Controls/SectorInfoPanel.cs b/Source/Core/Controls/SectorInfoPanel.cs
index 6a45b2e8a..0d5c6ecec 100644
--- a/Source/Core/Controls/SectorInfoPanel.cs
+++ b/Source/Core/Controls/SectorInfoPanel.cs
@@ -221,7 +221,7 @@ namespace CodeImp.DoomBuilder.Controls
 		}
 
 		protected void DisplayTextureSize(Label label, ImageData texture) {
-			if(General.Settings.ShowTextureSizes && texture.ImageState == ImageLoadState.Ready && !string.IsNullOrEmpty(texture.Name)) {
+			if(General.Settings.ShowTextureSizes && texture.ImageState == ImageLoadState.Ready && !string.IsNullOrEmpty(texture.Name) && !(texture is UnknownImage)) {
 				label.Visible = true;
 				label.Text = texture.ScaledWidth + "x" + texture.ScaledHeight;
 			} else {
diff --git a/Source/Core/Controls/TextureSelectorControl.cs b/Source/Core/Controls/TextureSelectorControl.cs
index c6ec8ac5f..56fb47dbf 100644
--- a/Source/Core/Controls/TextureSelectorControl.cs
+++ b/Source/Core/Controls/TextureSelectorControl.cs
@@ -60,7 +60,7 @@ namespace CodeImp.DoomBuilder.Controls
 			{
 				ImageData texture = General.Map.Data.GetTextureImage(imagename); //mxd
 
-				if(string.IsNullOrEmpty(texture.FullName)) DisplayImageSize(0, 0); //mxd
+				if(string.IsNullOrEmpty(texture.FullName) || texture is UnknownImage) DisplayImageSize(0, 0); //mxd
 				else DisplayImageSize(texture.ScaledWidth, texture.ScaledHeight); //mxd
 				
 				// Set the image
diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs
index cdc35aed2..0924229e1 100644
--- a/Source/Core/Data/DataManager.cs
+++ b/Source/Core/Data/DataManager.cs
@@ -62,8 +62,8 @@ namespace CodeImp.DoomBuilder.Data
 		private AllTextureSet alltextures;
 
         //mxd 
-        private Dictionary<int, ModeldefEntry> modeldefEntries; //Thing.Type, Model entry
-        private Dictionary<int, GZDoomLight> gldefsEntries; //Thing.Type, Light entry
+        private Dictionary<int, ModelData> modeldefEntries; //Thing.Type, Model entry
+        private Dictionary<int, DynamicLightData> gldefsEntries; //Thing.Type, Light entry
         private MapInfo mapInfo; //mapinfo
 		
 		// Background loading
@@ -82,8 +82,6 @@ namespace CodeImp.DoomBuilder.Data
 		private ImageData crosshair;
 		private ImageData crosshairbusy;
 		private Dictionary<string, ImageData> internalsprites;
-		//mxd
-        //private ImageData thingbox;
 		private ImageData whitetexture;
 		
 		// Used images
@@ -107,16 +105,16 @@ namespace CodeImp.DoomBuilder.Data
 		#region ================== Properties
 
         //mxd
-        internal Dictionary<int, ModeldefEntry> ModeldefEntries { get { return modeldefEntries; } }
-        internal Dictionary<int, GZDoomLight> GldefsEntries { get { return gldefsEntries; } }
+        internal Dictionary<int, ModelData> ModeldefEntries { get { return modeldefEntries; } }
+        internal Dictionary<int, DynamicLightData> GldefsEntries { get { return gldefsEntries; } }
         internal MapInfo MapInfo { get { return mapInfo; } }
 
 		public Playpal Palette { get { return palette; } }
 		public PreviewManager Previews { get { return previews; } }
 		public ICollection<ImageData> Textures { get { return textures.Values; } }
-		public ICollection<ImageData> Flats { get { return flats.Values; } }
+		public ICollection<ImageData> Flats { get { return (General.Map.Config.MixTexturesFlats ? textures.Values : flats.Values); } } //mxd
 		public List<string> TextureNames { get { return texturenames; } }
-		public List<string> FlatNames { get { return flatnames; } }
+		public List<string> FlatNames { get { return (General.Map.Config.MixTexturesFlats ? texturenames : flatnames); } } //mxd
 		public bool IsDisposed { get { return isdisposed; } }
 		public ImageData MissingTexture3D { get { return missingtexture3d; } }
 		public ImageData UnknownTexture3D { get { return unknowntexture3d; } }
@@ -136,13 +134,8 @@ namespace CodeImp.DoomBuilder.Data
 			get
 			{
 				if(imageque != null)
-				{
 					return (backgroundloader != null) && backgroundloader.IsAlive && ((imageque.Count > 0) || previews.IsLoading);
-				}
-				else
-				{
-					return false;
-				}
+				return false;
 			}
 		}
 		
@@ -156,6 +149,10 @@ namespace CodeImp.DoomBuilder.Data
 			// We have no destructor
 			GC.SuppressFinalize(this);
 
+			//mxd.
+			modeldefEntries = new Dictionary<int, ModelData>();
+			gldefsEntries = new Dictionary<int, DynamicLightData>();
+
 			// Load special images
 			missingtexture3d = new ResourceImage("CodeImp.DoomBuilder.Resources.MissingTexture3D.png");
 			missingtexture3d.LoadImage();
@@ -167,9 +164,6 @@ namespace CodeImp.DoomBuilder.Data
 			crosshair.LoadImage();
 			crosshairbusy = new ResourceImage("CodeImp.DoomBuilder.Resources.CrosshairBusy.png");
 			crosshairbusy.LoadImage();
-			//mxd
-            //thingbox = new ResourceImage("CodeImp.DoomBuilder.Resources.ThingBox.png");
-			//thingbox.LoadImage();
 			whitetexture = new ResourceImage("CodeImp.DoomBuilder.Resources.White.png");
 			whitetexture.UseColorCorrection = false;
 			whitetexture.LoadImage();
@@ -194,18 +188,9 @@ namespace CodeImp.DoomBuilder.Data
 				crosshair = null;
 				crosshairbusy.Dispose();
 				crosshairbusy = null;
-				//mxd
-                //thingbox.Dispose();
-				//thingbox = null;
 				whitetexture.Dispose();
 				whitetexture = null;
-
-                //mxd
-                if (modeldefEntries != null) {
-                    foreach (KeyValuePair<int, ModeldefEntry> group in modeldefEntries)
-                        group.Value.Dispose();
-                    modeldefEntries = null;
-                }
+				modeldefEntries = null;//mxd
                 mapInfo = null;
 				
 				// Done
@@ -363,16 +348,6 @@ namespace CodeImp.DoomBuilder.Data
 			// Mixed textures and flats?
 			if(General.Map.Config.MixTexturesFlats)
 			{
-				// Add textures to flats
-				foreach(KeyValuePair<long, ImageData> t in texturesonly)
-				{
-					if(!flats.ContainsKey(t.Key))
-					{
-						flats.Add(t.Key, t.Value);
-						flatnames.Add(t.Value.Name);
-					}
-				}
-
 				// Add flats to textures
 				foreach(KeyValuePair<long, ImageData> f in flatsonly)
 				{
@@ -383,6 +358,9 @@ namespace CodeImp.DoomBuilder.Data
 					}
 				}
 
+				flats.Clear(); //mxd
+				flatnames.Clear(); //mxd
+
 				// Do the same on the data readers
 				foreach(DataReader dr in containers)
 					dr.TextureSet.MixTexturesAndFlats();
@@ -401,10 +379,9 @@ namespace CodeImp.DoomBuilder.Data
 			// Add texture names to texture sets
 			foreach(KeyValuePair<long, ImageData> img in textures)
 			{
-				// Add to all sets where it matches
-				bool matchfound = false;
+				// Add to all sets
 				foreach(MatchingTextureSet ms in texturesets)
-					matchfound |= ms.AddTexture(img.Value);
+					ms.AddTexture(img.Value);
 
 				// Add to all
 				alltextures.AddTexture(img.Value);
@@ -413,10 +390,9 @@ namespace CodeImp.DoomBuilder.Data
 			// Add flat names to texture sets
 			foreach(KeyValuePair<long, ImageData> img in flats)
 			{
-				// Add to all sets where it matches
-				bool matchfound = false;
+				// Add to all sets
 				foreach(MatchingTextureSet ms in texturesets)
-					matchfound |= ms.AddFlat(img.Value);
+					ms.AddFlat(img.Value);
 				
 				// Add to all
 				alltextures.AddFlat(img.Value);
@@ -426,7 +402,7 @@ namespace CodeImp.DoomBuilder.Data
 			StartBackgroundLoader();
 			
 			// Output info
-			General.WriteLogLine("Loaded " + texcount + " textures, " + flatcount + " flats, " + colormapcount + " colormaps, " + spritecount + " sprites, " + thingcount + " decorate things, " + modeldefEntries.Count + " model deinitions, " + gldefsEntries.Count + " gl definitions");
+			General.WriteLogLine("Loaded " + texcount + " textures, " + flatcount + " flats, " + colormapcount + " colormaps, " + spritecount + " sprites, " + thingcount + " decorate things, " + modeldefEntries.Count + " model deinitions, " + gldefsEntries.Count + " dynamic light definitions");
 		}
 		
 		// This unloads all data
@@ -450,9 +426,8 @@ namespace CodeImp.DoomBuilder.Data
 
             //mxd
             if (modeldefEntries != null) {
-                foreach (KeyValuePair<int, ModeldefEntry> group in modeldefEntries) {
+                foreach (KeyValuePair<int, ModelData> group in modeldefEntries) 
                     group.Value.Dispose();
-                }
             }
 			
 			// Dispose containers
@@ -696,6 +671,20 @@ namespace CodeImp.DoomBuilder.Data
 			General.SendMessage(General.MainWindow.Handle, (int)MainForm.ThreadMessages.UpdateStatus, 0, 0);
 		}
 
+		//mxd. This loads a model
+		internal void ProcessModel(int type) {
+			if(modeldefEntries[type].LoadState != ModelLoadState.None) return;
+
+			//create models
+			ModelReader.Load(modeldefEntries[type], containers, General.Map.Graphics.Device);
+
+			if(modeldefEntries[type].Model != null) {
+				modeldefEntries[type].LoadState = ModelLoadState.Ready;
+			} else {
+				modeldefEntries.Remove(type);
+			}
+		}
+
 		// This updates the used-in-map status on all textures and flats
 		private void BackgroundUpdateUsedTextures()
 		{
@@ -709,10 +698,11 @@ namespace CodeImp.DoomBuilder.Data
 				}
 
 				// Set used on all flats
-				foreach(KeyValuePair<long, ImageData> i in flats)
-				{
-					i.Value.SetUsedInMap(usedimages.ContainsKey(i.Key));
-					if(i.Value.IsImageLoaded != i.Value.IsReferenced) ProcessImage(i.Value);
+				if(!General.Map.Config.MixTexturesFlats) {
+					foreach(KeyValuePair<long, ImageData> i in flats) {
+						i.Value.SetUsedInMap(usedimages.ContainsKey(i.Key));
+						if(i.Value.IsImageLoaded != i.Value.IsReferenced) ProcessImage(i.Value);
+					}
 				}
 				
 				// Done
@@ -851,7 +841,7 @@ namespace CodeImp.DoomBuilder.Data
 			Stream patch;
 
 			// Go for all opened containers
-			for(int i = containers.Count - 1; i >= 0; i--)
+			for(int i = containers.Count - 1; i > -1; i--)
 			{
 				// This contain provides this patch?
 				patch = containers[i].GetPatchData(pname);
@@ -984,13 +974,13 @@ namespace CodeImp.DoomBuilder.Data
 		public bool GetFlatExists(string name)
 		{
 			long longname = Lump.MakeLongName(name);
-			return flats.ContainsKey(longname);
+			return General.Map.Config.MixTexturesFlats ? textures.ContainsKey(longname) : flats.ContainsKey(longname);
 		}
 
 		// This checks if a flat is known
 		public bool GetFlatExists(long longname)
 		{
-			return flats.ContainsKey(longname);
+			return General.Map.Config.MixTexturesFlats ? textures.ContainsKey(longname) : flats.ContainsKey(longname);
 		}
 		
 		// This returns an image by string
@@ -1004,24 +994,26 @@ namespace CodeImp.DoomBuilder.Data
 		// This returns an image by long
 		public ImageData GetFlatImage(long longname)
 		{
-			// Does this flat exist?
-			if(flats.ContainsKey(longname))
-			{
+			if(General.Map.Config.MixTexturesFlats) { //mxd
+				// Does this flat exist?
+				if(textures.ContainsKey(longname)) {
+					// Return flat
+					return textures[longname];
+				}
+			} else if(flats.ContainsKey(longname)) { // Does this flat exist?
 				// Return flat
 				return flats[longname];
 			}
-			else
-			{
-				// Return null image
-				return new UnknownImage(Properties.Resources.UnknownImage);
-			}
+
+			// Return null image
+			return new UnknownImage(Properties.Resources.UnknownImage);
 		}
 
 		// This returns an image by long and doesn't check if it exists
 		public ImageData GetFlatImageKnown(long longname)
 		{
 			// Return flat
-			return flats[longname];
+			return General.Map.Config.MixTexturesFlats ? textures[longname] : flats[longname]; //mxd
 		}
 		
 		#endregion
@@ -1382,39 +1374,7 @@ namespace CodeImp.DoomBuilder.Data
 		
 		#endregion
 
-        #region ================== Modeldef, Gldefs, Mapinfo and models loading
-
-        //mxd
-        public void LoadModels() {
-            General.MainWindow.DisplayStatus(StatusType.Busy, "Loading models...");
-
-            foreach (Thing t in General.Map.Map.Things)
-                t.IsModel = LoadModelForThing(t);
-
-            General.MainWindow.RedrawDisplay();
-        }
-
-        //mxd
-        public bool LoadModelForThing(Thing t) {
-            if (modeldefEntries.ContainsKey(t.Type)) {
-                if (modeldefEntries[t.Type].Model == null) {
-                    //load models and textures
-                    ModeldefEntry mde = modeldefEntries[t.Type];
-
-                    //create models
-					ModelReader.Load(ref mde, containers, General.Map.Graphics.Device);
-
-                    if (mde.Model != null) {
-                        return true;
-                    } else {
-                        modeldefEntries.Remove(t.Type);
-                        return false;
-                    }
-                }
-                return true;
-            }
-            return false;
-        }
+        #region ================== mxd. Modeldef, Gldefs, Mapinfo
 
         //mxd. This creates <Actor Class, Thing.Type> dictionary. Should be called after all DECORATE actors are parsed
         private Dictionary<string, int> createActorsByClassList() {
@@ -1442,13 +1402,14 @@ namespace CodeImp.DoomBuilder.Data
         //mxd
         public void ReloadModeldef() {
             if (modeldefEntries != null) {
-                foreach (KeyValuePair<int, ModeldefEntry> group in modeldefEntries)
+                foreach (KeyValuePair<int, ModelData> group in modeldefEntries)
                     group.Value.Dispose();
             }
 
             General.MainWindow.DisplayStatus(StatusType.Busy, "Reloading model definitions...");
             loadModeldefs(createActorsByClassList());
-            LoadModels();
+
+			foreach(Thing t in General.Map.Map.Things) t.UpdateModelStatus();
 
             //rebuild geometry if in Visual mode
             if (General.Editing.Mode != null && General.Editing.Mode.GetType().Name == "BaseVisualMode") {
@@ -1486,17 +1447,13 @@ namespace CodeImp.DoomBuilder.Data
 
         //mxd. This parses modeldefs. Should be called after all DECORATE actors are parsed and actorsByClass dictionary created
         private void loadModeldefs(Dictionary<string, int> actorsByClass) {
-            modeldefEntries = new Dictionary<int, ModeldefEntry>(); //create it in all cases, so we don't have to check if it's null every time we need to access it
-            
             //if no actors defined in DECORATE or game config...
             if (actorsByClass == null || actorsByClass.Count == 0) {
                 General.ErrorLogger.Add(ErrorType.Warning, "Warning: current game has no Actors!");
                 return;
             }
 
-			foreach(Thing t in General.Map.Map.Things) t.IsModel = false; //drop model flag
-
-            Dictionary<string, ModeldefEntry> modelDefEntriesByName = new Dictionary<string, ModeldefEntry>();
+            Dictionary<string, ModelData> modelDefEntriesByName = new Dictionary<string, ModelData>();
             ModeldefParser mdeParser = new ModeldefParser();
 
             foreach (DataReader dr in containers) {
@@ -1506,7 +1463,7 @@ namespace CodeImp.DoomBuilder.Data
                 foreach (KeyValuePair<string, Stream> group in streams) {
                     // Parse the data
                     if (mdeParser.Parse(group.Value, currentreader.Location.location + "\\" + group.Key)) {
-                        foreach (KeyValuePair<string, ModeldefEntry> g in mdeParser.ModelDefEntries) {
+                        foreach (KeyValuePair<string, ModelData> g in mdeParser.ModelDefEntries) {
                             modelDefEntriesByName.Add(g.Key, g.Value);
                         }
                     }
@@ -1515,18 +1472,18 @@ namespace CodeImp.DoomBuilder.Data
 
             currentreader = null;
 
-            foreach (KeyValuePair<string, ModeldefEntry> e in modelDefEntriesByName) {
+            foreach (KeyValuePair<string, ModelData> e in modelDefEntriesByName) {
                 if (actorsByClass.ContainsKey(e.Key))
                     modeldefEntries[actorsByClass[e.Key]] = modelDefEntriesByName[e.Key];
 				else if(!invalidDecorateActors.Contains(e.Key))
                     General.ErrorLogger.Add(ErrorType.Warning, "Got MODELDEF override for class '" + e.Key + "', but haven't found such class in Decorate");
             }
+
+			foreach(Thing t in General.Map.Map.Things) t.UpdateModelStatus();
         }
 
         //mxd. This parses gldefs. Should be called after all DECORATE actors are parsed and actorsByClass dictionary created
         private void loadGldefs(Dictionary<string, int> actorsByClass, bool loadDefaultDefinitions) {
-            gldefsEntries = new Dictionary<int, GZDoomLight>();//create it in all cases, so we don't have to check if it's null every time we need to access it
-
             //if no actors defined in DECORATE or game config...
             if (actorsByClass == null || actorsByClass.Count == 0) {
 				General.ErrorLogger.Add(ErrorType.Warning, "Warning: current game has no Actors!");
diff --git a/Source/Core/Data/DirectoryReader.cs b/Source/Core/Data/DirectoryReader.cs
index 6e748078a..69f45007b 100644
--- a/Source/Core/Data/DirectoryReader.cs
+++ b/Source/Core/Data/DirectoryReader.cs
@@ -72,7 +72,7 @@ namespace CodeImp.DoomBuilder.Data
 
 			// Find in any of the wad files
 			// Note the backward order, because the last wad's images have priority
-			for(int i = wads.Count - 1; i >= 0; i--)
+			for(int i = wads.Count - 1; i > -1; i--)
 			{
 				Stream data = wads[i].GetPatchData(pname);
 				if(data != null) return data;
@@ -80,15 +80,13 @@ namespace CodeImp.DoomBuilder.Data
 			
 			try
 			{
-				// Find in patches directory
-				//string path = Path.Combine(PATCHES_DIR, Path.GetDirectoryName(pname));
-				//string filename = FindFirstFile(path, Path.GetFileName(pname), true);
+				//mxd. Find in directories ZDoom expects them to be
+				foreach(string location in PatchLocations){
+					string path = Path.Combine(location, Path.GetDirectoryName(pname));
+					string filename = FindFirstFile(path, Path.GetFileName(pname), true);
 
-				//mxd. ZDoom can load them from anywhere, so shall we
-				string filename = FindFirstFile(Path.GetDirectoryName(pname), Path.GetFileName(pname), true);
-				if((filename != null) && FileExists(filename))
-				{
-					return LoadFile(filename);
+					if(!string.IsNullOrEmpty(filename) && FileExists(filename))
+						return LoadFile(filename);
 				}
 			}
 			catch(Exception e)
diff --git a/Source/Core/Data/FileImage.cs b/Source/Core/Data/FileImage.cs
index a6105dac3..65d8d49ba 100644
--- a/Source/Core/Data/FileImage.cs
+++ b/Source/Core/Data/FileImage.cs
@@ -28,7 +28,6 @@ namespace CodeImp.DoomBuilder.Data
 	{
 		#region ================== Variables
 
-		//private string filepathname;
 		private int probableformat;
 		
 		#endregion
@@ -39,9 +38,8 @@ namespace CodeImp.DoomBuilder.Data
 		public FileImage(string name, string filepathname, bool asflat)
 		{
 			// Initialize
-			//this.filepathname = filepathname;
-            this.fullName = filepathname; //mxd
 			SetName(name);
+			this.fullName = filepathname; //mxd
 
 			if(asflat)
 			{
@@ -92,38 +90,38 @@ namespace CodeImp.DoomBuilder.Data
 			{
 				// Load file data
 				if(bitmap != null) bitmap.Dispose(); bitmap = null;
-                MemoryStream filedata = new MemoryStream(File.ReadAllBytes(fullName));
-
-				// Get a reader for the data
-				IImageReader reader = ImageDataFormat.GetImageReader(filedata, probableformat, General.Map.Data.Palette);
-				if(!(reader is UnknownImageReader))
-				{
-					// Load the image
-					filedata.Seek(0, SeekOrigin.Begin);
-					try { bitmap = reader.ReadAsBitmap(filedata); }
-					catch(InvalidDataException)
-					{
-						// Data cannot be read!
-						bitmap = null;
-					}
-				}
-				
-				// Not loaded?
-				if(bitmap == null)
-				{
-                    General.ErrorLogger.Add(ErrorType.Error, "Image file '" + fullName + "' data format could not be read, while loading image '" + this.Name + "'. Is this a valid picture file at all?");
+
+				if(!File.Exists(fullName)) { //mxd
+					General.ErrorLogger.Add(ErrorType.Error, "Image file '" + fullName + "' could not be read: no such file.");
 					loadfailed = true;
+				} else {
+					MemoryStream filedata = new MemoryStream(File.ReadAllBytes(fullName));
+
+					// Get a reader for the data
+					IImageReader reader = ImageDataFormat.GetImageReader(filedata, probableformat, General.Map.Data.Palette);
+					if(!(reader is UnknownImageReader)) {
+						// Load the image
+						filedata.Seek(0, SeekOrigin.Begin);
+						try { bitmap = reader.ReadAsBitmap(filedata); } catch(InvalidDataException) {
+							// Data cannot be read!
+							bitmap = null;
+						}
+					}
+
+					// Not loaded?
+					if(bitmap == null) {
+						General.ErrorLogger.Add(ErrorType.Error, "Image file '" + fullName + "' data format could not be read, while loading image '" + this.Name + "'. Is this a valid picture file at all?");
+						loadfailed = true;
+					} else {
+						// Get width and height
+						width = bitmap.Size.Width;
+						height = bitmap.Size.Height;
+					}
+
+					// Pass on to base
+					filedata.Dispose();
+					base.LocalLoadImage();
 				}
-				else
-				{
-					// Get width and height
-					width = bitmap.Size.Width;
-					height = bitmap.Size.Height;
-				}
-				
-				// Pass on to base
-				filedata.Dispose();
-				base.LocalLoadImage();
 			}
 		}
 		
diff --git a/Source/Core/Data/HighResImage.cs b/Source/Core/Data/HighResImage.cs
index 478fac6b9..8074e738c 100644
--- a/Source/Core/Data/HighResImage.cs
+++ b/Source/Core/Data/HighResImage.cs
@@ -104,6 +104,8 @@ namespace CodeImp.DoomBuilder.Data
 					loadfailed = true;
 				}
 
+				int failCount = 0; //mxd
+
 				if(!loadfailed)
 				{
 					// Go for all patches
@@ -126,7 +128,7 @@ namespace CodeImp.DoomBuilder.Data
 							{
 								// Data is in an unknown format!
 								General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'");
-								loadfailed = true;
+								failCount++; //mxd
 							}
 							else
 							{
@@ -138,7 +140,7 @@ namespace CodeImp.DoomBuilder.Data
 								{
 									// Data cannot be read!
 									General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'");
-									loadfailed = true;
+									failCount++; //mxd
 								}
 								if(patchbmp != null)
 								{
@@ -192,9 +194,9 @@ namespace CodeImp.DoomBuilder.Data
 												float bb = p.blend.b * PixelColor.BYTE_TO_FLOAT;
 
 												for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) {
-													cp->r = (byte)((((float)cp->r * PixelColor.BYTE_TO_FLOAT) * br) * 255.0f);
-													cp->g = (byte)((((float)cp->g * PixelColor.BYTE_TO_FLOAT) * bg) * 255.0f);
-													cp->b = (byte)((((float)cp->b * PixelColor.BYTE_TO_FLOAT) * bb) * 255.0f);
+													cp->r = (byte)(((cp->r * PixelColor.BYTE_TO_FLOAT) * br) * 255.0f);
+													cp->g = (byte)(((cp->g * PixelColor.BYTE_TO_FLOAT) * bg) * 255.0f);
+													cp->b = (byte)(((cp->b * PixelColor.BYTE_TO_FLOAT) * bb) * 255.0f);
 												}
 											} else if(p.blendstyle == TexturePathBlendStyle.Tint) {
 												float tintammount = p.tintammount - 0.1f;
@@ -206,9 +208,9 @@ namespace CodeImp.DoomBuilder.Data
 													float invTint = 1.0f - tintammount;
 
 													for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--) {
-														cp->r = (byte)((((float)cp->r * PixelColor.BYTE_TO_FLOAT) * invTint + br) * 255.0f);
-														cp->g = (byte)((((float)cp->g * PixelColor.BYTE_TO_FLOAT) * invTint + bg) * 255.0f);
-														cp->b = (byte)((((float)cp->b * PixelColor.BYTE_TO_FLOAT) * invTint + bb) * 255.0f);
+														cp->r = (byte)(((cp->r * PixelColor.BYTE_TO_FLOAT) * invTint + br) * 255.0f);
+														cp->g = (byte)(((cp->g * PixelColor.BYTE_TO_FLOAT) * invTint + bg) * 255.0f);
+														cp->b = (byte)(((cp->b * PixelColor.BYTE_TO_FLOAT) * invTint + bb) * 255.0f);
 													}
 												}
 											}
@@ -216,7 +218,7 @@ namespace CodeImp.DoomBuilder.Data
 											//mxd. apply RenderStyle
 											if(p.style == TexturePathRenderStyle.Blend) {
 												for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--)
-													cp->a = (byte)((((float)cp->a * PixelColor.BYTE_TO_FLOAT) * p.alpha) * 255.0f);
+													cp->a = (byte)(((cp->a * PixelColor.BYTE_TO_FLOAT) * p.alpha) * 255.0f);
 
 											//mxd. we need a copy of underlying part of texture for these styles
 											} else if(p.style != TexturePathRenderStyle.Copy) {
@@ -239,7 +241,6 @@ namespace CodeImp.DoomBuilder.Data
 
 												if(texturebmpdata != null) {
 													PixelColor* texturepixels = (PixelColor*)(texturebmpdata.Scan0.ToPointer());
-													int numtexpixels = texturebmpdata.Width * texturebmpdata.Height;
 													PixelColor* tcp = texturepixels + numpixels - 1;
 
 													if(p.style == TexturePathRenderStyle.Add) {
@@ -305,16 +306,17 @@ namespace CodeImp.DoomBuilder.Data
 						{
 							// Missing a patch lump!
 							General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'");
-							loadfailed = true;
+							failCount++; //mxd
 						}
 					}
 				}
 				
 				// Dispose bitmap if load failed
-				if(loadfailed && (bitmap != null))
+				if((bitmap != null) && (loadfailed || failCount >= patches.Count)) //mxd. We can still display texture if at least one of the patches was loaded
 				{
 					bitmap.Dispose();
 					bitmap = null;
+					loadfailed = true;
 				}
 
 				// Pass on to base
diff --git a/Source/Core/Data/ImageData.cs b/Source/Core/Data/ImageData.cs
index 56f5693fa..ee651d484 100644
--- a/Source/Core/Data/ImageData.cs
+++ b/Source/Core/Data/ImageData.cs
@@ -177,9 +177,7 @@ namespace CodeImp.DoomBuilder.Data
 		{
 			this.name = name;
 			this.longname = Lump.MakeLongName(name);
-            //mxd
-            if (this.fullName == null)
-                this.fullName = name;
+			fullName = name; //mxd
 		}
 		
 		// This unloads the image
diff --git a/Source/Core/Data/PK3Reader.cs b/Source/Core/Data/PK3Reader.cs
index b71339b3b..90dca5756 100644
--- a/Source/Core/Data/PK3Reader.cs
+++ b/Source/Core/Data/PK3Reader.cs
@@ -33,7 +33,6 @@ namespace CodeImp.DoomBuilder.Data
 		#region ================== Variables
 
 		private DirectoryFilesList files;
-        //private IArchive archive;//mxd
         private ArchiveType archiveType; //mxd
         private static Dictionary<string, byte[]> sevenZipEntries; //mxd
 
@@ -123,12 +122,11 @@ namespace CodeImp.DoomBuilder.Data
 				if(data != null) return data;
 			}
 
-			// Find in patches directory
-			//string filename = FindFirstFile(PATCHES_DIR, pname, true);
-			string filename = FindFirstFile("", pname, true); //mxd. ZDoom can load them from anywhere, so shall we
-			if((filename != null) && FileExists(filename))
-			{
-				return LoadFile(filename);
+			//mxd. Find in directories ZDoom expects them to be
+			foreach(string location in PatchLocations) {
+				string filename = FindFirstFile(location, pname, true);
+				if((filename != null) && FileExists(filename))
+					return LoadFile(filename);
 			}
 
 			// Nothing found
diff --git a/Source/Core/Data/PK3StructuredReader.cs b/Source/Core/Data/PK3StructuredReader.cs
index a7451c1a9..25003e4a6 100644
--- a/Source/Core/Data/PK3StructuredReader.cs
+++ b/Source/Core/Data/PK3StructuredReader.cs
@@ -52,6 +52,8 @@ namespace CodeImp.DoomBuilder.Data
 
 		#region ================== Properties
 
+		protected string[] PatchLocations = { PATCHES_DIR, TEXTURES_DIR, FLATS_DIR }; //mxd. Because ZDoom looks for patches in these folders
+
 		#endregion
 
 		#region ================== Constructor / Disposer
@@ -326,6 +328,22 @@ namespace CodeImp.DoomBuilder.Data
 			
 			return new List<ImageData>(images.Values);
 		}
+
+		//mxd.
+		public override Stream GetFlatData(string pname) {
+			// Error when suspended
+			if(issuspended) throw new Exception("Data reader is suspended");
+
+			// Find in any of the wad files
+			// Note the backward order, because the last wad's images have priority
+			for(int i = wads.Count - 1; i > -1; i--) {
+				Stream data = wads[i].GetFlatData(pname);
+				if(data != null) return data;
+			}
+
+			// Nothing found
+			return null;
+		}
 		
 		#endregion
 
diff --git a/Source/Core/Data/TextureImage.cs b/Source/Core/Data/TextureImage.cs
index 7d3a4d317..7acae7db7 100644
--- a/Source/Core/Data/TextureImage.cs
+++ b/Source/Core/Data/TextureImage.cs
@@ -33,7 +33,6 @@ namespace CodeImp.DoomBuilder.Data
 		#region ================== Variables
 
 		private List<TexturePatch> patches;
-        private bool gotFullName;//mxd
 		
 		#endregion
 
@@ -63,12 +62,6 @@ namespace CodeImp.DoomBuilder.Data
 		{
 			// Add it
 			patches.Add(patch);
-
-            //mxd. Get full name from first patch
-            if (!gotFullName) {
-                fullName = General.Map.Data.GetPatchLocation(patch.lumpname);
-                gotFullName = true;
-            }
 		}
 		
 		// This loads the image
@@ -103,6 +96,8 @@ namespace CodeImp.DoomBuilder.Data
 					loadfailed = true;
 				}
 
+				int failCount = 0; //mxd
+
 				if(!loadfailed)
 				{
 					// Go for all patches
@@ -126,6 +121,7 @@ namespace CodeImp.DoomBuilder.Data
 								// Data is in an unknown format!
 								General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'. Does this lump contain valid picture data at all?");
 								loadfailed = true;
+								failCount++; //mxd
 							}
 							else
 							{
@@ -137,6 +133,7 @@ namespace CodeImp.DoomBuilder.Data
 									// Data cannot be read!
 									General.ErrorLogger.Add(ErrorType.Error, "Patch lump '" + p.lumpname + "' data format could not be read, while loading texture '" + this.Name + "'. Does this lump contain valid picture data at all?");
 									loadfailed = true;
+									failCount++; //mxd
 								}
 							}
 
@@ -148,6 +145,7 @@ namespace CodeImp.DoomBuilder.Data
 							// Missing a patch lump!
 							General.ErrorLogger.Add(ErrorType.Error, "Missing patch lump '" + p.lumpname + "' while loading texture '" + this.Name + "'. Did you forget to include required resources?");
 							loadfailed = true;
+							failCount++; //mxd
 						}
 					}
 
@@ -156,10 +154,11 @@ namespace CodeImp.DoomBuilder.Data
 				}
 				
 				// Dispose bitmap if load failed
-				if(loadfailed && (bitmap != null))
+				if((bitmap != null) && (loadfailed || failCount >= patches.Count)) //mxd. We can still display texture if at least one of the patches was loaded
 				{
 					bitmap.Dispose();
 					bitmap = null;
+					loadfailed = true;
 				}
 
 				// Pass on to base
diff --git a/Source/Core/Editing/UndoManager.cs b/Source/Core/Editing/UndoManager.cs
index e018557e4..0c323c07f 100644
--- a/Source/Core/Editing/UndoManager.cs
+++ b/Source/Core/Editing/UndoManager.cs
@@ -691,7 +691,7 @@ namespace CodeImp.DoomBuilder.Editing
 							General.Map.ThingsFilter.Update();
 							General.Map.Data.UpdateUsedTextures();
 							General.MainWindow.RefreshInfo();
-							General.MainWindow.RedrawDisplay();
+							//General.MainWindow.RedrawDisplay();
 							
 							// Map changed!
 							General.Map.IsChanged = true;
@@ -701,6 +701,7 @@ namespace CodeImp.DoomBuilder.Editing
 							General.Plugins.OnUndoEnd();
 
 							// Update interface
+							General.MainWindow.RedrawDisplay(); //mxd
 							dobackgroundwork = true;
 							General.MainWindow.UpdateInterface();
 						}
@@ -833,7 +834,7 @@ namespace CodeImp.DoomBuilder.Editing
 							General.Map.ThingsFilter.Update();
 							General.Map.Data.UpdateUsedTextures();
 							General.MainWindow.RefreshInfo();
-							General.MainWindow.RedrawDisplay();
+							//General.MainWindow.RedrawDisplay();
 							
 							// Map changed!
 							General.Map.IsChanged = true;
@@ -843,6 +844,7 @@ namespace CodeImp.DoomBuilder.Editing
 							General.Plugins.OnRedoEnd();
 
 							// Update interface
+							General.MainWindow.RedrawDisplay(); //mxd
 							dobackgroundwork = true;
 							General.MainWindow.UpdateInterface();
 						}
diff --git a/Source/Core/GZBuilder/Data/GZDoomLight.cs b/Source/Core/GZBuilder/Data/DynamicLight.cs
similarity index 71%
rename from Source/Core/GZBuilder/Data/GZDoomLight.cs
rename to Source/Core/GZBuilder/Data/DynamicLight.cs
index 11d33e787..0416f3d05 100644
--- a/Source/Core/GZBuilder/Data/GZDoomLight.cs
+++ b/Source/Core/GZBuilder/Data/DynamicLight.cs
@@ -2,8 +2,8 @@
 
 namespace CodeImp.DoomBuilder.GZBuilder.Data
 {
-    public sealed class GZDoomLight {
-        public int Type; //holds GZDoomLightType
+    public sealed class DynamicLightData {
+		public DynamicLightType Type; //holds DynamicLightType
         public Color3 Color;
         public int PrimaryRadius;
         public int SecondaryRadius;
@@ -12,15 +12,16 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
         public bool Subtractive;
         public bool DontLightSelf;
 
-        public GZDoomLight() {
+        public DynamicLightData() {
             Color = new Color3();
             Offset = new Vector3();
         }
     }
 
-    public enum GZDoomLightType
+    public enum DynamicLightType
     {
-        NORMAL = 0,
+        NONE = -1,
+		NORMAL = 0,
         PULSE = 1,
         FLICKER = 2,
         SECTOR = 3,
@@ -30,7 +31,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
     }
 
     //divide these by 100 to get light color alpha
-    public enum GZDoomLightRenderStyle
+    public enum DynamicLightRenderStyle
     {
         NONE = 0,
         NORMAL = 99,
diff --git a/Source/Core/GZBuilder/Data/ModelDefEntry.cs b/Source/Core/GZBuilder/Data/ModelData.cs
similarity index 50%
rename from Source/Core/GZBuilder/Data/ModelDefEntry.cs
rename to Source/Core/GZBuilder/Data/ModelData.cs
index 8fdd81448..b99e7bb63 100644
--- a/Source/Core/GZBuilder/Data/ModelDefEntry.cs
+++ b/Source/Core/GZBuilder/Data/ModelData.cs
@@ -2,17 +2,43 @@
 using SlimDX;
 using SlimDX.Direct3D9;
 using CodeImp.DoomBuilder.GZBuilder.MD3;
+using CodeImp.DoomBuilder.Data;
+using System.IO;
+using System;
+using System.Text;
+using CodeImp.DoomBuilder.Rendering;
+using CodeImp.DoomBuilder.Geometry;
+using CodeImp.DoomBuilder.IO;
+using System.Drawing;
+using System.Drawing.Imaging;
 
 namespace CodeImp.DoomBuilder.GZBuilder.Data
 {
-    internal sealed class ModeldefEntry
+    internal sealed class ModelData
     {
-        internal string ClassName;
+		private const float VERTICAL_STRETCH = 1 / 1.2f;
+
+		private class MD3LoadResult
+		{
+			public List<string> Skins;
+			public List<Mesh> Meshes;
+			public string Errors;
+
+			public MD3LoadResult() {
+				Skins = new List<string>();
+				Meshes = new List<Mesh>();
+			}
+		}
+		
+		internal string ClassName;
         internal List<string> ModelNames;
         internal List<string> TextureNames;
 
         internal GZModel Model;
 
+		private ModelLoadState loadstate;
+		public ModelLoadState LoadState { get { return loadstate; } internal set { loadstate = value; } }
+
         internal Vector3 Scale;
         internal float zOffset;
 
@@ -20,7 +46,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
         internal float PitchOffset; //in radians
         internal float RollOffset; //in radians
 
-        internal ModeldefEntry() {
+        internal ModelData() {
             ModelNames = new List<string>();
             TextureNames = new List<string>();
         }
@@ -32,7 +58,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.Data
 
                 foreach (Texture t in Model.Textures)
                     t.Dispose();
+
+				loadstate = ModelLoadState.None;
             }
-        }
-    }
+		}
+	}
 }
diff --git a/Source/Core/GZBuilder/Data/ModelLoadState.cs b/Source/Core/GZBuilder/Data/ModelLoadState.cs
new file mode 100644
index 000000000..a3c0007d1
--- /dev/null
+++ b/Source/Core/GZBuilder/Data/ModelLoadState.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace CodeImp.DoomBuilder.GZBuilder.Data
+{
+	public enum ModelLoadState
+	{
+		None,
+		Loading,
+		Ready
+	}
+}
diff --git a/Source/Core/GZBuilder/GZDoom/GldefsParser.cs b/Source/Core/GZBuilder/GZDoom/GldefsParser.cs
index 8d42a4062..ccafc79dc 100644
--- a/Source/Core/GZBuilder/GZDoom/GldefsParser.cs
+++ b/Source/Core/GZBuilder/GZDoom/GldefsParser.cs
@@ -11,10 +11,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
         public delegate void IncludeDelegate(GldefsParser parser, string includefile);
         public IncludeDelegate OnInclude;
 
-        private Dictionary<string, GZDoomLight> lightsByName; //LightName, light definition
+        private Dictionary<string, DynamicLightData> lightsByName; //LightName, light definition
         private Dictionary<string, string> objects; //ClassName, LightName
 
-        public Dictionary<string, GZDoomLight> LightsByName { get { return lightsByName; } }
+        public Dictionary<string, DynamicLightData> LightsByName { get { return lightsByName; } }
         public Dictionary<string, string> Objects { get { return objects; } }
 
         private List<string> parsedLumps;
@@ -26,12 +26,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
             public const string FLICKER2 = "flickerlight2";
             public const string SECTOR = "sectorlight";
 
-            public static Dictionary<string, int> GLDEFS_TO_GZDOOM_LIGHT_TYPE = new Dictionary<string, int>() { { POINT, 0 }, { PULSE, 1 }, { FLICKER, 2 }, { FLICKER2, 4 }, { SECTOR, 3 } };
+			public static Dictionary<string, DynamicLightType> GLDEFS_TO_GZDOOM_LIGHT_TYPE = new Dictionary<string, DynamicLightType>() { { POINT, DynamicLightType.NORMAL }, { PULSE, DynamicLightType.PULSE }, { FLICKER, DynamicLightType.FLICKER }, { FLICKER2, DynamicLightType.RANDOM }, { SECTOR, DynamicLightType.SECTOR } };
         }
 
         public GldefsParser() {
             parsedLumps = new List<string>();
-            lightsByName = new Dictionary<string, GZDoomLight>(); //LightName, Light params
+            lightsByName = new Dictionary<string, DynamicLightData>(); //LightName, Light params
             objects = new Dictionary<string, string>(); //ClassName, LightName
         }
 
@@ -60,7 +60,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                         bool gotErrors = false;
                         string lightType = token;
 
-                        GZDoomLight light = new GZDoomLight();
+                        DynamicLightData light = new DynamicLightData();
                         light.Type = GldefsLightType.GLDEFS_TO_GZDOOM_LIGHT_TYPE[lightType];
 
                         //find classname
@@ -295,14 +295,14 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                                             }
 
                                             //light-type specific checks
-                                            if (light.Type == (int)GZDoomLightType.NORMAL) {
+                                            if (light.Type == DynamicLightType.NORMAL) {
                                                 if (light.PrimaryRadius == 0) {
                                                     General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": light Size is 0. It won't be shown in GZDoom!");
                                                     gotErrors = true;
                                                 }
                                             }
 
-                                            if (light.Type == (int)GZDoomLightType.FLICKER || light.Type == (int)GZDoomLightType.PULSE || light.Type == (int)GZDoomLightType.RANDOM) {
+                                            if (light.Type == DynamicLightType.FLICKER || light.Type == DynamicLightType.PULSE || light.Type == DynamicLightType.RANDOM) {
                                                 if (light.PrimaryRadius == 0 && light.SecondaryRadius == 0) {
                                                     General.ErrorLogger.Add(ErrorType.Error, "Error in '" + sourcefilename + "' at line " + GetCurrentLineNumber() + ": 'Size' and 'SecondarySize' are 0. This light won't be shown in GZDoom!");
                                                     gotErrors = true;
diff --git a/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs b/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
index abd8a42ab..624533ff4 100644
--- a/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
+++ b/Source/Core/GZBuilder/GZDoom/ModeldefParser.cs
@@ -6,22 +6,18 @@ using CodeImp.DoomBuilder.GZBuilder.Data;
 namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
    
     internal class ModeldefParser : ZDTextParser {
-        private Dictionary<string, ModeldefEntry> modelDefEntries; //classname, entry
-        internal Dictionary<string, ModeldefEntry> ModelDefEntries { get { return modelDefEntries; } }
-
-        private List<string> classNames;
-
+        private Dictionary<string, ModelData> modelDefEntries; //classname, entry
+        internal Dictionary<string, ModelData> ModelDefEntries { get { return modelDefEntries; } }
         internal string Source { get { return sourcename; } }
 
         internal ModeldefParser() {
-            modelDefEntries = new Dictionary<string, ModeldefEntry>();
-            classNames = new List<string>();
+            modelDefEntries = new Dictionary<string, ModelData>();
         }
 
         //should be called after all decorate actors are parsed 
         public override bool Parse(Stream stream, string sourcefilename) {
             base.Parse(stream, sourcefilename);
-            modelDefEntries = new Dictionary<string, ModeldefEntry>();
+            modelDefEntries = new Dictionary<string, ModelData>();
 
             // Continue until at the end of the stream
             while (SkipWhitespace(true)) {
@@ -36,8 +32,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                         string className = StripTokenQuotes(ReadToken()).ToLowerInvariant();
 
                         if (!string.IsNullOrEmpty(className)) {
-                            if (classNames.IndexOf(className) != -1)
-                                continue; //already got this class; continue to next one
+							if(modelDefEntries.ContainsKey(className)) continue; //already got this class; continue to next one
 
                             //now find opening brace
                             SkipWhitespace(true);
@@ -48,11 +43,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
                             }
 
                             ModeldefStructure mds = new ModeldefStructure();
-                            ModeldefEntry mde = mds.Parse(this);
+                            ModelData mde = mds.Parse(this);
                             if (mde != null) {
                                 mde.ClassName = className;
                                 modelDefEntries.Add(className, mde);
-                                classNames.Add(mde.ClassName);
                             }
                         }
 
diff --git a/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs b/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
index c56fb3216..13706c17b 100644
--- a/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
+++ b/Source/Core/GZBuilder/GZDoom/ModeldefStructure.cs
@@ -9,7 +9,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
     internal sealed class ModeldefStructure {
         private const int MAX_MODELS = 4; //maximum models per modeldef entry, zero-based
 
-        internal ModeldefEntry Parse(ModeldefParser parser) {
+        internal ModelData Parse(ModeldefParser parser) {
             string[] textureNames = new string[4];
             string[] modelNames = new string[4];
             string path = "";
@@ -311,7 +311,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.GZDoom {
             if (gotErrors) return null;
 
             //classname is set in ModeldefParser
-            ModeldefEntry mde = new ModeldefEntry();
+            ModelData mde = new ModelData();
             mde.Scale = scale;
             mde.zOffset = zOffset;
 			mde.AngleOffset = Angle2D.DegToRad(angleOffset);// *(float)Math.PI / 180.0f;
diff --git a/Source/Core/GZBuilder/GZGeneral.cs b/Source/Core/GZBuilder/GZGeneral.cs
index 488cf24ad..38166eef1 100644
--- a/Source/Core/GZBuilder/GZGeneral.cs
+++ b/Source/Core/GZBuilder/GZGeneral.cs
@@ -14,7 +14,7 @@ namespace CodeImp.DoomBuilder.GZBuilder
         public static int[] GZ_LIGHTS { get { return gzLights; } }
         private static int[] gzLightTypes = { 5, 10, 15 }; //these are actually offsets in gz_lights
         public static int[] GZ_LIGHT_TYPES { get { return gzLightTypes; } }
-        private static int[] gzAnimatedLightTypes = { (int)GZDoomLightType.FLICKER, (int)GZDoomLightType.RANDOM, (int)GZDoomLightType.PULSE };
+        private static int[] gzAnimatedLightTypes = { (int)DynamicLightType.FLICKER, (int)DynamicLightType.RANDOM, (int)DynamicLightType.PULSE };
         public static int[] GZ_ANIMATED_LIGHT_TYPES {  get { return gzAnimatedLightTypes; } }
 
         //asc script action specials
diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs
index 8ec553dc1..23c075809 100644
--- a/Source/Core/GZBuilder/md3/ModelReader.cs
+++ b/Source/Core/GZBuilder/md3/ModelReader.cs
@@ -31,7 +31,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 			}
 		}
 		
-        public static void Load(ref ModeldefEntry mde, List<DataReader> containers, Device device) {
+		public static void Load(ModelData mde, List<DataReader> containers, Device device) {
             mde.Model = new GZModel();
             BoundingBoxSizes bbs = new BoundingBoxSizes();
 			MD3LoadResult result = new MD3LoadResult();
@@ -142,7 +142,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
             mde.Model.BoundingBox = BoundingBoxTools.CalculateBoundingBox(bbs);
         }
 
-		private static MD3LoadResult ReadMD3Model(ref BoundingBoxSizes bbs, ModeldefEntry mde, bool useSkins, MemoryStream s, Device device) {
+		private static MD3LoadResult ReadMD3Model(ref BoundingBoxSizes bbs, ModelData mde, bool useSkins, MemoryStream s, Device device) {
             long start = s.Position;
 			MD3LoadResult result = new MD3LoadResult();
 
@@ -224,7 +224,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
             return result;
         }
 
-        private static string ReadSurface(ref BoundingBoxSizes bbs, ref string skin, BinaryReader br, List<int> polyIndecesList, List<WorldVertex> vertList, ModeldefEntry mde) {
+        private static string ReadSurface(ref BoundingBoxSizes bbs, ref string skin, BinaryReader br, List<int> polyIndecesList, List<WorldVertex> vertList, ModelData mde) {
             int vertexOffset = vertList.Count;
             long start = br.BaseStream.Position;
             string magic = ReadString(br, 4);
@@ -352,7 +352,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 			result.Meshes.Add(mesh);
 		}
 
-		private static MD3LoadResult ReadMD2Model(ref BoundingBoxSizes bbs, ModeldefEntry mde, MemoryStream s, Device D3DDevice) {
+		private static MD3LoadResult ReadMD2Model(ref BoundingBoxSizes bbs, ModelData mde, MemoryStream s, Device D3DDevice) {
             long start = s.Position;
 			MD3LoadResult result = new MD3LoadResult();
 
@@ -552,25 +552,23 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 				ms.Close();
 				ms.Dispose();
 
-				if(bitmap == null) return null;
+				if(bitmap != null) {
+					BitmapData bmlock = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
+					texture = new Texture(device, bitmap.Width, bitmap.Height, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
 
-				BitmapData bmlock = bitmap.LockBits(new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
-				texture = new Texture(device, bitmap.Width, bitmap.Height, 1, Usage.None, Format.A8R8G8B8, Pool.Managed);
+					DataRectangle textureLock = texture.LockRectangle(0, LockFlags.None);
+					textureLock.Data.WriteRange(bmlock.Scan0, bmlock.Height * bmlock.Stride);
 
-				DataRectangle textureLock = texture.LockRectangle(0, LockFlags.None);
-				textureLock.Data.WriteRange(bmlock.Scan0, bmlock.Height * bmlock.Stride);
-
-				bitmap.UnlockBits(bmlock);
-				texture.UnlockRectangle(0);
+					bitmap.UnlockBits(bmlock);
+					texture.UnlockRectangle(0);
+				}
+			} else {
+				texture = Texture.FromStream(device, ms);
 
-				return texture;
+				ms.Close();
+				ms.Dispose();
 			}
 
-			texture = Texture.FromStream(device, ms);
-
-			ms.Close();
-			ms.Dispose();
-
 			return texture;
 		}
 
diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs
index 610c21012..700669531 100644
--- a/Source/Core/General/MapManager.cs
+++ b/Source/Core/General/MapManager.cs
@@ -297,11 +297,8 @@ namespace CodeImp.DoomBuilder {
             map.Update();
             thingsfilter.Update();
 
-            //mxd. load models
-            data.LoadModels();
-            //mxd
-            namedScripts = new List<ScriptItem>();
-            numberedScripts = new List<ScriptItem>();
+			namedScripts = new List<ScriptItem>(); //mxd
+			numberedScripts = new List<ScriptItem>(); //mxd
 
             // Bind any methods
             General.Actions.BindMethods(this);
@@ -360,12 +357,11 @@ namespace CodeImp.DoomBuilder {
 #if DEBUG
             tempwad = new WAD(tempfile);
 #else
-				try { tempwad = new WAD(tempfile); }
-				catch(Exception e)
-				{
-					General.ShowErrorMessage("Error while creating a temporary wad file:\n" + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK);
-					return false;
-				}
+			try { tempwad = new WAD(tempfile); } catch(Exception e) 
+			{
+				General.ShowErrorMessage("Error while creating a temporary wad file:\n" + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK);
+				return false;
+			}
 #endif
 
             // Now open the map file
@@ -373,12 +369,11 @@ namespace CodeImp.DoomBuilder {
 #if DEBUG
             mapwad = new WAD(filepathname, true);
 #else
-				try { mapwad = new WAD(filepathname, true); }
-				catch(Exception e)
-				{
-					General.ShowErrorMessage("Error while opening source wad file:\n" + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK);
-					return false;
-				}
+			try { mapwad = new WAD(filepathname, true); } catch(Exception e) 
+			{
+				General.ShowErrorMessage("Error while opening source wad file:\n" + e.GetType().Name + ": " + e.Message, MessageBoxButtons.OK);
+				return false;
+			}
 #endif
 
             // Copy the map lumps to the temp file
@@ -397,13 +392,12 @@ namespace CodeImp.DoomBuilder {
 #if DEBUG
             map = io.Read(map, TEMP_MAP_HEADER);
 #else
-				try { map = io.Read(map, TEMP_MAP_HEADER); }
-				catch(Exception e)
-				{
-					General.ErrorLogger.Add(ErrorType.Error, "Unable to read the map data structures with the specified configuration. " + e.GetType().Name + ": " + e.Message);
-					General.ShowErrorMessage("Unable to read the map data structures with the specified configuration.", MessageBoxButtons.OK);
-					return false;
-				}
+			try { map = io.Read(map, TEMP_MAP_HEADER); } catch(Exception e) 
+			{
+				General.ErrorLogger.Add(ErrorType.Error, "Unable to read the map data structures with the specified configuration. " + e.GetType().Name + ": " + e.Message);
+				General.ShowErrorMessage("Unable to read the map data structures with the specified configuration.", MessageBoxButtons.OK);
+				return false;
+			}
 #endif
             map.EndAddRemove();
 
@@ -423,8 +417,6 @@ namespace CodeImp.DoomBuilder {
             map.Update();
             thingsfilter.Update();
 
-            //mxd. load models
-            data.LoadModels();
             //mxd. check script names
             UpdateScriptNames();
 
diff --git a/Source/Core/Map/Linedef.cs b/Source/Core/Map/Linedef.cs
index d28d4fa4c..cd9f9b7e0 100644
--- a/Source/Core/Map/Linedef.cs
+++ b/Source/Core/Map/Linedef.cs
@@ -104,6 +104,7 @@ namespace CodeImp.DoomBuilder.Map
 		internal bool FrontInterior { get { return frontinterior; } set { frontinterior = value; } }
 		internal bool ImpassableFlag { get { return impassableflag; } }
 		internal int ColorPresetIndex { get { return colorPresetIndex; } } //mxd
+		internal bool ExtraFloorFlag; //mxd
 		
 		#endregion
 
@@ -287,7 +288,6 @@ namespace CodeImp.DoomBuilder.Map
 			l.updateneeded = true;
 			l.activate = activate;
 			l.impassableflag = impassableflag;
-			//l.blocksoundflag = blocksoundflag;
 			l.UpdateColorPreset();//mxd
 			base.CopyPropertiesTo(l);
 		}
@@ -812,6 +812,7 @@ namespace CodeImp.DoomBuilder.Map
 			SetEndVertex(v);
 			nl.Selected = this.Selected;
 			nl.marked = this.marked;
+			nl.ExtraFloorFlag = this.ExtraFloorFlag; //mxd
 			
 			// Copy front sidedef if exists
 			if(front != null)
diff --git a/Source/Core/Map/MapSet.cs b/Source/Core/Map/MapSet.cs
index cc7bf4e5c..d471cbe1f 100644
--- a/Source/Core/Map/MapSet.cs
+++ b/Source/Core/Map/MapSet.cs
@@ -77,7 +77,7 @@ namespace CodeImp.DoomBuilder.Map
 		private int numthings;
 
 		//mxd
-		private Sector[] newSectors;
+		private Dictionary<int, int> newSectorLineIndices; //line index, sector order
 		private GroupInfo[] groupInfos;
 		
 		// Behavior
@@ -160,7 +160,7 @@ namespace CodeImp.DoomBuilder.Map
 
 		internal bool AutoRemove { get { return autoremove; } set { autoremove = value; } }
 
-		public Sector[] NewSectors { get { return newSectors; } } //mxd
+		public Dictionary<int, int> NewSectorLineIndices { get { return newSectorLineIndices; } } //mxd
 
 		public GroupInfo[] GroupInfos { get { return groupInfos; } } //mxd
 
@@ -184,7 +184,6 @@ namespace CodeImp.DoomBuilder.Map
 			indexholes = new List<int>();
 			lastsectorindex = 0;
 			autoremove = true;
-			newSectors = new Sector[0]; //mxd
 			groupInfos = new GroupInfo[10]; //mxd
 			
 			// We have no destructor
@@ -207,7 +206,6 @@ namespace CodeImp.DoomBuilder.Map
 			indexholes = new List<int>();
 			lastsectorindex = 0;
 			autoremove = true;
-			newSectors = new Sector[0]; //mxd
 			groupInfos = new GroupInfo[10]; //mxd
 
 			// Deserialize
@@ -258,7 +256,6 @@ namespace CodeImp.DoomBuilder.Map
 				sel_sectors = null;
 				sel_things = null;
 				indexholes = null;
-				newSectors = null; //mxd
 				groupInfos = null; //mxd
 				
 				// Done
@@ -3043,8 +3040,19 @@ namespace CodeImp.DoomBuilder.Map
 		//mxd
 		private void updateNewSectors() {
 			int n = sectors.Length < General.Settings.GZNewSectorsCount ? sectors.Length : General.Settings.GZNewSectorsCount;
-			newSectors = new Sector[n];
+			Sector[] newSectors = new Sector[n];
 			Array.Copy(sectors, sectors.Length - n, newSectors, 0, n);
+			
+			List<int> newLineIndices = new List<int>();
+			newSectorLineIndices = new Dictionary<int, int>();
+
+			for(int i = newSectors.Length-1; i > -1; i--) {
+				foreach (Sidedef side in newSectors[i].Sidedefs){
+					if(newLineIndices.Contains(side.Line.Index)) continue;
+					newLineIndices.Add(side.Line.Index);
+					newSectorLineIndices.Add(side.Line.Index, i);
+				}
+			}
 		}
 		
 		#endregion
diff --git a/Source/Core/Map/Thing.cs b/Source/Core/Map/Thing.cs
index d6b1c3703..4f2c6886e 100644
--- a/Source/Core/Map/Thing.cs
+++ b/Source/Core/Map/Thing.cs
@@ -23,6 +23,7 @@ using CodeImp.DoomBuilder.Rendering;
 using CodeImp.DoomBuilder.Config;
 using CodeImp.DoomBuilder.IO;
 using CodeImp.DoomBuilder.VisualModes;
+using CodeImp.DoomBuilder.GZBuilder.Data;
 
 #endregion
 
@@ -56,7 +57,8 @@ namespace CodeImp.DoomBuilder.Map
 		private int tag;
 		private int action;
 		private int[] args;
-		protected float scale; //mxd. Used in model rendering
+		private float scale; //mxd. Used in model rendering
+		private bool isModel; //mxd
 
 		// Configuration
 		private float size;
@@ -69,7 +71,7 @@ namespace CodeImp.DoomBuilder.Map
 		#region ================== Properties
 
 		public MapSet Map { get { return map; } }
-        public int Type { get { return type; } set { BeforePropsChange(); type = value; } }
+		public int Type { get { return type; } set { BeforePropsChange(); type = value; UpdateModelStatus(); } } //mxd
 		public Vector3D Position { get { return pos; } }
 		public float Scale { get { return scale; } } //mxd
 		public float Angle { get { return anglerad; } }
@@ -83,8 +85,7 @@ namespace CodeImp.DoomBuilder.Map
 		public bool FixedSize { get { return fixedsize; } }
 		public int Tag { get { return tag; } set { BeforePropsChange(); tag = value; if((tag < General.Map.FormatInterface.MinTag) || (tag > General.Map.FormatInterface.MaxTag)) throw new ArgumentOutOfRangeException("Tag", "Invalid tag number"); } }
 		public Sector Sector { get { return sector; } }
-        //mxd
-        public bool IsModel;
+		public bool IsModel { get { return isModel; } } //mxd
 
         #endregion
 
@@ -181,9 +182,11 @@ namespace CodeImp.DoomBuilder.Map
 			s.rwInt(ref tag);
 			s.rwInt(ref action);
 			for(int i = 0; i < NUM_ARGS; i++) s.rwInt(ref args[i]);
-			
-			if(!s.IsWriting)
+
+			if(!s.IsWriting) {
 				anglerad = Angle2D.DoomToReal(angledoom);
+				UpdateModelStatus(); //mxd
+			}
 		}
 
 		// This copies all properties to another thing
@@ -193,6 +196,7 @@ namespace CodeImp.DoomBuilder.Map
 			
 			// Copy properties
 			t.type = type;
+			t.UpdateModelStatus();
 			t.anglerad = anglerad;
 			t.angledoom = angledoom;
 			t.pos = pos;
@@ -235,6 +239,20 @@ namespace CodeImp.DoomBuilder.Map
 			}
 		}
 
+		//mxd. This checks if the thing has model override
+		internal void UpdateModelStatus() {
+			if(General.Map.Data == null) {
+				isModel = false;
+				return;
+			}
+
+			isModel = General.Map.Data.ModeldefEntries.ContainsKey(type);
+			if(!isModel) return;
+
+			if(General.Map.Data.ModeldefEntries[type].LoadState == ModelLoadState.None)
+				General.Map.Data.ProcessModel(type);
+		}
+
 		// This translates the flags into UDMF fields
 		internal void TranslateToUDMF()
 		{
@@ -405,6 +423,7 @@ namespace CodeImp.DoomBuilder.Map
 			this.args = new int[NUM_ARGS];
 			args.CopyTo(this.args, 0);
 			this.Move(x, y, zoffset);
+			UpdateModelStatus(); //mxd
 		}
 		
 		// This updates the settings from configuration
diff --git a/Source/Core/Rendering/IRenderer2D.cs b/Source/Core/Rendering/IRenderer2D.cs
index 9d564564f..fd4fb6546 100644
--- a/Source/Core/Rendering/IRenderer2D.cs
+++ b/Source/Core/Rendering/IRenderer2D.cs
@@ -48,7 +48,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		PixelColor DetermineThingColor(Thing t);
 		int DetermineVertexColor(Vertex v);
 		int CalculateBrightness(int level);
-		void Update3dFloorTagsList(); //mxd
+		void UpdateExtraFloorFlag(); //mxd
 		
 		// Rendering management methods
 		bool StartPlotter(bool clear);
diff --git a/Source/Core/Rendering/Renderer2D.cs b/Source/Core/Rendering/Renderer2D.cs
index 35d529047..43716b518 100644
--- a/Source/Core/Rendering/Renderer2D.cs
+++ b/Source/Core/Rendering/Renderer2D.cs
@@ -39,7 +39,7 @@ namespace CodeImp.DoomBuilder.Rendering
 	 * PresentationLayer(s) to specify how to present these layers.
 	 */
 
-	internal unsafe sealed class Renderer2D : Renderer, IRenderer2D
+	internal sealed class Renderer2D : Renderer, IRenderer2D
 	{
 		#region ================== Constants
 
@@ -49,7 +49,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		private const float THING_CIRCLE_SIZE = 1f;
 		private const float THING_CIRCLE_SHRINK = 0f;
 		private const int THING_BUFFER_SIZE = 100;
-		//private const float THINGS_BACK_ALPHA = 0.3f;
+		private const float MINIMUM_THING_RADIUS = 1.5f; //mxd
 
 		private const string FONT_NAME = "Verdana";
 		private const int FONT_WIDTH = 0;
@@ -128,8 +128,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		private Presentation present;
 
         //mxd
-        private Dictionary<Vector2D, Thing> thingsWithModel;
-		private List<int> tagsOf3DFloors;
+		private Dictionary<int, Dictionary<Vector2D, Thing>> thingsWithModel; //model index, list of thing positions in screen space, thing
 		
 		#endregion
 
@@ -165,7 +164,6 @@ namespace CodeImp.DoomBuilder.Rendering
 
 			// Create surface manager
 			surfaces = new SurfaceManager();
-			tagsOf3DFloors = new List<int>(); //mxd
 
 			// Create rendertargets
 			CreateRendertargets();
@@ -203,7 +201,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		}
 		
 		// This draws the image on screen
-		public void Present()
+		public unsafe void Present()
 		{
 			General.Plugins.OnPresentDisplayBegin();
 			
@@ -398,7 +396,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		}
 		
 		// Allocates new image memory to render on
-		public void CreateRendertargets()
+		public unsafe void CreateRendertargets()
 		{
 			SurfaceDescription sd;
 			DataStream stream;
@@ -581,16 +579,17 @@ namespace CodeImp.DoomBuilder.Rendering
 		public PixelColor DetermineThingColor(Thing t)
 		{
 			// Determine color
-            if (t.Selected) {
-                return General.Colors.Selection;
-            //mxd. if thing is light, set it's color to light color:
-            }else if(Array.IndexOf(GZBuilder.GZGeneral.GZ_LIGHTS, t.Type) != -1){
+            if (t.Selected) return General.Colors.Selection;
+           
+			//mxd. if thing is light, set it's color to light color:
+			if(Array.IndexOf(GZBuilder.GZGeneral.GZ_LIGHTS, t.Type) != -1){
                 if (t.Type == 1502) //vavoom light
                     return new PixelColor(255, 255, 255, 255);
                 if (t.Type == 1503) //vavoom colored light
                     return new PixelColor(255, (byte)t.Args[1], (byte)t.Args[2], (byte)t.Args[3]);
                 return new PixelColor(255, (byte)t.Args[0], (byte)t.Args[1], (byte)t.Args[2]);
             }
+
             return t.Color;
 		}
 
@@ -605,34 +604,48 @@ namespace CodeImp.DoomBuilder.Rendering
 		// This returns the color for a linedef
 		public PixelColor DetermineLinedefColor(Linedef l)
 		{
-			if(l.Selected)
-				return General.Colors.Selection;
-			
-            if(l.ImpassableFlag)
-			{
-                //mxd. Impassable lines
-                if(l.ColorPresetIndex != -1)
-                    return General.Map.ConfigSettings.LinedefColorPresets[l.ColorPresetIndex].Color;
-                return General.Colors.Linedefs;
+			if(l.Selected) return General.Colors.Selection;
+
+			//mxd. Impassable lines
+			if(l.ImpassableFlag) {
+				if(l.ColorPresetIndex != -1)
+					return General.Map.ConfigSettings.LinedefColorPresets[l.ColorPresetIndex].Color;
+				return General.Colors.Linedefs;
 			}
 
-            //mxd. Passable lines
-            if(l.ColorPresetIndex != -1)
-                return General.Map.ConfigSettings.LinedefColorPresets[l.ColorPresetIndex].Color.WithAlpha(General.Settings.DoubleSidedAlphaByte);
-            return General.Colors.Linedefs.WithAlpha(General.Settings.DoubleSidedAlphaByte);
+			//mxd. Passable lines
+			if(l.ColorPresetIndex != -1)
+				return General.Map.ConfigSettings.LinedefColorPresets[l.ColorPresetIndex].Color.WithAlpha(General.Settings.DoubleSidedAlphaByte);
+			return General.Colors.Linedefs.WithAlpha(General.Settings.DoubleSidedAlphaByte);
 		}
 
-		//mxd
-		public void Update3dFloorTagsList() {
-			//mxd. Collect 3d-floors tags
-			tagsOf3DFloors = new List<int>();
+		//mxd. This collects indices of linedefs, which are parts of sectors with 3d floors
+		public void UpdateExtraFloorFlag() {
+			List<int> tagList = new List<int>();
+			
+			//find lines with 3d floor action and collect sector tags
 			foreach(Linedef l in General.Map.Map.Linedefs){
 				if(l.Action == 160) {
 					int sectortag = (l.Args[1] & 8) != 0 ? l.Args[0] : l.Args[0] + (l.Args[4] << 8);
+					if(sectortag != 0) tagList.Add(sectortag);
+				}
+			}
 
-					if(sectortag != 0 && !tagsOf3DFloors.Contains(sectortag))
-						tagsOf3DFloors.Add(sectortag);
+			tagList.Sort();
+			int[] tags = tagList.ToArray();
+
+			//find lines, which are related to sectors with 3d floors, and collect their valuable indices
+			foreach(Linedef l in General.Map.Map.Linedefs) {
+				if(l.Front != null && l.Front.Sector != null && l.Front.Sector.Tag != 0 && Array.BinarySearch(tags, l.Front.Sector.Tag) > -1) {
+					l.ExtraFloorFlag = true;
+					continue;
+				}
+				if(l.Back != null && l.Back.Sector != null && l.Back.Sector.Tag != 0 && Array.BinarySearch(tags, l.Back.Sector.Tag) > -1) {
+					l.ExtraFloorFlag = true;
+					continue;
 				}
+
+				l.ExtraFloorFlag = false;
 			}
 		}
 
@@ -643,10 +656,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		// This begins a drawing session
 		public unsafe bool StartPlotter(bool clear)
 		{
-			if(renderlayer != RenderLayers.None) {
-				//throw new InvalidOperationException("Renderer starting called before finished previous layer. Call Finish() first!");
-				return false; //mxd. Can't render. Most probably because previous frame or render layer wasn't finished yet.
-			}
+			if(renderlayer != RenderLayers.None) return false; //mxd. Can't render. Most probably because previous frame or render layer wasn't finished yet.
 
 			renderlayer = RenderLayers.Plotter;
 			try { graphics.Device.SetRenderState(RenderState.FogEnable, false); } catch(Exception) { }
@@ -672,21 +682,16 @@ namespace CodeImp.DoomBuilder.Rendering
 				UpdateTransformations();
 				return true;
 			}
-			else
-			{
-				// Can't render!
-				Finish();
-				return false;
-			}
+
+			// Can't render!
+			Finish();
+			return false;
 		}
 
 		// This begins a drawing session
-		public unsafe bool StartThings(bool clear)
+		public bool StartThings(bool clear)
 		{
-			if(renderlayer != RenderLayers.None) {
-				//throw new InvalidOperationException("Renderer starting called before finished previous layer. Call Finish() first!");
-				return false; //mxd. Can't render. Most probably because previous frame or render layer wasn't finished yet.
-			}
+			if(renderlayer != RenderLayers.None) return false;  //mxd. Can't render. Most probably because previous frame or render layer wasn't finished yet.
 
 			renderlayer = RenderLayers.Things;
 			try { graphics.Device.SetRenderState(RenderState.FogEnable, false); } catch(Exception) { }
@@ -702,29 +707,21 @@ namespace CodeImp.DoomBuilder.Rendering
 					UpdateTransformations();
 					return true;
 				}
-				else
-				{
-					// Can't render!
-					Finish();
-					return false;
-				}
-			}
-			else
-			{
+
 				// Can't render!
 				Finish();
 				return false;
 			}
+
+			// Can't render!
+			Finish();
+			return false;
 		}
 
 		// This begins a drawing session
-		public unsafe bool StartOverlay(bool clear)
+		public bool StartOverlay(bool clear)
 		{
-			if(renderlayer != RenderLayers.None) {
-				//throw new InvalidOperationException("Renderer starting called before finished previous layer. Call Finish() first!");
-				return false; //mxd. Can't render. Most probably because previous frame or render layer wasn't finished yet.
-			}
-
+			if(renderlayer != RenderLayers.None) throw new InvalidOperationException("Renderer starting called before finished previous layer. Call Finish() first!");
 			renderlayer = RenderLayers.Overlay;
 			try { graphics.Device.SetRenderState(RenderState.FogEnable, false); } catch(Exception) { }
 			
@@ -739,19 +736,15 @@ namespace CodeImp.DoomBuilder.Rendering
 					UpdateTransformations();
 					return true;
 				}
-				else
-				{
-					// Can't render!
-					Finish();
-					return false;
-				}
-			}
-			else
-			{
+
 				// Can't render!
 				Finish();
 				return false;
 			}
+
+			// Can't render!
+			Finish();
+			return false;
 		}
 
 		// This ends a drawing session
@@ -794,8 +787,8 @@ namespace CodeImp.DoomBuilder.Rendering
 		private void SetupBackground()
 		{
 			Vector2D ltpos, rbpos;
-			Vector2D backoffset = new Vector2D((float)General.Map.Grid.BackgroundX, (float)General.Map.Grid.BackgroundY);
-			Vector2D backimagesize = new Vector2D((float)General.Map.Grid.Background.ScaledWidth, (float)General.Map.Grid.Background.ScaledHeight);
+			Vector2D backoffset = new Vector2D(General.Map.Grid.BackgroundX, General.Map.Grid.BackgroundY);
+			Vector2D backimagesize = new Vector2D(General.Map.Grid.Background.ScaledWidth, General.Map.Grid.Background.ScaledHeight);
 			Vector2D backimagescale = new Vector2D(General.Map.Grid.BackgroundScaleX, General.Map.Grid.BackgroundScaleY);
 			
 			// Scale the background image size
@@ -835,7 +828,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		}
 
 		// This renders all grid
-		private void RenderBackgroundGrid()
+		private unsafe void RenderBackgroundGrid()
 		{
 			Plotter gridplotter;
 			DataRectangle lockedrect;
@@ -951,9 +944,10 @@ namespace CodeImp.DoomBuilder.Rendering
 		// Returns false when not on the screen
 		private bool CreateThingVerts(Thing t, ref FlatVertex[] verts, int offset, PixelColor c)
 		{
+			if(t.Size * scale < MINIMUM_THING_RADIUS) return false; //mxd. Don't render tiny little things
+			
 			float circlesize;
 			float arrowsize;
-			int color;
 			
 			// Transform to screen coordinates
 			Vector2D screenpos = ((Vector2D)t.Position).GetTransformed(translatex, translatey, scale, -scale);
@@ -971,20 +965,24 @@ namespace CodeImp.DoomBuilder.Rendering
 			}
 			
 			// Check if the thing is actually on screen
-			if(((screenpos.x + circlesize) > 0.0f) && ((screenpos.x - circlesize) < (float)windowsize.Width) &&
-				((screenpos.y + circlesize) > 0.0f) && ((screenpos.y - circlesize) < (float)windowsize.Height))
+			if(((screenpos.x + circlesize) > 0.0f) && ((screenpos.x - circlesize) < windowsize.Width) &&
+				((screenpos.y + circlesize) > 0.0f) && ((screenpos.y - circlesize) < windowsize.Height))
 			{
                 //mxd. Collect things with models for rendering
-                if (General.Settings.GZDrawModels && (!General.Settings.GZDrawSelectedModelsOnly || t.Selected)) {
-                    Dictionary<int, ModeldefEntry> mde = General.Map.Data.ModeldefEntries;
-                    if (mde != null && mde.ContainsKey(t.Type)) {
-                        thingsWithModel[screenpos] = t;
-                    }
+				if(t.IsModel && General.Settings.GZDrawModels && (!General.Settings.GZDrawSelectedModelsOnly || t.Selected)) {
+					if(!thingsWithModel.ContainsKey(t.Type)) {
+						thingsWithModel.Add(t.Type, new Dictionary<Vector2D, Thing>());
+					}
+
+					if(thingsWithModel[t.Type].ContainsKey(screenpos)) {
+						thingsWithModel[t.Type][screenpos] = t;
+					} else {
+						thingsWithModel[t.Type].Add(screenpos, t);
+					}
                 }
                 
-                
                 // Get integral color
-				color = c.ToInt();
+				int color = c.ToInt();
 
 				// Setup fixed rect for circle
 				verts[offset].x = screenpos.x - circlesize;
@@ -1051,11 +1049,9 @@ namespace CodeImp.DoomBuilder.Rendering
 				// Done
 				return true;
 			}
-			else
-			{
-				// Not on screen
-				return false;
-			}
+
+			// Not on screen
+			return false;
 		}
 		
 		// This draws a set of things
@@ -1099,7 +1095,7 @@ namespace CodeImp.DoomBuilder.Rendering
 				FlatVertex[] verts = new FlatVertex[THING_BUFFER_SIZE * 12];
 
                 //mxd
-                thingsWithModel = new Dictionary<Vector2D, Thing>();
+				thingsWithModel = new Dictionary<int, Dictionary<Vector2D, Thing>>();
 
 				// Go for all things
 				int buffercount = 0;
@@ -1152,25 +1148,28 @@ namespace CodeImp.DoomBuilder.Rendering
 					graphics.Device.SetRenderState(RenderState.FillMode, FillMode.Wireframe);
 
                     graphics.Shaders.Things2D.BeginPass(1);
-                    foreach(KeyValuePair<Vector2D, Thing> group in thingsWithModel){
-                        ModeldefEntry mde = General.Map.Data.ModeldefEntries[group.Value.Type];
-
-                        if (mde.Model != null) {//render model
-                            //wire color
-                            graphics.Shaders.Things2D.FillColor = group.Value.Selected ? General.Colors.Selection.ToColorValue() : General.Colors.ModelWireframe.ToColorValue();
 
-                            for (int i = 0; i < mde.Model.Meshes.Count; i++) {
-								graphics.Shaders.Things2D.SetTransformSettings(group.Key, group.Value.Angle, scale * group.Value.Scale);
-                                graphics.Shaders.Things2D.ApplySettings();
-
-                                // Draw
-								mde.Model.Meshes[i].DrawSubset(0);
-                            }
+					Color4 cSel = General.Colors.Selection.ToColorValue();
+					Color4 cWire = General.Colors.ModelWireframe.ToColorValue();
+					ModelData mde;
+
+					foreach(KeyValuePair<int, Dictionary<Vector2D, Thing>> group in thingsWithModel) {
+						lock(General.Map.Data.ModeldefEntries[group.Key]) {
+							mde = General.Map.Data.ModeldefEntries[group.Key];
+							foreach(KeyValuePair<Vector2D, Thing> thingData in group.Value) {
+								graphics.Shaders.Things2D.FillColor = thingData.Value.Selected ? cSel : cWire;
+
+								for(int i = 0; i < mde.Model.Meshes.Count; i++) {
+									graphics.Shaders.Things2D.SetTransformSettings(thingData.Key, thingData.Value.Angle, scale * thingData.Value.Scale);
+									graphics.Shaders.Things2D.ApplySettings();
+
+									// Draw
+									mde.Model.Meshes[i].DrawSubset(0);
+								}
+							}
+						}
+					}
 
-                        } else {
-                            group.Value.IsModel = General.Map.Data.LoadModelForThing(group.Value);
-                        }
-                    }
                     graphics.Shaders.Things2D.EndPass();
 
 					graphics.Device.SetRenderState(RenderState.FillMode, FillMode.Solid);
@@ -1201,9 +1200,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		// This redraws the surface
 		public void RedrawSurface()
 		{
-			//mxd...
-			//if(renderlayer != RenderLayers.None) throw new InvalidOperationException("Renderer starting called before finished previous layer. Call Finish() first!");
-			if(renderlayer != RenderLayers.None) return;
+			if(renderlayer != RenderLayers.None) return; //mxd
 			renderlayer = RenderLayers.Surface;
 
 			// Rendertargets available?
@@ -1597,33 +1594,20 @@ namespace CodeImp.DoomBuilder.Rendering
 			Vector2D v2 = l.End.Position.GetTransformed(translatex, translatey, scale, -scale);
 
 			//mxd. Newly created sectors colouring
-			if(General.Settings.GZNewSectorsCount > 0 && c.r == 255 && c.g == 255 && c.b == 255){
-				int frontIndex = -1;
-				int backIndex = -1;
-
-				if(l.Front != null)
-					frontIndex = Array.IndexOf(General.Map.Map.NewSectors, l.Front.Sector);
-				if(l.Back != null)
-					backIndex = Array.IndexOf(General.Map.Map.NewSectors, l.Back.Sector);
-				
-				if(frontIndex != -1 || backIndex != -1){
+			if(General.Settings.GZNewSectorsCount > 0 && l.ColorPresetIndex == -1){
+				if(General.Map.Map.NewSectorLineIndices.ContainsKey(l.Index)){
+					int index = General.Map.Map.NewSectorLineIndices[l.Index];
 					PixelColor highlight = General.Colors.NewSector;
-
-					if(frontIndex > backIndex)
-						highlight.a = (byte)(255 * (1.0f - (float)(frontIndex + 1) / General.Map.Map.NewSectors.Length));
-					else
-						highlight.a = (byte)(255 * (1.0f - (float)(backIndex + 1) / General.Map.Map.NewSectors.Length));
-
-					float ba = (float)highlight.a * PixelColor.BYTE_TO_FLOAT;
-					c.r = (byte)Math.Min(255, ((float)highlight.r * (1f - ba) + (float)c.r * ba));
-					c.g = (byte)Math.Min(255, ((float)highlight.g * (1f - ba) + (float)c.g * ba));
-					c.b = (byte)Math.Min(255, ((float)highlight.b * (1f - ba) + (float)c.b * ba));
+					highlight.a = (byte)(255 * (1.0f - (float)(index + 1) / General.Settings.GZNewSectorsCount));
+					float ha = highlight.a * PixelColor.BYTE_TO_FLOAT;
+					c.r = (byte)Math.Min(255, (highlight.r * (1f - ha) + c.r * ha));
+					c.g = (byte)Math.Min(255, (highlight.g * (1f - ha) + c.g * ha));
+					c.b = (byte)Math.Min(255, (highlight.b * (1f - ha) + c.b * ha));
 				}
 			}
 
 			// Draw line. mxd: added 3d-floor indication
-			if((l.Front != null && l.Front.Sector != null && tagsOf3DFloors.Contains(l.Front.Sector.Tag)) ||
-				(l.Back != null && l.Back.Sector != null && tagsOf3DFloors.Contains(l.Back.Sector.Tag))) {
+			if(l.ExtraFloorFlag) {
 				plotter.DrawLine3DFloor(v1, v2, ref c, General.Colors.ThreeDFloor);
 			} else {
 				plotter.DrawLineSolid((int)v1.x, (int)v1.y, (int)v2.x, (int)v2.y, ref c);
diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs
index 49531ab9b..1bbd972e5 100644
--- a/Source/Core/Rendering/Renderer3D.cs
+++ b/Source/Core/Rendering/Renderer3D.cs
@@ -74,7 +74,7 @@ namespace CodeImp.DoomBuilder.Rendering
         private List<VisualThing> thingsWithLight;
         private int[] lightOffsets;
         private Dictionary<Texture, List<VisualGeometry>> litGeometry;
-        private Dictionary<ModeldefEntry, List<VisualThing>> thingsWithModel;
+        private Dictionary<ModelData, List<VisualThing>> thingsWithModel;
 		
 		// Crosshair
 		private FlatVertex[] crosshairverts;
@@ -418,7 +418,7 @@ namespace CodeImp.DoomBuilder.Rendering
 			things = new Dictionary<ImageData, List<VisualThing>>[RENDER_PASSES];
 			thingsbydistance = new BinaryHeap<VisualThing>();
             //mxd 
-            thingsWithModel = new Dictionary<ModeldefEntry, List<VisualThing>>();
+            thingsWithModel = new Dictionary<ModelData, List<VisualThing>>();
             litGeometry = new Dictionary<Texture, List<VisualGeometry>>();
 
 			for(int i = 0; i < RENDER_PASSES; i++)
@@ -537,9 +537,9 @@ namespace CodeImp.DoomBuilder.Rendering
             lightOffsets = new int[3];
             foreach (VisualThing t in thingsWithLight) {
                 //add light to apropriate array.
-                if (t.LightRenderStyle == (int)GZDoomLightRenderStyle.NORMAL || t.LightRenderStyle == (int)GZDoomLightRenderStyle.VAVOOM)
+                if (t.LightRenderStyle == DynamicLightRenderStyle.NORMAL || t.LightRenderStyle == DynamicLightRenderStyle.VAVOOM)
                     lightOffsets[0]++;
-                else if (t.LightRenderStyle == (int)GZDoomLightRenderStyle.ADDITIVE)
+                else if (t.LightRenderStyle == DynamicLightRenderStyle.ADDITIVE)
                     lightOffsets[1]++;
                 else
                     lightOffsets[2]++;
@@ -857,7 +857,7 @@ namespace CodeImp.DoomBuilder.Rendering
 						foreach(VisualThing t in group.Value)
 						{
                             //mxd
-                            if (General.Settings.GZDrawModels && (!General.Settings.GZDrawSelectedModelsOnly || t.Selected) && t.Thing.IsModel)
+                            if (t.Thing.IsModel && General.Settings.GZDrawModels && (!General.Settings.GZDrawSelectedModelsOnly || t.Selected))
                                 continue;
 
                             // Update buffer if needed
@@ -1028,7 +1028,7 @@ namespace CodeImp.DoomBuilder.Rendering
             // Begin rendering with this shader
             graphics.Shaders.World3D.BeginPass(currentshaderpass);
 
-            foreach (KeyValuePair<ModeldefEntry, List<VisualThing>> group in thingsWithModel) {
+            foreach (KeyValuePair<ModelData, List<VisualThing>> group in thingsWithModel) {
                 foreach (VisualThing t in group.Value) {
                     t.Update();
                     
@@ -1110,7 +1110,7 @@ namespace CodeImp.DoomBuilder.Rendering
                 radius = thingsWithLight[i].LightRadius;
                 radiusSquared = radius * radius;
                 if (distSquared < radiusSquared) {
-                    sign = thingsWithLight[i].LightRenderStyle == (int)GZDoomLightRenderStyle.NEGATIVE ? -1 : 1;
+                    sign = thingsWithLight[i].LightRenderStyle == DynamicLightRenderStyle.NEGATIVE ? -1 : 1;
                     scaler = 1 - distSquared / radiusSquared * thingsWithLight[i].LightColor.Alpha;
                     litColor.Red += thingsWithLight[i].LightColor.Red * scaler * sign;
                     litColor.Green += thingsWithLight[i].LightColor.Green * scaler * sign;
@@ -1196,7 +1196,7 @@ namespace CodeImp.DoomBuilder.Rendering
 		public void AddThingGeometry(VisualThing t)
 		{
             //mxd. gater lights
-            if (General.Settings.GZDrawLights && !fullbrightness && t.LightType != -1) {
+            if (General.Settings.GZDrawLights && !fullbrightness && t.LightType != DynamicLightType.NONE) {
                 t.UpdateLightRadius();
 
                 if (t.LightRadius > 0) {
@@ -1210,16 +1210,15 @@ namespace CodeImp.DoomBuilder.Rendering
                 }
             }
 
-            if (!isThingOnScreen(t.BoundingBox)) {
-                return;
-            }
+            if (!isThingOnScreen(t.BoundingBox)) return;
 
             //mxd. gather models
-            if (General.Settings.GZDrawModels && (!General.Settings.GZDrawSelectedModelsOnly || t.Selected) && t.Thing.IsModel) {
-                ModeldefEntry mde = General.Map.Data.ModeldefEntries[t.Thing.Type];
-                if (!thingsWithModel.ContainsKey(mde)) 
-                    thingsWithModel.Add(mde, new List<VisualThing>());
-                thingsWithModel[mde].Add(t);
+			if(t.Thing.IsModel && General.Settings.GZDrawModels && (!General.Settings.GZDrawSelectedModelsOnly || t.Selected)) {
+                ModelData mde = General.Map.Data.ModeldefEntries[t.Thing.Type];
+                if (!thingsWithModel.ContainsKey(mde))
+					thingsWithModel.Add(mde, new List<VisualThing>() { t });
+				else
+					thingsWithModel[mde].Add(t);
             }
             
             // Make sure the distance to camera is calculated
diff --git a/Source/Core/VisualModes/VisualThing.cs b/Source/Core/VisualModes/VisualThing.cs
index d20dcc813..5266092f0 100644
--- a/Source/Core/VisualModes/VisualThing.cs
+++ b/Source/Core/VisualModes/VisualThing.cs
@@ -75,8 +75,8 @@ namespace CodeImp.DoomBuilder.VisualModes
 		protected Matrix scale; //mxd. Used in model rendering
 
         //mxd. light properties
-        private int lightType;
-        private int lightRenderStyle;
+        private DynamicLightType lightType;
+        private DynamicLightRenderStyle lightRenderStyle;
         private Color4 lightColor;
         private float lightRadius; //current radius. used in light animation
         private float lightPrimaryRadius;
@@ -118,9 +118,9 @@ namespace CodeImp.DoomBuilder.VisualModes
         public Vector3 PositionV3 { get { return position_v3; } }
         public Vector3[] BoundingBox { get { return boundingBox; } }
         //mxd. light properties
-        public int LightType { get { return lightType; } }
+        public DynamicLightType LightType { get { return lightType; } }
         public float LightRadius { get { return lightRadius; } }
-        public int LightRenderStyle { get { return lightRenderStyle; } }
+        public DynamicLightRenderStyle LightRenderStyle { get { return lightRenderStyle; } }
         public Color4 LightColor { get { return lightColor; } }
 
 		/// <summary>
@@ -171,8 +171,8 @@ namespace CodeImp.DoomBuilder.VisualModes
 			this.scale = Matrix.Identity; //mxd
 
             //mxd
-            lightType = -1;
-            lightRenderStyle = -1;
+            lightType = DynamicLightType.NONE;
+            lightRenderStyle = DynamicLightRenderStyle.NONE;
             lightPrimaryRadius = -1;
             lightSecondaryRadius = -1;
             lightInterval = -1;
@@ -265,7 +265,7 @@ namespace CodeImp.DoomBuilder.VisualModes
             //mxd. update bounding box
             if (thing.IsModel) {
                 updateBoundingBoxForModel();
-            } else if (lightType != -1 && lightRadius > thing.Size) {
+            } else if (lightType != DynamicLightType.NONE && lightRadius > thing.Size) {
                 updateBoundingBox(lightRadius, lightRadius * 2);
             } else {
                 updateBoundingBox((int)thing.Size, thingHeight);
@@ -301,9 +301,6 @@ namespace CodeImp.DoomBuilder.VisualModes
             // Do we need to update the geometry buffer?
             if (updategeo)
 			{
-                //mxd. check if thing is model
-                checkModelState();
-
                 // Trash geometry buffer
                 if (geobuffer != null) geobuffer.Dispose();
                 geobuffer = null;
@@ -316,7 +313,7 @@ namespace CodeImp.DoomBuilder.VisualModes
 
                     // Fill the buffer
                     DataStream bufferstream = geobuffer.Lock(0, WorldVertex.Stride * vertices.Length, LockFlags.Discard);
-                    bufferstream.WriteRange<WorldVertex>(vertices);
+                    bufferstream.WriteRange(vertices);
                     geobuffer.Unlock();
                     bufferstream.Dispose();
                 }
@@ -329,18 +326,6 @@ namespace CodeImp.DoomBuilder.VisualModes
 			}
 		}
 
-        //mxd
-        protected void checkModelState() {
-            if (General.Map.Data.ModeldefEntries.ContainsKey(thing.Type)) {
-                if (General.Map.Data.ModeldefEntries[thing.Type].Model == null)
-                    thing.IsModel = General.Map.Data.LoadModelForThing(thing);
-                else
-                    thing.IsModel = true;
-            } else {
-                thing.IsModel = false;
-            }
-        }
-
         //mxd
         protected void checkLightState() {
             //mxd. Check if thing is light
@@ -362,11 +347,11 @@ namespace CodeImp.DoomBuilder.VisualModes
                 } else {
                     updateBoundingBox((int)thing.Size, thingHeight);
                 }
-                lightType = -1;
+                lightType = DynamicLightType.NONE;
                 lightRadius = -1;
                 lightPrimaryRadius = -1;
                 lightSecondaryRadius = -1;
-                lightRenderStyle = -1;
+                lightRenderStyle = DynamicLightRenderStyle.NONE;
                 lightInterval = -1;
                 isGldefsLight = false;
             }
@@ -389,21 +374,21 @@ namespace CodeImp.DoomBuilder.VisualModes
                 int n;
                 if (light_id < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[0]) {
                     n = 0;
-                    lightRenderStyle = (int)GZDoomLightRenderStyle.NORMAL;
+                    lightRenderStyle = DynamicLightRenderStyle.NORMAL;
                     //lightColor.Alpha used in shader to perform some calculations based on light type
                     lightColor = new Color4((float)lightRenderStyle / 100.0f, (float)thing.Args[0] / scaled_intensity, (float)thing.Args[1] / scaled_intensity, (float)thing.Args[2] / scaled_intensity);
                 } else if (light_id < GZBuilder.GZGeneral.GZ_LIGHT_TYPES[1]) {
                     n = 10;
-                    lightRenderStyle = (int)GZDoomLightRenderStyle.ADDITIVE;
+                    lightRenderStyle = DynamicLightRenderStyle.ADDITIVE;
                     lightColor = new Color4((float)lightRenderStyle / 100.0f, (float)thing.Args[0] / scaled_intensity, (float)thing.Args[1] / scaled_intensity, (float)thing.Args[2] / scaled_intensity);
                 } else {
                     n = 20;
-                    lightRenderStyle = (int)GZDoomLightRenderStyle.NEGATIVE;
+                    lightRenderStyle = DynamicLightRenderStyle.NEGATIVE;
                     lightColor = new Color4((float)lightRenderStyle / 100.0f, (float)thing.Args[0] / scaled_intensity, (float)thing.Args[1] / scaled_intensity, (float)thing.Args[2] / scaled_intensity);
                 }
-                lightType = thing.Type - 9800 - n;
+                lightType = (DynamicLightType)(thing.Type - 9800 - n);
 
-                if (lightType == (int)GZDoomLightType.SECTOR) {
+                if (lightType == DynamicLightType.SECTOR) {
                     int scaler = 1;
                     if (thing.Sector != null)
                         scaler = thing.Sector.Brightness / 4;
@@ -414,9 +399,9 @@ namespace CodeImp.DoomBuilder.VisualModes
                         lightSecondaryRadius = (float)(thing.Args[4] * 2) * General.Settings.GZDynamicLightRadius;
                 }
             } else { //it's one of vavoom lights
-                lightRenderStyle = (int)GZDoomLightRenderStyle.VAVOOM;
-                lightType = thing.Type;
-                if (lightType == (int)GZDoomLightType.VAVOOM_COLORED)
+                lightRenderStyle = DynamicLightRenderStyle.VAVOOM;
+				lightType = (DynamicLightType)thing.Type;
+                if (lightType == DynamicLightType.VAVOOM_COLORED)
                     lightColor = new Color4((float)lightRenderStyle / 100.0f, (float)thing.Args[1] / scaled_intensity, (float)thing.Args[2] / scaled_intensity, (float)thing.Args[3] / scaled_intensity);
                 else
                     lightColor = new Color4((float)lightRenderStyle / 100.0f, General.Settings.GZDynamicLightIntensity, General.Settings.GZDynamicLightIntensity, General.Settings.GZDynamicLightIntensity);
@@ -427,17 +412,17 @@ namespace CodeImp.DoomBuilder.VisualModes
 
         //mxd
         private void updateGldefsLight() {
-            GZDoomLight light = General.Map.Data.GldefsEntries[thing.Type];
+            DynamicLightData light = General.Map.Data.GldefsEntries[thing.Type];
             float intensity_mod = General.Settings.GZDynamicLightIntensity;
             float scale_mod = General.Settings.GZDynamicLightRadius;
 
             //apply settings
-            lightRenderStyle = light.Subtractive ? (int)GZDoomLightRenderStyle.NEGATIVE : (int)GZDoomLightRenderStyle.NORMAL;
+            lightRenderStyle = light.Subtractive ? DynamicLightRenderStyle.NEGATIVE : DynamicLightRenderStyle.NORMAL;
             lightColor = new Color4((float)lightRenderStyle / 100.0f, light.Color.Red * intensity_mod, light.Color.Green * intensity_mod, light.Color.Blue * intensity_mod);
             lightOffset = light.Offset;
             lightType = light.Type;
 
-            if (lightType == (int)GZDoomLightType.SECTOR) {
+            if (lightType == DynamicLightType.SECTOR) {
                 lightPrimaryRadius = light.Interval * thing.Sector.Brightness / 5;
             } else {
                 lightPrimaryRadius = light.PrimaryRadius * scale_mod;
@@ -456,7 +441,7 @@ namespace CodeImp.DoomBuilder.VisualModes
 
         //mxd
         private void updateLightRadius(int interval) {
-            if (lightType == -1) {
+            if (lightType == DynamicLightType.NONE) {
                 General.ErrorLogger.Add(ErrorType.Error, "Please check that thing is light before accessing it's PositionAndRadius! You can use lightType, which is -1 if thing isn't light");
                 return;
             }
@@ -473,11 +458,11 @@ namespace CodeImp.DoomBuilder.VisualModes
             float diff = rMax - rMin;
 
             //pulse
-            if (lightType == (int)GZDoomLightType.PULSE) {
+            if (lightType == DynamicLightType.PULSE) {
                 lightDelta = ((float)Math.Sin(time / (interval * 4.0f)) + 1.0f) / 2.0f; //just playing by the eye here... in [0.0 ... 1.0] interval
                 lightRadius = rMin + diff * lightDelta;
             //flicker
-            } else if (lightType == (int)GZDoomLightType.FLICKER) {
+            } else if (lightType == DynamicLightType.FLICKER) {
                 float delta = (float)Math.Sin(time / 0.1f); //just playing by the eye here...
                 if (Math.Sign(delta) != Math.Sign(lightDelta)) {
                     lightDelta = delta;
@@ -487,7 +472,7 @@ namespace CodeImp.DoomBuilder.VisualModes
                         lightRadius = rMin;
                 }
             //random
-            } else if (lightType == (int)GZDoomLightType.RANDOM) {
+            } else if (lightType == DynamicLightType.RANDOM) {
                 float delta = (float)Math.Sin(time / (interval * 9.0f)); //just playing by the eye here...
                 if (Math.Sign(delta) != Math.Sign(lightDelta))
                     lightRadius = rMin + (float)(new Random().Next(0, (int)(diff * 10))) / 10.0f;
@@ -500,7 +485,7 @@ namespace CodeImp.DoomBuilder.VisualModes
             //updateBoundingBox(lightRadius, lightRadius * 2f);
             if (thing.IsModel) {
                 updateBoundingBoxForModel();
-            } else if (lightType != -1 && lightRadius > thing.Size) {
+            } else if (lightType != DynamicLightType.NONE && lightRadius > thing.Size) {
                 updateBoundingBox(lightRadius, lightRadius * 2);
             } else {
                 updateBoundingBox((int)thing.Size, thingHeight);
@@ -525,7 +510,7 @@ namespace CodeImp.DoomBuilder.VisualModes
 
         //mxd. update bounding box from model bounding box
         private void updateBoundingBoxForModel() {
-            ModeldefEntry mde = General.Map.Data.ModeldefEntries[thing.Type];
+            ModelData mde = General.Map.Data.ModeldefEntries[thing.Type];
             int len = mde.Model.BoundingBox.Length;
             boundingBox = new Vector3[len];
             for (int i = 0; i < len; i++) {
diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs
index 195a544cf..4c1b76cfb 100644
--- a/Source/Core/Windows/MainForm.cs
+++ b/Source/Core/Windows/MainForm.cs
@@ -3084,11 +3084,11 @@ namespace CodeImp.DoomBuilder.Windows
 			if(warningsCount > 0) {
 				if(!warnsLabel.Font.Bold){
 					warnsLabel.Font = new Font(warnsLabel.Font, FontStyle.Bold);
-					warnsLabel.Image = global::CodeImp.DoomBuilder.Properties.Resources.Warning;
+					warnsLabel.Image = Resources.Warning;
 				}
 			} else {
 				warnsLabel.Font = new Font(warnsLabel.Font, FontStyle.Regular);
-				warnsLabel.Image = global::CodeImp.DoomBuilder.Properties.Resources.WarningOff;
+				warnsLabel.Image = Resources.WarningOff;
 				warnsLabel.BackColor = SystemColors.Control;
 			}
 
@@ -3107,11 +3107,11 @@ namespace CodeImp.DoomBuilder.Windows
 		private void blink() {
 			if(warnsLabel.BackColor == Color.Red) {
 				warnsLabel.Font = new Font(warnsLabel.Font, FontStyle.Regular);
-				warnsLabel.Image = global::CodeImp.DoomBuilder.Properties.Resources.WarningOff;
+				warnsLabel.Image = Resources.WarningOff;
 				warnsLabel.BackColor = SystemColors.Control;
 			} else {
 				warnsLabel.Font = new Font(warnsLabel.Font, FontStyle.Bold);
-				warnsLabel.Image = global::CodeImp.DoomBuilder.Properties.Resources.Warning;
+				warnsLabel.Image = Resources.Warning;
 				warnsLabel.BackColor = Color.Red;
 			}
 		}
diff --git a/Source/Core/ZDoom/TexturesParser.cs b/Source/Core/ZDoom/TexturesParser.cs
index 827119269..504969f9d 100644
--- a/Source/Core/ZDoom/TexturesParser.cs
+++ b/Source/Core/ZDoom/TexturesParser.cs
@@ -97,7 +97,7 @@ namespace CodeImp.DoomBuilder.ZDoom
 						{
 							// Add the texture
 							textures[tx.Name] = tx;
-							flats[tx.Name] = tx;
+							if(!General.Map.Config.MixTexturesFlats) flats[tx.Name] = tx; //mxd. If MixTexturesFlats is set, textures and flats will be mixed in DataManager anyway
 						}
 					}
 					else if(objdeclaration == "sprite")
diff --git a/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs b/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs
index 2221a3d2a..eafa7f785 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/BaseClassicMode.cs
@@ -99,7 +99,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		{
 			General.Map.Map.ClearAllSelected();
 			General.Map.Map.SelectMarkedGeometry(true, true);
-			General.Map.Renderer2D.Update3dFloorTagsList(); //mxd
+			General.Map.Renderer2D.UpdateExtraFloorFlag(); //mxd
 			
 			// Switch to EditSelectionMode
 			EditSelectionMode editmode = new EditSelectionMode();
@@ -144,12 +144,14 @@ namespace CodeImp.DoomBuilder.BuilderModes
 
 		//mxd
 		public override void OnUndoEnd() {
+			General.Map.Renderer2D.UpdateExtraFloorFlag();
 			base.OnUndoEnd();
 			updateSelectionInfo();
 		}
 
 		//mxd
 		public override void OnRedoEnd() {
+			General.Map.Renderer2D.UpdateExtraFloorFlag();
 			base.OnRedoEnd();
 			updateSelectionInfo();
 		}
diff --git a/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs b/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
index 2ccb34a7c..f6f99207c 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/BridgeMode.cs
@@ -117,6 +117,7 @@ namespace CodeImp.DoomBuilder.BuilderModes.ClassicModes {
         // Mouse moves
         public override void OnMouseMove(MouseEventArgs e) {
             base.OnMouseMove(e);
+			if(panning) return; //mxd. Skip all this jass while panning
 
             if (curControlHandle != -1) {
                 ControlHandle handle = controlHandles[curControlHandle];
diff --git a/Source/Plugins/BuilderModes/ClassicModes/BrightnessMode.cs b/Source/Plugins/BuilderModes/ClassicModes/BrightnessMode.cs
index e7b6f3409..b4338687f 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/BrightnessMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/BrightnessMode.cs
@@ -443,6 +443,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
+			if(panning) return; //mxd. Skip all this jass while panning
 			
 			// Not in any editing mode?
 			if(mode == ModifyMode.None) {
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs
index 0624b73e7..2dc88095b 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DragGeometryMode.cs
@@ -555,6 +555,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
+			if(panning) return; //mxd. Skip all this jass while panning
 			Update();
 		}
 		// When a key is released
diff --git a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
index 46172d15f..81fc36826 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/DrawGeometryMode.cs
@@ -541,6 +541,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
+			if(panning) return; //mxd. Skip all this jass while panning
 			Update();
 		}
 
diff --git a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
index f380f5701..54f26843a 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/EditSelectionMode.cs
@@ -1381,7 +1381,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
-
+			if(panning) return; //mxd. Skip all this jass while panning
 			Update();
 		}
 
diff --git a/Source/Plugins/BuilderModes/ClassicModes/FlatAlignMode.cs b/Source/Plugins/BuilderModes/ClassicModes/FlatAlignMode.cs
index 580a577c4..423f53d21 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/FlatAlignMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/FlatAlignMode.cs
@@ -735,7 +735,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
-
+			if(panning) return; //mxd. Skip all this jass while panning
 			Update();
 		}
 
diff --git a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
index bf631c8f8..cfdfc75a8 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/LinedefsMode.cs
@@ -321,10 +321,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			if(renderer.StartPlotter(true))
 			{
 				renderer.PlotLinedefSet(General.Map.Map.Linedefs);
-				for(int i = 0; i < Linedef.NUM_ARGS; i++) BuilderPlug.Me.PlotAssociations(renderer, association[i]);
+				if(!panning) //mxd
+					for(int i = 0; i < Linedef.NUM_ARGS; i++) BuilderPlug.Me.PlotAssociations(renderer, association[i]);
 				if((highlighted != null) && !highlighted.IsDisposed)
 				{
-					BuilderPlug.Me.PlotReverseAssociations(renderer, highlightasso);
+					if(!panning) BuilderPlug.Me.PlotReverseAssociations(renderer, highlightasso); //mxd
 					renderer.PlotLinedef(highlighted, General.Colors.Highlight);
 				}
 				renderer.PlotVerticesSet(General.Map.Map.Vertices);
@@ -342,8 +343,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Render selection
 			if(renderer.StartOverlay(true))
 			{
-				for(int i = 0; i < Linedef.NUM_ARGS; i++) BuilderPlug.Me.RenderAssociations(renderer, association[i]);
-				if((highlighted != null) && !highlighted.IsDisposed) BuilderPlug.Me.RenderReverseAssociations(renderer, highlightasso);
+				if(!panning) //mxd
+					for(int i = 0; i < Linedef.NUM_ARGS; i++) BuilderPlug.Me.RenderAssociations(renderer, association[i]);
+				if(!panning && (highlighted != null) && !highlighted.IsDisposed) BuilderPlug.Me.RenderReverseAssociations(renderer, highlightasso); //mxd
 				if(selecting) RenderMultiSelection();
 				renderer.Finish();
 			}
@@ -473,7 +475,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						if(selected.Count == 1) General.Map.Map.ClearSelectedLinedefs();
 
 						// Update entire display
-						General.Map.Renderer2D.Update3dFloorTagsList(); //mxd
+						General.Map.Renderer2D.UpdateExtraFloorFlag(); //mxd
 						General.Interface.RedrawDisplay();
 					}
 				}
@@ -489,6 +491,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
+			if(panning) return; //mxd. Skip all this jass while panning
 
 			//mxd
 			if(selectpressed && !editpressed && !selecting) {
@@ -767,6 +770,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					// Update and redraw
 					General.Map.IsChanged = true;
 					General.Interface.RefreshInfo();
+					General.Map.Renderer2D.UpdateExtraFloorFlag(); //mxd
 					General.Interface.RedrawDisplay();
 				}
 			}
@@ -896,7 +900,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				OnMouseMove(e);
 				
 				// Redraw screen
-				General.Map.Renderer2D.Update3dFloorTagsList(); //mxd
+				//General.Map.Renderer2D.UpdateExtraFloorFlag(); //mxd
 				General.Interface.RedrawDisplay();
 			}
 		}
diff --git a/Source/Plugins/BuilderModes/ClassicModes/MakeSectorMode.cs b/Source/Plugins/BuilderModes/ClassicModes/MakeSectorMode.cs
index f6349746f..28e23865f 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/MakeSectorMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/MakeSectorMode.cs
@@ -455,6 +455,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
+			if(panning) return; //mxd. Skip all this jass while panning
 
 			// Highlight the region
 			Highlight((e.Button != MouseButtons.None));
diff --git a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
index 0d18fd323..efacffe68 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/SectorsMode.cs
@@ -481,7 +481,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				if((highlighted != null) && !highlighted.IsDisposed)
 				{
 					renderer.PlotSector(highlighted, General.Colors.Highlight);
-					BuilderPlug.Me.PlotReverseAssociations(renderer, highlightasso);
+					if(!panning) BuilderPlug.Me.PlotReverseAssociations(renderer, highlightasso); //mxd
 				}
 				renderer.Finish();
 			}
@@ -497,7 +497,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			// Render selection
 			if(renderer.StartOverlay(true))
 			{
-				if((highlighted != null) && !highlighted.IsDisposed) BuilderPlug.Me.RenderReverseAssociations(renderer, highlightasso);
+				if(!panning && highlighted != null && !highlighted.IsDisposed) BuilderPlug.Me.RenderReverseAssociations(renderer, highlightasso); //mxd
 				if(selecting) RenderMultiSelection();
 				renderer.Finish();
 			}
@@ -627,7 +627,9 @@ namespace CodeImp.DoomBuilder.BuilderModes
 						General.Interface.OnEditFormValuesChanged += new EventHandler(sectorEditForm_OnValuesChanged);
 						General.Interface.ShowEditSectors(selected);
 						General.Interface.OnEditFormValuesChanged -= sectorEditForm_OnValuesChanged;
-						
+
+						General.Map.Renderer2D.UpdateExtraFloorFlag(); //mxd
+
 						// When a single sector was selected, deselect it now
 						if(selected.Count == 1)
 						{
@@ -649,7 +651,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private void sectorEditForm_OnValuesChanged(object sender, EventArgs e) {
 			// Update entire display
 			General.Map.Map.Update();
-			General.Map.Renderer2D.Update3dFloorTagsList();
+			//General.Map.Renderer2D.UpdateExtraFloorFlag();
 			General.Interface.RedrawDisplay();
 		}
 		
@@ -657,6 +659,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
+			if(panning) return; //mxd. Skip all this jass while panning
 
 			//mxd
 			if(selectpressed && !editpressed && !selecting) {
@@ -1121,6 +1124,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 					// Update and redraw
 					General.Map.IsChanged = true;
 					General.Interface.RefreshInfo();
+					General.Map.Renderer2D.UpdateExtraFloorFlag(); //mxd
 					General.Interface.RedrawDisplay();
 				}
 			}
@@ -1368,7 +1372,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 				UpdateSelectedLabels();
 				
 				// Redraw screen
-				General.Map.Renderer2D.Update3dFloorTagsList(); //mxd
+				//General.Map.Renderer2D.Update3dFloorIndicators(); //mxd
 				General.Interface.RedrawDisplay();
 			}
 		}
diff --git a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
index 147162bed..44a5d0d96 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/ThingsMode.cs
@@ -147,8 +147,10 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				renderer.PlotLinedefSet(General.Map.Map.Linedefs);
 				renderer.PlotVerticesSet(General.Map.Map.Vertices);
-				for(int i = 0; i < Thing.NUM_ARGS; i++) BuilderPlug.Me.PlotAssociations(renderer, association[i]);
-				if((highlighted != null) && !highlighted.IsDisposed) BuilderPlug.Me.PlotReverseAssociations(renderer, highlightasso);
+				if (!panning) { //mxd
+					for (int i = 0; i < Thing.NUM_ARGS; i++) BuilderPlug.Me.PlotAssociations(renderer, association[i]);
+					if ((highlighted != null) && !highlighted.IsDisposed) BuilderPlug.Me.PlotReverseAssociations(renderer, highlightasso);
+				}
 				renderer.Finish();
 			}
 
@@ -157,10 +159,11 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			{
 				renderer.RenderThingSet(General.Map.ThingsFilter.HiddenThings, Presentation.THINGS_HIDDEN_ALPHA);
 				renderer.RenderThingSet(General.Map.ThingsFilter.VisibleThings, 1.0f);
-				for(int i = 0; i < Thing.NUM_ARGS; i++) BuilderPlug.Me.RenderAssociations(renderer, association[i]);
+				if(!panning) //mxd
+					for(int i = 0; i < Thing.NUM_ARGS; i++) BuilderPlug.Me.RenderAssociations(renderer, association[i]);
 				if((highlighted != null) && !highlighted.IsDisposed)
 				{
-					BuilderPlug.Me.RenderReverseAssociations(renderer, highlightasso);
+					if(!panning) BuilderPlug.Me.RenderReverseAssociations(renderer, highlightasso); //mxd
 					renderer.RenderThing(highlighted, General.Colors.Highlight, 1.0f);
 				}
 
@@ -442,6 +445,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
+			if(panning) return; //mxd. Skip all this jass while panning
 
 			//mxd
 			if(selectpressed && !editpressed && !selecting) {
diff --git a/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs b/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
index 0a76e773a..6b3f45185 100644
--- a/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
+++ b/Source/Plugins/BuilderModes/ClassicModes/VerticesMode.cs
@@ -428,7 +428,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		private void vertexEditForm_OnValuesChanged(object sender, EventArgs e) {
 			// Update entire display
 			General.Map.Map.Update();
-			General.Map.Renderer2D.Update3dFloorTagsList();
+			//General.Map.Renderer2D.Update3dFloorIndicators();
 			General.Interface.RedrawDisplay();
 		}
 		
@@ -436,6 +436,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 		public override void OnMouseMove(MouseEventArgs e)
 		{
 			base.OnMouseMove(e);
+			if(panning) return; //mxd. Skip all this jass while panning
 
 			//mxd
 			if(selectpressed && !editpressed && !selecting) {
@@ -880,6 +881,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			OnMouseMove(e);
 
 			// Redraw screen
+			General.Map.Renderer2D.UpdateExtraFloorFlag(); //mxd
 			General.Interface.RedrawDisplay();
 		}
 
diff --git a/Source/Plugins/BuilderModes/General/BuilderPlug.cs b/Source/Plugins/BuilderModes/General/BuilderPlug.cs
index 6f6298c0f..9228866f7 100644
--- a/Source/Plugins/BuilderModes/General/BuilderPlug.cs
+++ b/Source/Plugins/BuilderModes/General/BuilderPlug.cs
@@ -467,7 +467,7 @@ namespace CodeImp.DoomBuilder.BuilderModes
             drawRectModeMenuItem.Enabled = true;
             drawEllipseModeMenuItem.Enabled = true;
 
-			General.Map.Renderer2D.Update3dFloorTagsList(); //mxd
+			General.Map.Renderer2D.UpdateExtraFloorFlag(); //mxd
 		}
 		
 		// Map closed
diff --git a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
index 14e39ee58..379a58169 100644
--- a/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
+++ b/Source/Plugins/BuilderModes/VisualModes/BaseVisualThing.cs
@@ -197,15 +197,19 @@ namespace CodeImp.DoomBuilder.BuilderModes
 			Vector3D pos = Thing.Position;
 			if(Thing.Type == 9501)
 			{
-				// This is a special thing that needs special positioning
-				SectorData sd = mode.GetSectorData(Thing.Sector);
-				pos.z = sd.Ceiling.sector.CeilHeight + Thing.Position.z;
+				if(Thing.Sector != null) { //mxd
+					// This is a special thing that needs special positioning
+					SectorData sd = mode.GetSectorData(Thing.Sector);
+					pos.z = sd.Ceiling.sector.CeilHeight + Thing.Position.z;
+				}
 			}
 			else if(Thing.Type == 9500)
 			{
-				// This is a special thing that needs special positioning
-				SectorData sd = mode.GetSectorData(Thing.Sector);
-				pos.z = sd.Floor.sector.FloorHeight + Thing.Position.z;
+				if(Thing.Sector != null) { //mxd
+					// This is a special thing that needs special positioning
+					SectorData sd = mode.GetSectorData(Thing.Sector);
+					pos.z = sd.Floor.sector.FloorHeight + Thing.Position.z;
+				}
 			}
 			else if(info.AbsoluteZ)
 			{
diff --git a/Source/Plugins/TagExplorer/BuilderPlug.cs b/Source/Plugins/TagExplorer/BuilderPlug.cs
index a86d6b87a..6bd1af05f 100644
--- a/Source/Plugins/TagExplorer/BuilderPlug.cs
+++ b/Source/Plugins/TagExplorer/BuilderPlug.cs
@@ -1,10 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-
-using CodeImp.DoomBuilder.Config;
+using CodeImp.DoomBuilder.Config;
 using CodeImp.DoomBuilder.Controls;
-using CodeImp.DoomBuilder.Editing;
 using CodeImp.DoomBuilder.Plugins;
 
 namespace CodeImp.DoomBuilder.TagExplorer
-- 
GitLab