diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj
index 862059e0603402e3495868ebd40d7914be4241d1..356382542d42487aea87226606b6c6143d706bc7 100644
--- a/Source/Core/Builder.csproj
+++ b/Source/Core/Builder.csproj
@@ -204,7 +204,6 @@
     <Compile Include="Data\PatchNames.cs" />
     <Compile Include="Data\PK3Reader.cs" />
     <Compile Include="Data\Playpal.cs" />
-    <Compile Include="Data\PreviewManager.cs" />
     <Compile Include="Data\ResourceImage.cs" />
     <Compile Include="Data\SimpleTextureImage.cs" />
     <Compile Include="Data\SpriteImage.cs" />
diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs
index 585a4c0c5ff4655e029f6e08e287c8d03d130e73..a378bd3872f8e7d3e0bb872126a8e2105c37b477 100755
--- a/Source/Core/Data/DataManager.cs
+++ b/Source/Core/Data/DataManager.cs
@@ -105,9 +105,6 @@ namespace CodeImp.DoomBuilder.Data
         private int threadsfinished;
 		private bool notifiedbusy;
 		
-		// Image previews
-		private PreviewManager previews;
-		
 		// Special images
 		private ImageData missingtexture3d;
 		private ImageData unknowntexture3d;
@@ -172,7 +169,6 @@ namespace CodeImp.DoomBuilder.Data
 		internal IEnumerable<DataReader> Containers { get { return containers; } }
 
 		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 List<string> TextureNames { get { return texturenames; } }
@@ -184,7 +180,9 @@ namespace CodeImp.DoomBuilder.Data
 		public ImageData Hourglass3D { get { return hourglass3d; } }
 		public ImageData Crosshair3D { get { return crosshair; } }
 		public ImageData CrosshairBusy3D { get { return crosshairbusy; } }
-		public ImageData WhiteTexture { get { return whitetexture; } }
+        public Texture LoadingTexture { get; private set; }
+        public Texture FailedTexture { get; private set; }
+        public ImageData WhiteTexture { get { return whitetexture; } }
 		public ImageData BlackTexture { get { return blacktexture; } } //mxd
 		public ImageData ThingTexture { get { return thingtexture; } } //mxd
 		internal ImageData FolderTexture { get { return foldertexture; } } //mxd
@@ -204,7 +202,7 @@ namespace CodeImp.DoomBuilder.Data
 			get
 			{
 				if(imageque != null)
-					return (backgroundloader != null) && backgroundloader.Any(x => x.IsAlive) && ((imageque.Count > 0) || previews.IsLoading);
+					return (backgroundloader != null) && backgroundloader.Any(x => x.IsAlive) && ((imageque.Count > 0));
 				return false;
 			}
 		}
@@ -236,16 +234,14 @@ namespace CodeImp.DoomBuilder.Data
         // Constructor
         internal DataManager()
 		{
-			// We have no destructor
-			GC.SuppressFinalize(this);
+            FailedTexture = new Texture(General.Map.Graphics, Properties.Resources.Failed);
+            LoadingTexture = new Texture(General.Map.Graphics, Properties.Resources.Hourglass);
 
-			// Load special images (mxd: the rest is loaded in LoadInternalTextures())
-			whitetexture = new ResourceImage("CodeImp.DoomBuilder.Resources.White.png") { UseColorCorrection = false };
+            // Load special images (mxd: the rest is loaded in LoadInternalTextures())
+            whitetexture = new ResourceImage("CodeImp.DoomBuilder.Resources.White.png") { UseColorCorrection = false };
 			whitetexture.LoadImage();
-			whitetexture.CreateTexture();
 			blacktexture = new ResourceImage("CodeImp.DoomBuilder.Resources.Black.png") { UseColorCorrection = false }; //mxd
 			blacktexture.LoadImage(); //mxd
-			blacktexture.CreateTexture(); //mxd
 			unknownimage = new UnknownImage(Properties.Resources.UnknownImage); //mxd. There should be only one!
 
 			//mxd. Textures browser images
@@ -268,7 +264,6 @@ namespace CodeImp.DoomBuilder.Data
 			foreach(ImageData data in commenttextures)
 			{
 				data.LoadImage();
-				data.CreateTexture();
 			}
 		}
 		
@@ -356,7 +351,6 @@ namespace CodeImp.DoomBuilder.Data
 			flatnamesshorttofull = new Dictionary<long, long>(); //mxd
 			flatnamesfulltoshort = new Dictionary<long, long>(); //mxd
 			imageque = new Queue<ImageData>();
-			previews = new PreviewManager();
 			texturesets = new List<MatchingTextureSet>();
 			usedtextures = new Dictionary<long, bool>(); //mxd
 			usedflats = new Dictionary<long, bool>(); //mxd
@@ -634,10 +628,6 @@ namespace CodeImp.DoomBuilder.Data
 			// Stop background loader
 			StopBackgroundLoader();
 			
-			// Dispose preview manager
-			previews.Dispose();
-			previews = null;
-			
 			// Dispose decorate
 			decorate.Dispose();
 			
@@ -845,72 +835,55 @@ namespace CodeImp.DoomBuilder.Data
 					}
 					else
 					{
-						// Process previews only when we don't have images to process
-						// because these are lower priority than the actual images
-						if(previews.BackgroundLoad())
-						{
-							// Wait a bit and update icon
-							if(!notifiedbusy)
-							{
-								notifiedbusy = true;
-								General.MainWindow.UpdateStatus();
-							}
-						}
-						else
-						{
-                            bool lastthread = false;
-                            lock (syncobject)
-                            {
-                                threadsfinished++;
-                                if (threadsfinished == backgroundloader.Length)
-                                    lastthread = true;
-                            }
+                        bool lastthread = false;
+                        lock (syncobject)
+                        {
+                            threadsfinished++;
+                            if (threadsfinished == backgroundloader.Length)
+                                lastthread = true;
+                        }
 
-                            if (lastthread)
+                        if (lastthread)
+                        {
+                            // Timing
+                            if (loadfinishtime == 0)
                             {
-                                // Timing
-                                if (loadfinishtime == 0)
+                                //mxd. Release PK3 files
+                                foreach (DataReader reader in containers)
+                                {
+                                    if (reader is PK3Reader) (reader as PK3Reader).BatchMode = false;
+                                }
+
+                                loadfinishtime = Clock.CurrentTime;
+                                string deltatimesec = ((loadfinishtime - loadstarttime) / 1000.0f).ToString("########0.00");
+                                General.WriteLogLine("Resources loading took " + deltatimesec + " seconds");
+                                loadstarttime = 0; //mxd
+
+                                lock (syncobject)
                                 {
-                                    //mxd. Release PK3 files
-                                    foreach (DataReader reader in containers)
-                                    {
-                                        if (reader is PK3Reader) (reader as PK3Reader).BatchMode = false;
-                                    }
-
-                                    loadfinishtime = Clock.CurrentTime;
-                                    string deltatimesec = ((loadfinishtime - loadstarttime) / 1000.0f).ToString("########0.00");
-                                    General.WriteLogLine("Resources loading took " + deltatimesec + " seconds");
-                                    loadstarttime = 0; //mxd
-
-                                    lock (syncobject)
-                                    {
-                                        threadsfinished = 0;
-                                    }
-
-                                    //mxd. Show more detailed message
-                                    if (notifiedbusy)
-                                    {
-                                        notifiedbusy = false;
-                                        General.MainWindow.ResourcesLoaded(deltatimesec);
-                                    }
+                                    threadsfinished = 0;
                                 }
-                                else if (notifiedbusy) //mxd. Sould never happen (?)
+
+                                //mxd. Show more detailed message
+                                if (notifiedbusy)
                                 {
                                     notifiedbusy = false;
-                                    General.MainWindow.UpdateStatus();
+                                    General.MainWindow.ResourcesLoaded(deltatimesec);
                                 }
                             }
-
-                            // Wait until there's more to do.
-                            lock (syncobject)
+                            else if (notifiedbusy) //mxd. Sould never happen (?)
                             {
-                                if (imageque.Count == 0) Monitor.Wait(syncobject);
+                                notifiedbusy = false;
+                                General.MainWindow.UpdateStatus();
                             }
                         }
-                    }
 
-                    if (image == null)
-                        Thread.Sleep(1);
+                        // Wait until there's more to do.
+                        lock (syncobject)
+                        {
+                            if (imageque.Count == 0) Monitor.Wait(syncobject);
+                        }
+                    }
                 }
                 while (true);
 			}
@@ -925,7 +898,8 @@ namespace CodeImp.DoomBuilder.Data
 			{
 				// Add for loading
 				img.ImageState = ImageLoadState.Loading;
-				lock(syncobject) { imageque.Enqueue(img); Monitor.Pulse(syncobject); }
+                img.PreviewState = ImageLoadState.Loading;
+                lock (syncobject) { imageque.Enqueue(img); Monitor.Pulse(syncobject); }
 			}
 			
 			// Unload this image?
@@ -933,7 +907,8 @@ namespace CodeImp.DoomBuilder.Data
 			{
 				// Add for unloading
 				img.ImageState = ImageLoadState.Unloading;
-				lock(syncobject) { imageque.Enqueue(img); Monitor.Pulse(syncobject); }
+                img.PreviewState = ImageLoadState.Unloading;
+                lock (syncobject) { imageque.Enqueue(img); Monitor.Pulse(syncobject); }
 			}
 		}
 
@@ -954,13 +929,13 @@ namespace CodeImp.DoomBuilder.Data
 			modeldefentries.Remove(type);
 			return false;
 		}
-		
-		#endregion
-		
-		#region ================== Palette
 
-		// This loads the PLAYPAL palette
-		private void LoadPalette()
+        #endregion
+
+        #region ================== Palette
+
+        // This loads the PLAYPAL palette
+        private void LoadPalette()
 		{
 			// Go for all opened containers
 			for(int i = containers.Count - 1; i >= 0; i--)
@@ -1001,9 +976,6 @@ namespace CodeImp.DoomBuilder.Data
 						list.Remove(img.LongName);
 						list.Add(img.LongName, img);
 						counter++;
-
-						// Add to preview manager
-						previews.AddImage(img);
 					}
 				}
 			}
@@ -1070,9 +1042,6 @@ namespace CodeImp.DoomBuilder.Data
 						{
 							nametranslation.Remove(img.LongName);
 						}
-						
-						// Add to preview manager
-						previews.AddImage(img);
 					}
 				}
 			}
@@ -1246,7 +1215,6 @@ namespace CodeImp.DoomBuilder.Data
 			crosshairbusy = LoadInternalTexture("CrosshairBusy.png");
 
 			thingtexture.UseColorCorrection = false;
-			thingtexture.CreateTexture();
 		}
 
 		//mxd
@@ -1303,9 +1271,6 @@ namespace CodeImp.DoomBuilder.Data
 						{
 							nametranslation.Remove(img.LongName);
 						}
-
-						// Add to preview manager
-						previews.AddImage(img);
 					}
 				}
 			}
@@ -1434,8 +1399,6 @@ namespace CodeImp.DoomBuilder.Data
 							textures[img.LongName] = replacer;
 							//replaced = true;
 
-							// Add to preview manager
-							previews.AddImage(replacer);
 							counter++;
 						}
 
@@ -1448,8 +1411,6 @@ namespace CodeImp.DoomBuilder.Data
 							flats[img.LongName] = replacer;
 							//replaced = true;
 
-							// Add to preview manager
-							previews.AddImage(replacer);
 							counter++;
 						}
 
@@ -1461,8 +1422,6 @@ namespace CodeImp.DoomBuilder.Data
 							sprites[img.LongName] = replacer;
 							//replaced = true;
 
-							// Add to preview manager
-							previews.AddImage(replacer);
 							counter++;
 						}
 
@@ -1586,9 +1545,6 @@ namespace CodeImp.DoomBuilder.Data
 
 						// Add to collection
 						sprites.Add(image.LongName, image);
-
-						// Add to preview manager
-						previews.AddImage(image);
 					}
 				}
 				else
@@ -1634,9 +1590,6 @@ namespace CodeImp.DoomBuilder.Data
 						{
 							image = sprites[info.SpriteLongName];
 						}
-
-						// Add to preview manager
-						if(image != null) previews.AddImage(image);
 					}
 				}
 			}
@@ -2460,9 +2413,6 @@ namespace CodeImp.DoomBuilder.Data
 
 										// Add to collection
 										sprites.Add(sprite.LongName, sprite);
-
-										// Add to preview manager
-										previews.AddImage(sprite);
 									}
 
 									// Apply VOXELDEF settings to the preview image...
@@ -2828,9 +2778,6 @@ namespace CodeImp.DoomBuilder.Data
 						textures[camteximage.LongName] = camteximage;
 						flats[camteximage.LongName] = camteximage;
 
-						// Add to preview manager
-						previews.AddImage(camteximage);
-
 						// Add to container's texture set
 						currentreader.TextureSet.AddFlat(camteximage);
 						currentreader.TextureSet.AddTexture(camteximage);
@@ -3304,7 +3251,6 @@ namespace CodeImp.DoomBuilder.Data
 				
 				// Use the built-in texture
 				ImageData tex = LoadInternalTexture("MissingSky3D.png");
-				tex.CreateTexture();
                 Bitmap bmp = tex.GetBitmap();
                 Bitmap sky;
                 lock (bmp)
diff --git a/Source/Core/Data/DynamicBitmapImage.cs b/Source/Core/Data/DynamicBitmapImage.cs
index a27b23285fc017821bae33280f2b5ee65fd479fa..0ac7dbc84ab7e632494c7bfb259028e1fd13c24e 100755
--- a/Source/Core/Data/DynamicBitmapImage.cs
+++ b/Source/Core/Data/DynamicBitmapImage.cs
@@ -69,7 +69,6 @@ namespace CodeImp.DoomBuilder.Data
 		// Reload the resource
 		public void ReloadResource()
 		{
-			CreateTexture();
 		}
 
 		#endregion
diff --git a/Source/Core/Data/ImageData.cs b/Source/Core/Data/ImageData.cs
index 33f519d72a7bb3ee2e175cddb15d96ae74757a2a..05fdeff1123f0decf8b878a2b91b81ea9c818fb3 100755
--- a/Source/Core/Data/ImageData.cs
+++ b/Source/Core/Data/ImageData.cs
@@ -68,7 +68,6 @@ namespace CodeImp.DoomBuilder.Data
         // Loading
         private ImageLoadState previewstate;
         private ImageLoadState imagestate;
-        private int previewindex;
         private bool loadfailed;
         private bool allowunload;
 
@@ -79,9 +78,10 @@ namespace CodeImp.DoomBuilder.Data
         // GDI bitmap
         private Bitmap _bitmap;
 		protected Bitmap bitmap { get { return _bitmap; } }
-		
-		// Direct3D texture
-		private int mipmaplevels;	// 0 = all mipmaps
+        private Bitmap previewbitmap;
+
+        // Direct3D texture
+        private int mipmaplevels;	// 0 = all mipmaps
 		protected bool dynamictexture;
 		private Texture texture;
 		
@@ -104,7 +104,7 @@ namespace CodeImp.DoomBuilder.Data
 		public bool HasPatchWithSameName { get { return hasPatchWithSameName; } } //mxd
 		internal bool HasLongName { get { return hasLongName; } } //mxd
 		public bool UseColorCorrection { get { return usecolorcorrection; } set { usecolorcorrection = value; } }
-		public Texture Texture { get { return texture; } }
+		public Texture Texture { get { return GetTexture(); } }
 		public bool IsPreviewLoaded { get { return (previewstate == ImageLoadState.Ready); } }
 		public bool IsImageLoaded { get { return (imagestate == ImageLoadState.Ready); } }
 		public bool LoadFailed { get { return loadfailed; } }
@@ -117,7 +117,6 @@ namespace CodeImp.DoomBuilder.Data
 		public int MipMapLevels { get { return mipmaplevels; } set { mipmaplevels = value; } }
 		public virtual int Width { get { return width; } }
 		public virtual int Height { get { return height; } }
-		internal int PreviewIndex { get { return previewindex; } set { previewindex = value; } }
 		//mxd. Scaled texture size is integer in ZDoom.
 		public virtual float ScaledWidth { get { return (float)Math.Round(width * scale.x); } }
 		public virtual float ScaledHeight { get { return (float)Math.Round(height * scale.y); } }
@@ -256,6 +255,7 @@ namespace CodeImp.DoomBuilder.Data
             LocalLoadResult loadResult = LocalLoadImage();
 
             ConvertImageFormat(loadResult);
+            MakeImagePreview(loadResult);
 
             General.MainWindow.RunOnUIThread(() =>
             {
@@ -272,7 +272,9 @@ namespace CodeImp.DoomBuilder.Data
 
                 // Image is ready
                 imagestate = ImageLoadState.Ready;
+                previewstate = ImageLoadState.Ready;
                 _bitmap = loadResult.bitmap;
+                previewbitmap = loadResult.preview;
                 if (loadResult.uiThreadWork != null)
                     loadResult.uiThreadWork();
             });
@@ -311,6 +313,7 @@ namespace CodeImp.DoomBuilder.Data
             }
 
             public Bitmap bitmap;
+            public Bitmap preview;
             public List<LogMessage> messages;
             public Action uiThreadWork;
         }
@@ -517,28 +520,89 @@ namespace CodeImp.DoomBuilder.Data
 
             loadResult.bitmap = bitmap;
 		}
-		
-		// This creates the Direct3D texture
-		public virtual void CreateTexture()
+
+        // Dimensions of a single preview image
+        const int MAX_PREVIEW_SIZE = 256; //mxd
+
+        // This makes a preview for the given image and updates the image settings
+        private void MakeImagePreview(LocalLoadResult loadResult)
+        {
+            if (loadResult.bitmap == null)
+                return;
+
+            Bitmap image = loadResult.bitmap;
+            Bitmap preview;
+
+            int imagewidth = image.Width;
+            int imageheight = image.Height;
+
+            // Determine preview size
+            float scalex = (imagewidth > MAX_PREVIEW_SIZE) ? (MAX_PREVIEW_SIZE / (float)imagewidth) : 1.0f;
+            float scaley = (imageheight > MAX_PREVIEW_SIZE) ? (MAX_PREVIEW_SIZE / (float)imageheight) : 1.0f;
+            float scale = Math.Min(scalex, scaley);
+            int previewwidth = (int)(imagewidth * scale);
+            int previewheight = (int)(imageheight * scale);
+            if (previewwidth < 1) previewwidth = 1;
+            if (previewheight < 1) previewheight = 1;
+
+            //mxd. Expected and actual image sizes and format match?
+            if (previewwidth == imagewidth && previewheight == imageheight && image.PixelFormat == PixelFormat.Format32bppArgb)
+            {
+                preview = new Bitmap(image);
+            }
+            else
+            {
+                // Make new image
+                preview = new Bitmap(previewwidth, previewheight, PixelFormat.Format32bppArgb);
+                Graphics g = Graphics.FromImage(preview);
+                g.PageUnit = GraphicsUnit.Pixel;
+                //g.CompositingQuality = CompositingQuality.HighQuality; //mxd
+                g.InterpolationMode = InterpolationMode.NearestNeighbor;
+                //g.SmoothingMode = SmoothingMode.HighQuality; //mxd
+                g.PixelOffsetMode = PixelOffsetMode.None;
+                //g.Clear(Color.Transparent); //mxd
+
+                // Draw image onto atlas
+                Rectangle atlasrect = new Rectangle(0, 0, previewwidth, previewheight);
+                RectangleF imgrect = General.MakeZoomedRect(new Size(imagewidth, imageheight), atlasrect);
+                if (imgrect.Width < 1.0f)
+                {
+                    imgrect.X -= 0.5f - imgrect.Width * 0.5f;
+                    imgrect.Width = 1.0f;
+                }
+                if (imgrect.Height < 1.0f)
+                {
+                    imgrect.Y -= 0.5f - imgrect.Height * 0.5f;
+                    imgrect.Height = 1.0f;
+                }
+                g.DrawImage(image, imgrect);
+                g.Dispose();
+            }
+
+            loadResult.preview = preview;
+        }
+
+        Texture GetTexture()
 		{
-			// Only do this when texture is not created yet
-			if(((texture == null) || (texture.Disposed)) && this.IsImageLoaded && !loadfailed)
-			{
-				Bitmap img = bitmap;
-				if(loadfailed) img = Properties.Resources.Failed;
+            if (texture != null)
+                return texture;
+            else if (loadfailed)
+                return General.Map.Data.FailedTexture;
+            else if (imagestate == ImageLoadState.Loading)
+                return General.Map.Data.LoadingTexture;
 
-                texture = new Texture(General.Map.Graphics, img);
-					
-				if(dynamictexture)
-				{
-					if((width != texture.Width) || (height != texture.Height))
-						throw new Exception("Could not create a texture with the same size as the image.");
-				}
+            texture = new Texture(General.Map.Graphics, bitmap);
+
+            if (dynamictexture)
+            {
+                if ((width != texture.Width) || (height != texture.Height))
+                    throw new Exception("Could not create a texture with the same size as the image.");
+            }
 
 #if DEBUG
-				texture.Tag = name; //mxd. Helps with tracking undisposed resources...
+			texture.Tag = name; //mxd. Helps with tracking undisposed resources...
 #endif
-			}
+            return texture;
 		}
 
 		// This updates a dynamic texture
@@ -556,37 +620,10 @@ namespace CodeImp.DoomBuilder.Data
 		// This destroys the Direct3D texture
 		public void ReleaseTexture()
 		{
-			// Trash it
-			if(texture != null) texture.Dispose();
+			texture?.Dispose();
 			texture = null;
 		}
 
-		// This draws a preview
-		public virtual void DrawPreview(Graphics target, Point targetpos)
-		{
-			// Preview ready?
-			if(!loadfailed && (previewstate == ImageLoadState.Ready))
-			{
-				// Draw preview
-				General.Map.Data.Previews.DrawPreview(previewindex, target, targetpos);
-			}
-			// Loading failed?
-			else if(loadfailed)
-			{
-				// Draw error bitmap
-				targetpos = new Point(targetpos.X + ((PreviewManager.MAX_PREVIEW_SIZE - Properties.Resources.Hourglass.Width) >> 1),
-										targetpos.Y + ((PreviewManager.MAX_PREVIEW_SIZE - Properties.Resources.Hourglass.Height) >> 1));
-				target.DrawImageUnscaled(Properties.Resources.Failed, targetpos);
-			}
-			else
-			{
-				// Draw loading bitmap
-				targetpos = new Point(targetpos.X + ((PreviewManager.MAX_PREVIEW_SIZE - Properties.Resources.Hourglass.Width) >> 1),
-										targetpos.Y + ((PreviewManager.MAX_PREVIEW_SIZE - Properties.Resources.Hourglass.Height) >> 1));
-				target.DrawImageUnscaled(Properties.Resources.Hourglass, targetpos);
-			}
-		}
-		
 		// This returns a preview image
 		public virtual Image GetPreview()
 		{
@@ -594,7 +631,7 @@ namespace CodeImp.DoomBuilder.Data
 			if(previewstate == ImageLoadState.Ready)
 			{
 				// Make a copy
-				return General.Map.Data.Previews.GetPreviewCopy(previewindex);
+				return new Bitmap(previewbitmap);
 			}
 				
 			// Loading failed?
diff --git a/Source/Core/Data/PreviewManager.cs b/Source/Core/Data/PreviewManager.cs
deleted file mode 100755
index 7463c1f7e82c0985e3587a983bdf5dfe6abd7cc4..0000000000000000000000000000000000000000
--- a/Source/Core/Data/PreviewManager.cs
+++ /dev/null
@@ -1,279 +0,0 @@
-
-#region ================== Copyright (c) 2007 Pascal vd Heiden
-
-/*
- * Copyright (c) 2007 Pascal vd Heiden, www.codeimp.com
- * This program is released under GNU General Public License
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- */
-
-#endregion
-
-#region ================== Namespaces
-
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.Drawing.Drawing2D;
-
-#endregion
-
-namespace CodeImp.DoomBuilder.Data
-{
-	public class PreviewManager
-	{
-		#region ================== Constants
-
-		// Image format
-		private const PixelFormat IMAGE_FORMAT = PixelFormat.Format32bppArgb;
-
-		// Dimensions of a single preview image
-		public const int MAX_PREVIEW_SIZE = 256; //mxd
-
-		#endregion
-
-		#region ================== Variables
-		
-		// Images
-		private List<Bitmap> images;
-		
-		// Processing
-		private Queue<ImageData> imageque;
-		private static object syncroot = new object(); //mxd
-
-		// Disposing
-		private bool isdisposed;
-
-		#endregion
-
-		#region ================== Properties
-		
-		// Disposing
-		internal bool IsDisposed { get { return isdisposed; } }
-		
-		// Loading
-		internal bool IsLoading
-		{
-			get
-			{
-				return (imageque.Count > 0);
-			}
-		}
-		
-		#endregion
-
-		#region ================== Constructor / Disposer
-
-		// Constructor
-		internal PreviewManager()
-		{
-			// Initialize
-			images = new List<Bitmap>();
-			imageque = new Queue<ImageData>();
-			
-			// We have no destructor
-			GC.SuppressFinalize(this);
-		}
-
-		// Disposer
-		internal void Dispose()
-		{
-			// Not already disposed?
-			if(!isdisposed)
-			{
-				// Clean up
-				foreach(Bitmap b in images) b.Dispose();
-				images = null;
-				
-				// Done
-				isdisposed = true;
-			}
-		}
-
-		#endregion
-		
-		#region ================== Private Methods
-		
-		// This makes a preview for the given image and updates the image settings
-		private void MakeImagePreview(ImageData img)
-		{
-			lock(img)
-			{
-				// Load image if needed
-				if(!img.IsImageLoaded && !img.LoadFailed) img.LoadImage(false);
-				int imagewidth, imageheight;
-				Bitmap image = img.GetBitmap(); //mxd
-                Bitmap preview;
-                lock (image)
-                {
-                    if (!img.LoadFailed)
-                    {
-                        imagewidth = img.Width;
-                        imageheight = img.Height;
-                    }
-                    else
-                    {
-                        Size size = image.Size; //mxd
-                        imagewidth = size.Width;
-                        imageheight = size.Height;
-                    }
-
-                    // Determine preview size
-                    float scalex = (img.Width > MAX_PREVIEW_SIZE) ? (MAX_PREVIEW_SIZE / (float)imagewidth) : 1.0f;
-                    float scaley = (img.Height > MAX_PREVIEW_SIZE) ? (MAX_PREVIEW_SIZE / (float)imageheight) : 1.0f;
-                    float scale = Math.Min(scalex, scaley);
-                    int previewwidth = (int)(imagewidth * scale);
-                    int previewheight = (int)(imageheight * scale);
-                    if (previewwidth < 1) previewwidth = 1;
-                    if (previewheight < 1) previewheight = 1;
-
-                    //mxd. Expected and actual image sizes and format match?
-                    if (previewwidth == imagewidth && previewheight == imageheight && image.PixelFormat == IMAGE_FORMAT)
-                    {
-                        preview = new Bitmap(image);
-                    }
-                    else
-                    {
-                        // Make new image
-                        preview = new Bitmap(previewwidth, previewheight, IMAGE_FORMAT);
-                        Graphics g = Graphics.FromImage(preview);
-                        g.PageUnit = GraphicsUnit.Pixel;
-                        //g.CompositingQuality = CompositingQuality.HighQuality; //mxd
-                        g.InterpolationMode = InterpolationMode.NearestNeighbor;
-                        //g.SmoothingMode = SmoothingMode.HighQuality; //mxd
-                        g.PixelOffsetMode = PixelOffsetMode.None;
-                        //g.Clear(Color.Transparent); //mxd
-
-                        // Draw image onto atlas
-                        Rectangle atlasrect = new Rectangle(0, 0, previewwidth, previewheight);
-                        RectangleF imgrect = General.MakeZoomedRect(new Size(imagewidth, imageheight), atlasrect);
-                        if (imgrect.Width < 1.0f)
-                        {
-                            imgrect.X -= 0.5f - imgrect.Width * 0.5f;
-                            imgrect.Width = 1.0f;
-                        }
-                        if (imgrect.Height < 1.0f)
-                        {
-                            imgrect.Y -= 0.5f - imgrect.Height * 0.5f;
-                            imgrect.Height = 1.0f;
-                        }
-                        g.DrawImage(image, imgrect);
-                        g.Dispose();
-                    }
-                }
-				
-				// Unload image if no longer needed
-				if(!img.IsReferenced) img.UnloadImage();
-				
-				lock(images)
-				{
-					// Set numbers
-					img.PreviewIndex = images.Count;
-					img.PreviewState = ImageLoadState.Ready;
-					
-					// Add to previews list
-					images.Add(preview);
-				}
-			}
-		}
-
-		#endregion
-		
-		#region ================== Public Methods
-
-		// This draws a preview centered in a target
-		internal void DrawPreview(int previewindex, Graphics target, Point targetpos)
-		{
-			Bitmap image;
-
-			// Get the preview we need
-			lock(images) { image = images[previewindex]; }
-
-			// Adjust offset for the size of the preview image
-			targetpos.X += (MAX_PREVIEW_SIZE - image.Width) >> 1;
-			targetpos.Y += (MAX_PREVIEW_SIZE - image.Height) >> 1;
-			
-			// Draw from atlas to target
-			lock(syncroot)
-			{
-				target.DrawImageUnscaled(image, targetpos.X, targetpos.Y);
-			}
-		}
-
-		// This returns a copy of the preview
-		internal Bitmap GetPreviewCopy(int previewindex)
-		{
-			Bitmap image;
-
-			// Get the preview we need
-			lock(images) { image = images[previewindex]; }
-
-			// Make a copy
-			lock(syncroot)
-			{
-				return new Bitmap(image);
-			}
-		}
-
-		// Background loading
-		// Return true when we have more work to do, so that the
-		// thread will not wait too long before calling again
-		internal bool BackgroundLoad()
-		{
-			// Get next item
-			ImageData image = null;
-			lock(imageque)
-			{
-				// Fetch next image to process
-				if(imageque.Count > 0) image = imageque.Dequeue();
-			}
-
-			// Any image to process?
-			if(image != null)
-			{
-				// Make image preview?
-				if(!image.IsPreviewLoaded) MakeImagePreview(image);
-			}
-
-			return (image != null);
-		}
-		
-		// This adds an image for preview creation
-		internal void AddImage(ImageData image)
-		{
-			lock(imageque)
-			{
-				// Add to list
-				image.PreviewState = ImageLoadState.Loading;
-				imageque.Enqueue(image);
-			}
-		}
-
-
-		#if DEBUG
-		/*internal void DumpAtlases()
-		{
-			lock(images)
-			{
-				int index = 0;
-				foreach(Bitmap a in images)
-				{
-					lock(a)
-					{
-						string file = Path.Combine(General.AppPath, "atlas" + index++ + ".png");
-						a.Save(file, ImageFormat.Png);
-					}
-				}
-			}
-		}*/
-		#endif
-		
-		#endregion
-	}
-}
diff --git a/Source/Core/Editing/GridSetup.cs b/Source/Core/Editing/GridSetup.cs
index 31a253f82f903fa9a9f6b24292730f790102ae71..6b668d1cab60ee3f986b03af2fd63308ca07321d 100755
--- a/Source/Core/Editing/GridSetup.cs
+++ b/Source/Core/Editing/GridSetup.cs
@@ -235,7 +235,6 @@ namespace CodeImp.DoomBuilder.Editing
 
 			// Make sure it is loaded
 			backimage.LoadImage();
-			backimage.CreateTexture();
 		}
 		
 		// This returns the next higher coordinate
diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs
index e6f76bfac2e9bd73598a539504b39d8f5b5b77fe..96e03289a54c9d9c2e608a21e205b73c0a7c81e8 100755
--- a/Source/Core/GZBuilder/md3/ModelReader.cs
+++ b/Source/Core/GZBuilder/md3/ModelReader.cs
@@ -147,10 +147,6 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 					//add loaded data to ModeldefEntry
 					mde.Model.Meshes.AddRange(result.Meshes);
 
-					//prepare UnknownTexture3D... just in case :)
-					if(General.Map.Data.UnknownTexture3D.Texture == null || General.Map.Data.UnknownTexture3D.Texture.Disposed)
-						General.Map.Data.UnknownTexture3D.CreateTexture();
-
 					//load texture
 					List<string> errors = new List<string>();
 
@@ -282,9 +278,6 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 					if (!image.IsImageLoaded)
 						image.LoadImage();
 
-					if (image.Texture == null)
-						image.CreateTexture();
-
 					t = image.Texture;
 
 					break;
@@ -304,9 +297,6 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 					if (!image.IsImageLoaded)
 						image.LoadImage();
 
-					if (image.Texture == null)
-						image.CreateTexture();
-
 					t = image.Texture;
 				}
 			}
@@ -323,9 +313,6 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3
 					if (!image.IsImageLoaded)
 						image.LoadImage();
 
-					if (image.Texture == null)
-						image.CreateTexture();
-
 					t = image.Texture;
 				}
 			}
diff --git a/Source/Core/General/General.cs b/Source/Core/General/General.cs
index 34ced7698f5b57a17656f5c03cefbc1841b3da69..2926c88642ed548b8127aa11995a3e42b143d9ce 100755
--- a/Source/Core/General/General.cs
+++ b/Source/Core/General/General.cs
@@ -58,6 +58,7 @@ namespace CodeImp.DoomBuilder
 	internal static bool MessageBeep(MessageBeepType type) { return true; }
 	internal static void ZeroMemory(IntPtr dest, int size) { }
 	internal static int SendMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam) { return 0; }
+    internal static int PostMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam) { return 0; }
 
 #else
         [DllImport("user32.dll")]
@@ -72,7 +73,10 @@ namespace CodeImp.DoomBuilder
 		[DllImport("user32.dll", EntryPoint = "SendMessage", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
 		internal static extern int SendMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);
 
-		[DllImport("user32.dll", SetLastError = true)]
+        [DllImport("user32.dll", EntryPoint = "PostMessage", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
+        internal static extern int PostMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);
+
+        [DllImport("user32.dll", SetLastError = true)]
 		internal static extern bool MessageBeep(MessageBeepType type);
 
 		//[DllImport("kernel32.dll")]
@@ -108,6 +112,7 @@ namespace CodeImp.DoomBuilder
 
 		// SendMessage API
 		internal const int WM_USER = 0x400;
+        internal const int WM_UIACTION = WM_USER + 1;
 		internal const int WM_SYSCOMMAND = 0x112;
         internal const int WM_MOUSEHWHEEL = 0x020E; // [ZZ]
         internal const int SC_KEYMENU = 0xF100;
diff --git a/Source/Core/Rendering/Renderer2D.cs b/Source/Core/Rendering/Renderer2D.cs
index 95644c9ad421eb3f70e4e1c509d43cbbdd19f0d9..350a57c070f46dc7b19178a735c2abea86c9ef2f 100755
--- a/Source/Core/Rendering/Renderer2D.cs
+++ b/Source/Core/Rendering/Renderer2D.cs
@@ -1329,7 +1329,6 @@ namespace CodeImp.DoomBuilder.Rendering
 							sprite.SetUsedInMap(true);
 							continue;
 						}
-						if(sprite.Texture == null) sprite.CreateTexture();
 
 						graphics.SetTexture(sprite.Texture);
 
@@ -1560,10 +1559,6 @@ namespace CodeImp.DoomBuilder.Rendering
 				// Set the rendertarget to the surface texture
                 graphics.StartRendering(true, General.Colors.Background.WithAlpha(0).ToColorValue(), surfacetex, false);
 
-				// Make sure anything we need is loaded
-				General.Map.Data.UnknownTexture3D.CreateTexture();
-				General.Map.Data.MissingTexture3D.CreateTexture(); //mxd
-
 				// Set transformations
 				UpdateTransformations();
 
@@ -1614,9 +1609,6 @@ namespace CodeImp.DoomBuilder.Rendering
 				
 				if(texture != null)
 				{
-					// Make sure the texture is loaded
-					if(!texture.IsImageLoaded) texture.LoadImage();
-					if(texture.Texture == null) texture.CreateTexture();
 					t = texture.Texture;
 				}
 				else
diff --git a/Source/Core/Rendering/Renderer3D.cs b/Source/Core/Rendering/Renderer3D.cs
index 1fa39127504318fff74b3c19b5196ed54a70675d..bd92225255e0049ac53cc8e20aa6f6f417927188 100755
--- a/Source/Core/Rendering/Renderer3D.cs
+++ b/Source/Core/Rendering/Renderer3D.cs
@@ -759,10 +759,6 @@ namespace CodeImp.DoomBuilder.Rendering
 				else
 					curtexture = General.Map.Data.Hourglass3D;
 
-				// Create Direct3D texture if still needed
-				if((curtexture.Texture == null) || curtexture.Texture.Disposed)
-					curtexture.CreateTexture();
-
                 // Apply texture
                 graphics.SetTexture(curtexture.Texture);
 				
@@ -858,10 +854,6 @@ namespace CodeImp.DoomBuilder.Rendering
 					else 
 						curtexture = group.Key;
 
-					// Create Direct3D texture if still needed
-					if((curtexture.Texture == null) || curtexture.Texture.Disposed)
-						curtexture.CreateTexture();
-
                     // Apply texture
                     graphics.SetTexture(curtexture.Texture);
 
@@ -1037,10 +1029,6 @@ namespace CodeImp.DoomBuilder.Rendering
 					else
 						curtexture = General.Map.Data.Hourglass3D;
 
-					// Create Direct3D texture if still needed
-					if((curtexture.Texture == null) || curtexture.Texture.Disposed)
-						curtexture.CreateTexture();
-
                     // Apply texture
                     graphics.SetTexture(curtexture.Texture);
 					curtexturename = g.Texture.LongName;
@@ -1170,10 +1158,6 @@ namespace CodeImp.DoomBuilder.Rendering
 						else
 							curtexture = General.Map.Data.Hourglass3D;
 
-						// Create Direct3D texture if still needed
-						if((curtexture.Texture == null) || curtexture.Texture.Disposed)
-							curtexture.CreateTexture();
-
                         // Apply texture
                         graphics.SetTexture(curtexture.Texture);
 						curtexturename = t.Texture.LongName;
@@ -2019,12 +2003,10 @@ namespace CodeImp.DoomBuilder.Rendering
             // Texture
             if (crosshairbusy)
 			{
-				if(General.Map.Data.CrosshairBusy3D.Texture == null) General.Map.Data.CrosshairBusy3D.CreateTexture();
 				graphics.SetTexture(General.Map.Data.CrosshairBusy3D.Texture);
 			}
 			else
 			{
-				if(General.Map.Data.Crosshair3D.Texture == null) General.Map.Data.Crosshair3D.CreateTexture();
 				graphics.SetTexture(General.Map.Data.Crosshair3D.Texture);
 			}
 			
diff --git a/Source/Core/Rendering/SurfaceManager.cs b/Source/Core/Rendering/SurfaceManager.cs
index 689fa01171a9dd7cce54e32bc6c449976c7d28a3..7c5a3b7ed0a91a9e3b356f592d0c6c4657add683 100755
--- a/Source/Core/Rendering/SurfaceManager.cs
+++ b/Source/Core/Rendering/SurfaceManager.cs
@@ -588,11 +588,7 @@ namespace CodeImp.DoomBuilder.Rendering
 					}
 					else
 					{
-						if(img.IsImageLoaded && !img.LoadFailed) 
-						{
-							if(img.Texture == null) img.CreateTexture();
-						}
-						else 
+						if(!img.IsImageLoaded || img.LoadFailed) 
 						{
 							img = General.Map.Data.WhiteTexture;
 						}
diff --git a/Source/Core/Windows/MainForm.cs b/Source/Core/Windows/MainForm.cs
index 5ddb0b484662c643ee980000a5d0bf599b71f7cd..42e9ef942c4f4afc3e8c0c53b61076facf853868 100755
--- a/Source/Core/Windows/MainForm.cs
+++ b/Source/Core/Windows/MainForm.cs
@@ -4112,6 +4112,24 @@ namespace CodeImp.DoomBuilder.Windows
 
         #region ================== Threadsafe updates
 
+        object syncobject = new object();
+        List<System.Action> queuedActions = new List<System.Action>();
+
+        void ProcessQueuedUIActions()
+        {
+            List<System.Action> queue;
+            lock (syncobject)
+            {
+                queue = queuedActions;
+                queuedActions = new List<System.Action>();
+            }
+
+            foreach (System.Action action in queue)
+            {
+                action();
+            }
+        }
+
         public void RunOnUIThread(System.Action action)
         {
             if (!InvokeRequired)
@@ -4120,7 +4138,15 @@ namespace CodeImp.DoomBuilder.Windows
             }
             else
             {
-                Invoke(action);
+                bool notify;
+                lock (syncobject)
+                {
+                    notify = queuedActions.Count == 0;
+                    queuedActions.Add(action);
+                }
+
+                if (notify)
+                    General.PostMessage(Handle, General.WM_UIACTION, IntPtr.Zero, IntPtr.Zero);
             }
         }
 
@@ -4177,7 +4203,11 @@ namespace CodeImp.DoomBuilder.Windows
 			// Notify message?
 			switch(m.Msg)
 			{
-				case General.WM_SYSCOMMAND:
+                case General.WM_UIACTION:
+                    ProcessQueuedUIActions();
+                    break;
+
+                case General.WM_SYSCOMMAND:
 					// We don't want to open a menu when ALT is pressed
 					if(m.WParam.ToInt32() != General.SC_KEYMENU)
 					{
diff --git a/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs b/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs
index 8e9a0d6f63efafa29f635493889924bfce3473e1..58c12504d9fb98962c167724de2d255ee9a51e38 100755
--- a/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs
+++ b/Source/Plugins/VisplaneExplorer/VisplaneExplorerMode.cs
@@ -281,7 +281,6 @@ namespace CodeImp.DoomBuilder.Plugins.VisplaneExplorer
 			image.UseColorCorrection = false;
 			image.MipMapLevels = 1;
 			image.LoadImage();
-			image.CreateTexture();
 
 			// Make custom presentation
 			CustomPresentation p = new CustomPresentation();